From 0f5996e84af68dfa721f18d7365485698eae046a Mon Sep 17 00:00:00 2001 From: Sabrina Tardio <44158575+SabrinaTardio@users.noreply.github.com> Date: Sat, 9 Nov 2024 00:36:40 +0100 Subject: [PATCH 01/56] point to BSK branch (#3559) Task/Issue URL: https://app.asana.com/0/1204186595873227/1208592742896624/f **Description**: Update BSK Dependency --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index f77ca62941..6f52dde323 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10986,7 +10986,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 207.0.0; + version = 207.1.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index db2341dd12..71287414b2 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "6319be3a8a52024c62cec4320e94536b51f427ee", - "version" : "207.0.0" + "revision" : "26cc3c597990db8a0f8aa4be743b25ce65076c95", + "version" : "207.1.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "6cab7bdb584653a5dc007cc1ae827ec41c5a91bc", - "version" : "6.29.0" + "revision" : "1733ee59f06f6e725a98cf6cd8322159f59d664b", + "version" : "6.31.0" } }, { From 1ae8ae8e27a7e48b5f5e7b6ae88d16adb1872634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Sat, 9 Nov 2024 01:49:43 +0100 Subject: [PATCH 02/56] Refresh toast updates (#3552) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/72649045549333/1207889813347128/f **Description**: We’re introducing a behavioral toast on macOS, which required moving logic from the iOS client into BSK. Some of this logic has beenupdated—specifically, we now only support an event for 3 consecutive refreshes, whereas previously, we had multiple events. --- Core/PixelEvent.swift | 14 +- Core/UserDefaultsPropertyWrapper.swift | 4 +- DuckDuckGo.xcodeproj/project.pbxproj | 66 ++++----- .../xcshareddata/swiftpm/Package.resolved | 4 +- DuckDuckGo/AppDependencyProvider.swift | 6 +- DuckDuckGo/AppPageRefreshMonitor.swift | 30 ++++ DuckDuckGo/BrokenSitePromptLimiter.swift | 106 -------------- DuckDuckGo/BrokenSitePromptLimiterStore.swift | 32 +++++ DuckDuckGo/BrokenSitePromptView.swift | 2 +- DuckDuckGo/MainViewController.swift | 29 ++-- DuckDuckGo/PageRefreshStore.swift | 29 ++++ DuckDuckGo/TabViewController.swift | 8 +- DuckDuckGo/UserBehaviorMonitor.swift | 132 ------------------ DuckDuckGo/UserText.swift | 2 +- DuckDuckGo/bg.lproj/Localizable.strings | 6 +- DuckDuckGo/cs.lproj/Localizable.strings | 6 +- DuckDuckGo/da.lproj/Localizable.strings | 6 +- DuckDuckGo/de.lproj/Localizable.strings | 6 +- DuckDuckGo/el.lproj/Localizable.strings | 6 +- DuckDuckGo/en.lproj/Localizable.strings | 6 +- DuckDuckGo/es.lproj/Localizable.strings | 6 +- DuckDuckGo/et.lproj/Localizable.strings | 6 +- DuckDuckGo/fi.lproj/Localizable.strings | 6 +- DuckDuckGo/fr.lproj/Localizable.strings | 6 +- DuckDuckGo/hr.lproj/Localizable.strings | 6 +- DuckDuckGo/hu.lproj/Localizable.strings | 6 +- DuckDuckGo/it.lproj/Localizable.strings | 6 +- DuckDuckGo/lt.lproj/Localizable.strings | 6 +- DuckDuckGo/lv.lproj/Localizable.strings | 6 +- DuckDuckGo/nb.lproj/Localizable.strings | 6 +- DuckDuckGo/nl.lproj/Localizable.strings | 6 +- DuckDuckGo/pl.lproj/Localizable.strings | 6 +- DuckDuckGo/pt.lproj/Localizable.strings | 6 +- DuckDuckGo/ro.lproj/Localizable.strings | 6 +- DuckDuckGo/ru.lproj/Localizable.strings | 6 +- DuckDuckGo/sk.lproj/Localizable.strings | 6 +- DuckDuckGo/sl.lproj/Localizable.strings | 6 +- DuckDuckGo/sv.lproj/Localizable.strings | 6 +- DuckDuckGo/tr.lproj/Localizable.strings | 6 +- .../BrokenSitePromptLimiterTests.swift | 82 ----------- .../UserBehaviorMonitorTests.swift | 124 ---------------- 41 files changed, 235 insertions(+), 585 deletions(-) create mode 100644 DuckDuckGo/AppPageRefreshMonitor.swift delete mode 100644 DuckDuckGo/BrokenSitePromptLimiter.swift create mode 100644 DuckDuckGo/BrokenSitePromptLimiterStore.swift create mode 100644 DuckDuckGo/PageRefreshStore.swift delete mode 100644 DuckDuckGo/UserBehaviorMonitor.swift delete mode 100644 DuckDuckGoTests/BrokenSitePromptLimiterTests.swift delete mode 100644 DuckDuckGoTests/UserBehaviorMonitorTests.swift diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index a19da94024..35429325fc 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -671,8 +671,10 @@ extension Pixel { case toggleReportDoNotSend case toggleReportDismiss - case userBehaviorReloadTwiceWithin12Seconds - case userBehaviorReloadThreeTimesWithin20Seconds + case pageRefreshThreeTimesWithin20Seconds + + case siteNotWorkingShown + case siteNotWorkingWebsiteIsBroken // MARK: History case historyStoreLoadFailed @@ -1494,9 +1496,11 @@ extension Pixel.Event { // MARK: - Apple Ad Attribution case .appleAdAttribution: return "m_apple-ad-attribution" - // MARK: - User behavior - case .userBehaviorReloadTwiceWithin12Seconds: return "m_reload-twice-within-12-seconds" - case .userBehaviorReloadThreeTimesWithin20Seconds: return "m_reload-three-times-within-20-seconds" + // MARK: - Page refresh toasts + case .pageRefreshThreeTimesWithin20Seconds: return "m_reload-three-times-within-20-seconds" + + case .siteNotWorkingShown: return "m_site-not-working_shown" + case .siteNotWorkingWebsiteIsBroken: return "m_site-not-working_website-is-broken" // MARK: - History debug case .historyStoreLoadFailed: return "m_debug_history-store-load-failed" diff --git a/Core/UserDefaultsPropertyWrapper.swift b/Core/UserDefaultsPropertyWrapper.swift index 1231840c9b..eae3ee9842 100644 --- a/Core/UserDefaultsPropertyWrapper.swift +++ b/Core/UserDefaultsPropertyWrapper.swift @@ -143,9 +143,7 @@ public struct UserDefaultsWrapper { case appleAdAttributionReportCompleted = "com.duckduckgo.ios.appleAdAttributionReport.completed" - case didRefreshTimestamp = "com.duckduckgo.ios.userBehavior.didRefreshTimestamp" - case didDoubleRefreshTimestamp = "com.duckduckgo.ios.userBehavior.didDoubleRefreshTimestamp" - case didRefreshCounter = "com.duckduckgo.ios.userBehavior.didRefreshCounter" + case refreshTimestamps = "com.duckduckgo.ios.pageRefreshMonitor.refreshTimestamps" case lastBrokenSiteToastShownDate = "com.duckduckgo.ios.userBehavior.lastBrokenSiteToastShownDate" case toastDismissStreakCounter = "com.duckduckgo.ios.userBehavior.toastDismissStreakCounter" diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 6f52dde323..ea3eb46242 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -17,8 +17,7 @@ 026DABA428242BC80089E0B5 /* MockUserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 026DABA328242BC80089E0B5 /* MockUserAgent.swift */; }; 0283A1FC2C6E3D8100508FBD /* BrokenSitePromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0283A1FA2C6E3D8100508FBD /* BrokenSitePromptView.swift */; }; 0283A1FE2C6E3E1B00508FBD /* BrokenSitePromptViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0283A1FB2C6E3D8100508FBD /* BrokenSitePromptViewModel.swift */; }; - 0283A2012C6E46E300508FBD /* BrokenSitePromptLimiter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0283A2002C6E46E300508FBD /* BrokenSitePromptLimiter.swift */; }; - 0283A2042C6E572F00508FBD /* BrokenSitePromptLimiterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0283A2032C6E572F00508FBD /* BrokenSitePromptLimiterTests.swift */; }; + 0283A2012C6E46E300508FBD /* BrokenSitePromptLimiterStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0283A2002C6E46E300508FBD /* BrokenSitePromptLimiterStore.swift */; }; 02BA15B126A89ECA00472DD7 /* ios-config.json in Resources */ = {isa = PBXBuildFile; fileRef = 02BA15B026A89ECA00472DD7 /* ios-config.json */; }; 02CA904924F6BFE700D41DDF /* navigatorsharepatch.js in Resources */ = {isa = PBXBuildFile; fileRef = 02CA904824F6BFE700D41DDF /* navigatorsharepatch.js */; }; 02CA904B24F6C11A00D41DDF /* NavigatorSharePatchUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CA904A24F6C11A00D41DDF /* NavigatorSharePatchUserScript.swift */; }; @@ -940,12 +939,12 @@ CB2A7EEF283D185100885F67 /* RulesCompilationMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2A7EEE283D185100885F67 /* RulesCompilationMonitor.swift */; }; CB2A7EF128410DF700885F67 /* PixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2A7EF028410DF700885F67 /* PixelEvent.swift */; }; CB2A7EF4285383B300885F67 /* AppLastCompiledRulesStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2A7EF3285383B300885F67 /* AppLastCompiledRulesStore.swift */; }; - CB48D3332B90CE9F00631D8B /* UserBehaviorMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB48D3312B90CE9F00631D8B /* UserBehaviorMonitor.swift */; }; - CB48D3372B90DF2000631D8B /* UserBehaviorMonitorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB48D3352B90CECD00631D8B /* UserBehaviorMonitorTests.swift */; }; + CB48D3332B90CE9F00631D8B /* PageRefreshStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB48D3312B90CE9F00631D8B /* PageRefreshStore.swift */; }; CB4FA44E2C78AACE00A16F5A /* SpecialErrorPageUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB4FA44D2C78AACE00A16F5A /* SpecialErrorPageUserScript.swift */; }; CB5516D0286500290079B175 /* TrackerRadarIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85519124247468580010FDD0 /* TrackerRadarIntegrationTests.swift */; }; CB5516D1286500290079B175 /* ContentBlockingRulesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02CA904C24FD2DB000D41DDF /* ContentBlockingRulesTests.swift */; }; CB5516D2286500290079B175 /* AtbServerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85F21DBD21121147002631A6 /* AtbServerTests.swift */; }; + CB6CC7E42CD2529000320907 /* BrokenSitePrompt in Frameworks */ = {isa = PBXBuildFile; productRef = CB6CC7E32CD2529000320907 /* BrokenSitePrompt */; }; CB6D8E982C80A9B100D0E772 /* SpecialErrorPages in Frameworks */ = {isa = PBXBuildFile; productRef = CB6D8E972C80A9B100D0E772 /* SpecialErrorPages */; }; CB825C922C071B1400BCC586 /* AlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB825C912C071B1400BCC586 /* AlertView.swift */; }; CB825C962C071C9300BCC586 /* AlertViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB825C952C071C9300BCC586 /* AlertViewPresenter.swift */; }; @@ -967,6 +966,8 @@ CBD4F140279EBFB300B20FD7 /* SwiftUICollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1AEFB02799AA940031AE3D /* SwiftUICollectionViewCell.swift */; }; CBDD5DDF29A6736A00832877 /* APIHeadersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DDE29A6736A00832877 /* APIHeadersTests.swift */; }; CBDD5DE129A6741300832877 /* MockBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DE029A6741300832877 /* MockBundle.swift */; }; + CBECDB6F2CD3DFBE005B8B87 /* PageRefreshMonitor in Frameworks */ = {isa = PBXBuildFile; productRef = CBECDB6E2CD3DFBE005B8B87 /* PageRefreshMonitor */; }; + CBECDB7A2CD981CE005B8B87 /* AppPageRefreshMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBECDB792CD981C6005B8B87 /* AppPageRefreshMonitor.swift */; }; CBEFB9142AE0844700DEDE7B /* CriticalAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBEFB9102ADFFE7900DEDE7B /* CriticalAlerts.swift */; }; CBFCB30E2B2CD47800253E9E /* ConfigurationURLDebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBFCB30D2B2CD47800253E9E /* ConfigurationURLDebugViewController.swift */; }; D60170BD2BA34CE8001911B5 /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = D60170BB2BA32DD6001911B5 /* Subscription.swift */; }; @@ -1335,8 +1336,7 @@ 026DABA328242BC80089E0B5 /* MockUserAgent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserAgent.swift; sourceTree = ""; }; 0283A1FA2C6E3D8100508FBD /* BrokenSitePromptView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrokenSitePromptView.swift; sourceTree = ""; }; 0283A1FB2C6E3D8100508FBD /* BrokenSitePromptViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrokenSitePromptViewModel.swift; sourceTree = ""; }; - 0283A2002C6E46E300508FBD /* BrokenSitePromptLimiter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrokenSitePromptLimiter.swift; sourceTree = ""; }; - 0283A2032C6E572F00508FBD /* BrokenSitePromptLimiterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrokenSitePromptLimiterTests.swift; sourceTree = ""; }; + 0283A2002C6E46E300508FBD /* BrokenSitePromptLimiterStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrokenSitePromptLimiterStore.swift; sourceTree = ""; }; 02BA15B026A89ECA00472DD7 /* ios-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "ios-config.json"; sourceTree = ""; }; 02C4BC3127C3F9B600C40026 /* AppPrivacyConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPrivacyConfigurationTests.swift; sourceTree = ""; }; 02CA904824F6BFE700D41DDF /* navigatorsharepatch.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = navigatorsharepatch.js; sourceTree = ""; }; @@ -2743,8 +2743,7 @@ CB2A7EF3285383B300885F67 /* AppLastCompiledRulesStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLastCompiledRulesStore.swift; sourceTree = ""; }; CB2C47822AF6D55800AEDCD9 /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InfoPlist.strings; sourceTree = ""; }; CB4448752AF6D51D001F93F7 /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/InfoPlist.strings; sourceTree = ""; }; - CB48D3312B90CE9F00631D8B /* UserBehaviorMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserBehaviorMonitor.swift; sourceTree = ""; }; - CB48D3352B90CECD00631D8B /* UserBehaviorMonitorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserBehaviorMonitorTests.swift; sourceTree = ""; }; + CB48D3312B90CE9F00631D8B /* PageRefreshStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageRefreshStore.swift; sourceTree = ""; }; CB4FA44D2C78AACE00A16F5A /* SpecialErrorPageUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpecialErrorPageUserScript.swift; sourceTree = ""; }; CB5038622AF6D563007FD69F /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = ""; }; CB6ABD002AF6D52B004A8224 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -2775,6 +2774,7 @@ CBDD5DE029A6741300832877 /* MockBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockBundle.swift; sourceTree = ""; }; CBE099292AF6D54D000EFC47 /* lv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lv; path = lv.lproj/InfoPlist.strings; sourceTree = ""; }; CBECB27B2AF6D58D006960FA /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; }; + CBECDB792CD981C6005B8B87 /* AppPageRefreshMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPageRefreshMonitor.swift; sourceTree = ""; }; CBEF49902AF6D50600BFBD7D /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/InfoPlist.strings; sourceTree = ""; }; CBEFB9102ADFFE7900DEDE7B /* CriticalAlerts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CriticalAlerts.swift; sourceTree = ""; }; CBF0FA762AF6D4D800FB1C5B /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -3148,6 +3148,7 @@ 98A50962294B48A400D10880 /* Bookmarks in Frameworks */, 1E60989B290009C700A508F9 /* Common in Frameworks */, 1E60989D290011E600A508F9 /* ContentBlocking in Frameworks */, + CB6CC7E42CD2529000320907 /* BrokenSitePrompt in Frameworks */, F486D33425069BBB002D07D7 /* Kingfisher in Frameworks */, EE8E568A2A56BCE400F11DCA /* NetworkProtection in Frameworks */, D6BC8ACB2C5AA3860025375B /* DuckPlayer in Frameworks */, @@ -3160,6 +3161,7 @@ 851481882A600EFC00ABC65F /* RemoteMessaging in Frameworks */, 37DF000C29F9CA80002B7D3E /* SyncDataProviders in Frameworks */, 1E6098A1290011E600A508F9 /* UserScript in Frameworks */, + CBECDB6F2CD3DFBE005B8B87 /* PageRefreshMonitor in Frameworks */, D61CDA162B7CF77300A0FBB9 /* Subscription in Frameworks */, 858D009D2B9799FC004E5B4C /* History in Frameworks */, C14882ED27F211A000D59F0C /* SwiftSoup in Frameworks */, @@ -3198,15 +3200,7 @@ children = ( 0283A1FA2C6E3D8100508FBD /* BrokenSitePromptView.swift */, 0283A1FB2C6E3D8100508FBD /* BrokenSitePromptViewModel.swift */, - 0283A2002C6E46E300508FBD /* BrokenSitePromptLimiter.swift */, - ); - name = BrokenSitePrompt; - sourceTree = ""; - }; - 0283A2022C6E56F400508FBD /* BrokenSitePrompt */ = { - isa = PBXGroup; - children = ( - 0283A2032C6E572F00508FBD /* BrokenSitePromptLimiterTests.swift */, + 0283A2002C6E46E300508FBD /* BrokenSitePromptLimiterStore.swift */, ); name = BrokenSitePrompt; sourceTree = ""; @@ -4256,7 +4250,7 @@ 98F3A1D6217B36EE0011A0D4 /* Themes */, 7BF78E002CA2CC100026A1FC /* TipKit */, F11CEF581EBB66C80088E4D7 /* Tutorials */, - CB48D32F2B90CE8500631D8B /* UserBehaviorMonitor */, + CB48D32F2B90CE8500631D8B /* PageRefreshMonitor */, F1D796ED1E7AE4090019D451 /* UserInterface */, 84E341E31E2FC0E400BDBA6F /* UserInterfaceResources */, 3151F0E827357F8F00226F58 /* VoiceSearch */, @@ -5289,20 +5283,13 @@ path = Configuration; sourceTree = ""; }; - CB48D32F2B90CE8500631D8B /* UserBehaviorMonitor */ = { + CB48D32F2B90CE8500631D8B /* PageRefreshMonitor */ = { isa = PBXGroup; children = ( - CB48D3312B90CE9F00631D8B /* UserBehaviorMonitor.swift */, + CBECDB792CD981C6005B8B87 /* AppPageRefreshMonitor.swift */, + CB48D3312B90CE9F00631D8B /* PageRefreshStore.swift */, ); - name = UserBehaviorMonitor; - sourceTree = ""; - }; - CB48D3342B90CEBD00631D8B /* UserBehaviorMonitor */ = { - isa = PBXGroup; - children = ( - CB48D3352B90CECD00631D8B /* UserBehaviorMonitorTests.swift */, - ); - name = UserBehaviorMonitor; + name = PageRefreshMonitor; sourceTree = ""; }; CBAA195627BFDD9800A4BD49 /* SmarterEncryption */ = { @@ -5765,7 +5752,6 @@ 981FED7222045FFA008488D7 /* AutoClear */, 1E1D8B5B2994FF7800C96994 /* Autoconsent */, F40F843228C92B1C0081AE75 /* Autofill */, - 0283A2022C6E56F400508FBD /* BrokenSitePrompt */, 98559FD0267099F400A83094 /* ContentBlocker */, 31C138A127A334F600FFD4B2 /* Downloads */, D62EC3B72C24695800FC9D04 /* DuckPlayer */, @@ -5781,7 +5767,6 @@ F13B4BF71F18C9E800814661 /* Tabs */, 98EA2C3A218B9A880023E1DC /* Themes */, F12790DD1EBBDDF3001D3AEC /* Tutorials */, - CB48D3342B90CEBD00631D8B /* UserBehaviorMonitor */, F194FAF91F14E605009B4DF8 /* UserInterface */, 317045BE2858C69A0016ED1F /* Utils */, 4B6484F927FFCF520050A7A1 /* Waitlist */, @@ -6792,6 +6777,8 @@ 851F74252B9A1BFD00747C42 /* Suggestions */, D6BC8ACA2C5AA3860025375B /* DuckPlayer */, CB6D8E972C80A9B100D0E772 /* SpecialErrorPages */, + CB6CC7E32CD2529000320907 /* BrokenSitePrompt */, + CBECDB6E2CD3DFBE005B8B87 /* PageRefreshMonitor */, ); productName = Core; productReference = F143C2E41E4A4CD400CFDE3A /* Core.framework */; @@ -7626,6 +7613,7 @@ CB4FA44E2C78AACE00A16F5A /* SpecialErrorPageUserScript.swift in Sources */, EE0153ED2A6FF9E6002A8B26 /* NetworkProtectionRootView.swift in Sources */, EEF0F8CC2ABC832300630031 /* NetworkProtectionDebugFeatures.swift in Sources */, + CBECDB7A2CD981CE005B8B87 /* AppPageRefreshMonitor.swift in Sources */, B60DFF072872B64B0061E7C2 /* JSAlertController.swift in Sources */, 981FED6E22025151008488D7 /* BlankSnapshotViewController.swift in Sources */, D66F683D2BB333C100AE93E2 /* SubscriptionContainerView.swift in Sources */, @@ -7775,7 +7763,7 @@ 9821234E2B6D0A6300F08C57 /* UserAuthenticator.swift in Sources */, 310C4B47281B60E300BA79A9 /* AutofillLoginDetailsViewModel.swift in Sources */, 85EE7F572246685B000FE757 /* WebContainerViewController.swift in Sources */, - CB48D3332B90CE9F00631D8B /* UserBehaviorMonitor.swift in Sources */, + CB48D3332B90CE9F00631D8B /* PageRefreshStore.swift in Sources */, 1EC458462948932500CB2B13 /* UIHostingControllerExtension.swift in Sources */, 1E4DCF4E27B6A69600961E25 /* DownloadsListHostingController.swift in Sources */, 850F93DB2B594AB800823EEA /* ZippedPassKitPreviewHelper.swift in Sources */, @@ -7825,7 +7813,7 @@ C13F3F6A2B7F883A0083BE40 /* AuthConfirmationPromptViewController.swift in Sources */, 851624C72B96389D002D5CD7 /* HistoryDebugViewController.swift in Sources */, 8540BBA22440857A00017FE4 /* PreserveLoginsWorker.swift in Sources */, - 0283A2012C6E46E300508FBD /* BrokenSitePromptLimiter.swift in Sources */, + 0283A2012C6E46E300508FBD /* BrokenSitePromptLimiterStore.swift in Sources */, 85DFEDF924CF3D0E00973FE7 /* TabsBarCell.swift in Sources */, 851672D32BED23FE00592F24 /* AutocompleteViewModel.swift in Sources */, 8562CE152B9B645C00E1D399 /* CachedBookmarkSuggestions.swift in Sources */, @@ -8045,7 +8033,6 @@ 6F934F862C58DB00008364E4 /* NewTabPageSettingsPersistentStorageTests.swift in Sources */, 987130C5294AAB9F00AB05E0 /* BookmarkEditorViewModelTests.swift in Sources */, BDFF03262BA3DA4900F324C9 /* NetworkProtectionFeatureVisibilityTests.swift in Sources */, - 0283A2042C6E572F00508FBD /* BrokenSitePromptLimiterTests.swift in Sources */, 9F8E0F332CCA642D001EA7C5 /* VideoPlayerViewModelTests.swift in Sources */, D62EC3BA2C246A7000FC9D04 /* YoutublePlayerNavigationHandlerTests.swift in Sources */, 1EAABE712C99FC75003F5137 /* SubscriptionFeatureAvailabilityMock.swift in Sources */, @@ -8065,7 +8052,6 @@ 9F5E5AB22C3E606D00165F54 /* ContextualOnboardingPresenterTests.swift in Sources */, 9F4CC5172C48B8D4006A96EB /* TabViewControllerDaxDialogTests.swift in Sources */, F13B4BFB1F18E3D900814661 /* TabsModelPersistenceExtensionTests.swift in Sources */, - CB48D3372B90DF2000631D8B /* UserBehaviorMonitorTests.swift in Sources */, 8528AE7E212EF5FF00D0BD74 /* AppRatingPromptTests.swift in Sources */, 981FED692201FE69008488D7 /* AutoClearSettingsScreenTests.swift in Sources */, 9F9EE4CE2C377D4900D4118E /* OnboardingFirePixelMock.swift in Sources */, @@ -10986,7 +10972,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 207.1.0; + version = 208.0.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { @@ -11211,6 +11197,10 @@ package = C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */; productName = SwiftSoup; }; + CB6CC7E32CD2529000320907 /* BrokenSitePrompt */ = { + isa = XCSwiftPackageProductDependency; + productName = BrokenSitePrompt; + }; CB6D8E972C80A9B100D0E772 /* SpecialErrorPages */ = { isa = XCSwiftPackageProductDependency; package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -11226,6 +11216,10 @@ package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Configuration; }; + CBECDB6E2CD3DFBE005B8B87 /* PageRefreshMonitor */ = { + isa = XCSwiftPackageProductDependency; + productName = PageRefreshMonitor; + }; D61CDA152B7CF77300A0FBB9 /* Subscription */ = { isa = XCSwiftPackageProductDependency; package = 98A16C2928A11BDE00A6C003 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 71287414b2..49d5d017ea 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "26cc3c597990db8a0f8aa4be743b25ce65076c95", - "version" : "207.1.0" + "revision" : "17154907fe86c75942331ed6d037694c666ddd95", + "version" : "208.0.0" } }, { diff --git a/DuckDuckGo/AppDependencyProvider.swift b/DuckDuckGo/AppDependencyProvider.swift index 4997f73e56..35d7bf45d0 100644 --- a/DuckDuckGo/AppDependencyProvider.swift +++ b/DuckDuckGo/AppDependencyProvider.swift @@ -26,6 +26,7 @@ import Subscription import Common import NetworkProtection import RemoteMessaging +import PageRefreshMonitor protocol DependencyProvider { @@ -39,7 +40,7 @@ protocol DependencyProvider { var autofillNeverPromptWebsitesManager: AutofillNeverPromptWebsitesManager { get } var configurationManager: ConfigurationManager { get } var configurationStore: ConfigurationStore { get } - var userBehaviorMonitor: UserBehaviorMonitor { get } + var pageRefreshMonitor: PageRefreshMonitor { get } var subscriptionManager: SubscriptionManager { get } var accountManager: AccountManager { get } var vpnFeatureVisibility: DefaultNetworkProtectionVisibility { get } @@ -72,7 +73,8 @@ final class AppDependencyProvider: DependencyProvider { let configurationManager: ConfigurationManager let configurationStore = ConfigurationStore() - let userBehaviorMonitor = UserBehaviorMonitor() + let pageRefreshMonitor = PageRefreshMonitor(onDidDetectRefreshPattern: PageRefreshMonitor.onDidDetectRefreshPattern, + store: PageRefreshStore()) // Subscription let subscriptionManager: SubscriptionManager diff --git a/DuckDuckGo/AppPageRefreshMonitor.swift b/DuckDuckGo/AppPageRefreshMonitor.swift new file mode 100644 index 0000000000..7152b57f75 --- /dev/null +++ b/DuckDuckGo/AppPageRefreshMonitor.swift @@ -0,0 +1,30 @@ +// +// AppPageRefreshMonitor.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Core +import Common +import PageRefreshMonitor + +extension PageRefreshMonitor { + + static let onDidDetectRefreshPattern: () -> Void = { + Pixel.fire(pixel: .pageRefreshThreeTimesWithin20Seconds) + } + +} diff --git a/DuckDuckGo/BrokenSitePromptLimiter.swift b/DuckDuckGo/BrokenSitePromptLimiter.swift deleted file mode 100644 index 69b962ab13..0000000000 --- a/DuckDuckGo/BrokenSitePromptLimiter.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// BrokenSitePromptLimiter.swift -// DuckDuckGo -// -// Copyright © 2024 DuckDuckGo. All rights reserved. -// -// 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. -// - -import Foundation -import Core -import BrowserServicesKit - -protocol BrokenSitePromptLimiterStoring { - var lastToastShownDate: Date { get set } - var toastDismissStreakCounter: Int { get set } -} - -final class BrokenSitePromptLimiterStore: BrokenSitePromptLimiterStoring { - @UserDefaultsWrapper(key: .lastBrokenSiteToastShownDate, defaultValue: .distantPast) - var lastToastShownDate: Date - - @UserDefaultsWrapper(key: .toastDismissStreakCounter, defaultValue: 0) - var toastDismissStreakCounter: Int -} - -final class BrokenSitePromptLimiter { - - struct BrokenSitePromptLimiterSettings: Codable { - let maxDismissStreak: Int - let dismissStreakResetDays: Int - let coolDownDays: Int - } - - private var lastToastShownDate: Date { - get { store.lastToastShownDate } - set { store.lastToastShownDate = newValue } - } - - private var toastDismissStreakCounter: Int { - get { store.toastDismissStreakCounter } - set { store.toastDismissStreakCounter = newValue } - } - - private var privacyConfigManager: PrivacyConfigurationManaging - private var store: BrokenSitePromptLimiterStoring - - init(privacyConfigManager: PrivacyConfigurationManaging = ContentBlocking.shared.privacyConfigurationManager, - store: BrokenSitePromptLimiterStoring = BrokenSitePromptLimiterStore()) { - self.privacyConfigManager = privacyConfigManager - self.store = store - } - - private func getSettingsFromConfig() -> BrokenSitePromptLimiterSettings { - let settings = privacyConfigManager.privacyConfig.settings(for: .brokenSitePrompt) - - // Get settings from config or fallback to standard defaults - return BrokenSitePromptLimiterSettings( - maxDismissStreak: settings["maxDismissStreak"] as? Int ?? 3, - dismissStreakResetDays: settings["dismissStreakResetDays"] as? Int ?? 30, - coolDownDays: settings["coolDownDays"] as? Int ?? 7 - ) - } - - /// If it has been `dismissStreakResetDays` or more since the last time we showed the prompt, reset the dismiss counter to 0 - private func resetDismissStreakIfNeeded(dismissStreakResetDays: Int) { - if !lastToastShownDate.isLessThan(daysAgo: dismissStreakResetDays) { - toastDismissStreakCounter = 0 - } - } - - public func shouldShowToast() -> Bool { - guard privacyConfigManager.privacyConfig.isEnabled(featureKey: .brokenSitePrompt) else { return false } - - let settings = getSettingsFromConfig() - - resetDismissStreakIfNeeded(dismissStreakResetDays: settings.dismissStreakResetDays) - guard toastDismissStreakCounter < settings.maxDismissStreak else { return false } // Don't show the toast if the user dismissed it more than `maxDismissStreak` times in a row - guard !lastToastShownDate.isLessThan(daysAgo: settings.coolDownDays) else { return false } // Only show the toast once per `coolDownDays` days - - return true - } - - public func didShowToast() { - lastToastShownDate = Date() - } - - public func didDismissToast() { - toastDismissStreakCounter += 1 - } - - public func didOpenReport() { - toastDismissStreakCounter = 0 - } - -} diff --git a/DuckDuckGo/BrokenSitePromptLimiterStore.swift b/DuckDuckGo/BrokenSitePromptLimiterStore.swift new file mode 100644 index 0000000000..9236ee3f0e --- /dev/null +++ b/DuckDuckGo/BrokenSitePromptLimiterStore.swift @@ -0,0 +1,32 @@ +// +// BrokenSitePromptLimiterStore.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation +import BrokenSitePrompt +import Core + +final class BrokenSitePromptLimiterStore: BrokenSitePromptLimiterStoring { + + @UserDefaultsWrapper(key: .lastBrokenSiteToastShownDate, defaultValue: .distantPast) + var lastToastShownDate: Date + + @UserDefaultsWrapper(key: .toastDismissStreakCounter, defaultValue: 0) + var toastDismissStreakCounter: Int + +} diff --git a/DuckDuckGo/BrokenSitePromptView.swift b/DuckDuckGo/BrokenSitePromptView.swift index b04b06a778..2f89e67dce 100644 --- a/DuckDuckGo/BrokenSitePromptView.swift +++ b/DuckDuckGo/BrokenSitePromptView.swift @@ -39,7 +39,7 @@ struct BrokenSitePromptView: View { Button(UserText.siteNotWorkingDismiss, action: viewModel.onDidDismiss) .buttonStyle(GhostButtonStyle()) .fixedSize() - Button(UserText.siteNotWorkingWebsiteIsBroken, action: viewModel.onDidSubmit) + Button(UserText.siteNotWorkingReportBrokenSite, action: viewModel.onDidSubmit) .buttonStyle(PrimaryButtonStyle(compact: true)) .fixedSize() } diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 9726c00630..de806d9737 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -36,6 +36,8 @@ import SwiftUI import NetworkProtection import Onboarding import os.log +import PageRefreshMonitor +import BrokenSitePrompt class MainViewController: UIViewController { @@ -301,7 +303,7 @@ class MainViewController: UIViewController { findInPageView.delegate = self findInPageBottomLayoutConstraint.constant = 0 registerForKeyboardNotifications() - registerForUserBehaviorEvents() + registerForPageRefreshPatterns() registerForSyncFeatureFlagsUpdates() decorate() @@ -497,11 +499,11 @@ class MainViewController: UIViewController { keyboardShowing = false } - private func registerForUserBehaviorEvents() { + private func registerForPageRefreshPatterns() { NotificationCenter.default.addObserver( self, selector: #selector(attemptToShowBrokenSitePrompt(_:)), - name: .userBehaviorDidMatchBrokenSiteCriteria, + name: .pageRefreshMonitorDidDetectRefreshPattern, object: nil) } @@ -1095,8 +1097,7 @@ class MainViewController: UIViewController { } private func hideNotificationBarIfBrokenSitePromptShown(afterRefresh: Bool = false) { - guard brokenSitePromptViewHostingController != nil, - let event = brokenSitePromptEvent?.rawValue else { return } + guard brokenSitePromptViewHostingController != nil else { return } brokenSitePromptViewHostingController = nil hideNotification() } @@ -1341,12 +1342,11 @@ class MainViewController: UIViewController { } private var brokenSitePromptViewHostingController: UIHostingController? - private var brokenSitePromptEvent: UserBehaviorEvent? - lazy private var brokenSitePromptLimiter = BrokenSitePromptLimiter() + lazy private var brokenSitePromptLimiter = BrokenSitePromptLimiter(privacyConfigManager: ContentBlocking.shared.privacyConfigurationManager, + store: BrokenSitePromptLimiterStore()) @objc func attemptToShowBrokenSitePrompt(_ notification: Notification) { guard brokenSitePromptLimiter.shouldShowToast(), - let event = notification.userInfo?[UserBehaviorEvent.Key.event] as? UserBehaviorEvent, let url = currentTab?.url, !url.isDuckDuckGo, notificationView == nil, !isPad, @@ -1356,18 +1356,18 @@ class MainViewController: UIViewController { // We're using async to ensure the view dismissal happens on the first runloop after a refresh. This prevents the scenario where the view briefly appears and then immediately disappears after a refresh. brokenSitePromptLimiter.didShowToast() DispatchQueue.main.async { - self.showBrokenSitePrompt(after: event) + self.showBrokenSitePrompt() } } - private func showBrokenSitePrompt(after event: UserBehaviorEvent) { - let host = makeBrokenSitePromptViewHostingController(event: event) + private func showBrokenSitePrompt() { + let host = makeBrokenSitePromptViewHostingController() brokenSitePromptViewHostingController = host - brokenSitePromptEvent = event + Pixel.fire(pixel: .siteNotWorkingShown) showNotification(with: host.view) } - private func makeBrokenSitePromptViewHostingController(event: UserBehaviorEvent) -> UIHostingController { + private func makeBrokenSitePromptViewHostingController() -> UIHostingController { let viewModel = BrokenSitePromptViewModel(onDidDismiss: { [weak self] in Task { @MainActor in self?.hideNotification() @@ -1376,10 +1376,11 @@ class MainViewController: UIViewController { } }, onDidSubmit: { [weak self] in Task { @MainActor in - self?.segueToReportBrokenSite(entryPoint: .prompt(event.rawValue)) + self?.segueToReportBrokenSite(entryPoint: .prompt) self?.hideNotification() self?.brokenSitePromptLimiter.didOpenReport() self?.brokenSitePromptViewHostingController = nil + Pixel.fire(pixel: .siteNotWorkingWebsiteIsBroken) } }) return UIHostingController(rootView: BrokenSitePromptView(viewModel: viewModel), ignoreSafeArea: true) diff --git a/DuckDuckGo/PageRefreshStore.swift b/DuckDuckGo/PageRefreshStore.swift new file mode 100644 index 0000000000..2f0a0baad9 --- /dev/null +++ b/DuckDuckGo/PageRefreshStore.swift @@ -0,0 +1,29 @@ +// +// PageRefreshStore.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation +import Core +import PageRefreshMonitor + +final class PageRefreshStore: PageRefreshStoring { + + @UserDefaultsWrapper(key: .refreshTimestamps, defaultValue: []) + var refreshTimestamps: [Date] + +} diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 94a89dec38..6be661152c 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -621,7 +621,9 @@ class TabViewController: UIViewController { reload() delegate?.tabDidRequestRefresh(tab: self) Pixel.fire(pixel: .pullToRefresh) - AppDependencyProvider.shared.userBehaviorMonitor.handleRefreshAction() + if let url = webView.url { + AppDependencyProvider.shared.pageRefreshMonitor.register(for: url) + } }, for: .valueChanged) refreshControl.backgroundColor = .systemBackground @@ -2473,7 +2475,9 @@ extension TabViewController: UIGestureRecognizerDelegate { } refreshCountSinceLoad += 1 - AppDependencyProvider.shared.userBehaviorMonitor.handleRefreshAction() + if let url { + AppDependencyProvider.shared.pageRefreshMonitor.register(for: url) + } } } diff --git a/DuckDuckGo/UserBehaviorMonitor.swift b/DuckDuckGo/UserBehaviorMonitor.swift deleted file mode 100644 index 4d905cbdd5..0000000000 --- a/DuckDuckGo/UserBehaviorMonitor.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// UserBehaviorMonitor.swift -// DuckDuckGo -// -// Copyright © 2024 DuckDuckGo. All rights reserved. -// -// 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. -// - -import Foundation -import Common -import Core - -public extension Notification.Name { - - static let userBehaviorDidMatchBrokenSiteCriteria = Notification.Name("com.duckduckgo.app.userBehaviorDidMatchBrokenSiteCriteria") - -} - -public enum UserBehaviorEvent: String { - - public enum Key { - - static let event = "com.duckduckgo.com.userBehaviorEvent.key" - - } - - case reloadTwiceWithin12Seconds = "reload-twice-within-12-seconds" - case reloadThreeTimesWithin20Seconds = "reload-three-times-within-20-seconds" - -} - -protocol UserBehaviorStoring { - - var didRefreshTimestamp: Date? { get set } - var didDoubleRefreshTimestamp: Date? { get set } - var didRefreshCounter: Int { get set } - -} - -final class UserBehaviorStore: UserBehaviorStoring { - - @UserDefaultsWrapper(key: .didRefreshTimestamp, defaultValue: .distantPast) - var didRefreshTimestamp: Date? - - @UserDefaultsWrapper(key: .didDoubleRefreshTimestamp, defaultValue: .distantPast) - var didDoubleRefreshTimestamp: Date? - - @UserDefaultsWrapper(key: .didRefreshCounter, defaultValue: 0) - var didRefreshCounter: Int - -} - -final class UserBehaviorMonitor { - - enum Action: Equatable { - - case refresh - - } - - private let eventMapping: EventMapping - private var store: UserBehaviorStoring - - init(eventMapping: EventMapping = AppUserBehaviorMonitor.eventMapping, - store: UserBehaviorStoring = UserBehaviorStore()) { - self.eventMapping = eventMapping - self.store = store - } - - var didRefreshTimestamp: Date? { - get { store.didRefreshTimestamp } - set { store.didRefreshTimestamp = newValue } - } - - var didDoubleRefreshTimestamp: Date? { - get { store.didDoubleRefreshTimestamp } - set { store.didDoubleRefreshTimestamp = newValue } - } - - var didRefreshCounter: Int { - get { store.didRefreshCounter } - set { store.didRefreshCounter = newValue } - } - - func handleRefreshAction(date: Date = Date()) { - fireEventIfActionOccurredRecently(within: 12.0, since: didRefreshTimestamp, eventToFire: .reloadTwiceWithin12Seconds) - didRefreshTimestamp = date - - if didRefreshCounter == 0 { - didDoubleRefreshTimestamp = date - } - didRefreshCounter += 1 - if didRefreshCounter > 2 { - fireEventIfActionOccurredRecently(within: 20.0, since: didDoubleRefreshTimestamp, eventToFire: .reloadThreeTimesWithin20Seconds) - didRefreshCounter = 0 - } - - func fireEventIfActionOccurredRecently(within interval: Double = 30.0, since timestamp: Date?, eventToFire: UserBehaviorEvent) { - if let timestamp = timestamp, date.timeIntervalSince(timestamp) < interval { - eventMapping.fire(eventToFire) - NotificationCenter.default.post(name: .userBehaviorDidMatchBrokenSiteCriteria, - object: self, - userInfo: [UserBehaviorEvent.Key.event: eventToFire]) - } - } - } - -} - -final class AppUserBehaviorMonitor { - - static let eventMapping = EventMapping { event, _, _, _ in - let domainEvent: Pixel.Event - switch event { - case .reloadTwiceWithin12Seconds: domainEvent = .userBehaviorReloadTwiceWithin12Seconds - case .reloadThreeTimesWithin20Seconds: domainEvent = .userBehaviorReloadThreeTimesWithin20Seconds - } - Pixel.fire(pixel: domainEvent) - } - -} diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index b32b0c035f..c526e40a7d 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -1258,7 +1258,7 @@ But if you *do* want a peek under the hood, you can find more information about public static let siteNotWorkingTitle = NSLocalizedString("site.not.working.title", value: "Site not working? Let DuckDuckGo know.", comment: "Prompt asking user to send report to us if we suspect site may be broken") public static let siteNotWorkingSubtitle = NSLocalizedString("site.not.working.subtitle", value: "This helps us improve the browser.", comment: "Prompt asking user to send report to us if we suspect site may be broken") public static let siteNotWorkingDismiss = NSLocalizedString("site.not.working.dismiss", value: "Dismiss", comment: "Dismiss button") - public static let siteNotWorkingWebsiteIsBroken = NSLocalizedString("site.not.working.website.is.broken", value: "Website Is Broken", comment: "Button that triggers flow to report broken site") + public static let siteNotWorkingReportBrokenSite = NSLocalizedString("site.not.working.report.broken.site", value: "Report Broken Site", comment: "Button that triggers flow to report broken site") public static let siteNotWorkingDescription = NSLocalizedString("site.not.working.description", value: "Select the option that best describes the problem you experienced.", comment: "Description on a report broken site page.") // Broken site report experiment diff --git a/DuckDuckGo/bg.lproj/Localizable.strings b/DuckDuckGo/bg.lproj/Localizable.strings index fe5c65f295..df72ca960f 100644 --- a/DuckDuckGo/bg.lproj/Localizable.strings +++ b/DuckDuckGo/bg.lproj/Localizable.strings @@ -2255,15 +2255,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Отказване"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Подаване на сигнал за повреден сайт"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Това ни помага да подобрим браузъра."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Сайтът не работи ли? Уведомете DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Уебсайтът е повреден"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Изпращане на доклад"; diff --git a/DuckDuckGo/cs.lproj/Localizable.strings b/DuckDuckGo/cs.lproj/Localizable.strings index 45df7910f4..86a9a53eb4 100644 --- a/DuckDuckGo/cs.lproj/Localizable.strings +++ b/DuckDuckGo/cs.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Odmítnout"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Nahlásit nefunkční webové stránky"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Pomáhá nám to vylepšovat prohlížeč."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Stránka nefunguje? Dej DuckDuckGo vědět."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Web nefunguje"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Odešlete zprávu"; diff --git a/DuckDuckGo/da.lproj/Localizable.strings b/DuckDuckGo/da.lproj/Localizable.strings index 382ee89485..3e89b7a158 100644 --- a/DuckDuckGo/da.lproj/Localizable.strings +++ b/DuckDuckGo/da.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Afvis"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Rapporter ødelagt websted"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Det hjælper os med at forbedre browseren."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Virker webstedet ikke? Fortæl DuckDuckGo det."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Hvilket websted er ødelagt?"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Indsend rapport"; diff --git a/DuckDuckGo/de.lproj/Localizable.strings b/DuckDuckGo/de.lproj/Localizable.strings index 5344dede4c..5f893a3166 100644 --- a/DuckDuckGo/de.lproj/Localizable.strings +++ b/DuckDuckGo/de.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Verwerfen"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Fehlerhafte Website melden"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Das hilft uns, den Browser zu verbessern."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Webseite funktioniert nicht? Sag DuckDuckGo Bescheid."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Website ist fehlerhaft"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Bericht senden"; diff --git a/DuckDuckGo/el.lproj/Localizable.strings b/DuckDuckGo/el.lproj/Localizable.strings index 70c05970bd..5df4692edf 100644 --- a/DuckDuckGo/el.lproj/Localizable.strings +++ b/DuckDuckGo/el.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Απόρριψη"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Αναφορά ιστότοπου που δεν λειτουργεί"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Αυτό μας βοηθά να βελτιώνουμε το πρόγραμμα περιήγησης."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Ο ιστότοπος δεν λειτουργεί; Ενημερώστε σχετικά το DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Ο ιστότοπος δεν λειτουργεί"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Υποβολή αναφοράς"; diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 98f79b49e5..4ab56d6e1f 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -2409,15 +2409,15 @@ But if you *do* want a peek under the hood, you can find more information about /* Dismiss button */ "site.not.working.dismiss" = "Dismiss"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Report Broken Site"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "This helps us improve the browser."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Site not working? Let DuckDuckGo know."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Website Is Broken"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Submit Report"; diff --git a/DuckDuckGo/es.lproj/Localizable.strings b/DuckDuckGo/es.lproj/Localizable.strings index 0b7bd2e9e0..b7dff0c463 100644 --- a/DuckDuckGo/es.lproj/Localizable.strings +++ b/DuckDuckGo/es.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Descartar"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Informar de sitio web dañado"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Esto nos ayuda a mejorar el navegador."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "¿El sitio no funciona? Házselo saber a DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "El sitio web no funciona"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Enviar informe"; diff --git a/DuckDuckGo/et.lproj/Localizable.strings b/DuckDuckGo/et.lproj/Localizable.strings index 38a5acaea0..b1376a0ab7 100644 --- a/DuckDuckGo/et.lproj/Localizable.strings +++ b/DuckDuckGo/et.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Loobu"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Teata mittetoimivast saidist"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "See aitab meil brauserit täiustada."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Kas sait ei tööta? Anna DuckDuckGole teada."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Veebisait ei toimi"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Saada aruanne"; diff --git a/DuckDuckGo/fi.lproj/Localizable.strings b/DuckDuckGo/fi.lproj/Localizable.strings index d0c31a4164..c745173f5a 100644 --- a/DuckDuckGo/fi.lproj/Localizable.strings +++ b/DuckDuckGo/fi.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Hylkää"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Ilmoita viallisesta sivustosta"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Tämä auttaa meitä parantamaan selainta."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Eikö sivusto toimi? Kerro siitä DuckDuckGolle."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Verkkosivusto on viallinen"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Lähetä raportti"; diff --git a/DuckDuckGo/fr.lproj/Localizable.strings b/DuckDuckGo/fr.lproj/Localizable.strings index f900fa4815..970ec2d762 100644 --- a/DuckDuckGo/fr.lproj/Localizable.strings +++ b/DuckDuckGo/fr.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Ignorer"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Signaler un problème de site"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Cela nous aide à améliorer le navigateur."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Le site ne fonctionne pas ? Faites-le savoir à DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Le site Web pose problème"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Envoyer le rapport"; diff --git a/DuckDuckGo/hr.lproj/Localizable.strings b/DuckDuckGo/hr.lproj/Localizable.strings index 269e54b844..1e91cfa4d0 100644 --- a/DuckDuckGo/hr.lproj/Localizable.strings +++ b/DuckDuckGo/hr.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Odbaci"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Prijavi neispravno web-mjesto"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Ovo nam pomaže da poboljšamo preglednik."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Web-mjesto ne funkcionira? Javi DuckDuckGou."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Web-mjesto nije ispravno"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Pošalji izvješće"; diff --git a/DuckDuckGo/hu.lproj/Localizable.strings b/DuckDuckGo/hu.lproj/Localizable.strings index 52618f6a75..6e011c1d33 100644 --- a/DuckDuckGo/hu.lproj/Localizable.strings +++ b/DuckDuckGo/hu.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Elutasítás"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Hibás weboldal jelentése"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Ez segít minket a böngésző tökéletesítésében."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Nem működik a webhely? Jelezd a DuckDuckGo felé."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Nem működik a webhely"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Jelentés beküldése"; diff --git a/DuckDuckGo/it.lproj/Localizable.strings b/DuckDuckGo/it.lproj/Localizable.strings index e01a9d279f..aa975129cd 100644 --- a/DuckDuckGo/it.lproj/Localizable.strings +++ b/DuckDuckGo/it.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Ignora"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Segnala sito danneggiato"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Questo ci aiuta a migliorare il browser."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Il sito non funziona? Comunicalo a DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Il sito web è danneggiato"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Invia segnalazione"; diff --git a/DuckDuckGo/lt.lproj/Localizable.strings b/DuckDuckGo/lt.lproj/Localizable.strings index c116362c61..aefc629f07 100644 --- a/DuckDuckGo/lt.lproj/Localizable.strings +++ b/DuckDuckGo/lt.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Atmesti"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Pranešti apie sugadintą svetainę"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Tai padeda mums tobulinti naršyklę."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Svetainė neveikia? Praneškite „DuckDuckGo“."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Svetainė neveikia"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Pateikti ataskaitą"; diff --git a/DuckDuckGo/lv.lproj/Localizable.strings b/DuckDuckGo/lv.lproj/Localizable.strings index 8f9c980cc1..53a83ff1b3 100644 --- a/DuckDuckGo/lv.lproj/Localizable.strings +++ b/DuckDuckGo/lv.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Nerādīt"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Ziņot par bojātu vietni"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Tas mums palīdz uzlabot pārlūkprogrammu."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Vai vietne nedarbojas? Informē DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Vietne ir bojāta"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Iesniegt ziņojumu"; diff --git a/DuckDuckGo/nb.lproj/Localizable.strings b/DuckDuckGo/nb.lproj/Localizable.strings index cd0ded480c..5c75a162e9 100644 --- a/DuckDuckGo/nb.lproj/Localizable.strings +++ b/DuckDuckGo/nb.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Avvis"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Rapporter nettstedfeil"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Dette hjelper oss med å forbedre nettleseren."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Fungerer ikke nettstedet? Gi beskjed til DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Nettstedet fungerer ikke"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Send inn rapport"; diff --git a/DuckDuckGo/nl.lproj/Localizable.strings b/DuckDuckGo/nl.lproj/Localizable.strings index 0ae46ad07e..49b2ffc582 100644 --- a/DuckDuckGo/nl.lproj/Localizable.strings +++ b/DuckDuckGo/nl.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Negeren"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Defecte website melden"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Hiermee kunnen we de browser verbeteren."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Werkt de site niet? Laat het DuckDuckGo weten."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "De website werkt niet"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Rapport versturen"; diff --git a/DuckDuckGo/pl.lproj/Localizable.strings b/DuckDuckGo/pl.lproj/Localizable.strings index 9888d7bfe0..a82a482b04 100644 --- a/DuckDuckGo/pl.lproj/Localizable.strings +++ b/DuckDuckGo/pl.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Odrzuć"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Zgłoś uszkodzoną witrynę"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "To pomaga nam ulepszyć przeglądarkę."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Witryna nie działa? Poinformuj DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Witryna nie działa poprawnie"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Prześlij raport"; diff --git a/DuckDuckGo/pt.lproj/Localizable.strings b/DuckDuckGo/pt.lproj/Localizable.strings index 7fd8ef149b..fbef6e16e2 100644 --- a/DuckDuckGo/pt.lproj/Localizable.strings +++ b/DuckDuckGo/pt.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Ignorar"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Denunciar site danificado"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Isto ajuda-nos a melhorar o navegador."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "O site não funciona? Informa o DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "O site não funciona"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Submeter relatório"; diff --git a/DuckDuckGo/ro.lproj/Localizable.strings b/DuckDuckGo/ro.lproj/Localizable.strings index ee562a26d3..a0d15fec4e 100644 --- a/DuckDuckGo/ro.lproj/Localizable.strings +++ b/DuckDuckGo/ro.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Renunță"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Raportați site-ul defect"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Acest lucru ne ajută să îmbunătățim browserul."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Site-ul nu funcționează? Anunță DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Site-ul este nefuncțional"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Trimite raportul"; diff --git a/DuckDuckGo/ru.lproj/Localizable.strings b/DuckDuckGo/ru.lproj/Localizable.strings index 5d041fb58f..35e1e8e6da 100644 --- a/DuckDuckGo/ru.lproj/Localizable.strings +++ b/DuckDuckGo/ru.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Отклонить"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Сообщить о неработающем сайте"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Ваш ответ поможет нам улучшить работу браузера."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Сайт не работает? Сообщите в DuckDuckGo!"; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Проблема на сайте"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Отправить жалобу"; diff --git a/DuckDuckGo/sk.lproj/Localizable.strings b/DuckDuckGo/sk.lproj/Localizable.strings index 43c3005757..e3ef7a8a83 100644 --- a/DuckDuckGo/sk.lproj/Localizable.strings +++ b/DuckDuckGo/sk.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Odmietnuť"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Nahlásiť nefunkčnú stránku"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Toto nám pomáha vylepšiť prehliadač."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Stránka nefunguje? Oznámte to DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Webová stránka je nefunkčná"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Odoslať správu"; diff --git a/DuckDuckGo/sl.lproj/Localizable.strings b/DuckDuckGo/sl.lproj/Localizable.strings index 088ce79181..08fd2dde74 100644 --- a/DuckDuckGo/sl.lproj/Localizable.strings +++ b/DuckDuckGo/sl.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Opusti"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Prijavi nedelujočo stran"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "To nam pomaga izboljšati brskalnik."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Stran ne deluje? Sporočite DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Spletna stran je nedelujoča"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Pošlji poročilo"; diff --git a/DuckDuckGo/sv.lproj/Localizable.strings b/DuckDuckGo/sv.lproj/Localizable.strings index de228cd093..8b073384b5 100644 --- a/DuckDuckGo/sv.lproj/Localizable.strings +++ b/DuckDuckGo/sv.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Avvisa"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Rapportera skadad webbplats"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Det hjälper oss att förbättra webbläsaren."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Fungerar inte webbplatsen? Informera DuckDuckGo."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Webbplatsen fungerar inte"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Skicka in rapport"; diff --git a/DuckDuckGo/tr.lproj/Localizable.strings b/DuckDuckGo/tr.lproj/Localizable.strings index 5b967dc65a..abaf73d410 100644 --- a/DuckDuckGo/tr.lproj/Localizable.strings +++ b/DuckDuckGo/tr.lproj/Localizable.strings @@ -2253,15 +2253,15 @@ /* Dismiss button */ "site.not.working.dismiss" = "Reddet"; +/* Button that triggers flow to report broken site */ +"site.not.working.report.broken.site" = "Hatalı Siteyi Bildir"; + /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.subtitle" = "Bu gibi bildirimler tarayıcıyı geliştirmemize yardımcı olur."; /* Prompt asking user to send report to us if we suspect site may be broken */ "site.not.working.title" = "Site çalışmıyor mu? DuckDuckGo'ya bildirin."; -/* Button that triggers flow to report broken site */ -"site.not.working.website.is.broken" = "Web Sitesi Bozuk"; - /* Report a Broken Site screen confirmation button */ "siteFeedback.buttonText" = "Rapor Gönder"; diff --git a/DuckDuckGoTests/BrokenSitePromptLimiterTests.swift b/DuckDuckGoTests/BrokenSitePromptLimiterTests.swift deleted file mode 100644 index c83836915c..0000000000 --- a/DuckDuckGoTests/BrokenSitePromptLimiterTests.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// BrokenSitePromptLimiterTests.swift -// DuckDuckGo -// -// Copyright © 2024 DuckDuckGo. All rights reserved. -// -// 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. -// - -import XCTest -import BrowserServicesKit -@testable import DuckDuckGo -@testable import Core - -final class MockBrokenSitePromptLimiterStore: BrokenSitePromptLimiterStoring { - var lastToastShownDate: Date = .distantPast - var toastDismissStreakCounter: Int = 0 -} - -final class BrokenSitePromptLimiterTests: XCTestCase { - - let configManager = PrivacyConfigurationManagerMock() - var brokenSiteLimiter: BrokenSitePromptLimiter! - var mockStore: MockBrokenSitePromptLimiterStore! - - override func setUp() { - super.setUp() - - (configManager.privacyConfig as? PrivacyConfigurationMock)?.enabledFeaturesForVersions[.brokenSitePrompt] = [AppVersionProvider().appVersion() ?? ""] - - mockStore = MockBrokenSitePromptLimiterStore() - brokenSiteLimiter = BrokenSitePromptLimiter(privacyConfigManager: configManager, store: mockStore) - } - - func testShouldNotShowPromptIfConfigDisabled() throws { - (configManager.privacyConfig as? PrivacyConfigurationMock)?.enabledFeaturesForVersions[.brokenSitePrompt] = [] - XCTAssertFalse(brokenSiteLimiter.shouldShowToast(), "Toast should not show if disabled via config") - } - - func testShouldShowPromptOnFirstActivationThenLimit() throws { - XCTAssertTrue(brokenSiteLimiter.shouldShowToast(), "Toast should show on first activation") - brokenSiteLimiter.didShowToast() - XCTAssertFalse(brokenSiteLimiter.shouldShowToast(), "Subsequent call should not show toast due to limiting logic") - } - - func testShouldShowPromptAgainAfter7days() throws { - XCTAssertTrue(brokenSiteLimiter.shouldShowToast(), "Toast should show on first activation") - brokenSiteLimiter.didShowToast() - XCTAssertFalse(brokenSiteLimiter.shouldShowToast(), "Subsequent call should not show toast due to limiting logic") - mockStore.lastToastShownDate = Date().addingTimeInterval(-7 * 24 * 60 * 60 - 1) - XCTAssertTrue(brokenSiteLimiter.shouldShowToast(), "Toast should show again after 7 days") - } - - func testShouldNotShowPromptAfter3Dismissals() throws { - brokenSiteLimiter.didDismissToast() - brokenSiteLimiter.didDismissToast() - brokenSiteLimiter.didDismissToast() - // Set last date 7 days back so the toast shows but doesn't reset dismiss counter - mockStore.lastToastShownDate = Date().addingTimeInterval(-7 * 24 * 60 * 60 - 1) - XCTAssertFalse(brokenSiteLimiter.shouldShowToast(), "Toast should not show again after 3 dismissals") - } - - func testShouldResetDismissCounterAfter30Days() throws { - brokenSiteLimiter.didDismissToast() - brokenSiteLimiter.didDismissToast() - brokenSiteLimiter.didDismissToast() - XCTAssert(mockStore.toastDismissStreakCounter == 3, "Dismiss count should be equal to 3 after 3 dismiss calls") - XCTAssertTrue(brokenSiteLimiter.shouldShowToast(), "Toast should show after resetting counter") - XCTAssert(mockStore.toastDismissStreakCounter == 0, "Dismiss count should be reset to 0 after 30 days") - } - -} diff --git a/DuckDuckGoTests/UserBehaviorMonitorTests.swift b/DuckDuckGoTests/UserBehaviorMonitorTests.swift deleted file mode 100644 index 265a05484d..0000000000 --- a/DuckDuckGoTests/UserBehaviorMonitorTests.swift +++ /dev/null @@ -1,124 +0,0 @@ -// -// UserBehaviorMonitorTests.swift -// DuckDuckGo -// -// Copyright © 2024 DuckDuckGo. All rights reserved. -// -// 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. -// - -import XCTest -import Common -@testable import DuckDuckGo - -final class MockUserBehaviorEventsMapping: EventMapping { - - init(captureEvent: @escaping (UserBehaviorEvent) -> Void) { - super.init { event, _, _, _ in - captureEvent(event) - } - } - - override init(mapping: @escaping EventMapping.Mapping) { - fatalError("Use init()") - } -} - -final class MockUserBehaviorStore: UserBehaviorStoring { - - var didRefreshTimestamp: Date? - var didDoubleRefreshTimestamp: Date? - var didRefreshCounter: Int = 0 - -} - -final class UserBehaviorMonitorTests: XCTestCase { - - var eventMapping: MockUserBehaviorEventsMapping! - var monitor: UserBehaviorMonitor! - var events: [UserBehaviorEvent] = [] - - override func setUp() { - super.setUp() - events.removeAll() - eventMapping = MockUserBehaviorEventsMapping(captureEvent: { event in - self.events.append(event) - }) - monitor = UserBehaviorMonitor(eventMapping: eventMapping, - store: MockUserBehaviorStore()) - } - - // - MARK: Behavior testing - // Expecting events - - func testWhenUserRefreshesTwiceItSendsReloadTwiceEvent() { - monitor.handleRefreshAction() - monitor.handleRefreshAction() - XCTAssertEqual(events.count, 1) - XCTAssertEqual(events[0], .reloadTwiceWithin12Seconds) - } - - func testWhenUserRefreshesThreeTimesItSendsTwoReloadTwiceEvents() { - monitor.handleRefreshAction() - monitor.handleRefreshAction() - monitor.handleRefreshAction() - XCTAssertEqual(events.count, 3) - XCTAssertEqual(events[0], .reloadTwiceWithin12Seconds) - XCTAssertEqual(events[1], .reloadTwiceWithin12Seconds) - } - - func testWhenUserRefreshesThreeTimesItSendsReloadThreeTimesEvent() { - monitor.handleRefreshAction() - monitor.handleRefreshAction() - monitor.handleRefreshAction() - XCTAssertEqual(events.count, 3) - XCTAssertEqual(events[2], .reloadThreeTimesWithin20Seconds) - } - - // Timed pixels - - func testReloadTwiceEventShouldNotSendEventIfSecondRefreshOccuredAfter12Seconds() { - let date = Date() - monitor.handleRefreshAction(date: date) - monitor.handleRefreshAction(date: date + 13) // 13 seconds after the first event - XCTAssertTrue(events.isEmpty) - } - - func testReloadTwiceEventShouldSendEventIfSecondRefreshOccurredBelow12Seconds() { - let date = Date() - monitor.handleRefreshAction(date: date) - monitor.handleRefreshAction(date: date + 11) // 20 seconds after the first event - XCTAssertEqual(events.count, 1) - XCTAssertEqual(events[0], .reloadTwiceWithin12Seconds) - } - - func testReloadThreeTimesEventShouldNotSendEventIfThreeRefreshesOccurredAfter20Seconds() { - let date = Date() - monitor.handleRefreshAction(date: date) - monitor.handleRefreshAction(date: date) - monitor.handleRefreshAction(date: date + 21) // 21 seconds after the first event - events.removeAll { $0 == .reloadTwiceWithin12Seconds } // remove events that are not being tested - XCTAssertTrue(events.isEmpty) - } - - func testReloadThreeTimesEventShouldSendEventIfThreeRefreshesOccurredBelow20Seconds() { - let date = Date() - monitor.handleRefreshAction(date: date) - monitor.handleRefreshAction(date: date) - monitor.handleRefreshAction(date: date + 19) // 10 seconds after the first event - events.removeAll { $0 == .reloadTwiceWithin12Seconds } // remove events that are not being tested - XCTAssertEqual(events.count, 1) - XCTAssertEqual(events[0], .reloadThreeTimesWithin20Seconds) - } - -} From becebe95961e2aff8d7560e6f681454972a52a41 Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Mon, 11 Nov 2024 11:41:14 +0100 Subject: [PATCH 03/56] [DuckPlayer] Base Overlay Pixel Implementation (#3545) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1204099484721401/1208686031091507/f Tech Design URL: CC: --- Core/PixelEvent.swift | 18 ++ DuckDuckGo.xcodeproj/project.pbxproj | 8 + .../DuckPlayerNavigationHandler.swift | 10 +- .../DuckPlayerNavigationHandling.swift | 3 + .../DuckPlayerOverlayUsagePixels.swift | 123 ++++++++++ .../DuckPlayerOverlayUsagePixelsTests.swift | 227 ++++++++++++++++++ 6 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 DuckDuckGo/DuckPlayer/DuckPlayerOverlayUsagePixels.swift create mode 100644 DuckDuckGoTests/DuckPlayerOverlayUsagePixelsTests.swift diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 35429325fc..2589576efc 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -850,6 +850,14 @@ extension Pixel { case protectedDataUnavailableWhenBecomeActive case statisticsLoaderATBStateMismatch case adAttributionReportStateMismatch + + // MARK: - DuckPlayer Overlay Navigation + case duckPlayerYouTubeOverlayNavigationBack + case duckPlayerYouTubeOverlayNavigationRefresh + case duckPlayerYouTubeNavigationWithinYouTube + case duckPlayerYouTubeOverlayNavigationOutsideYoutube + case duckPlayerYouTubeOverlayNavigationClosed + case duckPlayerYouTubeNavigationIdle30 } } @@ -1690,6 +1698,16 @@ extension Pixel.Event { case .protectedDataUnavailableWhenBecomeActive: return "m_protected_data_unavailable_when_become_active" case .statisticsLoaderATBStateMismatch: return "m_statistics_loader_atb_state_mismatch" case .adAttributionReportStateMismatch: return "m_ad_attribution_report_state_mismatch" + + // MARK: - DuckPlayer Overlay Navigation + case .duckPlayerYouTubeOverlayNavigationBack: return "duckplayer.youtube.overlay.navigation.back" + case .duckPlayerYouTubeOverlayNavigationRefresh: return "duckplayer.youtube.overlay.navigation.refresh" + case .duckPlayerYouTubeNavigationWithinYouTube: return "duckplayer.youtube.overlay.navigation.within-youtube" + case .duckPlayerYouTubeOverlayNavigationOutsideYoutube: return "duckplayer.youtube.overlay.navigation.outside-youtube" + case .duckPlayerYouTubeOverlayNavigationClosed: return "duckplayer.youtube.overlay.navigation.closed" + case .duckPlayerYouTubeNavigationIdle30: return "duckplayer.youtube.overlay.idle-30" + + } } } diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index ea3eb46242..58e5dfe98e 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -1014,6 +1014,8 @@ D69FBF762B28BE3600B505F1 /* SettingsSubscriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D69FBF752B28BE3600B505F1 /* SettingsSubscriptionView.swift */; }; D6ACEA322BBD55BF008FADDF /* TabURLInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6ACEA312BBD55BF008FADDF /* TabURLInterceptor.swift */; }; D6B67A122C332B6E002122EB /* DuckPlayerMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B67A112C332B6E002122EB /* DuckPlayerMocks.swift */; }; + D6B9E8D22CDA4420002B640C /* DuckPlayerOverlayUsagePixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B9E8D12CDA4418002B640C /* DuckPlayerOverlayUsagePixels.swift */; }; + D6B9E8D42CDA8375002B640C /* DuckPlayerOverlayUsagePixelsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6B9E8D32CDA8369002B640C /* DuckPlayerOverlayUsagePixelsTests.swift */; }; D6BC8ACB2C5AA3860025375B /* DuckPlayer in Frameworks */ = {isa = PBXBuildFile; productRef = D6BC8ACA2C5AA3860025375B /* DuckPlayer */; }; D6BFCB5F2B7524AA0051FF81 /* SubscriptionPIRView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BFCB5E2B7524AA0051FF81 /* SubscriptionPIRView.swift */; }; D6BFCB612B7525160051FF81 /* SubscriptionPIRViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6BFCB602B7525160051FF81 /* SubscriptionPIRViewModel.swift */; }; @@ -2823,6 +2825,8 @@ D69FBF752B28BE3600B505F1 /* SettingsSubscriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSubscriptionView.swift; sourceTree = ""; }; D6ACEA312BBD55BF008FADDF /* TabURLInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabURLInterceptor.swift; sourceTree = ""; }; D6B67A112C332B6E002122EB /* DuckPlayerMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DuckPlayerMocks.swift; sourceTree = ""; }; + D6B9E8D12CDA4418002B640C /* DuckPlayerOverlayUsagePixels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DuckPlayerOverlayUsagePixels.swift; sourceTree = ""; }; + D6B9E8D32CDA8369002B640C /* DuckPlayerOverlayUsagePixelsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DuckPlayerOverlayUsagePixelsTests.swift; sourceTree = ""; }; D6BFCB5E2B7524AA0051FF81 /* SubscriptionPIRView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionPIRView.swift; sourceTree = ""; }; D6BFCB602B7525160051FF81 /* SubscriptionPIRViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionPIRViewModel.swift; sourceTree = ""; }; D6D95CE22B6D9F8800960317 /* AsyncHeadlessWebViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncHeadlessWebViewModel.swift; sourceTree = ""; }; @@ -5324,6 +5328,7 @@ D62EC3B72C24695800FC9D04 /* DuckPlayer */ = { isa = PBXGroup; children = ( + D6B9E8D32CDA8369002B640C /* DuckPlayerOverlayUsagePixelsTests.swift */, D6B67A112C332B6E002122EB /* DuckPlayerMocks.swift */, D62EC3BB2C2470E000FC9D04 /* DuckPlayerTests.swift */, D62EC3B82C246A5600FC9D04 /* YoutublePlayerNavigationHandlerTests.swift */, @@ -5342,6 +5347,7 @@ D63FF8892C1B21C2006DE24D /* DuckPlayerNavigationHandler.swift */, D63FF8942C1B67E8006DE24D /* YoutubeOverlayUserScript.swift */, D63FF8932C1B67E8006DE24D /* YoutubePlayerUserScript.swift */, + D6B9E8D12CDA4418002B640C /* DuckPlayerOverlayUsagePixels.swift */, 31860A5A2C57ED2D005561F5 /* DuckPlayerStorage.swift */, ); path = DuckPlayer; @@ -7471,6 +7477,7 @@ D670E5BB2BB6A75300941A42 /* SubscriptionNavigationCoordinator.swift in Sources */, 6F9FFE262C579BCD00A238BE /* NewTabPageShortcutsSettingsStorage.swift in Sources */, C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */, + D6B9E8D22CDA4420002B640C /* DuckPlayerOverlayUsagePixels.swift in Sources */, 4B53648A26718D0E001AA041 /* EmailWaitlist.swift in Sources */, D63677F52BBDB1C300605BA5 /* DaxLogoNavbarTitle.swift in Sources */, 8524CC98246D66E100E59D45 /* String+Markdown.swift in Sources */, @@ -8001,6 +8008,7 @@ 5694372B2BE3F2D900C0881B /* SyncErrorHandlerTests.swift in Sources */, 4B27FBB52C927435007E21A7 /* PersistentPixelTests.swift in Sources */, 987130C7294AAB9F00AB05E0 /* MenuBookmarksViewModelTests.swift in Sources */, + D6B9E8D42CDA8375002B640C /* DuckPlayerOverlayUsagePixelsTests.swift in Sources */, 858650D32469BFAD00C36F8A /* DaxDialogTests.swift in Sources */, 9F1623092C9D14F10093C4FC /* DefaultVariantManagerOnboardingTests.swift in Sources */, 31C138B227A4097800FFD4B2 /* DownloadTestsHelper.swift in Sources */, diff --git a/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift b/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift index adb9d58ab0..f64a61f558 100644 --- a/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift +++ b/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift @@ -32,6 +32,9 @@ final class DuckPlayerNavigationHandler: NSObject { /// The DuckPlayer instance used for handling video playback. var duckPlayer: DuckPlayerControlling + /// The DuckPlayerOverlayPixelFiring instance used for handling overlay pixel firing. + var duckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring? + /// Indicates where the DuckPlayer was referred from (e.g., YouTube, SERP). var referrer: DuckPlayerReferrer = .other @@ -113,13 +116,15 @@ final class DuckPlayerNavigationHandler: NSObject { appSettings: AppSettings, pixelFiring: PixelFiring.Type = Pixel.self, dailyPixelFiring: DailyPixelFiring.Type = DailyPixel.self, - tabNavigationHandler: DuckPlayerTabNavigationHandling? = nil) { + tabNavigationHandler: DuckPlayerTabNavigationHandling? = nil, + duckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring? = nil) { self.duckPlayer = duckPlayer self.featureFlagger = featureFlagger self.appSettings = appSettings self.pixelFiring = pixelFiring self.dailyPixelFiring = dailyPixelFiring self.tabNavigationHandler = tabNavigationHandler + self.duckPlayerOverlayUsagePixels = duckPlayerOverlayUsagePixels } /// Returns the file path for the Duck Player HTML template. @@ -658,6 +663,9 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling { @MainActor func handleURLChange(webView: WKWebView) -> DuckPlayerNavigationHandlerURLChangeResult { + // Track overlayUsagePixels + duckPlayerOverlayUsagePixels?.registerNavigation(url: webView.url) + // We want to prevent multiple simultaneous redirects // This can be caused by Duplicate Nav events, and quick URL changes if let lastTimestamp = lastURLChangeHandling, diff --git a/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandling.swift b/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandling.swift index 1755a54cf2..168512c112 100644 --- a/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandling.swift +++ b/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandling.swift @@ -74,6 +74,9 @@ protocol DuckPlayerNavigationHandling: AnyObject { /// The DuckPlayer instance used for handling video playback. var duckPlayer: DuckPlayerControlling { get } + /// DuckPlayerOverlayUsagePixels instance used for handling pixel firing. + var duckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring? { get } + /// Handles URL changes in the web view. /// /// - Parameter webView: The web view where the URL change occurred. diff --git a/DuckDuckGo/DuckPlayer/DuckPlayerOverlayUsagePixels.swift b/DuckDuckGo/DuckPlayer/DuckPlayerOverlayUsagePixels.swift new file mode 100644 index 0000000000..459b762f40 --- /dev/null +++ b/DuckDuckGo/DuckPlayer/DuckPlayerOverlayUsagePixels.swift @@ -0,0 +1,123 @@ +// +// DuckPlayerOverlayUsagePixels.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Core + +protocol DuckPlayerOverlayPixelFiring { + + var pixelFiring: PixelFiring.Type { get set } + var navigationHistory: [URL] { get set } + + func registerNavigation(url: URL?) + func navigationBack(duckPlayerMode: DuckPlayerMode) + func navigationReload(duckPlayerMode: DuckPlayerMode) + func navigationWithinYoutube(duckPlayerMode: DuckPlayerMode) + func navigationOutsideYoutube(duckPlayerMode: DuckPlayerMode) + func navigationClosed(duckPlayerMode: DuckPlayerMode) + func overlayIdle(duckPlayerMode: DuckPlayerMode) + +} + +final class DuckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring { + + var pixelFiring: PixelFiring.Type + var navigationHistory: [URL] = [] + + private var idleTimer: Timer? + private var idleTimeInterval: TimeInterval + + init(pixelFiring: PixelFiring.Type = Pixel.self, + navigationHistory: [URL] = [], + timeoutInterval: TimeInterval = 30.0) { + self.pixelFiring = pixelFiring + self.idleTimeInterval = timeoutInterval + } + + // Method to reset the idle timer + private func resetIdleTimer() { + idleTimer?.invalidate() + idleTimer = nil + } + + func registerNavigation(url: URL?) { + guard let url = url else { return } + navigationHistory.append(url) + + // Cancel and reset the idle timer whenever a new navigation occurs + resetIdleTimer() + } + + func navigationBack(duckPlayerMode: DuckPlayerMode) { + guard duckPlayerMode == .alwaysAsk, + let lastURL = navigationHistory.last, + lastURL.isYoutubeWatch else { return } + + pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationBack, withAdditionalParameters: [:]) + } + + func navigationReload(duckPlayerMode: DuckPlayerMode) { + guard duckPlayerMode == .alwaysAsk, + let lastURL = navigationHistory.last, + lastURL.isYoutubeWatch else { return } + + pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationRefresh, withAdditionalParameters: [:]) + } + + func navigationWithinYoutube(duckPlayerMode: DuckPlayerMode) { + guard duckPlayerMode == .alwaysAsk, + navigationHistory.count > 1, + let currentURL = navigationHistory.last, + let previousURL = navigationHistory.dropLast().last, + previousURL.isYoutubeWatch, + currentURL.isYoutube else { return } + + pixelFiring.fire(.duckPlayerYouTubeNavigationWithinYouTube, withAdditionalParameters: [:]) + } + + func navigationOutsideYoutube(duckPlayerMode: DuckPlayerMode) { + guard duckPlayerMode == .alwaysAsk, + navigationHistory.count > 1, + let currentURL = navigationHistory.last, + let previousURL = navigationHistory.dropLast().last, + previousURL.isYoutubeWatch, + !currentURL.isYoutube else { return } + + pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationOutsideYoutube, withAdditionalParameters: [:]) + } + + func navigationClosed(duckPlayerMode: DuckPlayerMode) { + + guard duckPlayerMode == .alwaysAsk, + let lastURL = navigationHistory.last, + lastURL.isYoutubeWatch else { return } + + pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationClosed, withAdditionalParameters: [:]) + + } + + func overlayIdle(duckPlayerMode: DuckPlayerMode) { + guard duckPlayerMode == .alwaysAsk, + let lastURL = navigationHistory.last, + lastURL.isYoutubeWatch else { return } + + idleTimer = Timer.scheduledTimer(withTimeInterval: idleTimeInterval, repeats: false) { [weak self] _ in + self?.pixelFiring.fire(.duckPlayerYouTubeNavigationIdle30, withAdditionalParameters: [:]) + } + } +} diff --git a/DuckDuckGoTests/DuckPlayerOverlayUsagePixelsTests.swift b/DuckDuckGoTests/DuckPlayerOverlayUsagePixelsTests.swift new file mode 100644 index 0000000000..dc5be8e048 --- /dev/null +++ b/DuckDuckGoTests/DuckPlayerOverlayUsagePixelsTests.swift @@ -0,0 +1,227 @@ +// +// DuckPlayerOverlayUsagePixelsTests.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import XCTest +import Core +@testable import DuckDuckGo + +class DuckPlayerOverlayUsagePixelsTests: XCTestCase { + + var duckPlayerOverlayPixels: DuckPlayerOverlayUsagePixels! + + override func setUp() { + super.setUp() + // Initialize DuckPlayerOverlayUsagePixels with a shorter timeoutInterval for testing + PixelFiringMock.tearDown() + duckPlayerOverlayPixels = DuckPlayerOverlayUsagePixels(pixelFiring: PixelFiringMock.self, timeoutInterval: 3.0) + } + + override func tearDown() { + // Clean up after each test + PixelFiringMock.tearDown() + duckPlayerOverlayPixels = nil + super.tearDown() + } + + func testRegisterNavigationAddsURLToHistory() { + // Arrange + let testURL = URL(string: "https://www.example.com")! + + // Act + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Assert + XCTAssertEqual(duckPlayerOverlayPixels.navigationHistory.count, 1) + XCTAssertEqual(duckPlayerOverlayPixels.navigationHistory.first, testURL) + } + + func testRegisterNavigationWithNilURLDoesNotAddToHistory() { + // Act + duckPlayerOverlayPixels.registerNavigation(url: nil) + + // Assert + XCTAssertTrue(duckPlayerOverlayPixels.navigationHistory.isEmpty, "Navigation history should remain empty when registering a nil URL.") + } + + func testNavigationBackFiresPixelWhenConditionsMet() { + // Arrange + let testURL = URL(string: "https://www.youtube.com/watch?v=example")! + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Act + duckPlayerOverlayPixels.navigationBack(duckPlayerMode: .alwaysAsk) + + // Assert + XCTAssertEqual(PixelFiringMock.lastPixelName, Pixel.Event.duckPlayerYouTubeOverlayNavigationBack.name) + XCTAssertNotNil(PixelFiringMock.lastPixelInfo, "Pixel should be fired when conditions are met for navigationBack.") + } + + func testNavigationBackDoesNotFirePixelWhenConditionsNotMet() { + // Act + duckPlayerOverlayPixels.navigationBack(duckPlayerMode: .enabled) + + // Assert + XCTAssertNil(PixelFiringMock.lastPixelName, "Pixel should not be fired when conditions are not met for navigationBack.") + } + + func testNavigationReloadFiresPixelWhenConditionsMet() { + // Arrange + let testURL = URL(string: "https://www.youtube.com/watch?v=example")! + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Act + duckPlayerOverlayPixels.navigationReload(duckPlayerMode: .alwaysAsk) + + // Assert + XCTAssertEqual(PixelFiringMock.lastPixelName, Pixel.Event.duckPlayerYouTubeOverlayNavigationRefresh.name) + XCTAssertNotNil(PixelFiringMock.lastPixelInfo, "Pixel should be fired when conditions are met for navigationReload.") + } + + func testNavigationReloadDoesNotFirePixelWhenConditionsNotMet() { + // Act + duckPlayerOverlayPixels.navigationReload(duckPlayerMode: .enabled) + + // Assert + XCTAssertNil(PixelFiringMock.lastPixelName, "Pixel should not be fired when conditions are not met for navigationReload.") + } + + func testNavigationWithinYoutubeFiresPixelWhenConditionsMet() { + // Arrange + let previousURL = URL(string: "https://www.youtube.com/watch?v=example1")! + let currentURL = URL(string: "https://www.youtube.com/watch?v=example2")! + duckPlayerOverlayPixels.registerNavigation(url: previousURL) + duckPlayerOverlayPixels.registerNavigation(url: currentURL) + + // Act + duckPlayerOverlayPixels.navigationWithinYoutube(duckPlayerMode: .alwaysAsk) + + // Assert + XCTAssertEqual(PixelFiringMock.lastPixelName, Pixel.Event.duckPlayerYouTubeNavigationWithinYouTube.name) + XCTAssertNotNil(PixelFiringMock.lastPixelInfo, "Pixel should be fired when conditions are met for navigationWithinYoutube.") + } + + func testNavigationWithinYoutubeDoesNotFirePixelWhenConditionsNotMet() { + // Arrange + let testURL = URL(string: "https://www.example.com")! + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Act + duckPlayerOverlayPixels.navigationWithinYoutube(duckPlayerMode: .alwaysAsk) + + // Assert + XCTAssertNil(PixelFiringMock.lastPixelName, "Pixel should not be fired when conditions are not met for navigationWithinYoutube.") + } + + func testNavigationOutsideYoutubeFiresPixelWhenConditionsMet() { + // Arrange + let previousURL = URL(string: "https://www.youtube.com/watch?v=example1")! + let currentURL = URL(string: "https://www.example.com")! + duckPlayerOverlayPixels.registerNavigation(url: previousURL) + duckPlayerOverlayPixels.registerNavigation(url: currentURL) + + // Act + duckPlayerOverlayPixels.navigationOutsideYoutube(duckPlayerMode: .alwaysAsk) + + // Assert + XCTAssertEqual(PixelFiringMock.lastPixelName, Pixel.Event.duckPlayerYouTubeOverlayNavigationOutsideYoutube.name) + XCTAssertNotNil(PixelFiringMock.lastPixelInfo, "Pixel should be fired when conditions are met for navigationOutsideYoutube.") + } + + func testNavigationOutsideYoutubeDoesNotFirePixelWhenConditionsNotMet() { + // Arrange + let testURL = URL(string: "https://www.youtube.com/watch?v=example")! + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Act + duckPlayerOverlayPixels.navigationOutsideYoutube(duckPlayerMode: .alwaysAsk) + + // Assert + XCTAssertNil(PixelFiringMock.lastPixelName, "Pixel should not be fired when conditions are not met for navigationOutsideYoutube.") + } + + func testOverlayIdleStartsTimerAndFiresPixelAfter3Seconds() { + // Arrange + let testURL = URL(string: "https://www.youtube.com/watch?v=example")! + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Act + duckPlayerOverlayPixels.overlayIdle(duckPlayerMode: .alwaysAsk) + + // Simulate waiting for 3 seconds + let expectation = XCTestExpectation(description: "Wait for the pixel to be fired after 3 seconds.") + DispatchQueue.main.asyncAfter(deadline: .now() + 3.1) { + expectation.fulfill() + } + + wait(for: [expectation], timeout: 5) + + // Assert + XCTAssertEqual(PixelFiringMock.lastPixelName, Pixel.Event.duckPlayerYouTubeNavigationIdle30.name) + XCTAssertNotNil(PixelFiringMock.lastPixelInfo, "Pixel should be fired after 3 seconds of inactivity.") + } + + func testOverlayIdleDoesNotFirePixelWhenNavigationHistoryIsNotYouTubeWatch() { + // Arrange + let testURL = URL(string: "https://www.example.com")! + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Act + duckPlayerOverlayPixels.overlayIdle(duckPlayerMode: .alwaysAsk) + + // Assert + XCTAssertNil(PixelFiringMock.lastPixelName, "Pixel should not be fired if the last URL is not a YouTube watch URL.") + } + + func testOverlayIdleDoesNotStartTimerIfModeIsNotAlwaysAsk() { + // Arrange + let testURL = URL(string: "https://www.youtube.com/watch?v=example")! + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Act + duckPlayerOverlayPixels.overlayIdle(duckPlayerMode: .enabled) + + // Assert + XCTAssertNil(PixelFiringMock.lastPixelName, "Pixel should not be fired if the mode is not .alwaysAsk.") + } + + func testNavigationClosedFiresPixelWhenConditionsMet() { + // Arrange + let testURL = URL(string: "https://www.youtube.com/watch?v=example")! + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Act + duckPlayerOverlayPixels.navigationClosed(duckPlayerMode: .alwaysAsk) + + // Assert + XCTAssertEqual(PixelFiringMock.lastPixelName, Pixel.Event.duckPlayerYouTubeOverlayNavigationClosed.name) + XCTAssertNotNil(PixelFiringMock.lastPixelInfo, "Pixel should be fired when conditions are met for navigationReload.") + } + + func testNavigationClosedDoesNotFirePixelWhenConditionsNotMet() { + // Arrange + let testURL = URL(string: "https://www.youtube.com")! + duckPlayerOverlayPixels.registerNavigation(url: testURL) + + // Act + duckPlayerOverlayPixels.navigationClosed(duckPlayerMode: .enabled) + + // Assert + XCTAssertNil(PixelFiringMock.lastPixelName, "Pixel should not be fired when conditions are not met for navigationClosed.") + } +} From e8b0c2b7b525a81ea5c1f3d3922e9aa72f3a7497 Mon Sep 17 00:00:00 2001 From: Federico Cappelli Date: Mon, 11 Nov 2024 14:49:34 +0000 Subject: [PATCH 04/56] Release 7.145.0-0 (#3560) --- .github/workflows/pr.yml | 2 +- Configuration/Version.xcconfig | 2 +- .../AppPrivacyConfigurationDataProvider.swift | 4 +- Core/ios-config.json | 98 +++++++++++++++++-- DuckDuckGo.xcodeproj/project.pbxproj | 56 +++++------ DuckDuckGo/Settings.bundle/Root.plist | 2 +- 6 files changed, 122 insertions(+), 42 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 87a40966e1..2248bd73f8 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -40,7 +40,7 @@ jobs: name: Unit Tests runs-on: macos-14-xlarge - timeout-minutes: 15 + timeout-minutes: 20 outputs: commit_author: ${{ steps.fetch_commit_author.outputs.commit_author }} diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig index 40ae091e7d..a31bce32d5 100644 --- a/Configuration/Version.xcconfig +++ b/Configuration/Version.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 7.144.0 +MARKETING_VERSION = 7.145.0 diff --git a/Core/AppPrivacyConfigurationDataProvider.swift b/Core/AppPrivacyConfigurationDataProvider.swift index 3036ae8a6a..b83c4fa194 100644 --- a/Core/AppPrivacyConfigurationDataProvider.swift +++ b/Core/AppPrivacyConfigurationDataProvider.swift @@ -23,8 +23,8 @@ import BrowserServicesKit final public class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider { public struct Constants { - public static let embeddedDataETag = "\"516f95a16f7a556c58e14ee6f193cc30\"" - public static let embeddedDataSHA = "87314e1ac02784472a722844a27b443b0387a164ac72afaac00d9a70731fc572" + public static let embeddedDataETag = "\"bd1f5490770791f68fa9667d530758a9\"" + public static let embeddedDataSHA = "86b8c31a53f781d66dbc16eb09578d28149fee6c0e280fc75ddafeed8a4b46ac" } public var embeddedDataEtag: String { diff --git a/Core/ios-config.json b/Core/ios-config.json index b7d7ecc0d0..d04ad45857 100644 --- a/Core/ios-config.json +++ b/Core/ios-config.json @@ -1,6 +1,6 @@ { "readme": "https://github.com/duckduckgo/privacy-configuration", - "version": 1730481067679, + "version": 1731320660413, "features": { "adClickAttribution": { "readme": "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#3rd-party-tracker-loading-protection", @@ -1357,14 +1357,11 @@ { "domain": "flexmls.com" }, - { - "domain": "centerwellpharmacy.com" - }, { "domain": "instructure.com" } ], - "hash": "1cc80acd10d985c950e40c5b876c581b" + "hash": "96b2f778bab196aa424e9c859ddea778" }, "contextualOnboarding": { "exceptions": [], @@ -1424,6 +1421,12 @@ { "domain": "instructure.com" }, + { + "domain": "humana.com" + }, + { + "domain": "centerwellpharmacy.com" + }, { "domain": "marvel.com" }, @@ -1441,7 +1444,7 @@ } ], "state": "disabled", - "hash": "fce0a9ccd7ae060d25e7debe4d8905fb" + "hash": "33c2d56a2a9dd43c88a353d8a57dfa72" }, "customUserAgent": { "settings": { @@ -1802,6 +1805,10 @@ "selector": ".top-ad", "type": "hide-empty" }, + { + "selector": "#top-ad", + "type": "hide" + }, { "selector": "#topAd", "type": "hide-empty" @@ -1854,6 +1861,10 @@ "selector": "#google-one-tap-popup-container", "type": "hide" }, + { + "selector": ".google-one-tap__module", + "type": "hide" + }, { "selector": ".google-one-tap-modal-div", "type": "hide" @@ -2165,6 +2176,7 @@ "content continues below", "x", "_", + "sponsor message", "sponsored", "sponsorisé", "story continues below advertisement", @@ -3227,6 +3239,10 @@ { "selector": "[aria-labelledby='promo-header']", "type": "hide" + }, + { + "selector": "div[role='banner']:has(div > a[href='https://support.google.com/a/answer/33864'])", + "type": "hide" } ] }, @@ -4965,7 +4981,7 @@ ] }, "state": "enabled", - "hash": "d8fb8089fcfbd527940703c8e2665966" + "hash": "2fa4c7c9bfd50585ee22d6c2d3bd3279" }, "exceptionHandler": { "exceptions": [ @@ -5638,10 +5654,13 @@ }, "userTips": { "state": "enabled" + }, + "enforceRoutes": { + "state": "enabled" } }, "exceptions": [], - "hash": "324309d731591edf4174a6e5d11b837c" + "hash": "137177ca43449da8ce870fc838b35845" }, "newTabContinueSetUp": { "exceptions": [], @@ -5917,6 +5936,27 @@ "state": "disabled", "hash": "be6751fe0307a7e1b9476f4d8b8d0aaf" }, + "showOnAppLaunch": { + "exceptions": [ + { + "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" + }, + { + "domain": "noaprints.com" + }, + { + "domain": "flexmls.com" + }, + { + "domain": "instructure.com" + } + ], + "state": "disabled", + "hash": "be6751fe0307a7e1b9476f4d8b8d0aaf" + }, "sslCertificates": { "state": "enabled", "exceptions": [], @@ -5927,6 +5967,27 @@ }, "hash": "abe9584048f7f8157f71a14e7914cb1c" }, + "swipingTabs": { + "exceptions": [ + { + "domain": "marvel.com" + }, + { + "domain": "sundancecatalog.com" + }, + { + "domain": "noaprints.com" + }, + { + "domain": "flexmls.com" + }, + { + "domain": "instructure.com" + } + ], + "state": "disabled", + "hash": "be6751fe0307a7e1b9476f4d8b8d0aaf" + }, "syncPromotion": { "state": "enabled", "features": { @@ -6765,6 +6826,12 @@ "homedepot.com", "sbs.com.au" ] + }, + { + "rule": "sbs.demdex.net", + "domains": [ + "sbs.com.au" + ] } ] }, @@ -6863,6 +6930,12 @@ "wunderground.com" ] }, + { + "rule": "securepubads.g.doubleclick.net/pagead/ima_ppub_config", + "domains": [ + "sbs.com.au" + ] + }, { "rule": "securepubads.g.doubleclick.net/pagead/managed/js/gpt", "domains": [ @@ -8944,6 +9017,13 @@ "" ] }, + { + "rule": "tags.tiqcdn.com/utag/cbsi/", + "domains": [ + "cbs.com", + "paramountplus.com" + ] + }, { "rule": "tags.tiqcdn.com/utag/", "domains": [ @@ -9347,7 +9427,7 @@ "domain": "instructure.com" } ], - "hash": "c28128dee65a2aa7fef1528b73f33c7f" + "hash": "b7c276ffe1417313a46c0d13fbc9fcd9" }, "trackingCookies1p": { "settings": { diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 58e5dfe98e..7b12570caa 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9195,7 +9195,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -9232,7 +9232,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9322,7 +9322,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9349,7 +9349,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9498,7 +9498,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9523,7 +9523,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9592,7 +9592,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -9626,7 +9626,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9659,7 +9659,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9689,7 +9689,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9999,7 +9999,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10030,7 +10030,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10058,7 +10058,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10091,7 +10091,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -10121,7 +10121,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -10154,11 +10154,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10391,7 +10391,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10418,7 +10418,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10450,7 +10450,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10487,7 +10487,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10522,7 +10522,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10557,11 +10557,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10734,11 +10734,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10767,10 +10767,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 0; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/DuckDuckGo/Settings.bundle/Root.plist b/DuckDuckGo/Settings.bundle/Root.plist index 6e1c6ef73b..cac348ca4f 100644 --- a/DuckDuckGo/Settings.bundle/Root.plist +++ b/DuckDuckGo/Settings.bundle/Root.plist @@ -6,7 +6,7 @@ DefaultValue - 7.144.0 + 7.145.0 Key version Title From e6e1ec368d44256a8890d94e03ee501ef99c8f00 Mon Sep 17 00:00:00 2001 From: Graeme Arthur Date: Mon, 11 Nov 2024 16:55:16 +0100 Subject: [PATCH 05/56] Sync: Send pixels for account removal + decoding issues (#3557) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1201493110486074/1208723035104886/f Tech Design URL: CC: **Description**: Adds sync pixels for catching when the keychain read throws a decoding error and when the account is deleted for various reasons **Steps to test this PR**: 1. Make sure you've already activated sync. 2. Deactivate sync (either delete the server data or just turn it off) 3. You should see the `sync_account_removed_reason_user-turned-off` pixel in the console. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Copy Testing**: * [ ] Use of correct apostrophes in new copy, ie `’` rather than `'` **Orientation Testing**: * [ ] Portrait * [ ] Landscape **Device Testing**: * [ ] iPhone SE (1st Gen) * [ ] iPhone 8 * [ ] iPhone X * [ ] iPhone 14 Pro * [ ] iPad **OS Testing**: * [ ] iOS 15 * [ ] iOS 16 * [ ] iOS 17 **Theme Testing**: * [ ] Light theme * [ ] Dark theme --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- Core/PixelEvent.swift | 4 ++++ Core/SyncErrorHandler.swift | 4 ++++ DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 2589576efc..2ddc0806ca 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -632,6 +632,8 @@ extension Pixel { case syncDeleteAccountError case syncLoginExistingAccountError case syncSecureStorageReadError + case syncSecureStorageDecodingError + case syncAccountRemoved(reason: String) case syncGetOtherDevices case syncGetOtherDevicesCopy @@ -1457,6 +1459,8 @@ extension Pixel.Event { case .syncDeleteAccountError: return "m_d_sync_delete_account_error" case .syncLoginExistingAccountError: return "m_d_sync_login_existing_account_error" case .syncSecureStorageReadError: return "m_d_sync_secure_storage_error" + case .syncSecureStorageDecodingError: return "sync_secure_storage_decoding_error" + case .syncAccountRemoved(let reason): return "sync_account_removed_reason_\(reason)" case .syncGetOtherDevices: return "sync_get_other_devices" case .syncGetOtherDevicesCopy: return "sync_get_other_devices_copy" diff --git a/Core/SyncErrorHandler.swift b/Core/SyncErrorHandler.swift index 93609732ba..38dce71464 100644 --- a/Core/SyncErrorHandler.swift +++ b/Core/SyncErrorHandler.swift @@ -102,6 +102,10 @@ public class SyncErrorHandler: EventMapping { Pixel.fire(pixel: .syncFailedToSetupEngine, error: error) case .failedToReadSecureStore: Pixel.fire(pixel: .syncSecureStorageReadError, error: error) + case .failedToDecodeSecureStoreData(let error): + Pixel.fire(pixel: .syncSecureStorageDecodingError, error: error) + case .accountRemoved(let reason): + Pixel.fire(pixel: .syncAccountRemoved(reason: reason.rawValue), error: error) default: // Should this be so generic? let domainEvent = Pixel.Event.syncSentUnauthenticatedRequest diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 58e5dfe98e..e50066830b 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10980,7 +10980,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 208.0.0; + version = 208.1.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 49d5d017ea..cb461c0e9c 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "17154907fe86c75942331ed6d037694c666ddd95", - "version" : "208.0.0" + "revision" : "6be781530a2516c703b8e1bcf0c90e6e763d3300", + "version" : "208.1.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "1733ee59f06f6e725a98cf6cd8322159f59d664b", - "version" : "6.31.0" + "revision" : "adca39c379b1a124f9990e9d0308c374f32f5018", + "version" : "6.32.0" } }, { From f8fc6c5a486ee86da777447e23cf70ab4a31fd30 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Mon, 11 Nov 2024 22:16:29 +0100 Subject: [PATCH 06/56] Remediate TunnelVision, TunnelCrack and fix "Exclude Local Networks" (#3460) Task/Issue URL: https://app.asana.com/0/1206580121312550/1208686409805161/f Tech Design URL: https://app.asana.com/0/481882893211075/1208643192597095/f macOS PR: https://github.com/duckduckgo/macos-browser/pull/3422 BSK PR: https://github.com/duckduckgo/BrowserServicesKit/pull/1039 ## Description Remediate TunnelVision, TunnelCrack and fix "Exclude Local Networks". --- Core/FeatureFlag.swift | 5 ++ DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../xcschemes/DuckDuckGo.xcscheme | 3 ++ DuckDuckGo/AppDependencyProvider.swift | 15 +++--- ...orkProtectionConvenienceInitialisers.swift | 1 + ...NetworkProtectionDebugViewController.swift | 12 +++++ .../NetworkProtectionTunnelController.swift | 52 +++++++++++++++++-- .../NetworkProtectionVPNSettingsView.swift | 3 -- ...etworkProtectionVPNSettingsViewModel.swift | 30 ++++++++--- 10 files changed, 103 insertions(+), 24 deletions(-) diff --git a/Core/FeatureFlag.swift b/Core/FeatureFlag.swift index b877485851..de9c1df97e 100644 --- a/Core/FeatureFlag.swift +++ b/Core/FeatureFlag.swift @@ -49,6 +49,9 @@ public enum FeatureFlag: String { /// https://app.asana.com/0/72649045549333/1208231259093710/f case networkProtectionUserTips + + /// https://app.asana.com/0/72649045549333/1208617860225199/f + case networkProtectionEnforceRoutes } extension FeatureFlag: FeatureFlagSourceProviding { @@ -104,6 +107,8 @@ extension FeatureFlag: FeatureFlagSourceProviding { return .remoteReleasable(.feature(.autocompleteTabs)) case .networkProtectionUserTips: return .remoteReleasable(.subfeature(NetworkProtectionSubfeature.userTips)) + case .networkProtectionEnforceRoutes: + return .remoteDevelopment(.subfeature(NetworkProtectionSubfeature.enforceRoutes)) case .adAttributionReporting: return .remoteReleasable(.feature(.adAttributionReporting)) } diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 6f33031202..695adc1f30 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10980,7 +10980,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 208.1.0; + version = 209.0.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index cb461c0e9c..c542bb4b81 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "6be781530a2516c703b8e1bcf0c90e6e763d3300", - "version" : "208.1.0" + "revision" : "614ea57db48db644ce7f3a3de9c20c9a7fbb08ff", + "version" : "209.0.0" } }, { diff --git a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo.xcscheme b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo.xcscheme index b9ef06c977..a096dee425 100644 --- a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo.xcscheme +++ b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo.xcscheme @@ -65,6 +65,9 @@ + + diff --git a/DuckDuckGo/AppDependencyProvider.swift b/DuckDuckGo/AppDependencyProvider.swift index 35d7bf45d0..245901da44 100644 --- a/DuckDuckGo/AppDependencyProvider.swift +++ b/DuckDuckGo/AppDependencyProvider.swift @@ -113,7 +113,7 @@ final class AppDependencyProvider: DependencyProvider { entitlementsCache: entitlementsCache, subscriptionEndpointService: subscriptionService, authEndpointService: authService) - + let subscriptionManager = DefaultSubscriptionManager(storePurchaseManager: DefaultStorePurchaseManager(), accountManager: accountManager, subscriptionEndpointService: subscriptionService, @@ -126,17 +126,14 @@ final class AppDependencyProvider: DependencyProvider { let accessTokenProvider: () -> String? = { return { accountManager.accessToken } }() -#if os(macOS) - networkProtectionKeychainTokenStore = NetworkProtectionKeychainTokenStore(keychainType: .dataProtection(.unspecified), - serviceName: "\(Bundle.main.bundleIdentifier!).authToken", - errorEvents: .networkProtectionAppDebugEvents, - accessTokenProvider: accessTokenProvider) -#else + networkProtectionKeychainTokenStore = NetworkProtectionKeychainTokenStore(accessTokenProvider: accessTokenProvider) -#endif + networkProtectionTunnelController = NetworkProtectionTunnelController(accountManager: accountManager, tokenStore: networkProtectionKeychainTokenStore, - persistentPixel: persistentPixel) + featureFlagger: featureFlagger, + persistentPixel: persistentPixel, + settings: vpnSettings) vpnFeatureVisibility = DefaultNetworkProtectionVisibility(userDefaults: .networkProtectionGroupDefaults, accountManager: accountManager) } diff --git a/DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift b/DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift index e440446044..a72c4f0ab0 100644 --- a/DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift +++ b/DuckDuckGo/NetworkProtectionConvenienceInitialisers.swift @@ -59,6 +59,7 @@ extension NetworkProtectionVPNSettingsViewModel { convenience init() { self.init( notificationsAuthorization: NotificationsAuthorizationController(), + controller: AppDependencyProvider.shared.networkProtectionTunnelController, settings: AppDependencyProvider.shared.vpnSettings ) } diff --git a/DuckDuckGo/NetworkProtectionDebugViewController.swift b/DuckDuckGo/NetworkProtectionDebugViewController.swift index 0c0c34568e..fb38929911 100644 --- a/DuckDuckGo/NetworkProtectionDebugViewController.swift +++ b/DuckDuckGo/NetworkProtectionDebugViewController.swift @@ -63,6 +63,7 @@ final class NetworkProtectionDebugViewController: UITableViewController { enum DebugFeatureRows: Int, CaseIterable { case toggleAlwaysOn + case enforceRoutes } enum SimulateFailureRows: Int, CaseIterable { @@ -324,6 +325,14 @@ final class NetworkProtectionDebugViewController: UITableViewController { } else { cell.accessoryType = .checkmark } + case .enforceRoutes: + cell.textLabel?.text = "Enforce Routes" + + if !AppDependencyProvider.shared.vpnSettings.enforceRoutes { + cell.accessoryType = .none + } else { + cell.accessoryType = .checkmark + } default: break } @@ -334,6 +343,9 @@ final class NetworkProtectionDebugViewController: UITableViewController { case .toggleAlwaysOn: debugFeatures.alwaysOnDisabled.toggle() tableView.reloadRows(at: [indexPath], with: .none) + case .enforceRoutes: + AppDependencyProvider.shared.vpnSettings.enforceRoutes.toggle() + tableView.reloadRows(at: [indexPath], with: .none) default: break } diff --git a/DuckDuckGo/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtectionTunnelController.swift index c13dedcb06..ed22d7cd91 100644 --- a/DuckDuckGo/NetworkProtectionTunnelController.swift +++ b/DuckDuckGo/NetworkProtectionTunnelController.swift @@ -17,9 +17,10 @@ // limitations under the License. // -import Foundation +import BrowserServicesKit import Combine import Core +import Foundation import NetworkExtension import NetworkProtection import Subscription @@ -34,6 +35,7 @@ enum VPNConfigurationRemovalReason: String { final class NetworkProtectionTunnelController: TunnelController, TunnelSessionProvider { static var shouldSimulateFailure: Bool = false + private let featureFlagger: FeatureFlagger private var internalManager: NETunnelProviderManager? private let debugFeatures = NetworkProtectionDebugFeatures() private let tokenStore: NetworkProtectionKeychainTokenStore @@ -42,6 +44,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr private let notificationCenter: NotificationCenter = .default private var previousStatus: NEVPNStatus = .invalid private let persistentPixel: PersistentPixelFiring + private let settings: VPNSettings private var cancellables = Set() // MARK: - Manager, Session, & Connection @@ -119,9 +122,25 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr } } - init(accountManager: AccountManager, tokenStore: NetworkProtectionKeychainTokenStore, persistentPixel: PersistentPixelFiring) { - self.tokenStore = tokenStore + // MARK: - Enforce Routes + + private var enforceRoutes: Bool { + featureFlagger.isFeatureOn(.networkProtectionEnforceRoutes) + } + + // MARK: - Initializers + + init(accountManager: AccountManager, + tokenStore: NetworkProtectionKeychainTokenStore, + featureFlagger: FeatureFlagger, + persistentPixel: PersistentPixelFiring, + settings: VPNSettings) { + + self.featureFlagger = featureFlagger self.persistentPixel = persistentPixel + self.settings = settings + self.tokenStore = tokenStore + subscribeToSnoozeTimingChanges() subscribeToStatusChanges() subscribeToConfigurationChanges() @@ -180,6 +199,16 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr tunnelManager.connection.stopVPNTunnel() } + func command(_ command: VPNCommand) async throws { + guard let activeSession = await AppDependencyProvider.shared.networkProtectionTunnelController.activeSession(), + activeSession.status == .connected else { + + return + } + + try? await activeSession.sendProviderRequest(.command(command)) + } + func removeVPN(reason: VPNConfigurationRemovalReason) async { do { try await tunnelManager?.removeFromPreferences() @@ -293,6 +322,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr return tunnelManager } + @MainActor private func setupAndSave(_ tunnelManager: NETunnelProviderManager) async throws { setup(tunnelManager) @@ -319,6 +349,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr /// Setups the tunnel manager if it's not set up already. /// + @MainActor private func setup(_ tunnelManager: NETunnelProviderManager) { tunnelManager.localizedDescription = "DuckDuckGo VPN" tunnelManager.isEnabled = true @@ -327,9 +358,24 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr let protocolConfiguration = NETunnelProviderProtocol() protocolConfiguration.serverAddress = "127.0.0.1" // Dummy address... the NetP service will take care of grabbing a real server + protocolConfiguration.providerConfiguration = [:] + // always-on protocolConfiguration.disconnectOnSleep = false + // Enforce routes + protocolConfiguration.enforceRoutes = enforceRoutes + + // We will control excluded networks through includedRoutes / excludedRoutes + protocolConfiguration.excludeLocalNetworks = false + + #if DEBUG + if #available(iOS 17.4, *) { + // This is useful to ensure debugging is never blocked by the VPN + protocolConfiguration.excludeDeviceCommunication = true + } + #endif + return protocolConfiguration }() diff --git a/DuckDuckGo/NetworkProtectionVPNSettingsView.swift b/DuckDuckGo/NetworkProtectionVPNSettingsView.swift index 6d8ab17c8c..b01354f454 100644 --- a/DuckDuckGo/NetworkProtectionVPNSettingsView.swift +++ b/DuckDuckGo/NetworkProtectionVPNSettingsView.swift @@ -50,9 +50,6 @@ struct NetworkProtectionVPNSettingsView: View { footerText: UserText.netPExcludeLocalNetworksSettingFooter ) { Toggle("", isOn: $viewModel.excludeLocalNetworks) - .onTapGesture { - viewModel.toggleExcludeLocalNetworks() - } } dnsSection() diff --git a/DuckDuckGo/NetworkProtectionVPNSettingsViewModel.swift b/DuckDuckGo/NetworkProtectionVPNSettingsViewModel.swift index 4866dd6055..9442ff6597 100644 --- a/DuckDuckGo/NetworkProtectionVPNSettingsViewModel.swift +++ b/DuckDuckGo/NetworkProtectionVPNSettingsViewModel.swift @@ -29,6 +29,7 @@ enum NetworkProtectionNotificationsViewKind: Equatable { } final class NetworkProtectionVPNSettingsViewModel: ObservableObject { + private let controller: TunnelController private let settings: VPNSettings private var cancellables: Set = [] @@ -39,11 +40,32 @@ final class NetworkProtectionVPNSettingsViewModel: ObservableObject { self.settings.notifyStatusChanges } - @Published public var excludeLocalNetworks: Bool = true + @Published public var excludeLocalNetworks: Bool { + didSet { + guard oldValue != excludeLocalNetworks else { + return + } + + settings.excludeLocalNetworks = excludeLocalNetworks + + Task { + // We need to allow some time for the setting to propagate + // But ultimately this should actually be a user choice + try await Task.sleep(interval: 0.1) + try await controller.command(.restartAdapter) + } + } + } + @Published public var usesCustomDNS = false @Published public var dnsServers: String = UserText.vpnSettingDNSServerDefaultValue - init(notificationsAuthorization: NotificationsAuthorizationControlling, settings: VPNSettings) { + init(notificationsAuthorization: NotificationsAuthorizationControlling, + controller: TunnelController, + settings: VPNSettings) { + + self.controller = controller + self.excludeLocalNetworks = settings.excludeLocalNetworks self.settings = settings self.notificationsAuthorization = notificationsAuthorization @@ -77,10 +99,6 @@ final class NetworkProtectionVPNSettingsViewModel: ObservableObject { settings.notifyStatusChanges = enabled } - func toggleExcludeLocalNetworks() { - settings.excludeLocalNetworks.toggle() - } - private static func localizedString(forRegionCode: String) -> String { Locale.current.localizedString(forRegionCode: forRegionCode) ?? forRegionCode.capitalized } From 4ed25d190755cbaa700703f2b13124ca558ffb43 Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Tue, 12 Nov 2024 09:52:19 +0000 Subject: [PATCH 07/56] fix showing current tab in suggestions (#3562) Task/Issue URL: https://app.asana.com/0/392891325557410/1208712038329496/f Tech Design URL: CC: **Description**: Fixes bug showing open tab for current tab when typing in suggestions. **Steps to test this PR**: 1. Go to https://news.ycombinator.com/ and open a bunch of pages in new tabs 2. Type in to the address for one of the pages - should show as an open tab. Select it and switch to tab. 3. Type into the address bar for the same page - should only show as history 4. Validate that the same page open in multiple tabs only shows as a single 'switch to tab' suggestion and does not show at all when on a page with the same URL --- DuckDuckGo.xcodeproj/project.pbxproj | 18 ++- .../AutocompleteSuggestionsDataSource.swift | 100 ++++++++++++ DuckDuckGo/AutocompleteViewController.swift | 82 +++------- ...tocompleteSuggestionsDataSourceTests.swift | 151 ++++++++++++++++++ DuckDuckGoTests/MockFeatureFlagger.swift | 2 +- 5 files changed, 289 insertions(+), 64 deletions(-) create mode 100644 DuckDuckGo/AutocompleteSuggestionsDataSource.swift create mode 100644 DuckDuckGoTests/AutocompleteSuggestionsDataSourceTests.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 695adc1f30..96c03ad85a 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -432,6 +432,8 @@ 851672D12BED1FC900592F24 /* AutocompleteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851672D02BED1FC900592F24 /* AutocompleteView.swift */; }; 851672D32BED23FE00592F24 /* AutocompleteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851672D22BED23FE00592F24 /* AutocompleteViewModel.swift */; }; 8517D98B221783A0006A8DD0 /* FindInPage.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8517D98A221783A0006A8DD0 /* FindInPage.xcassets */; }; + 851952682CE2522700578553 /* AutocompleteSuggestionsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851952672CE2522700578553 /* AutocompleteSuggestionsDataSource.swift */; }; + 8519526C2CE256BC00578553 /* AutocompleteSuggestionsDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8519526A2CE256A900578553 /* AutocompleteSuggestionsDataSourceTests.swift */; }; 851B1283221FE65E004781BC /* ImproveOnboardingExperiment1Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851B1281221FE64E004781BC /* ImproveOnboardingExperiment1Tests.swift */; }; 851B128822200575004781BC /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 851B128722200575004781BC /* Onboarding.swift */; }; 851B12CC22369931004781BC /* AtbAndVariantCleanup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850250B220D803F4002199C7 /* AtbAndVariantCleanup.swift */; }; @@ -1740,6 +1742,8 @@ 851672D02BED1FC900592F24 /* AutocompleteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteView.swift; sourceTree = ""; }; 851672D22BED23FE00592F24 /* AutocompleteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteViewModel.swift; sourceTree = ""; }; 8517D98A221783A0006A8DD0 /* FindInPage.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = FindInPage.xcassets; sourceTree = ""; }; + 851952672CE2522700578553 /* AutocompleteSuggestionsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteSuggestionsDataSource.swift; sourceTree = ""; }; + 8519526A2CE256A900578553 /* AutocompleteSuggestionsDataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteSuggestionsDataSourceTests.swift; sourceTree = ""; }; 851B1281221FE64E004781BC /* ImproveOnboardingExperiment1Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImproveOnboardingExperiment1Tests.swift; sourceTree = ""; }; 851B128722200575004781BC /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = ""; }; 851B128B2220483A004781BC /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; }; @@ -4318,10 +4322,19 @@ children = ( 851672CE2BED1F9500592F24 /* HistoryMessageManager.swift */, 851672D22BED23FE00592F24 /* AutocompleteViewModel.swift */, + 851952672CE2522700578553 /* AutocompleteSuggestionsDataSource.swift */, ); name = Model; sourceTree = ""; }; + 851952692CE2569600578553 /* Autocomplete */ = { + isa = PBXGroup; + children = ( + 8519526A2CE256A900578553 /* AutocompleteSuggestionsDataSourceTests.swift */, + ); + name = Autocomplete; + sourceTree = ""; + }; 851DFD88212C5ED600D95F20 /* Main */ = { isa = PBXGroup; children = ( @@ -5752,7 +5765,7 @@ F12D98401F266B30003C2EE3 /* DuckDuckGo */ = { isa = PBXGroup; children = ( - 6F03CAFF2C32ED22004179A8 /* NewTabPage */, + 851952692CE2569600578553 /* Autocomplete */, 6FF9157F2B88E04F0042AC87 /* AdAttribution */, F17669A21E411D63003D3222 /* Application */, 981FED7222045FFA008488D7 /* AutoClear */, @@ -5765,6 +5778,7 @@ 8588026724E4249800C24AB6 /* iPad */, 851DFD88212C5ED600D95F20 /* Main */, EE56DE3A2A6038F500375C41 /* NetworkProtection */, + 6F03CAFF2C32ED22004179A8 /* NewTabPage */, F1D477C71F2139210031ED49 /* OmniBar */, 9F23B8042C2BE20500950875 /* Onboarding */, 98EA2C3F218BB5140023E1DC /* Settings */, @@ -7373,6 +7387,7 @@ 8540BD5423D8D5080057FDD2 /* PreserveLoginsAlert.swift in Sources */, 1E87615928A1517200C7C5CE /* PrivacyDashboardViewController.swift in Sources */, 6F03CAFE2C32DD08004179A8 /* HomePageMessagesConfiguration.swift in Sources */, + 851952682CE2522700578553 /* AutocompleteSuggestionsDataSource.swift in Sources */, EE9D68D12AE00CF300B55EF4 /* NetworkProtectionVPNSettingsView.swift in Sources */, 319A371028299A850079FBCE /* PasswordHider.swift in Sources */, 982C87C42255559A00919035 /* UITableViewCellExtension.swift in Sources */, @@ -8027,6 +8042,7 @@ 310E79BD2949CAA5007C49E8 /* FireButtonReferenceTests.swift in Sources */, 4B62C4BA25B930DD008912C6 /* AppConfigurationFetchTests.swift in Sources */, 31C7D71C27515A6300A95D0A /* MockVoiceSearchHelper.swift in Sources */, + 8519526C2CE256BC00578553 /* AutocompleteSuggestionsDataSourceTests.swift in Sources */, 6F395BBB2CD2C87D00B92FC3 /* BoolFileMarkerTests.swift in Sources */, 8598F67B2405EB8D00FBC70C /* KeyboardSettingsTests.swift in Sources */, 98AAF8E4292EB46000DBDF06 /* BookmarksMigrationTests.swift in Sources */, diff --git a/DuckDuckGo/AutocompleteSuggestionsDataSource.swift b/DuckDuckGo/AutocompleteSuggestionsDataSource.swift new file mode 100644 index 0000000000..73ac458f63 --- /dev/null +++ b/DuckDuckGo/AutocompleteSuggestionsDataSource.swift @@ -0,0 +1,100 @@ +// +// AutocompleteSuggestionsDataSource.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Core +import BrowserServicesKit +import Suggestions +import History +import Persistence +import Networking + +final class AutocompleteSuggestionsDataSource: SuggestionLoadingDataSource { + + typealias SuggestionsRequestCompletion = (Data?, Error?) -> Void + typealias SuggestionsRequest = (URLRequest, @escaping SuggestionsRequestCompletion) -> Void + + private let historyManager: HistoryManaging + private let bookmarksDatabase: CoreDataDatabase + private let featureFlagger: FeatureFlagger + private let tabsModel: TabsModel + + private var performSuggestionsRequest: SuggestionsRequest + + /// Specifically open tabs that do not have the same URL as the current tab so that we avoid shown them in the results. + private lazy var candidateOpenTabs: [BrowserTab] = { + tabsModel.tabs.compactMap { + guard let url = $0.link?.url, + tabsModel.currentTab?.link?.url != $0.link?.url + else { return nil } + + return OpenTab(title: $0.link?.displayTitle ?? "", url: url) + } + }() + + private lazy var cachedBookmarks: CachedBookmarks = { + CachedBookmarks(bookmarksDatabase) + }() + + var historyCoordinator: HistoryCoordinating { + historyManager.historyCoordinator + } + + var platform: Platform { + .mobile + } + + init(historyManager: HistoryManaging, bookmarksDatabase: CoreDataDatabase, featureFlagger: FeatureFlagger, tabsModel: TabsModel, performSuggestionsRequest: @escaping SuggestionsRequest) { + self.historyManager = historyManager + self.bookmarksDatabase = bookmarksDatabase + self.featureFlagger = featureFlagger + self.tabsModel = tabsModel + self.performSuggestionsRequest = performSuggestionsRequest + } + + func history(for suggestionLoading: Suggestions.SuggestionLoading) -> [HistorySuggestion] { + return historyCoordinator.history ?? [] + } + + func bookmarks(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.Bookmark] { + return cachedBookmarks.all + } + + func internalPages(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.InternalPage] { + return [] + } + + func openTabs(for suggestionLoading: any SuggestionLoading) -> [BrowserTab] { + if featureFlagger.isFeatureOn(.autcompleteTabs) { + return candidateOpenTabs + } + return [] + } + + func suggestionLoading(_ suggestionLoading: Suggestions.SuggestionLoading, suggestionDataFromUrl url: URL, withParameters parameters: [String: String], completion: @escaping (Data?, Error?) -> Void) { + var queryURL = url + parameters.forEach { + queryURL = queryURL.appendingParameter(name: $0.key, value: $0.value) + } + var request = URLRequest.developerInitiated(queryURL) + request.allHTTPHeaderFields = APIRequest.Headers().httpHeaders + + performSuggestionsRequest(request, completion) + } + +} diff --git a/DuckDuckGo/AutocompleteViewController.swift b/DuckDuckGo/AutocompleteViewController.swift index c358fe97cd..ba914b9418 100644 --- a/DuckDuckGo/AutocompleteViewController.swift +++ b/DuckDuckGo/AutocompleteViewController.swift @@ -40,36 +40,34 @@ class AutocompleteViewController: UIHostingController { weak var delegate: AutocompleteViewControllerDelegate? weak var presentationDelegate: AutocompleteViewControllerPresentationDelegate? - private let historyManager: HistoryManaging - var historyCoordinator: HistoryCoordinating { - historyManager.historyCoordinator - } - - private let bookmarksDatabase: CoreDataDatabase private let appSettings: AppSettings private let model: AutocompleteViewModel - private var task: URLSessionDataTask? - @Published private var query = "" private var queryDebounceCancellable: AnyCancellable? - private lazy var cachedBookmarks: CachedBookmarks = { - CachedBookmarks(bookmarksDatabase) - }() - - private lazy var openTabs: [BrowserTab] = { - tabsModel.tabs.compactMap { - guard let url = $0.link?.url else { return nil } - return OpenTab(title: $0.link?.displayTitle ?? "", url: url) - } - }() - private var lastResults: SuggestionResult? private var loader: SuggestionLoader? private var historyMessageManager: HistoryMessageManager - private var tabsModel: TabsModel private var featureFlagger: FeatureFlagger + private let historyManager: HistoryManaging + private let bookmarksDatabase: CoreDataDatabase + private let tabsModel: TabsModel + + private var task: URLSessionDataTask? + + lazy var dataSource: AutocompleteSuggestionsDataSource = { + return AutocompleteSuggestionsDataSource( + historyManager: historyManager, + bookmarksDatabase: bookmarksDatabase, + featureFlagger: featureFlagger, + tabsModel: tabsModel) { [weak self] request, completion in + self?.task = Self.session.dataTask(with: request) { data, _, error in + completion(data, error) + } + self?.task?.resume() + } + }() init(historyManager: HistoryManaging, bookmarksDatabase: CoreDataDatabase, @@ -81,6 +79,7 @@ class AutocompleteViewController: UIHostingController { self.tabsModel = tabsModel self.historyManager = historyManager self.bookmarksDatabase = bookmarksDatabase + self.appSettings = appSettings self.historyMessageManager = historyMessageManager self.featureFlagger = featureFlagger @@ -191,7 +190,7 @@ class AutocompleteViewController: UIHostingController { return url }) - loader?.getSuggestions(query: query, usingDataSource: self) { [weak self] result, error in + loader?.getSuggestions(query: query, usingDataSource: dataSource) { [weak self] result, error in guard let self, error == nil else { return } let updatedResults = result ?? .empty self.lastResults = updatedResults @@ -283,47 +282,6 @@ extension AutocompleteViewController: AutocompleteViewModelDelegate { } } -extension AutocompleteViewController: SuggestionLoadingDataSource { - - var platform: Platform { - .mobile - } - - func history(for suggestionLoading: Suggestions.SuggestionLoading) -> [HistorySuggestion] { - return historyCoordinator.history ?? [] - } - - func bookmarks(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.Bookmark] { - return cachedBookmarks.all - } - - func internalPages(for suggestionLoading: Suggestions.SuggestionLoading) -> [Suggestions.InternalPage] { - return [] - } - - func openTabs(for suggestionLoading: any SuggestionLoading) -> [BrowserTab] { - if featureFlagger.isFeatureOn(.autcompleteTabs) { - return openTabs - } - return [] - } - - func suggestionLoading(_ suggestionLoading: Suggestions.SuggestionLoading, suggestionDataFromUrl url: URL, withParameters parameters: [String: String], completion: @escaping (Data?, Error?) -> Void) { - var queryURL = url - parameters.forEach { - queryURL = queryURL.appendingParameter(name: $0.key, value: $0.value) - } - - var request = URLRequest.developerInitiated(queryURL) - request.allHTTPHeaderFields = APIRequest.Headers().httpHeaders - task = Self.session.dataTask(with: request) { data, _, error in - completion(data, error) - } - task?.resume() - } - -} - private extension SuggestionResult { static let empty = SuggestionResult(topHits: [], duckduckgoSuggestions: [], localSuggestions: []) } diff --git a/DuckDuckGoTests/AutocompleteSuggestionsDataSourceTests.swift b/DuckDuckGoTests/AutocompleteSuggestionsDataSourceTests.swift new file mode 100644 index 0000000000..29ea8e5636 --- /dev/null +++ b/DuckDuckGoTests/AutocompleteSuggestionsDataSourceTests.swift @@ -0,0 +1,151 @@ +// +// AutocompleteSuggestionsDataSourceTests.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation + +import XCTest +import Persistence +import CoreData +import Bookmarks +import BrowserServicesKit +import Suggestions +import History + +@testable import Core +@testable import DuckDuckGo +@testable import TestUtils + +final class AutocompleteSuggestionsDataSourceTests: XCTestCase { + + var db: CoreDataDatabase! + var mainContext: NSManagedObjectContext! + + override func setUpWithError() throws { + try super.setUpWithError() + + let model = CoreDataDatabase.loadModel(from: Bookmarks.bundle, named: "BookmarksModel")! + + db = CoreDataDatabase(name: "Test", containerLocation: tempDBDir(), model: model) + db.loadStore() + + self.mainContext = db.makeContext(concurrencyType: .mainQueueConcurrencyType, name: "TestContext") + BasicBookmarksStructure.populateDB(context: mainContext) + } + + override func tearDown() { + try? db.tearDown(deleteStores: true) + } + + func testDataSourceReturnsHistory() { + let dataSource = makeDataSource(tabsEnabled: false) + XCTAssertEqual(dataSource.history(for: MockSuggestionLoading()).count, 2) + } + + func testWhenSuggestTabsFeatureIsDisable_ThenNoTabsReturned() { + let dataSource = makeDataSource(tabsEnabled: false) + + let result = dataSource.openTabs(for: MockSuggestionLoading()) + XCTAssertTrue(result.isEmpty) + } + + func testWhenSuggestTabsFeatureIsEnabled_ThenProvidesOpenTabsExcludingCurrent() { + let dataSource = makeDataSource() + + // Current tab is the last one added, which has two tabs with the same URL, so only 2 of the 4 will be returned. + let result = dataSource.openTabs(for: MockSuggestionLoading()) + XCTAssertEqual(result.count, 2) + XCTAssertEqual("Different", result[0].title) + XCTAssertEqual("DDG", result[1].title) + } + + func testDataSourceReturnsBookmarks() { + let dataSource = makeDataSource() + let bookmarks = dataSource.bookmarks(for: MockSuggestionLoading()) + XCTAssertEqual(bookmarks.count, 5) + } + + func testDataSourceReturnsEmptyInternalPages() { + let dataSource = makeDataSource() + XCTAssertTrue(dataSource.internalPages(for: MockSuggestionLoading()).isEmpty) + } + + private func makeDataSource(tabsEnabled: Bool = true) -> AutocompleteSuggestionsDataSource { + + var mockHistoryCoordinator = MockHistoryCoordinator() + mockHistoryCoordinator.history = [ + makeHistory(.appStore, "App Store"), + makeHistory(.mac, "DDG for macOS") + ] + // mockHistoryCoordinator. + + return AutocompleteSuggestionsDataSource( + historyManager: MockHistoryManager(historyCoordinator: mockHistoryCoordinator, isEnabledByUser: true, historyFeatureEnabled: true), + bookmarksDatabase: db, + featureFlagger: makeFeatureFlagger(tabsEnabled: tabsEnabled), + tabsModel: makeTabsModel()) { _, completion in + completion("[]".data(using: .utf8), nil) + } + } + + private func makeFeatureFlagger(tabsEnabled: Bool = true) -> FeatureFlagger { + let mock = MockFeatureFlagger() + if tabsEnabled { + mock.enabledFeatureFlags.append(.autcompleteTabs) + } + return mock + } + + private func makeTabsModel() -> TabsModel { + let model = TabsModel(desktop: false) + model.add(tab: Tab(uid: "uid1", link: Link(title: "Example", url: URL(string: "https://example.com")!))) + model.add(tab: Tab(uid: "uid2", link: Link(title: "Different", url: URL(string: "https://different.com")!))) + model.add(tab: Tab(uid: "uid3", link: Link(title: "DDG", url: URL(string: "https://duckduckgo.com")!))) + model.add(tab: Tab(uid: "uid4", link: Link(title: "Example", url: URL(string: "https://example.com")!))) + return model + } + + private func makeHistory(_ url: URL, _ title: String) -> HistoryEntry { + .init(identifier: UUID(), + url: url, + title: title, + failedToLoad: false, + numberOfTotalVisits: 0, + lastVisit: Date(), + visits: .init(), + numberOfTrackersBlocked: 0, + blockedTrackingEntities: .init(), + trackersFound: false) + } + +} + +final class MockSuggestionLoading: SuggestionLoading { + func getSuggestions(query: Query, usingDataSource dataSource: any SuggestionLoadingDataSource, completion: @escaping (SuggestionResult?, (any Error)?) -> Void) { + } +} + +private extension MenuBookmarksViewModel { + + convenience init(bookmarksDatabase: CoreDataDatabase) { + self.init(bookmarksDatabase: bookmarksDatabase, + errorEvents: .init(mapping: { event, _, _, _ in + XCTFail("Unexpected error: \(event)") + })) + } +} diff --git a/DuckDuckGoTests/MockFeatureFlagger.swift b/DuckDuckGoTests/MockFeatureFlagger.swift index 1d2c8d642b..5434453927 100644 --- a/DuckDuckGoTests/MockFeatureFlagger.swift +++ b/DuckDuckGoTests/MockFeatureFlagger.swift @@ -21,8 +21,8 @@ import BrowserServicesKit import Core final class MockFeatureFlagger: FeatureFlagger { + var enabledFeatureFlags: [FeatureFlag] = [] - var enabledFeatureFlag: FeatureFlag? func isFeatureOn(forProvider provider: F) -> Bool where F: BrowserServicesKit.FeatureFlagSourceProviding { guard let flag = provider as? FeatureFlag else { From 1fd625fd1c4603763c1323dd69711a05fbbbf172 Mon Sep 17 00:00:00 2001 From: Alessandro Boron Date: Tue, 12 Nov 2024 14:29:25 +0100 Subject: [PATCH 08/56] Remove Old onboarding intro (#3554) Task/Issue URL: https://app.asana.com/0/72649045549333/1208711411340874/f **Description**: Remove the old onboarding for returning users as discussed in [Asana](https://app.asana.com/0/1205738382433043/1208592180486162/f) --- DuckDuckGo.xcodeproj/project.pbxproj | 4 - .../Base.lproj/DaxOnboarding.storyboard | 153 +------------ .../Lighthouse.imageset/Contents.json | 16 -- .../Lighthouse.imageset/Lighthouse.pdf | Bin 190691 -> 0 bytes .../Lighthouse.imageset/lighthouse-large.pdf | Bin 192356 -> 0 bytes DuckDuckGo/DaxOnboardingViewController.swift | 206 ------------------ DuckDuckGo/MainViewController+Segues.swift | 15 +- .../DefaultVariantManager+Onboarding.swift | 4 - DuckDuckGo/UserText.swift | 4 - DuckDuckGo/en.lproj/Localizable.strings | 6 - ...DefaultVariantManagerOnboardingTests.swift | 35 --- 11 files changed, 6 insertions(+), 437 deletions(-) delete mode 100644 DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/Contents.json delete mode 100644 DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/Lighthouse.pdf delete mode 100644 DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/lighthouse-large.pdf delete mode 100644 DuckDuckGo/DaxOnboardingViewController.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 7b12570caa..8b53f5f54e 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -507,7 +507,6 @@ 85864FBC24D31EF300E756FF /* SuggestionTrayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85864FBB24D31EF300E756FF /* SuggestionTrayViewController.swift */; }; 858650D12469BCDE00C36F8A /* DaxDialogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858650D02469BCDE00C36F8A /* DaxDialogs.swift */; }; 858650D32469BFAD00C36F8A /* DaxDialogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858650D22469BFAD00C36F8A /* DaxDialogTests.swift */; }; - 858650D9246B0D3C00C36F8A /* DaxOnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858650D8246B0D3C00C36F8A /* DaxOnboardingViewController.swift */; }; 858650DB246B111900C36F8A /* DaxOnboarding.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 858650DA246B111900C36F8A /* DaxOnboarding.xcassets */; }; 8586A10D24CBA7070049720E /* FindInPageActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8586A10C24CBA7070049720E /* FindInPageActivity.swift */; }; 8586A10E24CBAF5B0049720E /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F143C2E41E4A4CD400CFDE3A /* Core.framework */; }; @@ -1815,7 +1814,6 @@ 85864FBB24D31EF300E756FF /* SuggestionTrayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionTrayViewController.swift; sourceTree = ""; }; 858650D02469BCDE00C36F8A /* DaxDialogs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaxDialogs.swift; sourceTree = ""; }; 858650D22469BFAD00C36F8A /* DaxDialogTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaxDialogTests.swift; sourceTree = ""; }; - 858650D8246B0D3C00C36F8A /* DaxOnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaxOnboardingViewController.swift; sourceTree = ""; }; 858650DA246B111900C36F8A /* DaxOnboarding.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = DaxOnboarding.xcassets; sourceTree = ""; }; 8586A10C24CBA7070049720E /* FindInPageActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindInPageActivity.swift; sourceTree = ""; }; 8586A10F24CCCD040049720E /* TabsBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsBarViewController.swift; sourceTree = ""; }; @@ -4431,7 +4429,6 @@ 984147CB24F02E9E00362052 /* DaxOnboarding.storyboard */, 858650D02469BCDE00C36F8A /* DaxDialogs.swift */, 858650DA246B111900C36F8A /* DaxOnboarding.xcassets */, - 858650D8246B0D3C00C36F8A /* DaxOnboardingViewController.swift */, 8524CC93246C5C8900E59D45 /* DaxDialogViewController.swift */, 8524CC99246DA81700E59D45 /* FullscreenDaxDialogViewController.swift */, F42EF9302614BABD00101FB9 /* ActionSheetDaxDialogViewController.swift */, @@ -7746,7 +7743,6 @@ 9FF7E9862C23D10300902BE5 /* BrowsersComparisonChart.swift in Sources */, 6F64AA532C47E92600CF4489 /* FavoritesFaviconLoader.swift in Sources */, 4B274F602AFEAECC003F0745 /* NetworkProtectionWidgetRefreshModel.swift in Sources */, - 858650D9246B0D3C00C36F8A /* DaxOnboardingViewController.swift in Sources */, 312E5746283BB04A00C18FA0 /* AutofillEmptySearchView.swift in Sources */, 8565A34B1FC8D96B00239327 /* LaunchTabNotification.swift in Sources */, 311BD1AD2836BB3900AEF6C1 /* AutofillItemsEmptyView.swift in Sources */, diff --git a/DuckDuckGo/Base.lproj/DaxOnboarding.storyboard b/DuckDuckGo/Base.lproj/DaxOnboarding.storyboard index f95f44d472..0b72f7c384 100644 --- a/DuckDuckGo/Base.lproj/DaxOnboarding.storyboard +++ b/DuckDuckGo/Base.lproj/DaxOnboarding.storyboard @@ -1,149 +1,14 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -331,14 +196,6 @@ DuckDuckGo! - - - - - - - - @@ -348,7 +205,7 @@ DuckDuckGo! - + @@ -442,12 +299,10 @@ DuckDuckGo! - + - - diff --git a/DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/Contents.json b/DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/Contents.json deleted file mode 100644 index 19cb768f2e..0000000000 --- a/DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "filename" : "Lighthouse.pdf", - "idiom" : "iphone" - }, - { - "filename" : "lighthouse-large.pdf", - "idiom" : "ipad" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/Lighthouse.pdf b/DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/Lighthouse.pdf deleted file mode 100644 index dab3dccc1f10964d303160da929a6a5249e61a75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 190691 zcmeFaO_QuSlAX7|zalqU&h3ovNHf|jNVd4qLL`5|sMws5tZHP`jLG!#^&Izu14P7I znHkmHGq;9$Hx+df9}b7R!{Kn?{a^m~|M&yTBfBawHUS9s)zkB(^ zAOF99{!jn)pa1Tk|J47tKh%GJ`n#9c@26M&d->bHrRc-IKm2k3`st#(%jb)pK40|s z>7x7nr;F~MC^{S67qfnqSG(&h`T<*ayU!PW`*hJ|0uJv_>+bUsaQ<}n`(;oc^uKWG z1ExMPQJ<&u^DJGY?*l>?j($+`3E}^g_WkYON+kdEkN-^y|80Mx`TyIW{_*es`5#^m zfd56M{^_6ppFjQGFW>&~AOH0K{+~bn>A(D^fB*6y{_FaGKmF6U|MBe)f84$N{Xc!% zeJ>$;#Y*_c-{e>RcDNqKUyq0H=i}Sk`S9}7FW+9jA6o=5F~`&E+w~zh0Z;=a<8|Ci--E*}d1Qb1Xu`*NH9qJ;6o2u@sUJYKzr9gNW0DGI~iiluneUjKOJBbU>Ol|F18H z)1dvQZ%ClbI93b2P%AZ}6Gq7>y4NU%y;h3-%V|GoVi8a=+MJkd?BTH})n=w_c7Ywi)MGQ)-Qv!n8T#sK1%Do)Vbw=v(wV+^> zzZR6Q1qExmED>J|iWa|r`wPn4pWr`eZM>X&gTm(V?OGd@>v?}U-EOE;>!dwL{bPS} z*>B-LuXqY9-r*LuwEOe2=^{k<=~zLU-S2S1q499h$m0J${?OKI8G~HCa*r<>8{U)t z2Y+FAAZozR)8*x|Y#tB93_#DXpuIDwvc0uZnBv>{4ZpovtZh5L-p>1%^YuJD(H$a76*C$Lq^ky9;1;mpeJ=YUB0ge4Jqq2nAGsv>{S^ z(stl-jYS7L0Qpp~N&9&@jZl4lrE|~z+y zl!qmLK(ofuZQ#SZ8?{k%uzkVDFXAvq_|@`%)yA#|D}LZuhaV>fFxtRu&g-yE&|%za1~x zTWgC))8h4!1$WGVUDY$&F@`%v&hEn_*Y;+abI&fNsi-2?4)#>bZ1kA^F&1>w{J@9B zl#O}Bp*F8^OWAh}oQ;snAI_71mkv50?FV+VgFecJz5`B_CPeeAiu_b*oN1TV-o&M4 zQb!waOB=+&#ujQvkE8V5R`1y4d5n8`aP<#ej0oLq?stf|>DXO+N3YNtZA4h6l-;zU z4XoOh-d%>QN<39jyC@W5w1G_+bRb$rp@Y4Jw}XnvS#ov+AxCL?v`jMA0W$lVxiS^( z>xXoYq>51&xU?(L{Q z{L)quUSciI#2bOxR}(HC>%du@q%2mC$cQZk4IBi@yq$^Bh`}^)QQ!txk+L%r=Q$!c z#D42^r3cmn$r?ScU`9I|pj|fiZdb85HE>nCOqb?}?LEqQZ7R;ljt%kxPJ3KdwJ5-Z zF`}V@3U)VTIQEMozY^PR{51Xj-HLX^LnfUz!i&=@F#?#(5kMZN<}HFnAwrNz1Onqsab?Eh67dz!0HTJM;Go)j+#1q zW$um`4a>xZfTQ4(+C>lC#6{~cFioISCJoT+IkIlr2GD>9EEAdrb_5bMOK*D`K2UR* zjEY&&GQn63t6P>{6f4+dupEqV=R_4^n336XJGzZ!_GsB+cwpFRL-8)k%Dp(e5^&PM z35v*bsU{TuAmF6wyS~6?k9+?XGsnVZfm5KwjH7|@bI<=+zOV9Hsyo^hJ6c7kXWH-- zOOO!-HKwvehFC1TCgJOZ-o4hirk6lubZn0o>BupjfTwTI@;|}RE-TDvK(th6S_Wbg z(fH8Ic*gv*_`AE^RZ^-^DEQ|g@1WB3(tu0Su4Yv99$p}9w#$@OOz};T)6oR_Xko)- zsH_5esEKV(R33?uDjbIniKTA)oM@^hpIINSL9)=jVxL;RfNgb z$bEGa@(;zeUh5nf1vGyZ0`-7do7|aPzY!Qkh{6U8aS0_8Pb6Ed9&p1(Pjwguc2a;; z3nGgcwbLf;OO}Lc;VznpUb}ZN%K;oVnarkTd5J#jyeEPbVYVQ?G5E#3-$r*@)78I9 zZ>}y+FKs)Ppw}zb?m|Evb8`{*eF}8u-$iTNE9ZrzQG7oVvODZ*Z9_75r^D{}0wYdD zOo_4Tr1P~wSRzazbuFh?%;uT;7l9nWem`_EZ1h0h?htM9M{6mDUbDd7m1H~MUef`k z++GMl;`rTFC&>sLo^hjiEk{xF`oh#cLJz}z`n>JT{7VsFrDDl%bjJEq2gKs^ud*5v ztrD1L0;nweI1w#s1hFwL4I&b?<}rUd@)UUD)T=DhEmXR&R$ZhteH3r*JAPWe&KNnS zf5+L0R0b^?hvJvxjzcVo7b?Z_tvLAMjm#CfPFM;~tvCnA)sgu@&@5g8nMq+&yx;)! zrI3InUMdzBfIoF>K@bOm`~oH5b|4sWiS-TGV%X5wiFP>OXmYbdp!TXW1Zjg&AT;|H^i!5@_B# zKf?RQbLD`ExYYOS`Lri~^9!4cpln}+a)gR$a7lIz!VdC2u8nD1D@;)+_TuV&&(StZ zZll<*3m6L^i6}c^tbQCv3!`l;ajWHMf{k{9+cSSw+&ZdI4mAGU^qv^AuLI$;yeW~l2DU^FrKkb-dZ+486u z@vQHcE+sF24B7muwO!j;nj?)v<#5*Umb)sZ&6svItW4c6UR$?_FEwa!$4B{G?wHyk z8pfNk=CvY>EMUcJ;tp!>^n&xAQsFdi+9b!E-mxWgFUlL}+S+F{-R!B;Gu20%_yIja z1$fl;UP9=OwnXe{1FfBg*Hb06{O)blr$Q$v(y%z%t}Z^$@6tYhYRve)nP{y~zxPGy zQ-fY&WJGN~?dV+ymyS?9KfQm#zr}o5S%^M(`=uCH=bzv>Vn!8TAuH!h?An1ZS!-dO zIuLvJvN%EQ4>w>8^9c56iBJRBDyo?RjIKkbG@t+u1)uLNxtjva1ZjY>j##N|6DH96|69;xO^_7?)9Kg`!JH9HsC_(SRfK1NOwL1BGytrC z2Sb?cE;*0_+Y1rsd75B1@Br`U=?607iQG$O)KhE}Q;^t4u-2HIDRyim2%ebbQ$%$L;PFfu-@W!h z9#S>IpT23S)084q(GeM^o@N+RQ$v(EiD6Uk56h+ZXbUPudPEgOc^6%1z{AA_bNFzfSLdl7&N8xX zQ}whPaAGhVUSHoxe?C_j+~D_DVG8+H#D$oP&c|I4 zmULb1?yIVHt5q>bZDEP@sEdH!!QO)SZr4%n)V%@?>INa4C$PhA;zBWoa@1v>4ysIE zy({F&gYZ+T-_QW5wv5I#9^L ztuv-B2FF#bQWNeF7>y3yfiM~$`VN#<4agk;xoQac=^OrY7n>CS4CsQ4-NQingfX%} z8-snC(Ptv>*X!#WiG6#P?RD*cH}Q`Fw|o$;svysZA-2$zd3}^<%tJ+sBGJ+INVJiX z=(i!M24OUuy90qD(IdzMO_tt4h$Q-SPqCtIZcg!CQAcc<5Kj$ag&qd`G^4reF(evu zF3Umqssy_B$CAUdf@&vzD5%D%ih^l60q=R|2v9nQ8r({>Fdak5iHk&c!BwJ#V1G)A zPz5?^goQWK77(+|YTNw=1S*ME)J?Hwc~L~{`PZr?sP?hglY5dY`YZ6bd*M{;*ku*R z1ETtZZ4CHnW)s~0&T5WtNIb32Mn>rJU8(*GT|Uj~nOd@!$GjTq_imz0X9D?ZYx@h4 zW3Sw}YBqa614{debup2#h2_%SLgl0ZrRt5B;y$n-@nX{P(}8gk8b)B8=00sRzohGF z>59uJKi+v9AA12hLAGZoqt$M*ZslRP^gl$$h*3$XbezM+2aJ6S@>{7b94yzdWS0!c z4ujypXdv*OEwi0|HVAHj6=acRcg32E-Nn-h7aMAA4{M<4w~vj>LqO87aQ8Cb1o|6}ik!vEswc7MP_ttXM<> z3GTe8lRICu6rvZh^~+;zK%muHD>!PqSWX2;fH5v`#8 zXS!mehIEWLL^@*{*_IlHFpup-M9#Z#ZA5wyIP@7pQdMYo3#MJN20UOSMU+DYw_L-> z33`_dz0=&&u6NX8WF((OnN0F*IGG>Xm+k41B&eaj zNqtnJ&Y0oEFbR?zjN9AZqZ}{FB4y~InSLa4G5DWfa-cefrNC3d zN{9JVIhkTEH-cc~Xf<77SGMfc)2otFU_Crt&f+v&)b|+-o7QsrPU8;Gk=*O!X}Fjk z6im@lth8kGsTjn9O0=d|b*;rEX@EpZ8k_@OAO{>~)y1Bq6YO3pFW{30PkX{_W7L>L z8v#a*t6TqOf_V@**5TF6P5Ol>*r+s73CKVf1DBuqf#i>JYwc&p!_v(Xl zFK4nou-k0GmECbO9_3>7z;&^A{GKSbIksV;JwNkf8P8h#+3}FgXL{IIE%U^98M*`h%3xAEKmJ04NyiTp z)AGX%k<_v4}7d178Au<_)QJM zIw{NKxfa-n`zO{T&clJ+!2&(MLa zFFW?VryXNZ`oz6p#0d>K3`U{bOGQ*Yhf|3apXCV;!kPY48o#r7MqPT*gEd zt3!|*x&PF7V!jZStV;o(a0D~3rShLMn4IH(ygNzP`BCBT9)GOMI+g|e^mP3>gIOI3 z1nj+;!7$dJbxP+S%V>fvBE^o=1$9{ApDVc0D=HT+tiu9 zv853U+@e8bFy^MiSFd_gqyBMh=pO`1?vRWUKX8=V;>;G7x(f%>gJV4l6_2z&Z*!J) z-dP8qvN;)ANQQM`Pe6F*jW`#$1~=v!Mwp|yH=&G)xI}($@oEc8g@u3VgL9PbEQCA` z;xEd-_qK=G*oGKP_Fzyj9F+&6Gwuv5NQS>GS^49(Gn~~ib(eDKfkd7=);-eyJnLBF z6#C+-hVCS+%fn2|-_Y8OC_h*peBo&^Oo(1Qm1S^vt38w(te~69Pg~T!$*aNWn$_at zy*n6UjrOKOk1XovXr!`Z@L>fzxW^WsH>mT?q}!>xd@z*QvfnfmhZ&clJht~6hSDcBk}(dPr;L3t6i)l@ME=j6mHYOd z9||sjJPpnzZin*0iXDdLM+FJJ!3&5M#6V^Kv?h4DxxxNy-QOv%(;U{Cwdnrm_IER4 zq03cnYJ!XBw2Ux6^J7``*2+&>vK>b{V>CCrkVx6%kDH*3ZY?!8Skh8T);%H)osA4t}0bQ$FY)6>%m zrPNK+u)mqL4-|^?)`{*?I9b zMcvK(y$@wEa(DXj?m|1w**vvc;uedHW&ZNx*Q`6I>ejcV=meKGw|altRB-<-8G*#j zzjC(zdY73GoPLk=I44YfC13t^?u}n~nT6yL{?m_Db6YJbAMakfRmT6}s(ld21of6d z>2rfjpD;bm)b|ne1OO*Y4eG3=>gwF8s_IDV7O6COPG$}S3R8?=47u}nC4q_*m2(F` z)t(>|^3yl=VBOrLm<%yxeyb0R8Hqq5nYS6bhZTAl?9;Ip@`Z*->xL?B)0as9bwv6= zELv&o+*ej=&!-cLH!eezNOyjDE?nH@$#)KuQidxH9oZK0KgG=tu1Aw2CQjFz_Mg7X zbi-)!__+jh%V=S~%XD)gp`Z5%qg9M&@5c=QSl>w54oc}-K)^ceo>y#KcfDdGh?kJo zD>j1kAVA+JpgC-UuPxnPvC(w|O0r>9zxa7%bvCpy*yn8rDT*;3x30&#m&O=MzcqqJ z++4A#$5oQMX(P>LhkB$Nr;4E<(Onk~4rJpU6#~3>#b7j!*&PUEQV3gib3pDPgy@P5 zPxt6;l}WK&b-%4bnq{uo@FGu@TcC%*KFw&ob$0fxkGs75FGf$^|M`qQbLfcaAcYjS z0~?LeB&OPDx$n6hB;B`y5fzbw9rdIl?td#g!r0iIjc#zY(L!{a&lTHBfM7bJ{{fL` z(&xM1fI#N~Vedr=kPys72;t^!Q4BUIRu-%+kq$_@GU+hg+zLGm_GyVe5#Sh%=4$X4 zqp{I{6-Mv5(!&F3XCBMl<5RCsso_@sdhRrrIPTviYe%}?SIY}#!$yBSrN$%HIjY>x z+=Y+xK!^hP)WqRg0?%up3p<2Yu1g(69Fm?Td(h}iyF$@@IbdEenHV-CcMc|s5#iQi z1uSGJMtxd0mVRa|bW*e&Cu>8c6;$t^@tRH5etlU{jt_jINsnVhGcjEcMAk5sZBYNn z%kxbT^6l@T$^vkEDc4yAYUfQ!ecc|;k%rajd-ak7)_sHNPaCnsccfXQ8lSlX+WBtp zT@XCY!N5{JSi>u+OgMTK?z5Y0nAea-A{}MPiBs8ntD_l&6u1FhF3HIszb-E8XHU4n zL2UlqpzfQPvGOJWFIr-FNO4?4K@#XmuqKn%nv-5$-A<_~V(Uv|?u>p-0rO_UluVsWJf_&~9{ASJ zXq9>IR`HDowTcyYs|XO+<}6maDdVzwjzg$+4-?G8tLw-P+zy&tFkuJIk_HztJ=*+D z-7>9EAdY4#HD~ZvpTil>sQf-aF4*XrV3Vc1)uxpOwqS+#Aw7eTou}PB^E>8&+dAEZ zK5%9V7_KIgl3d);gCA+YQ>h1{JUMW|lfLH?&=8ME7!4?}z(3wEML^73U8Ehu<%<9& z3pp743P=My+w9wi*hQCRWLm^pm?o@;YKw~`409o{+pRZgg|Zhz0DHI?K{hR;0rrVq zR<2aeg`w9Iq({F;*$iT*XVL1PMiwdOUi-MM1`Y0xcIDle3dFU$<89Z$2KEU}8ILsA zGQd^HrB#BvWr$G+T(Utd_uFc6KoP61PcC+)Nf7#i=q|~jq^1VThkQ@HnQ9Y#MuDnD zwun)XDVwwyrHRTgUW?1kVTml=yFX`=R-~V3bFz=NVp8<4tYf*dhEJV$)Ff0 zDQYmvr7xtJT9IUHx~wi#iqT3iAb2v`J(HWGd6N5`f$2jNQaXL$fpeBFdtToEM?||- z-Bj&|7HAjc@C2|)oX;AgUuMI3UZI1A(XOAZ*ANI9hA<|?^g@Ftn|A3$V#VRjwDx-c z+=){N(ddjNz^s{T2=oGv28c`cFwQf*hq9)Dw@O06qDUt^OXcB1*_got~p~;GnFUb1ZLx9WmXeB1nB*~1fZFtm2?=@MMO3i*r(4` zBImL=yVvWL80^OzL1x=bmHFFIPfPn$Z9St@D1)?hW3pWmH5;CwoR=ymgB4#)&HyNH z&H836laJa9Q-IhSOoi%1?{8%k$iu$N-DsK_d{6Q8d?U84m7rmnQ=Z~EPMl-7ls#5 zcY|d{dBAP-A}6jPrb?A{Q1LK~r(Mc}UcT-zmQ#5>aEbRbEcCtMS^)Vr!U^qR6Tu{i zNHmmnMkuR`9_?=oaWggr5B==g3mdr{+vOHEB9spp_HAIgf!)0qCEisbnne+4^mQC^3e0Ebo1<8*21iPIo1J?!GXU513ZHVJ&7!bhfuRa<@~Tn>WKv zoETE8ez3_bF&gnuQ?!Yqb(_46H%6Z2kNl@0?pg`V4c4|X=lwnaqpT$5>K~Qu zZ593F9#u)ikTs?ISsa1hs~3-^yteJ4vb1-)o#K{S93~YJ@*17JHjsIt2zYsyx?>=Z zn3`<5Mc)o&Ebgm)?m|dD#Md~cK2;pUe8~QmIHW}n;J7(9A4b>~iow zvSU`AB(_yqug$xhqUf}&FIUWg`Kw{Hm&YjBEf&SfR<6PF&TqUeM>O_&5Ni1@@r3dD znNV*VCfpxDp?4nK$kdJbT#U_X>HhG?ChS+PejH$eF9#yI#|Jt|)Y zC44=%Rd}=>!m|JBS=VZa*EBS)-(10s7M*ivhst*Y+8R!c$c3MEzi3y0c9*?n9{^Rm z@NjIrabZkYZ)GL&MD~Ek<_%|i7`Kq7uYrw~#=k_b9>XXi%N+PueY>xvoau9Cd+iBT zpxknoqyeIDhP~`)ruTYI+l7ZtYCG?0`N75cA?CqolXbQ4gkmVj z)eS@+4vKI!-7$3sOr~oGqfHE&xf)c7)tFc6bAoz(%cJDDs?0L^Zow2HNLtF}pedJEBX{dn_7o}<)ygaid+F=MQfc09ico?Pis;}iD!?ahO7ICeB;c+#6ST-%U?(LPbw5pR)$X~ZcCg-*n|VQ@ zh#ior4|-CRpAjMa1WcM-Jvi-hb`NBycwnRW(Ln*P^6W*%(B~|Xwebkz{!TW{vK?VE z_Y}2i5|)+fLvZdX{_w}sr&n4O#C=uVv01<_cN*jTef-c;s{>`%i?S_iZLnnk(I1Qg z-XuLSZwttE35#sN`Ce7*6j6E4Xb6xr505o2C9_o1$n#@^P<&volYy|tZ1cTp1jWM7 z;ccVK09U@BKh5_&Zq;vMy!I;fZ(6wz7@v-mPGjb+7=}x8p?H8>#{0;QC?H{Jb2LoG zM{$j1GKi$PJ=<T(jGtv-{As#waF0bL!lZDyTmap~{$Cd&20f&<>1`w2#yI8-+1L1~k?xEH;kI(Qq#xUCZX%vT{vrm2y!90+xrv81#~ zDFs2bFmz|em#aSRnveDBNu{ru2ikp59X8~JWPn=W9{Qmsv#Vw4A!wc zWv*i*ToSiSCF@hIj+V2NVPHae(K4rhU_dIl99RcqV)JCE<8ldwsg1 zgSNWKu<;5ethB~qN^GHd7a`FU{w{f{#2uKe5_RjMYLUpiOgXEl{&<7=Q;14OrlkE7 z@5oiMR|+Pw^_p&wHVbedL@;5!fH2*=dA@O4BBsi*LG5H{=d^fZ9!aZ?Sfp3TYDCIQ zLZ7_*$Zi;LzW7x(3Zf_E1ZCboP1O$UP>N1EW=bc0d=4?R7fC^F%x^4W`5zTNkbfbv z`&gFBcnHRt526=q6jTfDAbg^zz~FYP0NeqS6syhF0s4_+Fi=!cvY>hCQwTk`+$*PQ zC(@59%9E(t{2uaSPeQC@i&}mXi+pc4Iq75PKd|@$&^z3yV9U{xLcHD4qIR?xaH{eG zE;^siu??g13}{RA*Z67-ex__=F*vgZFa*w6Vd@jh0UYvb&M$c^nBO{*W4!#+A-|>y z)Vo`qK5*74tWp51iQ;Nwn8gfIyRAm~yIYL)Mg7e5Kx`B;+JMWt8Z2|zA_sXL&x7K2 zS=dp}ReG#ydoY0AjZo^+6x|TPIre-8t@neQ>3r`0I`Qr)q3u?+s~Q=X@lHI8t0wliC0Zar0fv(qemaP zWl$bzG6?421JMKPVmB8M0b_Z&1F@O=hR`5;xL{^5rYIa((By0|(WYijq*mN+k*Rk8 z2i?Yh7FuH9HnFo4Z7UDsKsN;GX(`54E6btJ)M_h?3`w_Z@ABRexfs$D7x$FlmtWA< zWg{~QUe*HjHp4FX+~xE zs!$MJKp`hW0}G~M-y-J7QU;%Ej6U_W?{q!7Q-5Jc;^UG5mufG%xS^S^njNBncr74r zr#Ic2sWpXST5_vU>uN1dTI!4ye-x$jq_i}N53@{>r32&guU*j~&YcVn?luAE^}j?_NMmPcRhSrXdkul7(1gOS1K<)1)~l)M&46m>N#8lE0g z+uA-W|6P9$8}xN`DI{ZIu}1s=iVFok889JU?2W(n$;*tt`;ZcoVZO74lfz0X zDc}7bGdaP93lmJX9a};P&S`n2kG+*RdF&KOPn*MGRnB~#(44ZCI7%_Q%{!Pl3zoRh zHvblswayE<&t#}SLxXH+JiJw6dWI-SlW{>75Sboiwqt})A}0Bz*$rp zXJnl6mppLBi`%4I(`4c8$trUUctx3XM}d{G=QePnVETyk&pv5eNzkKDcw`Th_;R@@ zgps&uGfiaCDL3=lRbJMxLV$4!-%WAm9Pc*aO5Oiw^CONM+#2-L9Ou;=ar~?c z2&_b3LS9pb=XT3-Oa2YZUGiy`>;8zXI*ZKel)roNAOBTlrNJFmWjDcdtqJNOWongE zO#7dby!M%ewJ**lZej>^PNye|RQC=ZMVKfT14i#1(4%)8K#zkoZ#i1*P|9O+NvCVm zJ1JptHEcT#&2HGlh)Lj)_1Gs$jC>pIb4kn^eac=89GW&GgqGF(;hb?(a;czbUW+RMAgGz5k95;ZAt;?wi29HFuREJ0Y$Tn#;&_@3g%CP%kXHd!9q)02F1 zE*?2124v&&atX42Lo)Al-W2p5!hsYtrXXfY-q%)1WSg1c= zD;hjkQb!-PQ%VveW$jh%h&B!Z08|5YR6n0w@Zv+ex*0r%FmH@<3+w^JKlLdm-dc*{ zpY{<2d(nxKpx{uYuqI$;qk}nENSj`w@w3BsrLxyQVRa6|`C~jUyi3mtwfVbR$Gh}W zPRShIf_d;@re|Ip#)qF?c;*Hlo-KK|i90lYCACZ*zW#cB;p)!#Yi=&+uE>x|N_v#K z2frAkUYd%di$Uro0*2lhB+H8Kt`^6&XEWy(gQOG? zxG9Qm43bBAV~|FRt3k3jtp*7*Ws$`AST!*-7U&y;!96P)^NloNi#f2h__Bdx{js109BXMI+F&Ecg3oNsac**?-RR zC^z}y8;iZWcFDLB?6b{j-L2xUT5K?J{HPfP9sTH49nixI{I8uZPX%;vhD*g@V_zS; z!HjljM>~7=IOe)mWW5fbHVCd`YJ0)dXBjU3G zo%#(r33aPgS*s*1Q*yCv(NAF0DkJ8DT@E&=-}W+>^mN+Mt;#gQbkR%xD+NZ`Ifh>6 z%3>!Go04IRZ0n%5FEiLUOJF$AB{Wjha%haj9wkZXP*<`Wqzw)+Q<{%p86zE`T2^qX z$H-=CKM`d&p*7AYx~$rkG}@hRIcxk<)-;ezP=s;JI=yy|a3^af?1RG!!fE++6Tbr6 zrC`<=#`HfRE*(ynA{w)~tUv8iaKKXBB=);wgvYmo<cO(Nwyb{xM6)!}-9`roP8H zKxN((XfK*_Qrm)J&48HWgKle(hE~lfyY|``C&fKYdRxU+iQo0yD?RAg&9M%Rx^lp) ziyRtvZupo8BKnCoIaYO$v3DYv|baIYHW;PQiqC^Y}s0P}RaCO&{H8ILOkK8 zxF;jU>G;Gua~1sH9WvKSid8C2(g+So?J@B(=Zhe;&4T@i)3%nYuDX;zDkWr4l3^WD zhe4nA_o^nBUN1*@$I4z( zN^)D4#bS_5vv#!32;UeW+b-*|9IPA@@@c%mU(6@MFs2b_+Wh4k4k3B&yZNxr1}bMh z=1YoQLzOXI@Dy0Q-)+nj_}i^6NmvqTeIP(K^!;x^WSS~_N;<2zDfLm$%vgB?r&^v7 z2g_*R)Ko?^?v0Cjfj^?M(-clnrZ67hgm>fkOKGq&Q^Xl}X!DR>C={r@u@0|o$nY8@ z5S1snJgkn#BfF`TX4Z4F5;>7gq+MA;tNR3P2`PcWny@Tk^lifXxpPCMRSDAe8bkei z@$Ek-kRinR5e!E--!c&xD+;;zP9mj7WC&wLlnvq1t0A1|ts$Ja3?Vyd8s}#J(h7PK zT~S(TlYK-%qAR_u!cZB)=C0JOuiw`6^9hqdwy)q*`UuP2pLY!Kd9i{Mlo4zjr&om9 zbyQj8)e}Xl765XChE^&@0J(^oEMRN2tQ4NK8OMvFLj)D~GUHYYIMG`RIB{7(=?eCj zc+JG?jT^BOdpUbN$@>R|j+H#V4m)7S6e>CQqzi)ePyW4Z9(|Q0A}G z9`wx5EUWxs+T#5jS{)4_aW<3$Y58j_4mnrFEN$w^_HGK=_L+vA);Qt1KBecB-Ad(g zb~8NV8I;w+Y+h~RL~m{4#BXe(9?FYO+_ZCp_m)c&Fw5(`<^=7?ycdP!JK5a0Vw){-*9@jrgqeN~Q!5j=ytt&m3-u%iC#;_|tt7k; zMxb}~2rvyEF}k*R5EI86Qkbg#p(iP?r~k(?I(yXH|6Uv>d9nkTVG)J;bg+^Ua$=aW zz3DIOGL1t(8ek;u4gE9Yj|6JXc(;1wX#;GQO)wO=Bn=?pV}VoVffytgm3uD37%4y7 z<@Mr-O_cP((zd#y6U8zwuIt2Q^%JF8Tfx~=H`rS3?M(@rvFb)BOtzt8r6R8Afg>Okjdcux`BCHGt#c z^NuaV;ByC8ir(efpqB76uHlrcjw7LBpp6e0nmC$Bx%j1cAl>MK6i|NAXe+d0F$R_qrS%Lp zGz58irgXK!bkzCG*Hn=x{ew;wTI{LPY1G$D{jf8|8}c<%Q_2W*J^N6HXgb2Q->Ic>;w&T_+qD)^i_2bUec`DV+ z#QEA(A-wb9@@$|8#gtfU3p#%Mi*2eDFB~fsfz>ai`f-&?u}i+=K>Vw6icfq{fTweG zzV+@kf0Cey3~~NKIX)TBbB4;(z}XkZskkuZKb#sNI4p#GNj^JOWeBed(SwOJ(HN%# zRdHVr16@x%_^xktymbd`{#=X%t66v7ASZ>ctB{5pRO-p7Y)W(j)0L^HRg+ z$C;t&W8kXHb3$PseHr5PX|zW;YxJVK^EE#@dU4N0;f!&rXN+?UVVVzWPt-JmdE%6E zoZ99yn3-C&JtfL3?lw7{$Y3Hc8sT6gHlj-sH*A79HZlK^9YdtXb1LOA_$ucN6)MSD8Lr7sv?E_^eOQ!bj@lbq%61iq`{da#dAx#*$W^X0;m@H)Td zDZRoNYGZ`c8{w2>AlxxkJ@{ehr@EnkIbRR>!%IPTpe%RQ<*1hD`>L*VNRUpa2{8-g ztGrBc_rY7Eh)h7gIt#z7ylllf;lU5?IFm1l}ZRb->ddz99v z^N@LrXzo>zG|CVD|9IKG=#zj-739o}oFf7%Y=d`a?P#5}gj`ZsXnhTO+y~;% zZ(WpqUnf0Ll8{7$o!c)n%toXkwn4Vc1WFoGi0c8YSL>8kr`p6Mx+v+}1LK0neT&4$ zMvL=OCp8+>oti;6TgHGetGi)OC6GMaaDwe!mzz+SLo6rd0zRESPl#iv70KSK0p#mB zeBwisHD--O)cxr+CaZ|n)h+)}`uzAEkU@_zXC@T^tV}co#w&Sl$&`XK%?);V{UZ(B zBuLc-2VFKuIp1kgTmEDIlqQ0}Ja~53Q{|@_jIjai%?yID4C~qVTG?!$5V8~BaN<=s zq~SE*#6qKnMXQi)T85T-mo@_0EqP=t{GA%3!=3WTZV zf|5cvN_OU{l3{}pigTMpb|y+YqbGuE-0D$JSmcQ+s&|JfDrv0m*Fh=iicJt5N$Dz4 znK3um`QBjtXk=+6DUcEp>gw`DLuhzIrcjb3k*d}nnfAO^C^%aG^swKm74J@0#EWRI ztMkHheos^>rlUkE-N>@5FW6f9S?SZ(u7{(T7}7V^&g>5$%H;>` zg}RL5d3hl9*4-(aISfqGShQZr;G`6}m$VGEQ>t0or12Swm%C+-3DoPanh-O$FQOIV zgyPl_R9c}|51k05|EjRPesK!e`FJlHE&`SQT5*^S`k%S)QQeyKcbDk zZMI+;C1LdZ4i8C14QP2PYvP>a`L}3cAZQ$e4kiJ-Uq|xCzV`v^gJd$E4ngj@-(`!3 zKyXulOI&Tm-}bz*E%m{jk&#D_$g1-Cfg^N)@NYkE6vOs*Olw%yli8-uz^-jYCqA<+i{aSBOLw*~1l| zTt=D8Tq2R;3Rx=-F8bd%@DujRf8|D;Iand6kIHZibJ9YWF3prWhX`nzMc&3xioD0N zkBwH^^F90JEk1DPd8>dpSY2cvVii7E)E7Z?Z5H)dlH_KumMc{jTd{>Lm7iTA{1&9V zoZA)e-6bOSB-HSc&%u;nVz=#Cu>5%ZQyN%3zOWj;WSG-=UD4EE!E~dy2J{aBH2WV1 z@f$1yt#Q`DQ6e`&WY|CD-(jm!8N5E6Dmyu{4BR!k1zA-Dp*>u~f@)Ne{tWdp2~_%X z;L8zj2V7M#9DhhBNmZ52LL)kvDx~kIR7Dn^#^OiuMR4UcHLgjS?A2-hL%~`!?`!`Ca}WoEo7T^p0~T@QM(FBkU zvD9;(Xh`ELADMEfjLMx~{w8-bSPQhs>aCbjSN>Kvr{$siaHcHR?tH@>2;16K^VLE> z?4&g*Tj+lGgbw_?%=|i`zUAe8pFDZ~@l;CfV!h>?D2khH@eOL_-PK;8TVR;3&vf^A zC)AM$dAmAYbvZ`j5ib~v|mI!W;L?zF)}AKsA;O& zwtq~XQ541g4ii6Ww;Itmc|Svfrpq|NWgVDe^Ss2u3C#oj`6a@!FL?L%e75p(W z3MLXQO~IBQ_kT(QtI;2gF2hawcUqsT!6+U?672y7`(56Hs@DQ~ru6!JOX^p0r6f0w z!6HGA*uPkEj}+k;htey?kQ4>4DRHUy@tM9Ig4F)Vz{gvGToy%qSYX^{mPDZvLuG9 z?eNstG?Bqc^r=Ud~GWuP9y-X)wFli)ITS<`j;uWfN4iB1-f>AY-4`QO#X>SlEA~< zWhq*$e@L)fh5rGw8DKlKoNkRRTJ{fNHCqaEB~a}>+(|$-DH4~G1n)s+C_cSXHSzg? zkb*L)E)m;tU<;IRwHt=FCZ&&~=o%r+>6MBm^Wt=65_6uuN2`G#J${ChI&7k{NZf;a;`pO$IdWTH< z!($&6IG8;jcz*|uSs$};08K1H3-vE?(K~iya@cK zHI@&zmR(?95@G?3osU<%TFk)WO+YkT)bO^A7LY+#FvV8wV+2b_X+21OEF0D|dK0lTIcYtdNbw-g&s22vUS~cq0QYjQ zqq|`DY=|KZV`A+jr)Kk%beY}A{T;bGD8XAR{vuQ_L3&bK(33q2t>V_9S~8AAE-SUiYQW87>odF=Ox z(37^gNpro>z-JjoTPv|oGEbjokb6do25EKf<6}3O=m8F;9<_xCIF1AM3*#WQ#9+PZ z$;VttxEPS1!(`ue4@v#;cwN=y#N&s`Oh0L#J3X%5$53ro$Ss|4Xr&ts>RZ9cq^m+q^iu*SqqMUV zEiQPs!YZD`z6E5EGh&dU5NEfOI6_b#f8wi$vv3}NTC^+E!Gk0tEs#gU{CKn}#hTMH z3p4uNUw*LY;EZ&89GW*%xXbHi;*)HM#?$LgeQpmWV`p<`65dU{-q43HlfcA1X^`g! z{`eLGTfx)yQwiDaR3mMAzx>K0-q>UAq!0B$K^i3}m?f7Sj$NaErIzX?w$#^Cy%9K+ zxXU4%EVdRycEpYHQn34>#l0|c2B+#OwWF}w+FRUFx^vfFlyVa!0QFE%TGQPOeZ({F zQt_yR&~20}AZE;dj$%2k3;Ba#{OAs16T(865Kxw9P{*?X)=*6C0@l;YyaYUY;RGU( zhryh<QGoS~JF)zHS&L_KUXUZ{n zH_8b^Y}|E)4M`z$gWyTNlrz!ZKG~9`Y<591Ze2aWUS1V&evEwl;d&FtRyp0ji6f}x ztSiT-(W=ws0H=;cZ@@PM;rg#u-hwtNB#CZob{!=Uf(Zl`|p4{VvJ-ssWPQShmiOM5!k_{csGKdB0$x z74eRvn8p$BfOA8iUQ&5>7wCB)W2dcY5xHWPn2varqna zwusOGhP|P9@!Any8jBdg1KkHu7i)Zj?nY&ccAXR)7((TzMgz`WEaY*@d518akE3{6 z@b#?1^?2pebV}@B`1j#TygPB?qz90!0>8k8H-UW7D`1IhgF2z&pFTRGCF**-aQ=nu z7g(3Dy4W&e98|Ry`O4yApv3` zvdL%J(4Cxv+$@%UHVk~dfny}@>~J3j(*X#9^a#i$FwPnaysxfSS@L*<2`7s%$fe7& zuIec2m6J;d)nz=q`+{hd&)Vs2vsX?XRh6T-%U&ZyRVoStxIglL+Ln|BsE4C2T%qAJ znLvDClH*dj=a=&tv7;(iiR!FN?cI?g3O86(S8j+3orwzJA#(P2RqD;|#6&60fuIy$ zQ`ET~4-WD$mL8Bg>f16}&QAKqWSzF1E=LYCb(sLMuM zPe-gv#N5k3iBv!fix~7sE^-l7%oq@XfXg6Kdkb4CBY>$Mn2zK#T;V7bOSoYc29ODO ztGi&Ym|A^8rNy-Fa7awAx+20tb0STNyPjCP15&EXw)jL>g1X$qXNAM4>{$O;QQvm3 zRfnhUBBTVOy?`ObdULN0CE<^kRx_T;zz1Vn`F&uEl{IQK9 z=BJOOqC$G@?tJF%i;hc?{8!`~kcbS+7#)59k%-2vv(g9t z#1~8oBqGcFu}pBrtt&6AWPHtxMzAC3Gzt!MI&fD|SL-%N5fhjN8Fjtxd6hRPE804& zZ$Ytn>iRy5=lUSe+UdLGSXt{fy=v+c`h6AhMwwi*Pbi{ zC__b{k?E1qs1Y4BqG8o;X%J-_v-T@f0go+JFuR0Gsbmk5CYSj^5Y*GgBvnr+y1w>} z--%8mN0ieW4tp^M1EDDjQ-dsw&UDCQ;T|VW<(wjEIb4#UVZJe_ngOn&?KQC{K8sia z&d|lbBCa9PgG?6$GJlRJ%6F$Hs)0iamO*rNn! z-*-PtSd9%?d~8p>JY`7qT_ae@KYbH>^%mca-Y(YCwU@)NY*aMm{_}!ilI;^Gdc*J# z4i(i}=Y8#@EGOF&%C43P&j{dA{nJtqFu^>93;WNZ9>_HUEjzSePjfXj=a=WoI%mgD z`i@?PQHG9kj{2PflHH0iEa{=^7ky3Lal(n>B0Jj0?YWfY#%qOQunIZXm|tyY8TD9k zNK$8_v}r!mKc{8QDt#1I;T^s`mO=SDi4yr>Y?$y&R1%F1iXmVpua;1uphPNtuz}ZR zmT>cU)b`c0GHKa>5@zz>Y148;|H+onXQ7*7f?V|jfliMTTc&q{%MLtM5FwJD-R2Ey z@jd9YvIi{j?E^W|=m@yDmTqIz@G!}f;aju(^d1?4=$cU5y@0*x0Sx2{q0;*o2tS{n zBwixBnIX?r@pwpGe-%>(A`&#EhWQ<%&0pEnu@-3(kffkLf71uD zg|dzXT|O0?ps&8yC&t3dunn1o??SQq*`_1Mqs8bx(VmJU(RVP61fnts4Xk-%Id)%x zcSMd|HfMpFU}KR)S|#jk0&Ya)Il&pMx)Gc~Y&f8c0;6O=*y0p&j<|!Cc^K0dRNp%F zq z6J_aVbJ)`}QL+v!*UK*lj`8GSZ`U9OnH(v&RTHk13@nuE&tpmUSVJHZqQsjhIuVj! z%VbP&+wz}do-(PVg9OC>m1B2FC!SyFMw`SvM zN!U*h4Y~caBt%8>LlLB?T~HR=i7G6kS&>q&urqx0T~vz_n^%|RAcskpbYbzM^sImu zRj%lv_WHXLU~o2yO=Ko;&aJ+P7s7D;nM{??$BoPfjN`Zs6lL#^G~d+c!5KTV9MpSE zoTrcTc^)EBkBXMe1NxOtC>hfkIyv=rOL!tS5SY_p0D|!@fG=TTJcD8;y&kS8TY{l* zQBstn#EX4#49#LDm#KSlSNV=8y|=tbObI@{AhQtKL`LJ_669|!ZORF~{=qKAjU*apRwAP|Q@vPBG zFQVN2@ZZrO|MI7|XlY_>D`uN1iKYjgT1|X?Q-h}*|KX2>gZ}=XW)etvOq{8hvE&Tv zQ_}@KgQ(=l1>+04YqhR*-xbP zSiKYv!e%DK2E;g{d`)e@WtkWzWraK@T)0Pq%Y$=)jB9o=D}vG22?LIwsC%p;7 zKV042%@^ImgU275yGLLD$DO*+nn^+}9wshKjbJQDrtJ}{1KIk!0t@{kt!IKlLy)^E z+kbk>_THUfkXZ6RuWgygknrP9*$hrBa|U>?ZPQv&#N09#C-STlRDw6SgcNB$*AMAn9BN? zD5qOw%aQG(Fco2L?|s?v^02jFUeKsZ0ZP(PG8rJ}PBXa8e)%j=nR$YJf~7Mz!Ie-l zLwnr78SQeeFv=37al1;OQ80<`Kc)d4Z6#EulU0}HG|2HH25~jWO7E>YskJUyM@SBp zv1xy8x;TULxtO;1!cH%o>RB?@?yqt9^ij*M&0_?EP-42mb}wwmM{PFjjS*-|0E^B0 zD4D6A{mj6@#Oh#Yv>AqQ4Z&w7%%excERBE~5ysIsA+r&B!@+9G34n|UHi0=|JhBl# zOjFh6Doc8tg$amD+Gm81Yt1i&PBWT!UG~vV{DH%qpb7_$IGe{hh=i`ZaB4oTV zqjI{MX$-*91d zJ1&f@Gy)sO5Q#2FB#iT1qi9X{q-d;KeZliDf+M(Iqn;sgzngiyQ8Tyll$7 zN{^TENW{D3r1H!@yIZ7f_j4gR*cc|K=|Pc-a#2ZbkDHgLYI5L3`aumh`o5w7?mH!Q z4DWu3|EV9cThpTCP?+YClV$UlgNUN&qW8m1r4+JDa#n46z&sC#^edi`IwCy{?dy(o zH=o{Ld61twNah>O4B~aB)Fo{I)c`S1q(?ADSXNODR1QM1j=Te%k@q+Wr>kH+YfN;{ zeUStv6!Mj4TTN!xFmxWJQkJU|LXr{9^vo%PIm~cX?x=$YvzK9+mDJ^6L&T8cs$_Ob zlJ8BHgD_G?P`A`JEep}itqX=`30SumniUb%FqDiPnsuYleIT6Ohr+QvUU+OhW{L+! zc21W=MM_N7Bqy(?nrZjM4ves`XLXj7sOVI<37REQWVll;VkWvDCbDLaY$DhxOf#ip zpDwA)p+KW=S!5zk(3aa@UKFnWLl&Gq zUWEUoeBruX;3sgjJxhbE^%g++{NwjTH|R8_l~*6Xlzd zTYl!tJFIOd)=Z6q3p6};(#f-W6>@hypI`KpTe9BV>gLTo!qSDyp<>EEcd^cLx&xWMqab~|NP9S4N73PZK_P_2Oy`!>-Xxg=GTFyQ zV|?(Q$zHF)t=PkWpJz5gM;`Kln`t{aw@TzERY8n0 zAWmRo#ci%4a+3;Xya^Py4_%DqT8LgTd30iX+!V<4~w1J#&^Zu#Ex#25#dsv(+NHuIuYu-cPR8 z``oT-db>d{dvT+Viwn(eZcH6{Z~-d86imQKp7>A|w|VfX1d83KE{3Zkgq&gSsZ_-v zm5Fu_vhosyP)SL=>*8ZpbGmoq4wT}pQin+h%EIos!G&hjg?&-C$UP(7-m4c3*q&{H zqvRa)^DLJqc;Xvg$CnFSgyZ^t*vImXzEVryrlEl&WcofQ_nw4e35404@GUaL1cqp8 zD98@Ci%B;?#Bnzlq!J{!&Uj`%0+JuWK1^W05?XcH7FK25VR8pRMF_@j5CX^X(N$IX z(V@Ba!`x-*p`d4?r<~o(C>s!$`*F}ubDT9(Q8Ml{+$2hT5L)QZB56-Sj7tHSlJGpa zz?Ip4dqX!aog=uD{cLOPP?u^4!-9;(dqL|+w4!+Ih%hFq-$A$z5RoI+7ZK=xo|Ll5 zb5GoOZ=ZES+E=i5;or*y>4(KomEL$bzB0^M(Lj^7$PTy`2U*_ko45+PN)6cuw5!{k z7#rPOS)XXF7*$ly`zn>KI)V`+jy0A;@+{n@T`8`C(YJ$G6RT~O(@`c$KS>3d=v?Tt z>gv5P(W9v{IbQ38E@PxcWUq_fj3<{mCW_lJxEa2Isj}J(hv8B3if(2jPZg{vOsXI! z-*e3jLzB5QB|%%z?rF*lJ+YQIdMjW_uD^w$@uBn-heg5xtKf|?tf@W(VJs%{>MYHR z;;iw&zj@E;ntwd&LMi`9lDYeC-si4?O~3bt@TGYHc?^ee@!Y~GK=97DyW`PMvDQ-I z*_hzs59hDj4t6}^)tR1PoN0u*dRg4~v^@KL+8CdeQqM(0U8ly?vtWN>{bOy$cOVWn zT~po+WT6+TYoy92EO#1jR~JcFce>6*sy6G8%HdDrXLW;tFbY^zifI9iKh3<|VHg|k zB45vozYc49Egzd?<>7_mk!jO&=k0RR(6!?|DjWoxiTwWHlB# zm^uaf3%v2B8Nbo#ITJ2?z%~Z_Jh!p`yYrD#T2@Pz{m**SsMDio$~8DvM>(POC7- zG`(l`#g8CdfkO{v%gTxYFl+ipph&0D=~JU+-N52;A+RnNFO06R;`b$Klc-adojxC^ z$Hk#TyhH6nRFdG}^r}tKim`Hprdg6UwQ(%A#En%Rtb5NABbU63Ay`_%nmih5-BYWsa%Bl=&<4s%pZun1}%Rat537&FM zXs5hnEbp)1r$-N5O=gE$Y}}Xq0tQ4_J-nG%!~!Cn57iNRY+1oNKy{;ZuV+T{#fzL!>ES9WVIiR>0cQRWs1*0K|fY8tmK@ z>pXqJa2;}Cl`=W_FD7SVYrG)^mwm6pd<+JEs%k4{0-YKD#mM4E~0F^Ly>SqA=dK+s?&V%{f< z`5?K*nQegx9^>k;*EV9oB8~(p=L01{>z1sEoKwFDal~f976F?loao%=ulML(6pu;^`=^&i z;%8&tlpIt4Fu0MI2})3hET&|BB#0XXE_Q2+*yriqMd}lLX4}yf!pl$*1O>!hzAJ`^ zB98(UAN5~#;9LI)tPJBHC~AX+UwqWA$33Bs?cyS&J$ zg!QH`T}&tq(_YF2q`iO{9I{xlsuLqOtldp_5eUCJfCgL+<;p_*e6~ zdFE1W=Ab;Yt~P^4I@HfluJC6eX^PwP>n@UEizbg_Y5>ufT6mc_cGvxak6wA?iOO1a zI)zAvAy;zwYC<2m@Y;?Z^KLE@j`Um+yI>sVZRVDotHE#fAo|HEb+FE?l@zcK4_e_T z%f>{pn>MEO<3ZsMSpa9?9(Bk81ba^Rjy^<5um!G9>$b8SWw|6IY{M8e3QF`X`nFy*s0 z6GiNb>=uUZXP#HkV_x+qZfZKENL>;G8#)m|)2U?VrW2;RcV+F~WB3NB4=qWNQWEC? z{l7<1Sc{5I+SEIT)(A+KgA4Ab)^ew_<9wPTq{=%767_pXc%0S_oj})-Q9&ii2fe2# za_hlivUML&TC_Q-_a;RU)!CG&79k`@?N5qKjY)GjLAjbbZx`u!Hs0!M(s6-&uYovh z4e0VhlJm&U&&k%pwqRJL$>N|`B`lbFs#j-fn2gtlELgQnFji?;1)_T*O>|anj`*PW zNv$enl}fTfVXMm48`#4tC8VTD6+d*q(k#~dk5gnPS_id5yi!&{GF2yP6q->H^PJ^R$A( zFrzFZKC6K0idgbbmkOa5(*zaB7ctg?n)3CmT+noT8>%R~x_fQQQqLqaPP z+^ykjbf1wEqJ?)zZFUR1Sr#$M*gRg$y>VMp&JI1BH$%|~+Is{s+zaUO1DW3#aI`_` z8HAM8tIikQ1q!kukiS725SLcD2W@C($=!Q=2o#Ur_Aop|8R8Pf!9{1={9|LC^-!rj zoKVVE}kCCbNV27yZ)u?4phX{A6+BSvBn_v}GjAHI`KW773HC>lC<%a-NMCo%L z*D~pk9m?jLlPS0Sxc^fcSeOuO+1N%H(t4CD#e*#CM=-4)mXly{^3(c)m_?{=xHWz- zIpb%@N$VMGOns2&onv_!^^escy81O$ump#3aAy4Y*PW^*0ww3Y&Fa@w{eV-&mj#B% z@O_4xsfu~pTK1yHcuJPNHJNOp*qTUZimqTfhDv7)4 zWpYI~x_^4r<1zbcnk0xjOZx7}lTtcKUrx|&iS#_KAmj0(Gwb7ZWRxqH!jP4p8~y)= zp|?xJ&~GeL7S6{XH}{YtjmyY`EmNK-Ui|L}>f;Xr4?~IaN2Ms*)d`m1Y+4Tz8VERy zwt_8mE!flQLO`9*?2z5UDVdyaKJ$Q0e`HvYJ|ZWX@mimeQY-<*C~Xm@g#8LIl(wJ_ z0kw|?WaHg++5TCpX!{?CYM@@m*&DvT!^?DLK6N6Jw6NA`hV&>^S`(01W#FmMf;4(22 zoD(zm;h7ky&CKXUhMI)l`4RRd*xO@fw)RJj~(4(fha z8Gh6(*Y|ByklR_09Q+Lmq`R18d*aPN36g?EDVO`*O96E4MY+@d$Sfp$5ev?Y@=u?G z%HrF(Wq2qWaQ##Er%FlKQA7JT0rk42%}6k~+*QfO?G6(4>JuvLS=n`Wz>ZSIZoDcO zS?ff7Ov-aAPBtlt9%wLKSIcY&F;)}ao%Dn=ijZsj2sDQ^v7Yj-JJFu=dsLI&m{+`> z^oDT8L}0zR@Hib$tMP#+Iy6jHvO81yt|Xvy*2uOiR7Z_jfI!a49VcC6nC<)=VZKPC=w}UVvIZF)KVPp+r7+Vo% zue0u^W(fD=e_9E-iaL}~X=)6Eo>0KOyGeqCzq2|mjJTMDQ-KU;j@YD0W~T8c{9F@ zdEnYHON>Mn40gC!&l9&yWpPFyHFsbl<=h23T2EDtxVmkt#R9DJB_p)n=YBY0DJCOJ zMVv5~>j-K?_bhpSHgqYa{&CW!aScI^5b$Fo7><+DwIUi4bRyZ z_u83-f6T?!RB?cA>(7)d z55o%q&a=(b%qAksW?*s1Cx#Lw?Q){ENV@-ta@JZT;p?^d%e>66L?~KTn4ayTvYi9O zp*H{}OVO)HNLbM-Kuu5hSPel+ifa3#-E!DKUWStv0wSxmY$}gaQ;d~IKg!r};M`VT zpB0_b--l8~9IvuD-Jw4P2RNZlQH7XUHH!1+C@sQ0;so~A-%DZ-^ATn-1XahvW}28B z=bcQ)ZRXa@iJw@BL+#H{+a)(=iqk}ObYJoyArPlX$(RB7DHOt703An45su%L_Ju4qIDZ_QLK zs*nt!Wd-POgO=be3btfsO;u#aV@aDTE9LLe+m_1+2fJATg5InEL8ob7;2PD$l8g8A;rM3Ufmg;`TeY#h0qG6ZQtE5CiB__jjp1*nO#E9n+)Bulb^7lc1M zCClY*CCdewi!qgYVYYjpVniIM8=Me&*rgsMtLV-$*n)M7)q~VUpwjU?-IEtd2(*g8 zo(+yYJz4w34f_fniR+m6`*_!nVet1ewnGS%m6^k+viI*MKjw^rNUh^R3iEkysM9C@ zvGb0v!6vUZI_3~)K z`Fg5AbGMkLISL{3{>ZcSqqF2nvdbD+8px0QDaC_e_a7P!F=-%38d%I!8pw~w;z6G0 z?3%fToepcYQF$kZGSku0H|JdWoga&XOt`?)v98Z6y3y$Kdm4Y*OZI|wdL7Wat6YeS zP5Fg{G7}t3NoMylwG1(hEZ9=_*<7J@DE%E^ZDv1noMTg<*ULCgys}`2H18sLLuwh! z3bM5O(2TiJAcOifV?Im-Rcz$SJ&D|WL+`twj#65!()ZIc=~$!uPo*_Tng~+TOF)Dd}xSu z3`xC^TBK|_x%^<_00BnRq$S%X58qr~yF>Jap1;Ec;iinhuVr(P$ z@S`5~voS4>4ML3}-M=Xs&`LwP%2d!#deNAaw$laqNA&Is>K2sij^=P6MqMVy4eAD! z%b5~pE|8f)JZq`SCwRmml+J9^2CpGbJJcFEP0d?Mv04bycWJ_0op5xo92mJO(a^3c zC%juDuGo;))d_lHw38a;+yz?PkfeE59SqQIwxUiRdR4}U(RH>0In-8VAl+IsG)l2V z2vXVz19B&xAC0!EmWvZ1Dd7ULbXCU5;7X3HVtc=SlV8b2J8cvp{*g9Fdf>rI9I8;o#{c4MePV>pYAD2sqna#{JF zjOr-@3nC67(~U8l#t?H}N!($^dEr}-?75qQw}w=6fC`Gb9F{>H$gv#|pLi+=jcrI( zd3xMn%9%D+sO5wqfn6S z$i<*eecT>4GN5}_y66D)eo0jqIA~N(Lsf?aD(jt7hS}xNoNf=j_Kay`pb@K_PUfmA zcFN@f!EqBvT|PF@vj%@PVr7PEJuh^@*kE*n)E?~8N%5#nQj%+<=B_=bQ|qe98G{QC z_1c@sR*a_WDhEy_MUE#x>-At)CW^32506qA3Ugr)>)!oxOcL4B0YZ^26Edbs-bYcm zP5=k76C8c(fX>wsB6p61BW^34QazW_sS2fZ&^(A315Jmq15aBZZb{p7(&H`o9K(}+_wf&8 zscK;uTzic?Dc4E=_ zubZd%G5Wz*5{HM5#`m8%%JAQiFetMS0ek$Rpa#{2Cpk1s^ z!u?w*)!oYcwN+@^zqj_ z0VU?$T07sH!`S1*7rS2cnGjT@ZWrL8RFHx9#5#7WmrUe$=-&&Wc`Jxc{RLeYj2(v$ z5B3X+S?#=wo3b2m6-{L2r5~QBsZ%5#%??HQSlBN0L>^#rr}0)gFQ4b@9EqZJJz1lY zV4;H{j_MOcv)E0U{t3&bO*q8J04AzIZ>EtDPp1da^F(cKgrTyc=33ut45vL7#?`qA z8dnFPD2Wxst?IIHsH|@Ba$qq~^N~Q_>xxO|62u651SPD{Ie5(EEX(YBo@YO}bVDLS z(Gs22o8~#JsQL|qsjK_-WUG1s0LJ}Z1xn`=p?J5w;r5}7h1 zrUv6R*r!-EIL^Q{KdS_F4m@u_MIh$nPAC*COI!YmicYp~qbu8|TalG1l^pbw>oNqI z&!Co&BMExr5J~uyhdl#{omWefE(%cBY+ z^MHFB);jUQO>)uJR7!H|b>FpnUInojchx{lYhiQ}Oq@91RmC)sy778dR9xamYjCLx zg$^2H=iA^UxwdO63duapEuo|~@~L5Ha1+}Y@Y8GO5o>(dU3i3_Xwt2x`aZW=efR(* zUq~TELmGqZp}9oTgzBSsGM<102pF+IJt-y)1jI`}3DW+?L<;5O#!jk$%};#Gfmvd(he zpdO9Ei*Nue^xUE&QdYB~BoVGHB;u7&9o5;g{dKe3~G2q|8 zZ3V;*d$y?h);zE4#W8%J+w39udL!S{<1NcQb5u8(ac-|db%t>Qtb9QpkvlYq*V7=U z3@XRL6^nC2%*jQibPvUl!kir1o-q-@iraS>+~zBj2NXXYAlqFibii#qhz2LgG^Z2k z>VvJBgpJHa7UxH7W5B1r z!F0uA3x%SMvbfhe(5arrH+#kjv*&4nQI(~vZkx3Jc*a@xPyUa-WP9%OOw zi;$q16T^UeWIeFD;0pz+Fhln|!SV(h)ahYqMt=jkZ5IoFgXY3+JVIO_f%e!ib$AE* zE_6LSq~_{927}^OO~4B36ss7M9<;y~5<*Z%scV63n#1Qz@(SwjcO`W~*H8x+pi0NL z-HDX9hFeN+VPN8{4lo+Kt+M-szvMhmie_1zX?8)K6Y>v>6ZujiY-4n^X$7BkvwwBZ z@Ii){15X%TZ>*N{j|o2P4{8sbV1G~bEjD+q(gDpnf0rHZUpdg2oyhO#QX%H~WlOfp zt;h$3$sIFDPyvT?Bhe}pW++Ota!bKV`?~e^+iS@A^MXCL_xv_+h9q$nf8Rsl*+=OB zQ$a3jh15Ex_u;HK(v>$p7U>MzH7k~?uziVGrtb4Iz}-Zzdc5hgkWG{0g|4l)C)jF^ zC`AVt*dSCUX~iP21K1#>sJ2u13j=LJ2kMY&M?nDP{k7=z5v?{I7_I?Hb$}j%bYR%0 zgtPdis7iG*PXpa{qX{XkD6Yzg#xxz2oxw@=0g8kO+ZZ}qkqz`~HZX_3BcTQyfQ_4e}CjVoOCl%Z_pHew{(QE_R@TO0o zR9lyn+|C5OL|y-M$-IBnLipWVvnoxa(ho%M_2GS`)Dk1GvUhYsmM7?QO9qY-hhrzQ zlECX?wS{R%!9*<(&Q5N6fpM7L!{w{41@-=`VkK11?Ky3gAYqLm84TBz=+5>wgpM)=h=m;JSX zH5Tr!y9E5Ap?H>kttBk~jG`8fZ6z%r%kT)=jf*5!hMo)UZuJB)tDgx%$-=l+6hog} zy~Q>vmvZ?LZ48nIHu{FicB`B97E7iI5VbGr?Iyy88OQus5YblJUMMlLH>5DDslFz8 z^|HZ24s9+~n=WZGU`SiNWTcCnKsPHS3GNv&jeP0ME%Gw)oAm=J?QnaoMgwk{=m}U* z6mw&J^VjWqccv^Iga?;DDo;`*ExTMU(%q-V+7J!j7ZfrGg`(F?Z^pVov!krcMEAV7 za)o<0&l?(N`|rd^FUCpW@GU+L8t;8%CDr?HTzS0j_whOa&?cX$)-JM_g2AM44y}T1 zf~dDl3-{nlDh8ynd@Yq9S#hO(ADP-vb~8(q?rB!PGD4qW$rUBK8==a+{NFP|oJP4m zb8O6=IAqRhgwJqU6`)LgleaITbaG-T-gX7B(40b9P_Ct2kT&+l4@52_$2ocuB;vMl zG|88wsZH@$X9HldzP7OLr4;0NPzy?GFA$oRZ~6kR^A%}hK^tNhm@%!^7CTl(abY*> z$&a-Nj$uwBD>OH;d-ua2@;WbWl}uFo6t3lZhp8_Xh@@54G4%^PRUSq zJqv&1T41etuCp#Y%#SkWBgmm}6Ho@*uwX-U8hV8}{Shp~P4;Jln0eB8|4gGBrs#}; z{;^!B>ggWRmlM{@am0rz;|PKjQ1e$mw+R665XYSAw8Di6j&IG`vd(}1rr)C?eh zO}-$IqB^RU;5EpKLwOR)F{XwrGu7IYp^9&-CN8Nl=i9aacOJx~u}3k8>EaV+eO5-6 zfxLSk1EYN~7@@smuPq_t%1Cc#@;U=O?__u6oC&=AA^E)9Oih<0q5jRjbm@YjC*BA@ z>L3p%*k8-yLGlGsYIT*JfA}enorRo~z&C-i;s0rX( zyp>R@^x3=HW?8vr`ueJim)$`NL@^lZV=0yBdgLC3g`|PaN?KWuY9K$-K#B*!2VFFp zj?+MpG_di5X&^r?iwF4yobB8Vqkh?X{LgJj4)fBp7Sy}?RBLfI!=W{OlBK(9&Gh)2 zO}--yDbT`~qvx30t;NUOHJQ->X>vZVg^Z z2VG-lQtkrsO|sxiu&DUuI}$_wbADv^$~XMGa2j!>`@m2^5z!* z=D?pmMd6#afwV!v0=w>g1yCXxW9$wBZR@rZ2dRsLx@LcyM@3c+gJ{W2 zsgT>8^n8W+lu;trpdb5m2pqe#JI0+a83S=PY3#CvdoHv_j3JnU*<9c z+rXAAUpULATN2x!;q2Wk6dS|4D@%qAXZein&e;;YuM#BedDhvjz1mT@%WQFFg$=*J z&St~u&e_GsOKW#CXZPg7?W(ycMt*RXx!ys#?!hj5zK35eg3Iw-OB9U8hlO8ZlbPN9&DM52_1smm$_j@X5vabd*bFhnO;)h zd;>7cP98~U9TpqCn*}QEl&vswCfVu#Ha$1}Y)VGLf z0nPz29bv!%@=2$w)*0U^%6YBnMH`M)l+WkV^*RSjV5ySY5AfL?mbdmf3kucR+jP0@ z_^xo`<}YMUTr}vlJr~`1cl`4Q>k}_$g6|9Ap74l153P+*`{If>$3Q-F!fV6X%T3k| z|NsBn@0HBjTyPPiHSzN@8+EyJwoKDClkD&1Fv(bhwWx?t-(|M7{N@1d#DOIxJ`Yd2 z%IMD7V&hjy-kdfvd*^Iy+oiSpRWf_G249u4D>k@$u$55wDl(hc;2w2-WzMp`!ECcp z$LkqaRtgCc^5eb`4l80ku0&nj!OrLJ-tJ{zN6$glfu(mJ>_pD{OfVmdYq3fC_j^4E z5zt4Ixrp9SZ+UX`oz-cenMj?HpX1N{u^dN_7q-sLr*aR8=5!I6`{*4LNC_dm2;#M? z(7QPh&F*#+Li3J^0`YNxX-myD(wlu5cZuuUdJZh{HS5ahW_~VzNOwDdmVL{c`{AYpOGtnO;B1ge?(!>1)!CC zb(y{F`M$m0=4r_+E8fZ8_BRlis=LfyO3p8^v&qtsW1PVL^Oq#e24)=7U1l$27V*U) z5_EA%mp%GjX1|Ke=6c!tj>B4LeGSfHXC2tC*G}&;`!zVrUXE>mZtBNYu(Z5$_N#DK z52+MCxhwF>N+D51e%y16VMYA+l{8KM#*cPn2&|G7CvJ1Y?vQ_cAbE9XZpz^c34 zQpfF)>f4;OnY%!rbV>DkTJaUk+FFyy3w{gU>0J~s9%JA_OPzyZ>Amxt9niwz8ZCf% zJCvNVyInR8RFGBpXh`z+QlB|G!WP0k;3xW_I%RkRvB>h z3Sry9+j;` z78a~qg7cWlg0TvvKL{QZW$qr?u&|7+i)d+=>G4zo&meg4RirbKP@4wW9?)-I$+Md9 zAu$b*c50~s_ME}uG|-2Am>f#YG?Mqw^kYMKWsymrcJW4nk$1o$%MwPa4>_2w^Z-kh zR0DoPz2f{d(5C@=#ysV`;558t%1fd2&D;s`7*R?BLEwmz9^ffzPmjHABk`~W=>{Sm zh@A;Lu{~m9kXq_XO;22vG@{%Yisk{gIeTQNv>V{X7R>6jMuN~y@cP@Rf3)Gm^;-79 zSjoj2Y?rtHuplMQ@OE=$bF&_^eUee31FR^w$CVt&mh;Bk41$-rJ-fU`SF*^l7|wtW zfxJ6vCN7W$a5AQL!HkU4U=ruoO<=Sgm{E2na&sGaAMr<&Xcq(F61IHG1;gl}p$$xd zu{C^i5sf@Cfo3^loIzNTxl?kT8|JCKbQOLzFw3>)G=z1S$V8s;d^6=6-ky0a zZp69oj6y^qjG1y1sEPS-W>$xJ;V!q_&Jgfr)*J@B@SFAeC;=fI^kdLP^rnF4v=_VrzsW*;#1^c$aJ_PqCJtQxWzi;zwZI-^|HUmfryM&~oP`xJ ztUcEzO!w5sJrcMZKA;Gu0fR)*3KoeA9ZW0`dJ+HX4Q)7iZy zQXI?08><0RK)Xn~*+|*qn9AbgsfJEK?GT3knzw+lz?_&#yPI$^0`0{dW|t}{xiO#+ z6)v=_IkX&VBVmdmhhK16xCBZNXe~S8 z9!=o_85vS#VOwyAix;I&I7kx)KZcEDFB~}lx(@AP^#{&sQHPMla-uywqrfjka9BG} zB~Tx3=) zq*zIn#zG;DrWV~9!iWp?lX;L}tE3$58E<34@Mc593IW$GBnkn?Oy?I3urgn4FpFnV$Tj0ZfG3UBBR%(~B~0@n>g3 zxG@&->gP?^7n4l8Ru7qgCFcYiqY*J}TCI&*2c!YKl<6fvH)|jaKPg6I+!lPo`&uLD z%(YIq?*TW2ornO|Ak4@Uv4YDgdDVPA>C)NyCmuw0wd@^3n8l$M$OC4gw3Hq&T$aha z0^Ns4APva-HOJPvnUSFfR;dLm1v4}(&x5=U7?Vl6ST75yytbx?e9p#!M?g+= zU}2)p8X4mmJ&Rvga>=%wZcBG?9I$RcXY*t-PZ)N$Mo1lLRNhPE=%icL*otl}VT64n zVZ=dZ;|eBe7uXzIfv3`O5;xWbfHMzD+<_??jmcC4$!Y4VE(%oKn57MiX&*A zHLV7+a9#Nx6r?0YWQC20#;^tnw+Ym0HuHchw+gU$#)?`%aE%tb0|rw+X;uKsDCaCIl|*f56JFx?UKTBM1eMJ9_(o^FXHPm*o3n}%4W-Ob+Hg30k9sNC-4-U>B#@+KOP?IVO#N$ zPi6X%XrV|-dn;a>Abx1b$qXRYVGYGPvCoYTHrVT1bV3(GG~~(D``dqc67)oBvFwt( zB-3hI9IKqQA5SnkC5v(Ok~FTQL7b%pot%+-0dt#jrQP$wbos?GVCkItK_k+l!Hk5; zh6o?tR>hX^`BIIAawZ1VzNC=BOiBABeF3s}UC5VQ2=ag#x<_0$SZZ=#h+7@*!2cdF zqLif#HQZeGFht+<5fEGaw%i&;O6jYR;i;{xxQ}O4WoFSK!#E^ zeZ%%yrI#32?J7Xh zvvivXq$~2ZlR896;h$PB3u_PoZBW|K<@9|>l?xRZ7G1DY9G2vFIjzjA3+ApNalfld zsHzm16qboyRm#wyLj9_WS28631jNM#NYs?_u=JIQ*@jDS7c8$_PRqio3PpzC!}OY} zGNTR3c=i~Sta4QoLa7?QqzRjua&C`IML=TWu8a+EIgC_yAr0s*h!ndNG2M`iGPx@H z<#Nhs6e+kzLrlO_MY|ddd3waAddTb(FgCK05u8Y4a@91CnHVD6p^VvEnfwLHfLG?U z%(L1@D~@O0`&E{ zP@fuOjno*6fJSN})jlk0gp{btNEyhIG=_#SX)4A<87jUDqESO~FYXdS5{Mfhgmj-w znhVO&Rza;b-|k}ufNSgEAS(I#rts0?OTM%KDPIS-&0 zy%K2l5$p>R8yNjdR}BbM{c>z4tzku`wXi`RzCon3dqowyF?syzfwj|=NuRj8H(2N| zT^42L#}hQT?Q*MKk0oyRhcI`4M5>L1_R>1DX9S{5kudCPw-jl+6w2GRfu+px`Se8l ztSNW+xG#wZF$#OiV!Uxr)ILZZh^!0??SEss>@SA(W~iI31`OlK`>~Fo=wGIruLK%Yau9q&eLMN>zAf z5RL4rNV{7jKJBWoAyAFJ#J;!;=U~@USJjGv1CL^-RH{LYi+;%)LVY)gDRD6jX+yFl znl{xXf7Kww2XY_S)Ig?KMt-_YRSbd4naSe7jEp6_I%wvta&C{ThpQ42cR4; z$Z~;#H-vx^Qg$bvwW>NSXmLc`FV*5^g*>qGC-b;};-hRuh{PF;{ImXvsiEjuR)SDU z@4)JAgp)An`b*BI?oS-Y!NOH3d_^NDK_kdQBN7W^ScJypN2(sKvk^I)Y8x{;_2ks6 zln8H-w1OdIa-c^;n=WyP28obWuKcDU5`F_s)#ec+@|uT;cK<+bbPKIpeIYV3J%oCE%=>SVPRpo+eXlP(#5fP$@?vsZvy9|oh zh;(@0Sb8KoZenLlmm+z)GO+E=mc=6+LZ*0g{rUVQ%D|*^VxHS3 z@7Wl#*@(23Qd;OdH$rw)2!SEy)%9RZV+#93lb-hjQ85rVu3xEXD#{uG?p6m_iWik* z=WE(09^%+*cPeYs#Im$*5MyMB*hrA>V3=M}!Y);7ahD_2+U2wsXZyI8e<+T?GAXQ#$1Fi3c+O2>cphRX&|&ZZQMhCkv)76@=yI zs^?M}JAri9Qy5UxUy9}J3Q^X9O>A5xMy^vqpZ5+*ZtnT^q28UH^d0kV5KR!+*M+DY zsfgNtAkBx9ei1~HeM%t`vM*H*8{X|92fOYvJiPlL)C7I93k zkW~z7g-2uwOk&)^&=Kwy*$=^j;ig?4wwpz+oy(P16cT+?e@Qa~nF8tgA6m&Y+eA7f{XR z>#ADSO*vC1e?O3WRZ3u>nkG>!13zF*3STa4AkVPYP?Rd`?ADlJwu@btV5FI%Wo4J_ zJ#YzD1crv2B}=gMkg~xMKs{IM@uLLAV@>4}EMnO10zGrDS~@pvCFBzi zwhq~m)d8-f(rI6kLeQo!UgO9dp;Jn5JmHsU;n^qxBb22-LlIUn{a`x8(Y5(&m&05s z-PI)tn7d6jk)F~bZ_cV8Fg9^{L$%WJsf`*3#VJ(Z_&#BXDuKE&<@UNZ{iU|}+$bt3 zlzy;{uFY&2BUj;a=wf4){w&I&h}IirUWam0M#2d1wUJ3La1Bm1hMX*Jpir)DUYz8K zTsf>jQd5_JrduQ?OSzc@Eae5p#0jevNGe0NS;2G;%ZSRlB-jj^ziw&|dl;(wAuwz9 zNH&92Ipo!hsJ=Zlpe*NHGLrx{eaoH~%fLJ_^2FvNv91e--Sko;e1>(FQHb&EtExp0 z@X%vX(zd%m$D0)8EL$ARSJAu$Jz&fz19ef>@7*BQ%|liS*Mq}#x*Wk#W6V9a#3CoHRLufEgbBAl>yy0$DLvypBHGcnlFZjMmnEhKj`!%I2& zlZ%ovna#!Yi$^g;BSVU!P;8JQV`7{}*D$OUdi!kZW}ddR1jGZn4?|k_ud0!M!mX66 zUO7@1Hb+5~Ztg+6lA_h#D7U;}i4m5%na5}h#h}%s8DyE^av2%@d-$1fLXd{2szXH8 z1w(W>d5wZtu?DhKL--2KtKBd_ZnGu>x%6liXcYqp-vr@kVkskb^oj@Qsxk0mqIKcnu#>s#QnqQ*d)DH` z_WCNMyTHhdv_~pri@L7#e@Mn`EzPZ7@GSV;l(Y=s)kaxtz^dzIqGLSk>`gI2)}#BW z6W@cyvw(V%DCvIKr-fqoj*#_u@aKau72W1FAAfUv!68fb#h4)?9zJ8_P~{gSfE3N| zIH#c}=8xNm}_YFE!VgMRNDTyUjpOq{=#BFMw3kE+VE!~e6no~|=r0>>CmxM2kmZH~O zP#>4=`pC5FJ|wiT$@EkW7O6ff7+bdmIE>v(!Hh!!3{l;BltR0M&cNc7Ub0? z6wi2+n*pm)Oq)u|G)5RgKS&G|VWwR>+@MWmUz$$ha+QV0^x5^zqsH7O*pd&+JBdVD z%Bo#-dfwoYh!SFpdv4GNNa?qQ5m5w7h+-!pwFeWnLOjc}gfZ%J7~7fTAz1czNKxviNCq77o_>KmS{AD= zrRc@trMzKRjT~8w5DrDRRc=WejGbO9JILk0*fnyhQ*byCV+Kjx!$r1C5KEMTv0%W}tS$s_MonOs@(@Af;7frcDd29-6X=T{XruB1Kh;fYR@t zak>asXj+xAJb0dN&yJ-avmgpY)sPZJ1N11$6b&^S^&1G4=z-Yz;3!y%&)67|2NF-A z{ehu6V6=$JvYmv%f7+C&LlwzVH3DH$r& zjUcM1m=e{i#i+l0hYCtX_&u}-wfo&s+d>o58FMAeX~P!LvS8^taMvSnZaS10FrQg4 zHRhSDV+@TjrClm=rl8&RpwzMw4Tte=KbC-@yHwm2E;Ob(PJ@wamjfngbHT)+ItB4U z&de@??iq`06WYbCDM?WDVH_OcXp6)ONGBf2CRDxo8LuN>c97)bAAOgG5vHYkHw$CoSAuJ-U5 zLo3#=+QXksDfq_2+ufelJ=HIK<6&_1i{T1X{VEabQDFW}aJhSz3&|2`V}v%{2bl7z z`YIlxreBFsqs&bP0y^x<@KCJc1IkKh&G3C!lI@|F-B7(AJya##duyB3`=g)jXrfr7=%g* zC4R^dVPG8xXN2femxO(mJ<55?dfDwZ2{oooO|{#ESFYc?2@-@%`Dzn7E%(sLN? zWYMF++ox}QrBQ;EZj(51I22xh4R^x}`evrOHs6w2GAlRXp7eF5+JvjjuKwZHV`qLY*8acY%wae36 z3YQh8^%^-X#aXCF5nfv3zPCDwg9jB91_G>&%Dr}K^ywL zk)V__@??gE&iEKkhQ-q})NmvdQho^GIxyT&uZTi8s zsCLDyo*~VZTSV(p+pZfA6)RrBl=+F5D2iB2Ku6OK=6>W?>Yr*y1DAE?@0PA|(i6gj zdX+Ry*pa4*mWIx)4#hJuO3yHSUt9{hEHNcLPUK@kk@SOnERHb$>YZ8F?xp@InyY@8 ztLR0PlFCXQSHX;&_AKo>=x-FcsO6k<31p^(CMWI+Ku2J5c=I2o1FxXC5U#(~j^UMxJf1rnf z!ZIXg*WJIFl}!Bom5`pWu#-b6!&xq*PI%6=KvaAGB<7N+o}V4zerV z#Rj~>f}1l8d+zk9hC6S!;r_eVV`nTOM+pWu6igr0I&~9l^W*KG(!gdZ6>NK@&tj09 z$c&|U5G8D8fb)aQ?=+EeS?eXOutD6wW=WZj>TpQ?ov_a2r1cCoGz7WXX_Ba$acu36 z4n-;hL+{UANLN32U`Idx)ML`2J;dB6YIyq;6JNIp(R6* zcH{20Z>3a!W43Rn6ry$NZv0@xZ+52mT)1Y6ubZ{=eAlVp>`bx4o0-Dv-Dm1IJ5y{$ zjP+Y@>Qo}?9#ITqej5?RQMb>wpIR5m-)Bk=>o*or9M-dJI?r^se!p4khwbaxsjqFh zw!}&Jce6vfCENE0*8#WPu5M%E#MRvN3%utV7A`sBPR>zU&H!-XwaV(=>uG>93j%e~ z(Sggxbp(f-uQ}TE(y*Qr)%F0#1$64mt#XI6a#6298sHkxIuXV79w|#cg7#%;X)lL zqO2a-J+LxTa*Ky@fH~GEJ_vNXfWBN=pmsIT0 ztujcnae;757oNL;l;tcFX+!UJtY0yj+U3yB_ zsX?V8i!5En?QxO$>vGiA8w~Z2q~FxmOBKJ8wE zb(V|_Cxg|Y;gsI%K?8Nh7m}+pJ&d;)TKJYg|cRcxGMGRMU1Gk6D5#br>ZizJqI!%#Zj6jXiP+__(Lqgv}mmHUv zKoZ9qhtmwh_2EP1jWHOcecb?;^FbByZ6{`gB=`o*~a~zcofMHR-ap13JaZ>6F+GL6sxJeajHw=1?C;}&lX3n=LXG}ep81!fj z7xawK=|HgB;25`L8bQ{hVII4lY|iumx+Gk>=74U_&YyXdgXhS1y49u62G17syWUR+ z;&$g}B%v1$9G2tqHEgy(-7BR$HOB-rNJ0AWtWNRuT_;_&H#O=wp8D>pt%^Fwr|*ZV z3xrL|tpj;*BA9KnG?fpPx@4cRq$HXe5;0aT3(65zm+j96)D!%FjnNZ_A%)>SFr?i( zJ()}tAVZ{0W;^vga4dSN8$u7>LP|~+f2u(_UC2?s-+ZK(fc$jz3UtRm$rkVsT8ew8@%Bem_gxybngu-Apa?*#}Yk*>j zd+HO!ptQM&@2Ev>Lb2Oqyp~8^VbHS2Veg(mtPpZ&w7(OhO;n*KkR#xcXE3+e-;oqS zip08ddR|b(?urK9yx{}grKr!Pl~BAte98B9tq^!X{Qff!tsLs?uXm;}=#9lZBjSU^ z);~2O<0_`n7Q7W!H>)**SYVmdeDjM!Xey7usMN+RYpSQJcRe+y1Ig@A70>3@5Tn`Z zWXJ2+<<^c$$h8NhDiSokq7H5^1ZPWDNfedSXM`pM+rN6v?j3HNkWmF0qj|zkjypj- zygiF}gi)ZyVNSn?31Hr{Wguo>J{|%x-}TwxQ0?jIryHi5Fgjl|VSHUVpMk*B>O!A5 zyVkbg>A9oLE(qXnVSd zH5sgpQkZ>yf7qcQHlr{Grez=iK}q2 zz5{hhn(?S8=dn^dq0>UKqKWwE$wXpBYr1KZ2)YRZvn)!(LlHK(1%n|@?;SMo!487% z%K1`YF{fOG^<|-mrq*L{3am)ySFinKT!^02b(`%*rym5?wL{MOgjkV*Ihhp#WE&)y z^GIl<%Y|X6S`TEiRS7>DixD!fHScD>JlxFPU<{_QwIpjc)s@jrLL~Hd-O!@oygzd1 zJE1H}$orvR^05dDlmmC|OZ<68dzwRizX&JXMKX+#WT$9D*LGs*;%DBB4b=2nXBE@USvY2cFs-}%Y?ww5gF(6~)OS?`Gmt43 z^J+F2BrEhT7bXK`Di*=v0K@6_7??!`*Yek=$LywaG{w zv7f%>;8rBAh@|J2{R=n2@PlWQU-tW&w6#njcwkm3sLv72A(+OS@B(%3R56Q~oY+U8 zt~Z>;&;~O1R@KddE`1O{W_`2)|J#SZ|M0_y|M=m5UO5nY<@7I+aRx2>$VbFlXa7Gw zXnjz^C)A8ok7|zeY0&Rl8a5qvFbEmMNyl#Q#iuv&zg zP*2h$;1oKZ}}lJ<1vOC6%rRW7Bar}Z zHkL3F!4Ov`n_z8Fj09^9wX{Vs2t#wiCEl2>4ogw|SB!*q`1G$XQB?ts9Igv4Qb)%- z>R;_s_AjD~#0{vn|BjJx>I{m4;wmf40tOG<Z+sTi(h$~GQ5#FRZSFQx(tHa}7M{v*39{UZTRXU~zOAPSYtw_vn& z86=^sn;u-HJcN7ORL4OTXEsUYa%JAv+>}Ivz2z7XW%Wd5ASkOvIV7O0EGtEZ)Gg#( z5&GNXH(a?Ut8(Jf5j5lThrckYMTPbh?E$5to&i8BF3Re12q|Jnwje`C(Vm^rB`+O%I^-3bk>1T2rA_U2pj8q zB*1)uwZkQtumv&+k6s^P)l(M2IDt`0ftw4AsM-D~6sg7@*oGL_w;_u~_gEI&!MX^@ z`yRxWq{Et4{JTkAjDuIEbYX~D9MM9FLZIU{@=}@3n`f5_aMoQvPabKRDpz;yM)~^^NnWg^g#)Czi zX>kqsI=Uq4W&?g$%qALowH7_=pDgYRj}5c?gshS?;o=#Y6|81_*>7h7{^8>ffB5O= zA3uKky?%ZAFaQ0+2mI=TemoH0=*@@x0qf^K{MBDQeDg1U_~FyfKRx{2f2JV+zWGo8 z>wkQF_~viE{fCbR{{6>4eE03Y{Pa%`f46*4W`lIn2r}XL*pO-K_aA@y^p8LO*N;Cv zz{H2&yTRXm`r+q~KhP(sjevji?T=s&9GfWUum3va3hHr)+<*7oA0YNYWBC2U^z*w< z|47~4#Rz@^*|bFLyJ@Kh`nzv`{`QZb{=ro>?4Pa?@lQW~{QD1&4^JOj?o0O1rxTm> z!2ZY0%=PPmEMfiIJ?`1;(LX~w1nL0kZ=e&&#@7(x{9EYAmC94<=O4fQ?vEdT{2+$> z+kXW+{`{v;-+%mzhd=-B4}Z~2`R4bZKK=Zl0TUR Pe){ldfA+8c!@v1IHnTGj diff --git a/DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/lighthouse-large.pdf b/DuckDuckGo/DaxOnboarding.xcassets/Lighthouse.imageset/lighthouse-large.pdf deleted file mode 100644 index 5d648895d71649610c4a457564705fbede037157..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192356 zcmeFaOOxcgapk$MPm!Bhs&2+R!mLdTO|!KbvzeB9(Pm?_kgl<%Y2zi;BsJFk?dNyg z4-OEIo0(CR#G;tBAmg6I!{KnaI~)%D|F{3^KmMn`*nB;G`LcO=efiDb|MxF1FaO~` zy!`N2fAyRH`SO3iyncPHfAhy_yBXMNpP&B^)%f?r-~94-zxn6i{`kw^RU^OnpTGa> zzy1B+{r;EzU)x>%|Bru1Ylm+3FaNSDR_&kppC5j)ef`FYo71;eJbY`#{Wn(JZojeO z=9??d4!1QOFCUwY&3RUQY8p42Z>@Ow#)`}I@17C3&9_SG@f!)H6mUEu z)!)Y=|DhZBum9)Y|My@1_zwZB*KmGXAteIl@@w*>?{Ut>g!}8OY#|GzDE1rtKnr%G7mUe&j zp}W&_rlO#zwU>jJnRpzm-EZj z&~~reuUiVBtT$U)pdQ-rr!U*n_Umcjr-A?K%l5b#CUUbqkAAj0id^`&p_Pel4`0th z_n>Lx$1j`9@#}8j>GM}#HggCYjCrjN$UUCF9##58D-%5&zLq}Pt#s42`qY4hr%&46 zY?~1p=lSbd{5if{&P_JGOz^y){iTH;ztEu=^{OE*MB{3tzfecdHb5)M`>z`{@VYke z;}nd|cK`Jv{%>Ed#D!UFY;!q`DP~p&x;;W!T(R>({Nl&H2z}8~+`Te+Ej#TUoS74 zZcBsRL^_#nuk-CI`av9ceVL$EW#(seVpf8(4 z*3-Ua5`NJx|FKaMrxyx{9^lQC+QWJ3pW|4%6a4WDVqYYjUncsiFNcWzM46kDdb%t< z?ONu*CQ(0r+3klu@Ukvar5aTIEHM%fodPE}4soFNdgp zjDU*K=ES69clSjhU);Mby}=lHn)m5yL;qIklPcOp)7vf}<5~_y?B;|T(qNH~OA8w+ zRLfW(Rsja7ESjAKZwe;JikSjGVXYVzhnm1VrHOSJ?V1Lb(Ohz^Q4oNug&34p=Stp2 zV`#;9Pp$MA*P2b2!hh);X(Z)ovjE8BGx)A99m-hUdCTN%DGdqWj{8k5o|i;4L(CZEP+xXQ5_pT^|hkuiy(*}i7K zRU2tGjhAz6OwPyc>2SS~POSsRzLdr*+vwBw5v~|P@cdZ3!bjNB?sbe{`{5Wtn%!XjNm|`Q-?yV^xmoRAS_t8ieu>HX?;8}i*5<5A&@%OL51Z$CzeKkW^}VZ)}~{J^31yg&y7 z7;WITmlMY(i2%rOlR*b{%!^&S&FbPGaG8V0ecZFlc15}Hb}ILmWuJN)ov`&dr^tq3 znR~zbvOi@{T_GBc?EJE4=Qd_wx~Y4HJ4Vi~!z0(WW|{MzUHqB7D#DSof;@4g_e}H{ zi?`m$Fa9fju^ZgrOuKVjQuZ4IX9Fbu5lz}1C;v|DQ;d4|h|q3k#EiCapvKyuqUS)4 zv`3>oi93;hZgg|W)(gM=fLqRJw8f#vQF?BtwYM704Pl0k$?L04{RR;?9h>tuEwe%N z%xu^(4?3>efY)Qz*@BjwDG0_A6m>{D3u3f^P8e+Cv4q z)&VlW+LKCEK;4iJZ68(Sh}4V?`-aVi!Kp|#^42I=As$F8dSDTpHSD2*F-;~bYI1{i z$`FDciv@_pl^TDHE(&v1+7W{^`e0K74fdxkZYqw* zjwV_3PH^hu(yB!P^1_J55>$}8DI-F(EMyG4@xu%pZC11+9a8DE5ndc#r&Zb%Gm96< z=a{mC2373b6SXxRfX5!+o`vq!BlXauL#<)rESR-KX+YuGJ^OmwvNPc}wTtLaodu}Q zb_do2wu#w57PRZ{lC+D`uuPl?4t966%R2CyI>`=q6Ratd259!|v72Lgve?zG*5r;T z%vh9|^_rzK1n;Qn;$^_q^7ciFb*Ky+39*84>@WvIA52u?g&C0rKe>%%_Rvcf!yUs; z8!U^^_Zm%s8Fmv2eY66{48UfOdwYqR!*E&P6eKa@XdwLD@*kG(vplI{2knX-y~e0# z+VB*IQBq?ndm@ylS?AyW1z#uhZn1IZ8-cN`u`S->FgOa4!A)X>nEwfmcCj#{0nt*O z$qYoNvf@K8;~CS3@ppHdv!qm`P|(jq-aw`4r2&_uUCpTYgMB1;Iry+)O0BmsxT6Wy zqh&?bMT1c6E-^S7@Zz9d%<34%BCi`n(@h|`?rwuh{6UGaS7%2g#$114AW)0>JY4ElE7#k zo}FK)oi=G-vP9IGz`SW9YVF>^EC+D7cugU{8kWrOMlVM$}Z`XY1M?PDzk9%*RT#n90Mx!fQ)U1=@FSl1ZXo03X48jw4nl-mm- zNHV{>+$0%+!!vFaIo*qz-3wED58Vy->2tOtKCv~}78`da!i;(t%?96Mh~%)wwm^5oeOkQa znhfz0s~7Pisp02Y{U>OXmQbdXoRCDwEzO7-=1w?7@(?o{H;TW3dj-*~PZ zE)kdddOjYuyFCh02X#i-z6j;$6xCpiU4t+@3jC19w5=89!&-tPhb_?>Om3r?jT0Du zCjn(64C}|~yD-{DBMXyrqqv$;T&XU}!KF%~mKdd5Bs5X<;NRi&cQ3dwRasqgoY+m0 zetSkso*)-vD6Fig+C#CjHS9hxnxihO+I1CRY+~>sRgPn6wmhoKG5pt)Amv@id+7$v zud?mh&e8{mnB4^qm|2KwGp1b)mZ=IVw$&}-OQ~NfE6mWf6&w@BVHQ)-Sj7{}So8Xz zncPwkUK26uayaiP6;9)(O>)fX4O>F@qI`j_t$jxK%$_3FAK-qNGIhOuk?$;Q zr!B5)PZ4`sL2IXBd#YrXKY3jhwG-X&Aap`dYiJy{WPct;X{WVrHH&@v^O)!*M)sQ1 zi1!`66X8+?_Ix$M8|3im#A)L+qk_D*|8A*1|Y3Aoe~= z2GsuW0gPfE!5*0iHLyp?Cy@-L>yRl8D1bu&TvuE=PcyMB_Q?)75Dc-Od+;U~!U*|# zY-q$Zz!Fktih*PG#vm{sH8Q++RGGV=DVN>X-n3|}ow|sjfqm_xX^ga?By{bWixEPK z!G8$Sz??TU)#wb+`~PduWK9qYLcG|qAA&jVc31m&$f^j>0GS*I$F3Rx_Nl>ym)u8z zy{-g$o+bzdkKpY*{Xk|skz2`(+NyYo9eeDjW1VnxGF(25XLL@D4hTG0<~Gx~As#i_ z&F(-45@zBQj?Ij!O+jKGfvqt)Q|#DC5IixIAHT@dN!Adm zEC)Hy!YJt@gtI&^cR$x1(%FL|IL~^uAQN0{wg^o)C{v_hg-gajunieAc(vv9tZD<6 z`l&=em`exX7gP)B9@QD?o9IFV9xg7}IQ^US>O9rVUPksWi)pu76@%0kmPn7f2*Ox}j}D>UXbcE;4j;JErztm5?sfzhm?8xTh0 zL*IZ}RReMdK&~1>e*D6bWEYzh{|e9rIkNIFSbV}5S)d1leVWlnBJXD;`aohVYHAJg zyqWaJfLlHYS5<&jfh`ueg{F1WX#{yJ(Jr`3v{abFI8&k2eEnH`u2c&0Ug`=zT?)&q&zbH%n@NtPt%{ zk)8uT6jb9>MZq+kfcLy}1h^x@OR~weL<`eV-<3pn!BwI`PFev|q8q{RM%w7PLDV+Z zw)+jJ&?^w<4d{^W07!*;X$jH}8s%_Daz%etbiaAwRBPX5702u93-(~ZPcxg~_E)Sq zz9H%(4#4~2h|kdF)2v>yCx}8^DeAXwpiE~1`D$(Z6OrT6^8`7N+y;LID3^e}gfcH0 z?DUBnsGPL5>Xnz`KF}cXV$$)`fpH}?I55uo{IJgal&+_xD=y=f-IQJSTE=f4aOniu zo}rYMEQ(U?h)QK=(-~G==-3iElzCz6#jc_9RJNEx9ZT|$I9fn78^M7)Sow{%J8Tf# z02XACVRWd$vQ?BB!}2R(!bG0<#o{6^lrh!<`rHx+{3Z4tn$90t!!f`U!Es z`4O{Vo`<5!ku~k=VweO;6uqf`I!*AR zq}`b=LX6wn-n|?z%5u2LIyBSwgeV68^Ggm?$FLN5N?2((e-hHM@a&AwU_HDoVS8^n+Ua4_ij$^uCEwpsO3VH*TucuNrs$V+CF`jegh3@*BUFdf&QJs- zQqtfY@B&p7Wv#mClXQaKOXUT8^598^VT>Ai^iM{Ot6Tr%^WOZBV;x@2+@zm~f{n5h zm4FO1?LSt9588Zs7ImM_^ls5e{<)3^_xf}s$4%4O*&SEoQ7%@G7mJ63-M=S_ZjNsF z=y=xJPtQ*}+37sK$$4KYQ#3sIiEXi~=a0zHy&2Q~*#+}snXm=>L&lP3*15^t<%i}b z^fS<@ZF{<_1lrh4e?*TKidfe0Mw%!~D3C$JsZB z?qg^Z#Fh{65#^7tweqv0!BrZwGcENKvy5-P&n_(V~ zs_~r^uq}PAshMg43v9EzDvODtE&P@SVda#C|E>jQGmO_#8;MtC#}$X!GGw^-btrH+^)76S$DV{833mSZzF@=&4LJ-(q1#jC-+AF=y(%^G!qXjO ziTF=x00(oHWPZv1qgY zszD}-D;VnXW08tS*joEpQJHmh2=e@RqP`H7*rk9^ID+YXsr&~FW*SK^;x~3D={i3u z{N3{zWw4HA0Y5xlf5>2>QQns{l%QuZKbFx1TSRKgu?{O-c?BOd`Mj~3+0EB}kuse| zg0B+Hw1wQsXmzGn*@HpBa8&My&bTwMAQ}E*vhv5r&Ty<_>MrHd zgReD`4>d@dcdGLiNr4P6vL@%DoGB~`|?&u10 zou%^A8a3}*5xE;QygwLXjdr0zk2LDXXr!`FjTXWmwD`P2oo^*wPffOAk2jh**!qUS z^kY{XiY;TgZ|@t1k~_KA6Z6hcqRYN%C>7AY8p?fp-!PP%)NJSVXk_f2q4@eTXURh@ zKQ3aAXT`%yd(RIA7r;4m*F$;7Vn;Ueqk@Fq-~}X(ku|swX;ZW?VzCoTmfM`yIRik+`$QCjp*`)=|jex5bOqGT5 zN7z#N>A{3`+^k)uW?Afy4t_#Kx@It`ACSQWOqGAV!OYC=Edj49IqT)}PADe4STuUD zZ&2t<-Dl@zxu*E1K9oht-K>{41F2J;&G7URw^(E>l9eAnr`-0$eq6_2~?!0T-`_D$u=SZDkaE-{P=}ESYwl7GQ^bmt%5|(_DwR+ zz;q8QbT`sxxVXua zSL>DE(8ZALMsQhfkP>MyCA+6sox%Qz-u&QtG#^Uf3JkBukix3FOhgjfdHyh?$>Znv z^_tPbeDh;ovFU<07ZQ-7mC-7r>y%OxVRVBxjBbz(%)DaL9RRs1GcHKCEBi(P^M+2) z6$&W6zGCB&Y* zD3fBj>V8{=G|ODE;YFS*w?KD;eVWmF>+I-TA2)gVpNyWo|HB!5z_I;cGzX2}%;>Xk=RqT5X{y0) zj3Gk-ykRu)y&Fb@+%p>Rp3$m%!)Q9VWi-$|ql>y*Mg!h5x}a-DS9?!x^0!>+;eoUx z_D46y*QeBA%FpLc*PBzHPpSD!TL?=1Lx%iA`-g_|H|{ak>6{*|LyhRKJc239_9mx^ z0{GMf(^Cy-&oX0L=%MOJS0S-9n~u%%&>mm`fms2PV@Qb{fx;mOcil7Y@4XT-u$%`9PHe z;PwJ`PJzt$g?(u;754O9`cB@{6$M|yh$H2MC!mpFca$`vDuh_x+v^*fx z4d}LsFW6ABTGi)jct$a0kpq?Oxui8(kj6t4+yqyrrpy(!x8MAN`8 zH=wHrd5IKJXR9xIbvH$Bm^QvN)-+(%2L;TV2~#R{^6;2qx4YvDKYr6f^WLp;p?^@T zRW%6X?W7@Tx+l}{@=`1(O9AujDoZFM+i^E&a>0b{$W0k6&-7^PH)c0XM1;lBOl8g4 z0ehVLIjqN`fY(46taXdBR(o7D@Ca6LAJWyXHb8jjHI+I|9rM6loo+&(H8Ta2tck2o z7wNf=G~fa2c_>c~T=1kT31EmvB#e7M3M*(Ld4$1(;9&`t_82afs2Q#x`rubUUA4vl zsRcc)Kgu#P!a{eYd8c(uB*&7)9JO7ywJ_<) z?@=~`*vy0!N=6pA)jsa3=>WUOM!P(F;%yPbaJ#xAC(2NyyinXld7`=W6&E3wRtfF; z)|Qm~Xq4M+H90I2#7ZbDy@f{CJ|S9|-U_OzLGx*Y(wNrc=$*yjHd!mxA{)dkkSUwA zm_?H%!+0$&S4StsS)&72@UW~#XHN9*R z=cC4~FSFq|FVI25Xjd=)O5SVDdR}z(vIRr!X5rH=osDafky*GB|Wy8+(TK@!272qnxX(rJ_dZiuhjYy$9PAmVSVC4I!2$T@H}9! zcxil4kU7I(>7Ggtm}QWuJop}PecL0_O#-4aIYkk)Qe(2XI`!w*D)8k53`Cnjfr+8B7> zi)Hdz_QH7Yeym_BR43YdWE9B5w#!|uR`-lN-4p&a%MKVLtv6o(5YxE$fhqd{)3i8? zYdT9f@E)PQFUu&*3=FQo@;b`|D$Vt5D7QoOC{C4H2F)7i=9V!t&N~dlH?VnKcmZ`Y z7(rzRg-Pj>a^f0dsv3GQjHg}7o!-4}UX)XL-tk=bM_A}v!(~zUG6J81&=vyyCn8y) z*qKJ*tJaJ##Ld_gJl1Dp3mfsI8(Y|jP~KtaH(}a*>;853vVdIGH#v9@U7IZSL5&Vj zif(+ovGriNH1;$jH|#d-FNu+&A z*Jb1P5M&XfSceX9>MS1@&dqXKQbRO~svPBlaYV!l(GbcPa!HshEx|wZa?0}B@*r#kDaz zFreiMl><{FLxl4z9lH#>KVZe{s=bcKC?y>Yo+b6XLuj0}y&HjY=S9(XD=tx)>BSrm zdion5%#L?FWv5 zr3fB*hm9CcN5I~-=$!J(9YZ+MKQeWEeQ0Aq7VzUakoUUgk8$MZB0P?5~Yh>4*n+x#;oG0 z-rjI&zdYJg3|&3&uJIfgOUvSo7u2I=w^$S_8MMZ6c;QJ3LuRZ?>{51~ty5^kdj3h8;5?m2srx%-!xUr5demgqzf!N=nwki#*8&_OpZs-Kl%ywwy?3=@8CR#z`PHIb+qs%WgICSJjWg@k=}6|4tDu4U+HvjP|3RtF}9@n0V;!35+Yh=Os#6G9)M%t^{M1hGnq?#grjd z8Y?mul*is{vT?0Da*G-}*nF@nPq1BWCSs9iz}TIP32bt!cF!fXgHd~ihJr#7+aFUO z^q>eoBO+Kq7^unBThlIQ-$2WRw>63%9TBjJKj3hA=yR4x*tiGreJ7h{*$ywc35Beh zgvC<53(jM-AAWK8u%%^zxUUVLZSzm!0#g|eFo;a;l6arRw%FQW%K)-|Pztz`5-C~T zjFg)a7TJLFsjBEHLh@b?5qnAVa986`GE4TfBTcxvwv&O-#%!i+HG-ny=gd4tmjSMP zKYp0+d|F}*{W-?t2byJ};T^`OBW2Qd&^I74X>&A8#z%3DWikk( zjs4Z|nz$uc3q=p6x`MtgXv-c9r{#fV)p=fGTB%<`t~WQ+cf3OEERLm>Pn5up0}D;~s*v?P zS6kkUo7${Dn~0!L#1b?`L3xPmjz>GzrEAA;qfJorD4e5B^sM-fJ@=lP5fO%Q{jgw% zH|MzsMw>WPR_H-#lc2bbUQnI74Q1R~iGJpTki4K#Ba_zz>NYdgv`N_5Xk=l>JCp8b z@`I4cE$2{YydrqZIgIl}v-0JOhUf)db<*kMI!T8DJ+KX|^3M(uH~h}NYi#26A#f$; zxvilF;7c~e**mdnyppoEiA7pb2a+Q+2nr~NWvHou>xC>k(h~}=#N^T5vM-z0t*J9VT~_*@|CHd8hn0d`|qb2Hc*&vQacFl>U0tYCA@ zwgn6;VQ{)$z;#QU+N%&e1dHvO$#0iQ2QNk}yN)^$uSc(64o=I84d;RP5E4q^?<6I5 z&hX$hK?pk!=bGJ~GiJBugn49cjoEL}F%#$rJK!Gn-z7u(bzz54|F7(hDZhr0zy$PC z4xW1}uf6H090kM=VQhvLSIi?}!@8Mg6LY3A#)x^4@=!fao8!Gg>Xh{wqr{yIP5d&{~QK*k~yVrO!M?qa`Mc zqY5v6xdH>bS&Ln8S$4GO+EV+qzoGg9E^9uWqZ?|qQ8EL1B>QW0^+TrMh{G=Zr6X>B zirO3^^-N)wAG{;U7T&ge{8EM&Gfxg`9~ac=f2ln%@8L@=W{~W)tX%lJ zTa5M{ryqI{FA8}m@daG0Y6@l!{qQ^IB4Y|{)J4dY@&2Q1P`ne?ktovQ$~Gg0E?jXF zI%+5ylP0M4;{c`*gpc}8JC}Bp2SK)oRte#c zb`9QC!}zgv_eP!Dej^R+h=i8H^*E4$`e-rwC_DZI>+lK+m5m?XqHeX+$?lLAB8S~# zR*nMk-E|=9x@Sp)SD1FXRd>N~+PbPO4&Rde`r1fzq@=+V$L4qDbzN>^(@|REB2`>h zqf?dwSxB+9g(W8&ZO5qOT>|@TsCzXI6&=5D}5HBps z4agF$k3g5VWY-qV3`PriB2khPO{NADZEEI3B9CSjQ}4(PwQ-!)b%}x7L|!Kv9|!b- zAU!R`h;1niJ`c3KFWpl7*1@gf+l~941Xx-4=4x8 z%%1Oh!mi?*J`$@l0D(FgtOZ1_nga8N9L+$WI2-CxhG45?z1mCE1GZ`cuEDaSuIw&K z$rj{uS0#cz0BKKWE>+UUO=v{zBMM?)Cquc1b{7hwyAWhTh~!`j99$#j$Wlf|!J|(- zZ8)nQK1%l&cH|UE>dB=D9CfL7HmatRD)!|lGIx9Yn09D%C&z@^T@){5<*K5SR#eJl z4Of#Bicx4n_{ZAGRMm;%+DT`EZsMt85tSFkNTty9ZGox61{r1_RE@N43Y< z-{1i4SsENttc2ftIedN%5XF(-QwB0S`S5wKk|`_5&A=tv!@M+Bs&v8?RgDhA?%c-3*_CpDx}cfJxF_+e*M$ojVS14 z0IpoF^_%{facrZ@ifELiel-cA&YXLAk%wCw0*hOfL0W_YW}nBU}-(q`O~6-BHEp%_KA zDyJIxw`9}5#7QqvWM8o`=mC4z?avRtIDa_I302;2X#bA0!uq~m)Q^%&_|n|4up7<< zUUivJSM|2~5=@J~GGL6$GMi*&#-J|y&4VrZW0sB;W!fDEUfPf=HgB-ZK51Ji(4$Z6 zVmqh$kdZf=8=|iRMV>2Wg~pt1Fn8)xZ3tiJ-sm2qa3+1yt%SicgP4>B<=7xSrVWlb zm9fh|rT2wZc)oq^%BFjvZ;3HXq7kz6mIl_X8qyR_XQiO6#feHb<7$T|`7wG$7)hxm z^2)}Bh zVzvieRo_MIf|B7X+8-G-inw1?vOYXGvAfz&bDN_R-_7NSaOL%z_ZX!JZwarnR=~QO z>mmMW@)~v4vqd^B|jX zCD>&%knnlqysNU%x;cw$r*6!ficLzYegpOc0AqY0w zxjW%r#Go0;CYCZ_%zo3uM$H6mI9DCuqd`B-@I7tsT9xSYW2-@XGmLZ9d40jyPYap& zzW1-_{uRfI_A8DHL354)!pBDN0!ay@wPtREHym&9isOO^&a52Ql9g(@=D2CT<9N3T zSL*IRN=_U%_-N2ibNq-U6UTYLNw%{H{uFYI+BM59`By9-ym~fRse6)ACEAI!UEPiQ zOK%CeTzGjRoO<}6N0DoeXxtV8sy|;yS&K`B#E4CJ%f`p%Q<5F9+r+brd`E2dyn z_@lF)4Vx}k!_oIIzV{o3&WwDf*o%tkWMaG7nt10&OjJ{=zY|%F2=U8xbVEUduan5c zV6}YepUiaHS6+LUW#YXQ#)PoU@ul@w5=wKPRuez!1g(j$T~{56`tPvbbke$ep9khF zeT%?4@nH>n-w|txSb$BAK1L^>pPuByd?wUiSp8IsS+ICRQ?W$V{)__rREt_OQI`L1 z)#72^NWEP#t!qBjBF?Q9Y?S4nm|9%YZab?d2itGXG1VM~Q`oADawy0FgY67aXaCyp z(=je;CE7)lM64sPD3LKjZNy&P8b-;c5xc;)WZExV9f6~4ycKOPN68*fSxUj~4x?zZ zS9ioj1J7kx6KV&Ph@1?m{#@}};9(aXfmB(7Z#{O(+OygaaU6CLPz}_v{d{y``ntLs zJci&T5cWy)+rN~I5%rr31R*DikE-)R{;ep<3JcZ*%#?I$J79?4Ya@-X9lk4{z5WTS z@IGge@xAacJuB4q0T~Yv*qBo?$GBh~JecWG2CnE4NAcc=$;sT{$8!Xu5_q`2^2M*D zn90lU`rO|c<(xe$PZ-ovNlA}VH+@_u*->Q44;L#g6t$hg!htLSK~s@2f_bj>c2Kt{ ztbgH!N1#F7x~^n*JM+19zG{Dm;dVt3W=Z)&V=gu`k!Q)7`WX~q_Y^K=Gr=^gjIo~M z$0%-=xqDT396=D3W+iKOIolu{Wr+}Yrxc!!7|@7mBf2W)jbQJaL9w;(oJ!p)B!{`L z6;dMmnLk46J_fi|NJW@7DAx+9D}@yFS|KfPw217tr)^O^CBjWAO~k%j!Fmy>{wcJPCh$OqqF&Kh z*jbhv{F(Ti!&1uS*R?8Q?8Q#-0X<)N?TB8vo%qSuGJq0=i+8x&A04KVWntY{-N z6@v;^qZLJjt}IWe9G7H$c#P;Vw>Yo4fqAs$KvYW=gswWQuBk%&0L1BKUYI0SV6{T+ z*>_OsR%A$w=dp&s8-kh>^qSRipr?qEi)M?%0Bl;N#Jq$6i)iV~+|(ny8BHMA|Dj78 zDy*_Gnt;*R$;So^TU2&Xn{K6?D{+N)DV(^%!7<=0S!8KeNFf|kfJ+@^q@!5R>&WVm zEpG8cY=$q6E#mLi4p?nV8tqQET<602*JVuu2?dtg#Yl3DJ6SWGc`y1hhtsitjN(wZ z3FdctACQ*rR)->lO@|`O|7nMUBbE`9)q(u(!b?jZN#3>W>C_qGk31Qvcz90+pe#p$ z_Mr>9G!$J%DP~wzmnfKYd10It_aybRDaJhWq_o2vV^LI^pTeTBWXnL_ZpuBDiciOOe+v$>X@-E7oyQ?f_o(qCkXHsDm~ z&eZJfUh2sb{8)Fc$0Z_{K{<9~)yo!%>RFm~&uAoC%F>)TDO?#NB0qeIVfxW)48SDO zHli{3hhmJR>P^UjV`_~bF>gbpBH%piHaeVAk7vbBQj3H=<%EwIi$OBY+QJ?YzA-?e zKz3Gem{~6R4-F8v%lyTOFKyin!Ik!4_<}=7p1W>7tMdS*ZC0J8j$>6VZ2zR~iKoEg z`##1zf#0rmksixsC5*iNC5TLuyr^Q<1yiPX^2Utycs6n;H;BVnwWBcKwHQTvJd|8C zVK5Y|9vi5CSRwttN{+KHCBlx?#8Muj+X6*FB|yc^lc`pH87#f2UX5ZDdxNnd`xj?r zD3UnNQiERWNRDO1YOuA{grx?v*e1+Vl0!mRt{%fyW2k>GzHSc%(t>fWHe?UGKQtAE zTzrE(Nf0To2d2lG$Nh5YRSQn^S_@8GTCg|P-0a^>oJEp_g7sAAaCFb=$U<>7xdnPx zXRNhe1QeDM%sC@FZ1EBH?_qiUWDC)rAbMp{ffJMlYz3!Rgl1WC20c-fGFuovAoLFqm=;gr-fKeMa?Q3x&X=g{hC0EzR= zL4jJYg+uO8IXpz~fwOR=_*6zpi!R)T6k498Rz%TF!$)QNu-hz~NnaUv`4KNb-#`+tYh>T-1-mT(9 zN@rQALV-)t01_VS)*dHJW^nB7MGrN#8+3WSI1;qIR#e#PhtjoW5Y4>!trM5l&txkN z+U51;i+vz%>&=WE0_SxsCR@>AsW|uWz+t!uElJixdTtMG>e5?Ec(IsHpCIkd z{lSD~S!ovm*M4R;F@qBJbYY#|#1I8|(QrI`*7GNW&mABsdY5N|TEcnRc{Al|@lWwB zyVYQL5!3k$sx165&qE3}60@$2FIW7LbwhWHg`^)<%tgN{S169nMj1#dp=bMQ8aSid zjNnJz;TT)W2`)SMrRd`7sZ~$H)ed%rWrDzbB1Ga5i^jGv(ujWMv0lh(tD&=BP5nbOS)&yS?`bE**8F^idkOv@j4s_Zhc zs^;O;=b}Pn=fjoX$4nj8eOTi6pHuZcP8F{9(0_A%eNNT)I8`%Du$+p0PSy7~RZ9vH zTQx7R&#C$zr;6>k=ZDzY=S+RS{@-yfs(BLdxu(9uHKll=SCYayQmbq?_Kdp_$oz&MhM|7zByG0 z;Z-3z8>WfIh?-Z$T|LipKJb-EeXHZr9Uw<8M&{M5yKRu;K-X1B!wo8mG%A}CoxpTu zD!3{h@NDmFkYHAWAsP3psuC~a`&=~&g8TYLJi{l{H-<(G(!CM@?Q(e59t9@~hA6M9 z%28pp7$n5k?dcgd)5n3K>0{t3$1|{DAAK3({@Q4daMtLB=wUYqa|ba*c8zfc=#DwZ z5T^N{_C!si0%R#US`44bLo!pVwx>iX#oZ>S5E)DaMk5?-#PD`WqSD=sj!haub_|j7 zEJ(~IA;=)!RhOIM2ag*Hv*)ZUa5Y4M48T!tN|9NEOt=H&u1jf(U6s&r=80HWmqb(z zPKbjyRn}7QY!YW~M3lJOObDl6?sYVEztElzaq08Lr_+(gJowfIkL;0K@{uL3cl-F1 ziyrzp!gO-+6pZA{7{VB;Fuj+*ZG(z}-Kc%Z`HXKnd=GNLb+& zziMA=s3GFY-312&OmSD`I8fz)I7t@7aW_owx%(DfDO?Xo&|5LWj)O}Q4mF^;}euFkGm_l+_c#YE2MIrTLb zR?y<$HC$0`X^Pno(QA(qY>b?^yh`%nUq+@DnJG?mglT0fC($UhHHzYNKk(AEIaD*{ z97JqKZH{(4Mq&nomzixw>v<(3r8|L9nFyAtL0ah+5&wo1A{Rs^<)9DQ$^0{&E=Omh zoU0-mqcIl>8Bed1)oYmtxStN@cj#d1o#5eMj_g~%Z}DbMPGVh1QvEBP=AXen4_F3w z?)mlfsycE2Zw7yE1;mK&_I!ocV#Z8yt;2Knss1!&-`hzTiCLZ>oo9be)%Uxomg8mZ zAN6>7%a+sgGwzOkx)d$1-N?h@ z^z=&7D7#bsd(ZY;p9EB@U?%~w5c$R^`(bvpPFg~PP*|wa)%<`KAmOJj%D%6Yo&X6+ zH0a!|f=KmJlk7j5X;kHbPC*KB-GTLJozm*$5fGE;qP)B`Fw&uKTO>XSGjN*BD zaNaR1iR|>rz%-3cYg+~>u>SFF5$i~a zx`$4T(tlOp-anCHr~G!FG{ z1k!^>lVZaITAm2P6aHom!=(AQ2x}n4`90`h62Mzal0R~1cm>ij4b{ zyYp$cb+G=jz3kEHxDtExw}!x{QqNpXlpZG_ONu?8`5>0MzwCD0-{8Y@Ob%Bmu=l#% zLkyLJBZAL_nh6jy{bxeNJOm}fu;q>{5T7a~0FRjKxZ;%;WCe00sQc<1obe6%9eL@nkBx-?VjB;uA1k@sLI zMc#ec`$jAA`Ii0i7w@?9yjGZx!66P7{U@wM60x!B(If#^%@t{0bj2fVsr;;om`_2@ z@a_91BEt?feCKnpBAD21eHJV~?*EhqR-Z4b0KR0H(|ujh)L+4L(-&e;hN0ko5Z|B~ zXpPg34e8IE?jQ>v^6=2rEOWg#(aH}mN1B1#M%N(AP7teyv7yc=M}LN}oekCc+41R! z%Z|?tX%mJ+q_d=|%8_*=I-4qlozkd?;b|<66jxY;;IR&s$9|*Bpntk0o=O>|Sm@mr zlFX$R(TZl!n!szt&bv#r*yvI>e7Xln6v($bJkGOXdR-34RpW!A0Cfyl#32f!Urx4+ zg_kmNP0Qr34)pH|mesti{SEpc9>#n|=Lvm4wnr%u2|&Q*u4 z=bWXCu=caQ07bc6>-vja&%oN0sa)!^h^k@LjRQCQ1AUdyOBa8>EU!$9DX}lqAD6K| zVXs5x?AlOs|8@9|9$h`_k{xhBmhD5(D_6dd`7}nTr##Bn;d_xDbbS*^#YEf$wJ8zG zAW{&K9hJj&m{M+(YD>se2RGH+J4saS6ODFsDRYcZr@s2<+GgNzdMFvMgy|iZ?9w7~ zU~Ex<6I^V-l$hs*6;2e5Fe+YO3F~L|_shVGLSRUW{oT~3}s^*E09$oQ@|D39S+o}5D7ncuzBTwPR1AaLQ zdfsnm!lrf{vlyg~6$klMqh6q#$(Y_0>qYeMSlhfDQ9f@GiB*U(SvyXZAr#Nv_~cV+$B*#((?q#>vSjzpFwG| zMR-88j>0p#>z?49eD|(9FFY8%LLgTU;R6&9*u zlZT^X5P7=yGw`%$NjGD9=L=%eIRS*LJtRLjT9cncynbqgA?aJ~E;x21 z3W_@D35%)`reyq>kRqo3>jW2f`XQJqdL;0+?Z=p(F_VAdjYEPCbA!di^>8DB@IPQS z18j!8?^49V`>wfv2&;k2l|Z#~aVG)Uq(}~6BtbguyAh^@;nOQs??FiMR#7R_3WTb% zW7cB08-|UyGx>BtWxknpbMfoV@2DcaH8wpS=^rSNj6Gl_@K*uR?~k%fm|yW&LQ-P`xy<>57J-@I5?r5P&I;(llM@0S@apMV z;vqyc?~F!OMCK!B{RC;b)uPBWzxaQ&xB?!>9kFh{C(4faaN5@|Nb7}NfLTZ&_Pxy*wqRx`_Gr={wkYs({EXDWdQZ zgETdade7TXHR^LeW&^P`ha@TV6p9lM82PA4b#>1+`3D<<4?5W3o1;5YM-)SX0SB3W zGbfL?22sT8c7%GO5&B{kMG{ZpO06X0n6wLp9yc4^fSOfKR~cF$New5@?4WNUEq^>-x94)=@m*y+4U#@LdRMzg zPakm7b^Ebb+*L`g>oO?yE6hMwTbit3uAN(jfZVOUG~KE93Tgt+4ir8#tc05B{CwnK9wZ@ymo*GF`Q1 ztA3IjIpz{Z%pFCJ3vfIv+6>=S&{*SFFplN!LG2ms<1e*`Z%;D`(2uQEY`cWh)GGSi zbWho|-?+raGLA*8Gm0y*9?E#MpH@>mh&IC4!ml`ULU8_5R)0I)+J=33Fkw$y#d)&M zqvqy#S;hC1k;`TnOC&5;D8x@@`A5OkWK z6>#igVGQS+Hwe>tKZ>UXpD#;rBjHS@vwpRZen{{y@*KIMkrDp{7YZb4HeiXXO2UTL zPx^X~qWSm{!~q;`tgBaDY#DJmr^^&6;hIMU)NM-XJp8sCC*-44Sr(4aP+|>blT)kV zZV*rN55-}_z*jC$e9qyFMXmF^x8x6ZjJ!r3SkumNdqGH41@DeG-@)*Pj{Fg#&)j+0 zE1iAI9M!R&uI&<%kPbeuV@LnN%_Co~;QWu8=i`a9Lm-;x!-hb6_V@d`KbSsW`SMD= zx^z#67=R(N6~JtqNfoL0wJ`mg!}+LGiwie(xE_n@0E9s8GrwLK2?tIE-d0zum^>a| z!jr_^JgKY#I)G=)R&jzWc*?jhh*nQx4rv>E&i|;&Aso-EF+#qdT=5q`n8JUFJ+G%d zjK@l&3AQK$pv{g$EkStCN3M`jm6zb^lBC+ZAw?9zwOba|MH}KlN8&+5&CgtPl9#qQ zFi}cyARKkn{Uk2`P^k9PTdu(ACMJL6!;*(OXFHq@T!7LQ0>r+~Iyq+JBr%q>=1U0Q zKpo4Fol=*o_#N}k6{KJU><@ejtrB0z^6$e!PKmkBh#h68r5hO1LHi?@TV+W(Q%01a zy+^|wU)X_b31-li#S*E278Wrmq=noyzaU_H-mObQa4poI$Ck*Vt!B_pA|d-}X?ZdXG|_`R$>kV*)G$`)0qY*DSnblax7dg`Qf(ecFM zalny-_jMHEK5nKVqtL2ljCJ(PamI!CBt)BdQ3* z84#bRto5)zV&_Q5(HnT=+T&O#iT7GPJA(L$0bcjwXy7!tRu~jC8#V*eqgG_(g#D*NTG7f zHstEUtKPA_=l=aHp*0@J;(dGSb|x_7OnXAv)iUAna^X?^lPL(8K%PQ{{pV0W_u_$;9a^xbxtf}a zeRiMC)6qYPJG?7{?C1>=R7YnEJJW!av3T1*=>zJH5l$4#>qs9KGiCXRT7_cjR;B&5 z`Jr~q=pg0GBa}AHXZrW;I|3Z#!z#>+fpdL-A5n?L!Pqe2ne?7>q9}s?o}Fw&%Id1Q zN|s~j$>u$RQQMc!>LXv-fD&f%-)YlwL;uN>(6^wQx${_x5UDAi*fPBnTz258f(ViB z>^84Zi|d>QXXz%F|B0=Yt{ z^y&q|&u1rba3x?oAY1Vy<|5%n?0?SrnIWGM7LSM2^#Lgxf_W!=$`bQCM!U!t-;1jy z&KQG|JA@;r3Bis9B^lO%VpgoT==x5dc^S6hM8kKXIK0`WBgdn~@PXUjm7`4G!B7&2 z${;kb<_&Y~z5=t&7-e$|s0nucNFuEgay9{1BJ!Nz3|3*wTZAPz<7YVVGlGM9D7JC9 zouZ{4#`Fb6J&c}m;`vAs6srddzaK>~MAwD_aYQ+2>QE!O`8uC9nF<5X=nqmDyb&@~ zQ><8Kdn%C!(5h@=j|l6|23K@y%Ajbq(&K2l1Oy+g;-~e;fiGlA*0i^bjkei;Lxb>j z8BfEE2jRjbcYdOnezul9Jrm_H!g9U*a^M(G9`<$(wzkJAu$8@%gsGygCBgNtB*FD3 zHy_Q$(~`iReu(}2^}gGhO8KD(QkGp%jO|1fmeEw}ldUW4oQ+}=dtT1C)fe$XmYxKW{d4H!F6JG^aohux#m?6RZtL^bfSp+m z={+XS(#P3+zpuoCV6jK-uXIAmn9k72*|uBKBZgi&vGWt-c?(~^LV2bnYSQ*_MRBjj zg3BVUD<@)&cLadm2JvUh^;qU*CWi6B$k{QkHIx&3Rz~@5 zIQj94kP>?^i`os=89EXJLeD|VO&Jms6z9X9;mjRG+AXdAzB(Qm+d*I7t5xY$%L^~3Z8QO!!HO2{lo7*b}?o7Sg$^M zUA(FstGQSDq6&lQuv*zFFtvon`8Q1J$RtPD9R&&POZ9Y7A2VAc~$JLkILe>2b z&E37P|NTx~Xw6V{Q|ET#!qm*$f@Iq6vE`g6la|&qL7^eY&6I6FJY{^lW=t8|+dL*m_xmAXsT1rwS#24^GG~n7cGA%ILwbjaUZKGpou#Fmf3SK3X5wZSVaNl%-Avu? z<5S101A`9StwG*04;goUXtia+L)B6x*!MAYp*7=Es+MhKux#S9+7@K+g@cm8t?`5X z-}sqHOY7l8Xb5sMW&00L88=i%hs(=MIR2TS`yc;4rtEgDh4KF)Q|8t)LGMo4;loqL ziDssZUGb2n&nZ)sdaxr>tE176t+J=5?D*j++nhqgoV?FP#=QL7&e-Y0Ge!nh#AY6S z{5ee7_hiblilaw4T)$n-ynkBpAf>F3c~8!s_MkeFe)GGsI^nBWtWILdBXe5ZL^<86 zY`IGOAk6K(FFRhIv#xX{Vx~U7;^=_~wD+W+=>0Xbkp1#epz<>W`vgm8ZrvR|+6?V+ z`)0Juxxy$*3aQ&w0!{CVX9GIgN~laHt1ioFkORgH;%pF0@2xs_hFp>Wnok}Mm2lg1 zaRxU+UDOeFc;QrU4$JhjDUZXak6CtY_Q-=!V!Fb()tRk7<%|(%O8|?_`zVFy)T1$y|p4GNo;a6p<#d(;v;HOTxKB#z0W@idN*@w$x4(apdREMYp{ z*BPBl5}9q3w|;i1&1xc*_j@hEP%AD&sK+$%b29gjr3 zOHL|}?6bQ?+IBxDl7o$*a+)3%Qc*4{sqJy|=2T4%ya?Y|h7bBavjE(8O6nNi{Sg0C zKP2I%MaiKs%_Aqv<}U{kMbYtv1Qk=M1=%H~Xw)KyjyS{JA|m~YXC#;`LsnnIq7iM-3Ec<6*?lM++vA1DUdK%Fz{t+&ax9S& zQ#HxStEpz%Jplt_iao2doJ2*Z!cEXDsi3qm)I|5gMAD-8z|llzO2 z2Ti5rc;ykc)}Cig9~#WuZQhLL&1-Ksay1CKs~OD$P!~>I@)6ySu$e)%3>v@ID?1N= z&Ysi7gjUV@AvXL4M(0%yFbSjVQMBFh)rRenf4V2OKVUO;RK^7wZbEhPtlop%oVhT- zj-q_fEy0nfvE+1-OSK5GSy);`W}aJ(WU#5r{j6i&n)j%|gWO(+yH?hA87< z%oHQa4kHBC0}NePp13M2liwZ4zY&CcJqUr@@@os6B*Se^%Z;+fXrgf_RFa-K%NW>$ z0e=Ix@tJpg)k;ai(8!fJbZUhu-jr=fS2bNzV*~F&7Q2P+b&IVjFLodJOcl3z@Tmmi z2y^MCis9-AA!nF-D%VJ5qTPZVL=c4Nj#C#OvzpVr8+V`-ZQb(aF*d5XvOdwW7*%w9AgDURjEqdoVGdC_ZZp=Nt{uY) zgr*EV0qG=pAOWY5kHyt9VWMS&D)5+X=Y%d}p+V%Xi(ZW-7dj@2%P}|^o`I>d+6;H$ zPjZT`W+KlNtSAhs0Ow_yHE1%2rW9!V**#5pp{MyY$CYp;vHn`-9J7-kM-(B}oh{N0 zSe>b47Q&k5GjBY|qq|=;Yb@|D-g3C+ACL2yfSWJnee4R@^m)GvKbkAzgNO48kW%?? zI?@lsS_B^JF&*gP+dCl=)amO&D4Ngy2=OI-)PBMn+7D6d-6_R3g@FE_UY9{CJ8pF79 z51IJ%bfsZU7YZG$My?15JS-%mfmvW(bb8GUj%%MaxOmc!2K)`&MhVK%)#awTKm9>Z z8uevobMd6{V9UR*i@w9R!_!sKD^HhGhOQkaSs@FR(j_pv*Z2l^4mRw$bHl~$8(;n2 zrDy6C=&v5GJZZ*nbb8H%3h%H71Ad;{=>LuUTz!fWgN|RvInDci9c8b)QXDLOn^2e7 zYfmB#*#vgKYk_-N4Iz;Yd0>@U1#!ok3YJ?ZjF z53ic2>6Mbx%}EKjrnvzf54Mtnb(Q*{4dL)~VP%(#lgxn%*R%DWKp=6vnp-e&yjokZ z^3@r_(t%w1YAkfXarR~cuV}`TmeXuFPP5K*0rgD9;$F)Yzir?fIIajfQ^>JPEJMlo zn}^zvQJv$!P8WhlE06-wBsk8rQp5%7xFn7V{@*d0} z3tJv1z&h%jm6qLokf#+aZ(oi1kr#mymuW2xi`M=5d-SXWPb(^CM=kt-Wv_tp5T@-u z`qd>D5b3J%$K(4U6+Ru-Co<;I-4acJO(#rd`<$C1WzIK$|6iIFJ zv)q$);8RFs7s;}qafgSS7? zJbA)!9d4QLEa1BoU93IdUDl&cSx*yO_PjE!Js7qZ{exK@;kOQH(Ov>6DEWxHld$Uj zbc_uwSB}t#g2)x<2J=QJo`|Ly&IKy(%pC`WUyjG|LZjL1(rc zT_L;-6+u{lxXL%h5K%imijDfOx-Z$~@YVbyP?ilMdJk6c#g(U(Krx7`c`%yrXqrhI z$V3)?KtzJjtLiQtTWRl0EW3sEj$`L9r9Blof^g zyxE{@UMcszSCr4hGM8#Id#KF1+6)@$P(S1Sneb;JX^PuweKL+z!J!{i<_D5tji#4p zG?-oiL|$rBht9wl_scyz)TY-!%j$5-+#_eXdy4r`f^{*Ek>PPS7YRjL9Ee-w-B0(3p zKCN2;5-c#CY`gtyVpxHwsEOil!9EpUUz=j%=S99m+!J#}{n<(&B7=$E;mJ^C!TZ%G zojlw4=By(G=0~aWQbbD@FPhvdpzL1||nFQI;L9`RtZzd_R2#j6XQC0$Dz_r1Uw z$C=N?)DL7&KO||HUXMlLF+`3(SIOe8!Y9M_k3+1P_}sIlE8y(o%v&7_s)c%BHpel{ zOf}5WJt0N?oyF@@5wN+)gCR?PSbr^vEagKsvp!N+t(PpA74xWq9&3K|AS5AE)5$st zo%qF;WhBsaD#y9$95PQ(Fmz4~*8oO(9a*|HcHWS&e9yA1S4)a=9@RQQF%)#y9xjj` z;72f=PlCs4iV!Mq9LOE*hEB@Tt@+VWfBoR#GP)uYi;(&RNsk!Tu;jTbaaaGr$hte) zV@D#0*pZ|96$Bhp=2(JQd1A4(qL2dUW>85veqftbwNT+RB|p?IObdoenhXw#N^?3=ibu~x?{8%Hxey|ALEjt6UPCI+C6zuGH*y) zLpj>hrv3(^K_ub^)UvvPX!ZtSb=_es(Jqya+dT7 zWkJwh$_2zLUceDMAz0tUpnO_oP^$Q*b47Q-`gkCaYZ&l@tHItSc2{xsbv4xZ80W+H zw9L$fIV^^_Lve0dvU$YF*$ylaD}a7OUftAJVf15xSRV0kl(ndT2m&jil*aNg6ZDgz zbb-8ENUrND z*0P_ow$o56Gm`>ha;e2zuqq3DRtI7nO#8EaoGa%!lP9*xccdKP`x9XX%Dp;|G&7eukX1p20?a2YKExmXlHc zum*Tc%L4tJs&Hof_~TC15`B`L_?#;2sux^VOP1;%b*lK9zz~_ud;#VY&>BAY0>CPPlq6--MN1#nvnn4ef4|8>=cOPf#Xem04<=ON8^21jb-Z+=NQUZ;c2 zWXN+!KS;xf$g)-{XXvG*3?3y#d0Ac}<6Wmf@)l}n_N5BL+q?%KbpEu>X6Yw2--Y+KmO0&ce6bckZ8|GZL` z>x>J1B3tSVRR>;Jpj=1rtQqF;#4dZ$6O7Xg2hFUgg~`;#hYa^wabwrivfvS0)~vJ* zdJ_g{7RGCzq$I#Np{M;isbN0p%||(&`fMC2Qd~~jvH!#_cq<6I2zUvtD12?D3q<$=ie*gEHHd)mZSf<~5;U0g8XJ>t5Thbt()L|%2^2BQ%ER9B1$I%m zf`k{llYmN;ACNb{1UX$b=g9Q&fDcbgEXlwm!7?KDX4fX+&D3kcX(lKaIcf^b?h(tY zgo;cI?m$fpalK5;Jkw{V>xr4zGBFceCT4~=Q&3Y{vc}catJz};mZ@?%92`zwZYnE=Dk$4s9FKbre!~Ll*sc7S>&bib8US5e zbUWb0`!@tGVgmc55pZ50=|zD(*MRFE`+faC5HW>#HUagP<%s2sf^fO3c4(Ro67OoG zSDLw17K?~^RQb|LSsNBC>MHWp&4K9$q)ezMyc$d=9eb_zLP{UJQ8natS0Hm#fqKHb z*ML3YH=riGA=|n-+Ox9iCBqolq2Eu%(@S{AV;nm6z^drwlJ2(scrL5{?4@c&xmA{t zwll1ABf!w@HY*sb-^A_VbazBKuO7tM5C?hsiE13sVu^yuE3ssB1;`ebXo?|Ja_BIM%f*i4X=t`1}YmY`7PBtK;H-SZMe zRTZz09&-7XQC-23#j`MNoa?0j>ANllEiUC1c3T(j4gHWF;(3IMds?67oNN!@n%r^! z67^N9+4)>?l6IZX6$MkA)6vxC$Xn38o59=TV4XQAjFnens4IdxBy5oLE{SG+C(lrO zv!v)KV%w!iJXNWBU?%O6og}a{&K_#HWQ=O^-5l8Ax?T`E0V3{duop>_a%>DC?mh@Q zH=;K9r?4;I5JT)xO%*BHfY4%ErXg zmQD;kcF;xj+EuqM$GfY~i-;3r1teQ(qO_T_kt;M#*F;gI#lCXpYju!+F)8YBeXY|+ zC?^nF`TD0^x$)SaPbjb>IO6)ZS0tuHd&TfMrzK0ttK_W(MR5&ESCnIs>SE~&Uv+Sg zL&5G}=U3(^XX}mO6hyi)S=EeYM8~IH7Vp_(nn^??*9~mvtIg8FL;*@C!sLMI5@A$3gD=s%Mo*l9wo_0AWshjVu}Qj;gPCYJb%c-<;j$q z@(-Q7&j~=F%XwE8_na#JUK2?UPSoDatC^EOu@VV8q!VQVbC5XEDSGr%3kIthA)OTU zfvg4ElAsA&MBnZV?-|S`VuuE7E~a3$94(M22#>v%<5*$~IxiBhWfe};9HI_VmdE*O zs`WsCSvM1glTSk`OX$R55FPa@pb4@{0dgEh-@-JBNN@CAz*PyZV3LQtMW)55JLhQu z&6U}4k4oRkeB089;fSi&jh*e2z^Uwpvo)pM4jwm%Bjw3eVI=9hiH6^wNVIE@1rmo*VwxeX~yuxF{VkcNoZqa{JgTu0;g{t~JeD-i6; z3Ix5f0t>nb?utUP#V+Ww6p|mbSOI^mO{rtc0$cL3=2B$iV@aD!mc>7?X$68^S%IKe zRv_q9E%f8{u_&QXv{(TPqC{hn$yzCeSxN|{M1?)Q*X82wuuhw+t6HBv>WnJJPhKYH z-`+=E&KL2J#;m>XqlVJd`P@!0xBr^k3HG#Oen@xSA5QwnEg?2NS&x8f@QMc22p3B#niO*X+3g+5B|WzZH>FA#%b;FAcBA>$+Kmjn7H z>PYsk%b{NfOL=9=1*N#`67doeUy8ldm30qtmJ7GYqda!0>!l`457$i!!=M$!FYyqs zP)t-eN_CTix8jnMy%VdnE>k&C+KkGbC|=ztsYjBV=@Y|`Y~pEiqGWStNE78`)^w(y zWpW>g!PD;Yy@{-2`#HMQG!uI>&>T$;*xd?SCS>! zsK<%N{td};xogRCLFQsirQX=;-lrH53+e_ZgeTRd?j)<|ju~vhy2kJwH8T*XWV|81 z;YHE`y+ridaTY^LJv~|5#S8n4ABpQT-7)j}o!I8NyJ%t9_!9M-`E+&;85XA{a%>fN zO?;XST{*itad%KbSEqz6_bP!L#Z>O71A?54I`|Pt2_mYxpKeVbQ?Rkuif|8()aY!$ zafd{!LhT3=D4Ocree6tczKIA2f(mz;s&k;vuLkx)UU~Bh3#u!D)%zcv3gAkS7(UU< zdkM!gr{uxXG|^-d?|I-Q$V_jU=_P3(KkkbMLGj-;nvT;zkfpz1X&^uHrxXwJJZIO$ zwWv3{D{s63FtgFpHwRw%ogYgSm))eNV>Qq#`k>M0H#PHXUb}g7=6y34;-XZ3LcmRM zFs=s;EESd^KEjr|&!!8lL&+V&8p?ZTI@Sfr0ehTk^=K?ucAuLuGd?1$`SP&^sJ&-O zT20J3#IE0V{j^9DAJI;qqs$GlHiy{P#g3jj>DvmW8#$BR^b5%GK?mV-RGhY7DF-zg zd6JouSrY%Y=33tg(2wQjhQlyYl~FTJch`*)i-=C&s$R$lLcK68VDZ%a3y6OI4VTXO&AI{3~!nwa}`R_Umh7o+TV6XX~o-6;2-Idno=ztFyaW9`3|A|~2 zT`G{r4<;_`8siYNOOaIC2zO$-41W@$Yz(4&jiJ#S!<;ojJgVy<6pi4*HzJ$rdfF~E z2sK>{-nf0#g(2Nza+k8O44TJv*`3@Kgd<&WHpgMdsLM3EL0zA!215xm7s$*Y!nIW8 zn>*qV2Nho3B9p%hA z2zD1N;tb17SJlB!U1j6NVLe(0A5{_;Mt9kYWKL)d>B^d+Q3{JUNMV=aPCP&5aT;Q! zbh$79xpoKIqnIn13K-TkVT3B`31oA`T}rz2sh(mm3#^;h2XvbLLF>IVKfjK6Vr75a zZuBy_!q%Gu?>Utjd2<~h2fNdGtH%_!mopq=9ii?TV;MAtuh@u=@hK(6d2EE6r9zY< z%2YO{bG<5snDaE^1}&~jC{+x^jq5}-H3ujs)8)_vB8)pQT7x>-pjYLbBLo3YU2^h6c?y)1MHtlS(E*QwJPKDu*N^tlkpbPa&i4kW zwEC(paL}lwztj4&Cyex)6nT+#JTzU)B4w0JWG}=g{um@_UsqwN zbP#$|K_Yw0lc#q`cs64Y^8o1m*$5j$&9bTR5ms}+16VLtN`dHllaC)GgwG<5Ke6Jw z3|asELt4PaS+tF517?i%Sy*+-^5_Djc)2eWcGCW{dzyhuKa9xqB|aHv9_1AX zi@}1;JsodBef&G&+S-`Rvc~8mN%=|U~I_pfVlzg?$yVz+b+?mY;nyoA{KS>{FF&kOaFO(wQt;}DK>P$@6 zlB#iLGL7fQY$edzaljCm#`33GKG4&g-f^+Xfj@|xj4t!_#*>oXfO4NtzJj*@3WxeF z0lw^zm*MJ!y|%YJB$hW+h+;WAfKv+hsx$v?X<}>}e0H#XnJ8*iR4e-%NGvm#<*BNT@o#rFd-Z& zty{dT>bM(GQ1f-biQ#eNV$VdGQ`{ysKuf95?0cSPKRAAlH83ZpNLxX7&VWK@lIIxt zZAgdrygb}Uy1shXBdpzfH8>p)xd1jWsj*-LrQO~NCS%1Bq`Iu?VWQ}4rl!C@zt}ix zc7{KTt<2}`8=j96R|%Aid7Y9)w6jz1k>ZKgGj>CYBeA@mI;1#ULn@p{$gyQvXzg%0 z6tjfP^-`;?N~|l36KdC*E0A=tDPLwV66EA1e1}XU5|k;JD6un7+FZf%>U(l0McRp% zh^*>|CWox~TJ0JXJm`~?9z4<{z_&z2e zf08He?vu`%yA&*++XYPPE?$9^y9Jy_iNZ&wByrSq`?Nc~oyJ(Ix%+*e^`RmWYCMaf z6G9E!)^0E=B%W-x6ViWUp03zF<{}q6VUfjL+eH1-Cf7b~=qTscYh;!SNwD5EroS*J zp2~UlCPUQD-5oDjex~QAd5@<>P=kMay}p0N`?qdurRRAqZu!{O1V#6i$Inf+yVIU) zY_0t48Yc8Yn!+n@UT*wC>4!e*p>r6*#T&k~WiLn{Bh!8MUF?y7;9*23r{m^g8~sfubMbK~`_K)XAD*Dey0twbAy=VRPP(elMdB4K1``1GBXOC(LGER9h_STf+aDs7|G=lW@k@#4^amqr zzsrVJD4S@3%FQ8d*hO{Z0LVRF=>*E@C}=N;taw&{ARQhV61S_l1%o|Zb-~1K4M8_I z-2oA}ZY*@bZCTCgVUkR9+R7A)OLS`T(4QX0f;|}UH*i~qh|Bf}2H$oc<5axnZEmxN zxEzs{7v8b-9FZ}>37Js795Oz6iI*$+DiFU*vsoV@Ryhu?SWXQwCnuHC#Y{swE#b`e zh>8eS+`hr!HlLN;vGCIYvfYJ32i(SkXmFBDbHtR5@^{gKR#W7*`enN|um=PF25w7! z;I<-xoNu5>w*F-Ao98PP*@hsvjp(xe&eGeDPzIzZ_)S?*Ol^kb778_kXS>*ln#1a= zwn%7b*qAnDA~+v{p^ADJoAiwYsRc@UvbQf_f}j-4wa=}5_&!wCzC)qtL0OEEOhomh z5A{d`)$L`iiaQu^DJ#vX&wyz`x`DojRWxXGGX{`WSJ30v29k0$C^K(`ys=W$<&I6b zGhG!9n@9Ml-7A}B_p12i9VmaesAej98wT4o|3&hElu0!q6Rh?IDc=3+o@+rk>jWu! zY7~tatr@BVm0R#ZIj`5XHB}u8C#h=MzNR^INhC%{>%b{LxA5p@in3cQFU@%<$f>_b8CX)RxxI~RMsh0F(y5P zdm)77n6<>FIeg9}ub}>34Ng!ebPaWUi<#B&Z9zCP5iORtg@K9la)8n3ZI$Jk_=<+2 ziRw(V3p)0P#)*6>4^})>G~uxpeAdnW**(KdCK=BPal)@WBL&`N>h(`&kJuCaTFyTv zc(*^GphUZ>EDsbc*xb3UVB!=x(3qV(Am(|qCEZp3(B%mvtS1mSoDcG>?uVi*tNY<) zE1Hej!kPuUZ}0hS;0#Ir$qz-Jp%621-PrMz%vDS;GxT$_;z(DX`dFm1^-Bq2PQ=1? z$=q$-=VySMiMD$B%E=^qd86ym^Al_}y_i_rTIQ7ojbX3gD0(2bgUeqSC_L!0g*v2a z<-rcaS;$J@DbtC!(ta5%aP(ZdHf*u3h3DlxReQbAM=$d@kjA~2qikYID+=`^9Fwv$ zI!PVV{%Gv%MILbEb2^wfX}>?!=^&g#N+0=eUergvT>61KVVHo;e$PcNne-jEP_#eb z9ks%gvQn7TYB0Wcta3>7Rvq$nfKd#a(G{^LT?m89<7m~GTzxlo-|6$>M+ja^RnH8u z2d@ws8Ku%l|9^XD*CS_=T<3fKioOvbU1-Sas;=$^gax!8S{SwD9

*-bKNT*yAVP2 zSlvahQa(x5;}PJ&7qOZQR{*EV(!(11kcnO>%a$H22`YIYxl77*zuLmIs-SWpZ-KCO z8ot1c4s>2?@Pg=7DnnD=fd0@8T!*ygNpRLcYtoaXG{KD_DC&`Jn#z8H#a8cC*AVs; zTA{ESW9Tv-+nH^o9*Fbm+rk#p{|rBJQT9;a&uTq$g8I|E)x6X;ZG*%a%=4VDL)K0g zzjZ-Gl|scr;Y3!G7s{rmQcIS~EOzdbV|hcWTA0<3GUMv=nBnkj`L$nwqJ?1_Jqxxt zd$uiO5@<<0*s%8zCzP!^&XrD~16Pl+O?OMWe55A^NdcR_hP`&Fn@NS{p@k|O?vF4d zrQk<6E6&yvC{{4tZ>3$fWYx04LJnoFjy4rhWWbQNYDr5MIf2gZjs&>fymKVC$cx}N z^9MrOE>lCq@HpU>iT-gx>6RPIn_su{-4R(T2oFv_Do)Z8&W|-dy83`?9XfnpP{_a$ zO0Pz|Y3l~{T_Otco-*JG?wu_+dYrBQqf=}5I_jbo3_=mFZWLVSj>nKKQ2J0EfPvG10ctZO2*aBK=ib1MF~hC!G)xZ z1#O63VA`}wTkKfXF6`_+`J9-3&seBO^;q z*&U$L3Jb$!fw>uku_jQBkld=tQIAQLn?YzmgUmQ8s#Aw68j^pfKh|u&x;4~sB%J_f zNNUXScCG&%2Qg{Hry7}PlWqq2Yv$^EqDlnbd!3L9z+MUC&B28FpJ?j&TxJur24Z-- zdChvejulbnLkfB^nx*+s?~$K6gMOh`-10j3f!#BNksm4Wvm0B8R%?S3laky3tMRC| zAp!RKG#<7w1xHAJ3itaM1FnO#rAE(KKFbbU%nu=3EkWGETQb0cPQ<4YyGdP<_4^MTO zBjrpz%h?PVsaaF%T^-h1oK1l`s>>!y-PqwOQottSkpl8@nmmYng(|f6H&&^u;uH|_ zHuVJyRVgVyC3%pa!r4cs4KAEjxBDrajqzRANM3aIv*>J=4KAEr8v0o{+aX(SKJ@WM z_HkZx_Oo!dukgeFVqH?PZ34j;&VCloMrSXa{mj-NI(xAOpP94EpIsh?b_Ch+JpIr- z_q4ZM{Mq)Y7r*Y=q@?Lyz4$RZI~1>acAl&IJ5`d7mS{%-!(Od48N^c;c*_)%hqo%7 zE}a6>nU=di-Z#mtli**YOmw|rePM)q9_96nl>>-6RO32`yEiFJC%UlS^FyVfSCfJw zS97>sr^@-^AS`~9O07!9)zGu&3|v(-divlB*M#68v)?C+Sfss~6h-4N^IYlDCQ5@} z5YC3jM71%>_V|IyqoyXk8n2WE}T8poU^ULHE%nY8WZBk*M+m6fwQc>UO4-I zCF*reG`zMGu%EUM+Rr@qVrMlVEerYL%ss<9y_+px<5u?rZs)ld&i*vcZguv;*=Xoz zv9n8OFV^65a(3&_ZheEy3r;^S^W5+xl6b*G5?8mI8H1#+!FE!xp5+P6q0)dP+WEv$L9a%7(MI(%f**p!O;d(B;Ug zC+fJp8|i)ekz23TM&OzIWi>U(>P9+XUVm)m_>Z*M%QI``oGDZuZhoAzk7SCjU4mn+ z9$}(%R&K9!HYb!WoITZ?vnRnf>!=*oV8VbOwFaj(Uv&0FXZuyuJx}ni>sT(F9owHV z<0t9tg|p$~X`eiwvs|H|O{mh@i#7PHoL#=bWdvJcn$M!M@eM9s*JtKzpXHI))q7Ao z*ci9$^y4xK4o_k|o|pu)E1`D$)>^OphIyX(+2=aZ^WG4=-rW3N??D9g4tyrLffUhX z<2w^AL%BY!cF51>=j?{p4*A}Tymrke^Rz_U>r+W~F^7`u)DOX%{m>k{Yf32JH!}oc zQ@(dZC+BMF*@GF25I*m~X;x3Pw{wO_Dj(9`?1YZ|F6WpYdA3L0>&tTt&eNNmqH@i8C4l)fE!jYF}9^m6fJ8 z$a7;Gn*(&&l2LZxcV1svLTP%PsfycbFK8tct<`G?%W$Eh5{dvX1W+z_d5L6&Gx*bW z7g)khws{Mez1K>`AxP^lcjq>wJ3%JrnJW@U$C0?mlgoii2K8iG)b;e^qQK!vI5uM6 ztf}w0>$djAa4+BrOMP^&4N6c_(BUD+0;Rx+o&k-moX6Op@6qgzG=DYm#? zbmGiZXGLw5;}utG>VM?SV-tPmzcS{cdMu|>$-ZZm%K09h1EeG!vPkK+hiw?C5AB!Z zU$MxOR-SEo_d2R0wLi#ns7gQW0yz;6HDT9fqfIj;YQ5(b3G?$VL)CUv)2XD>hiOm! z>`T1ngtIJ12s>6>oDcQ2OT1=Ap7hD{tpRW6II_rnpEG`6IQtnm%lk27XYq3|xQ}LN z7i-YH{Lj!?5A4S)Ztb#Hcd-ViXI)z6``__H&D`BlD$Glh7*`MAUw!;1K1PfT+28z(yWrx5-v9qRjzbLq}V^U*v;JQM? zRLAqQ4$}}6sckk~>#=rh&h1logkW-0>H@ieg?WC3mu?lLaof0rMKAt!Z(cBWM$Le~ zD!ay_dfv4Nqg*{hNO4RR6zNgH+%3X^beB3eAwn2$zS?jskTWy9)-nZn)3o@z*JCLv z_fD?`saP(l+H>?}ZjA80Bra%y923Sa_Aqi!Hp9Fe7)I`SD9+XKuwl_lxoa!&1eySK z9c!~@fzZ3&##}J;vcz3f@<>wnyGO>hnt&ej_grIY39}PSZG3f$;Pn8p$1big*8U`5 zy_2hJE^fKJ#xW1BNhPj3ggN@Cc=Ul6rCk{$T1B|qkqy%`_plA;ED<~Z9RNYB74Fb` zwh7Ikutk{epE)c6(MEIZ@QR~Kkcils(YUh1tG?8>!A$|30vKf(QN7CEH^7SBa5k!5 zoG2gOYQ+USP~cm~;R3zGY&@`U%@lAq@RZ60jwc`mto!^|T3ryFwSWa5)=f5m5(A2N zV7z|#nxd-bk9z!bpZ0D>eQL=((J6=04stfpIY!Yl>&&N*JH<$RIF zD0f`NN;o$Neaa1q0*5SX81IXr2UZWX(o9qV;VAHQ7}R6f=vW?a*KX9qH%;oPq8rp> zR4MTTflED1?F~9JDQ()ifT#y*XTok+9I@ihv-MEGMXGHVt{0Sq#xcEPla&0xy-un3H{YNipS z9YLH}Ug!LK`%EZk*p@C&6wM<}a4R7;`mg1)Lqt&YxUt>RR(YAFEc{)!Yd|_EBi;fuzvBD6XP=KG#5iZ6wr6g7-TmL zr<0m7TtvNifE6`w=hkX1GbG5&g=?U5HDm+0v< zL2o%r=(XU9Ub$tAW+{LnsC69Bm2o0Bpa-QYKrcQ!ZS2w!)t9cI%=jYK8i5uLV1&*? zmlF}3dqvcI5~{cfq6`O!5OP34SIV6FZowQu8HEF#RhG(o3^(}M8 zANNh1jy2?CA1qWkit)G^FKv?L{5b`E&mB?DpUdT8u=Gy3e>Pm04d*)G=Z)3j$umg> zPt*5zqhQODKp61!`nVkj`hW`{t;HkIl9Pt{C{Ht6KxjhI zQY~YuH-v2*#V9mZa#(}+I4L)#6DVBp4c z;aIu?hcWT@RX{ExL_JKcK=WV?HS#o8e=EH%Jrc(yk2akhIy@$EY&O%p`A8uGiCE z@P1+`1r#v|xahbY(}{BQ9%~!iKOThHV<0 zVeW|dCT(Wx+zmVZVT_^l_K5T6v?y!QqR`9HFW*Q>dpb?;kxyu9={rLh9-)PfVjEPs z(Q-yJmn)ypD$4QV;TYgMZlpICt?X;05U{Ebz zTIjUpC{_tNPo4rc9^rx?IEql?)NqU#uB&?p_e`DbqYFM_k;dXhp*IdQe2(slk!Ct@ zRmUZ;fYao3)gzM7?{q2X-4wt`4Gaaql}n;Tq3OSxdo3?od}@2gJi#)PDC45>RegO= z0T~MBOQkOPCe}p(n20e!aV6jw9e<2l#r!Wbt#iCypwqpt@JK&$Bu!}ow2!fx;YOalhXgx%mPI4vz3 z8-h<>6bEnHrBFj?bn^^nl^53U~r$Fu;;d>dYBrb%$D8QiiTg zygG8wU=UFDD?PIB+~y1v9MUYZk2W%=}s)6lnCTKSH)s z87)(vL3f!MELg#pscelrn3DlxGAS49WhKQBR_}Q@fJd2bsKClZp4BqO{pn{J*Kfp- zCW~rkoP>1)I*zC4?+u3Cgy9ES^=TPeu2>>n75_@olP+xBWKUh%4>B8JZQIYg`SAdo;UXs#a!s?;WCI zEkYWsvT)Rycw3Nw)&$KTPCyD+vyGLOX~kGMUGkkGqzOgtm0}pKOp)~nr}RLfQ_Z-B z3w>@$lR~8HE{(*@TY=NuOjcCDVof?!O$4coP{EplXwoaYPZK=x?F}kSGJei*Q~(|xQ)z`wSZvQZNxe# zz%1}uBi|H&1+(5R@ZqdJX(4Q_3a!)%BE&W>c#nxNL5!1b+a3#2Qe_U21t_Z1I9Y$1 z0+=+)mD3Bw$b!M3#t2>$C9X1-JWSuLqoGzVfM^UePiy3Y3Gtw)Gb|_dHG_faUBeuY z1r1>eVzxd~?o+TrN12W}GQbvjEpv4n!pO~XWH1WF*o-llst9or#xPk)yF)*WrJkMI z)GXXmx|>xPyyxVnR3;(A*>t`g)1U#<*v(S!nyzf05=qKU%#eUzgt#f-0Zga2;w@KW zM-*Nv$^tUfx|=*15j=a}Q9WgSdw)~_Z8}%2h(CYt1VmoH+B3y-0O81zI9hovkmEbe zavsWNIBdxJ0)(&BP>d4`+;qVP9fT$w&PzjPFBl`@qW%D~f_tO^RKWdMX+U zIwiwmNxx8rlAxp0s7zNwN*Ai3^f9J8FAf2#c(PD(VGrcjI_CjF1I(z!XeRE;5> ziJ@zsQixVgN{>lLxL%w_9a?DcoOZf6PkzK4Hb9^zM;#xry8{=y!Q{=Bs3-E0RiwL58R9e9bCrhkSR*tsc?2qw zQcD^|GNC$WR`;!X)d7Z`<}fbZkW624RxG;HY06Ti5lS&6_pC}ouZIEhBMKu((#axy z)Uc6_jxaH8OhZTIThi(ZF=11-JaE@{=4#xIX~ltUGItubh+;Bt{DjVcly2_t@c2uU zar@~EQeg_x+j!!Zzy%d+4yZTU+Bs!@NTi7#)HlX#t1+gujg%l&6fA0lL16L`E@_M& zg3weLf-+QmS568wq|v45l7bus!a_`EgP5#IsDZYM(^T_ux-!QrrE_CCDajRK!JHpU z8qAXkaFDxFaS*K<}&D-GNiopU@jH3fH>>%efH60;QggWNct0 zZjixC;JrfS#Il)Yuv~oXbdp`CqCYfL0(E(?+39F*r^9v$s)3>r7~Y7~+Nlt%i-Xaf zjH(R5=|EMO6c880AUf9N!GA%F;h2Vjc7c)=o*AS^b~?1(rQx3rG_|_*>iSr)q`U2O znlP}_QS4Ng5?Gc*U$XpA-w81#PKF_ENVa4OBv8;G#5)}$Pea($K&DtmeyUAY41v>` z$%GQpGQtm2D}zSTxjbAOLwLlUj`Q?^Oq-lV>jVvRV=;P42j7|PbXKZ&R_jSIZ*d?j zMaomJ^$s>h$xw?@@5&t+G0=7`OOYAN16eQV;0+-)Jjy1AI78A63tAnSP@Q&*vpeLT ziU0lW-SvT^*y`wP8|KXFN1Zi9LsHxx>>Ii1#kv#WMi|}jD>kMIlMh>|7%Li~6EuP@ zG$OSyhAeRG&pvl@if(}o4?ymQ>TyX4!sY444U9Co=ZaV$5p-oFQrSGhA{Ygi_0z2L5G%@Y0 zga|qnOAj0HiFBqosc_%Sl1)~?+pdBjZ!;7nBF-_SnCo6y8Vo7Rbsm(P`n@&~o{LY}A@^`ye zyk<;8@Ef?A;1fCnLT9V|jSf(=M`Xuadju=65{1#J8l%8Q)N4tl6YF=4Fn1QB)9JD} zl@G==CLd2U=}kWnB?EEc`bthyQPv1h=iglclDbzqO~{5WnN(+$wP|9RSvQC=GK6m= zXwQR)Q!AaYQ`J=5>4=$hIz=s5Jr+aIIM*w~7;LYEWpIWVT%gX}-j-9!#8=fcsmLJ@ z)~Wx?MV!Zc1tgiOV8Aeh{b^|NMVu_+dSL4+ zQ2$Q1SV|`z$o#|cYeY88l}5Ihfv%GYQ>O~T^mFBNs zGVprigorc7=U$K=PjM=ALI$SN;rTlq;g>EAJ7EYO4CK;Eosv$;s6s)*qNCSMK;Zr( zMEYfQ&_oOnW$XwD@d{+A? zQ@U0fs1Xi#S@@=nc#vX(0y`O?C!J}Pjc&;N!VkhtoV*Iw6}1c0oZtj1Sw76FY2BnV zbsF#oa;=I93>1oG;Rm#YqZ<%nPHGZGDzp*B8-n>Bis410nhA7DvKWfOAnoL}V(9_p zNoNIQb#j;@m!L~Sl*x({+aMDWSE0Fc(^m_t++0K8=cFr~-wiq4!P?l(@`J z$=IC|d205Sbp%$HSjFY()C$NaH|!3|5FmPv1cno&kar^Gr6 zBR9Rvm=>2hH=QxLWr`Z5^hOcvP>ul-hWDzKOwz$MI5oLJhZ}T3=Qb~HG!{8?Sb^Rp zuU4k3M7%O*4MZhoI6@l1Ah^@a4B}?Rq@>aKWhrqQO*z794nk*B)ug1ULTMm+-HecO zIyd8*F*BlKCJO2o%MjAk9U*{C-8u+R4b*yJm#DGWe8k&z!mt}}w_11)>#U;?W9cia znGLw_wkT}dRbbJ&3Pml8I+Qjo-hys0c9e!XDOS==rY9MTj@2O7MdBV!Lu5>xlHtd> z!v=nJllOG`k8Kvx?`f!Jn#x|oL3X-4!zq2x*D z{-l8OKpQPuF^t013(Xh0Rq6b-0j|qL6v3=*Ym7hJzhIXoD`VG;5{#>?e}7s~ z7EfWvjtsple>mP>A1Ww|tI(jvKR}e9uZEDq!tR8zlp)DfIygc5g%X3*P*+8=y92+? zs0N`z!LFU36&+(3JY({9DqWR%aBkc_p|z*`)+s|eR8Bf3f|Hv;b11?;6iRzEyKO4* zaXKZ~8UswDU9I3nSRG%G96$R!+jAULC4(QziqF^4D6RQ806k?k1sYj<4Bt(T@Bg zOM0?7M~|!8F(7HBWZL!6ib_W~jaf!xv{JMDDRXjL4~Su??{yndT&H7FliV0yqtQ6p zqbYgwIIW~-S4w1otX!s|CZq$y4H4#0@Z^?#86GhvrY3g+X?f>2kHq(s3AXgZ`d)2c z`k^U()eo1f@6bN&l+#7+75z1xSgNHTZaZ9B+KHaIM7-E;5w^zKB}>)qf$#VSNjde< zLxWis3hT6ZQlOkRb4YW9rcp7WP8VWg4Yc>HQ)yXc%0p?J7)7EwYjkC)kKFnaf&7D! zwY8jMAyJ;xN`?@etXh2NDm3XSrm{b>Q*!BPEEC44(_w%|$V0H^SVM|}KUE&!sQ1(h zEGtF@vP8VM(X_ zGJ{beabR>>qfAvCQ-VsGme`@ymnDo*G!#}@>u5*Hlc!wet<2$+wZ6jY>2+4z0?if% zgkkgQUy6CPBsHj46%huhqG$M8PA3nOblN^LqsFod!z#HWorZlytOZv@mZ`A*xRI8v^MP-4G8x3=~Yo zr){*z4arEM6@sBUV0sam%i^#jdAgs57L_N5Xfa09!2%WZ?&f-s&{hH~3sxr*j|Rz% zDr+qWbXNBR-uX#RwiHYwREn#}xC&dW8ZcFUREeCgQkTLkOZ^%G(=C_XrJN`rqtlEK z?){8yjB-O|RRcs8K?+r`64U)@pv6?e8`^_<_}$e^rFaqUnG1I1EBH;Y_OH8uxtVXBn?k#?%+nVfd#gK8&B51&Dl{mrBEG(Ck`4*e}?R~~;$EIw0o8`mzwnt}vHAI8BRjuuJW0jb0-*|@4_Kj3xHy&Cl= zmT|WB26yZe)=6tWAYKyMsVzhYB5<1N>rWbDP|=Ns7{5CmPMIObDM7k+1g0BAx(&)8 z*8XM6!(kDKy&PJxepMdF>LwL@I&p z?6G6235N&^X_}Cr=_K%-G6%y#bvnvi)Z?x+TDx);@MX~!Rc(-=*Co=~yTpi@u|EQ& zK$FAiooWuII86j|)sXGR=t7T>gDLK6D02w+Du%Y`4~ZJ1oQ`gg+)TMmH~pzm7(|y6 zivN%%!oUiz(?a@_Qle6(yzbn#$moPvK$nTDF=gVRPnnpNMoDSi)s_QeDHCtYdJoeP zzNyDjE9Fi*XBkF=TBkSd#4qkL!K@q{tJ=1`IEP<{^-)UH2vg}25uY*5#`z=NR<#hS zQFk$pM&PDu-#HVgW)A%bbSd_zqrigM}rXw|ibv%FMv-AaD!CXg6oICA? z!;A0f`&e`|(=@q7$XshQ`qS6YxpWZI+q`6uNKd0zEjkI&DSORqY)Fw%Ns`{Z_>plA z%zc+K73tHTW*OG5#W^g;lo&}eRuq+56Qv&WT{_mwIdX4L*%y5HpR+(DJ;E(*NUnyG_GnUq|DEA9ly5T!@TEd|2 zYseB?TYrjM6z9lqsZ)>k-O_)#)&Qw09dxFzl`MzvT6C|T4(Ch}7Hl+O4X6xwp(r}1 zXp!r|wx~T7L9m1*t8OFX&T5YbKZf2|@p7ij&*g52j;0;V^?+5gD?(%p+aBx8@7Asw zq{oE`^-5`)up>=7bPS!_K9o^}R$9XFeQ_x$+#WiYd?~#M)i@k|-*ALH&39>vQ=+@V zkYD;mIwi^#)x`Rm>(J1x!3h^s{*aZ(y+^xHpxRm;wS=V}e9RkS^0DABS*2;9pz*_S zl%Y{r%Rm#NXOPn}kpASBj<}ZZ6{CUrO~Oryaq>_P)pA|ulQ@GOU0-@$pm~+BE zA>BSn9f^Mw=Zl7EYwiDs2@+&tYT{wHHIpu zNZhwsO5l#HneMKo7DD80^obQX@CRY(hr|jpg`H&z9XhILk3L+PHty+tz$RAHXo0FN&%axRIu%(K8ryvA`(mTAd1*b1Lvb|eQ9vitp{<=(2(YzJ!lfCb75SA!yB&vgS>WLEYi~QK-EhFf_PI*H@+TP0jn_)6i?62uZD;`0RY!Yn8`l;b zZmz};y>D1AiE5Vu>n_^$C6H2eqyJ-&0=Nj&%~@#)NBAiows$O;ixJy(;4TmXRVtTV zdW_mr02`%3*m~=O9SxHf(9H!rDlO0St#>Q5vt|_#F4UHyY6OJg8Ys5K$_FryDu@pP zXZHqMBL!-SWcfGj@kzPbLg)gtrK;1iUrQTFc-2Rnaa<~mG#eKP$8_Vl3rJe_G7&XY z>`t3j17CAPyf%lZTqfaN?)AEvoWPsK!?q$#(>tvsRdneUU5DYY3C@lnsfRxW{yH7G z=Q&Kp{3bWA^tb_ROLFeH7M}rOFmm%w)Z>&iiPutGd(vL7hgGx{rl~}N8HArrBNFj+^DJ+#IZFTDgjAS{qE8=Dc~Iw=pNBHqB-75p>6! zFYbups;=O6Q`smvE!{1(W<#ebV(*G2#hx=^9DYWnr|HsTK-q>JTNpcl? zRkJ7u0Ql7`w!RPo2($?lFK`nn)?ygt9q0&bAR3u(QTCWxmKgN(8gA$rrPGFBmBBV{ z=`=0ZgG_Ea&-|eBW)h%N!lkDMptFPXM?KZSjcZ)*qg}BGhk>W2XwNT==&bPZ4o#TV zmbxq+qb*c7OHGq$rJy>rCfTzOS4XreubNm8azjF$RbxPbi0Y=(u}#_#oM;FIboWwE z$6KSr_W z$?k;ogU679$i<#IxK^7EOOb|+HN+G%(BZBGg3=s1q3e|fRXRo|L+p`lsBfl{jIo*7 zObMr)(8o?#C~xLcgA7p>r=^YILqG=6WOX`>#bc=NZEdlzKUwAN=_HJVPN|+;mC&GJ zmaJl9XpquDjBG!D-fcTo+m?u3NV;f*iS&N`Ayb;~dc0r{H4+oh|HyKrWC$EqST0OH9S`%^F($ zD%!m|;MwavP*au`4+m0c2U7Z!&c7B4d4cNocCTg8S%t%(Hx~1ZiVqT7f7^(RYmLV8 zeC~zi(OL{RUh!nqaG>4649T5pW0ocA$?8Q<)EqayOY_EJMmCp5H=YK_6m`0_pb~OD zf-)Fj)~D9qBMm7!P0(OgMioO5w5Ks91lzxA&Eg$-aT%46Hkv2euhQjVP8`ldC}9+6 z4T_vp2ou1(WJ^O#4a(KL0y5uqY;d?>@!ZgDvYj2AQ{4r>3p=_>-!NM;1eD(%@uI zzB8|mXMm1K5cVDK4t~nDZ_#6o1w1tDyW_3gXjg-Ytzj&L)JqD@BpIhdq}mo2rmwMd zFSsU%ox?QR++{X4IisHRl)DCVdXau|Xeh_i5Fbwri46IMqhLt-S}2EA+z09$s8dpm zTSYpzmE3Wi7K#;($0y6&HDOuh;&9}KJXKF$@8ZUw+@S~?oF-1~Xhi2m(OqCp3M}S8 z5Ng;77YbG;nhGr@zIyH_#8aw8Ce8hk}I`v*`TStiH85GYn?p0Pw42Y+b z;<)cyybZ(XYF*f7NtwRcSd5T)&Ee2tzeczsLI%wup)p;0W|>xwx-_~;h=!g&UT9Ll zA4jB5Us_hY!Gk8 z>F5m&;cN>kAvr68bu#i|GCQGstImugVhH2ZnHi4_>3DsWrz0a(2i*c=*I*g}bUzRe z?sAF0)Z3&;uv05JIvtAcDqxQw0yAIT7{aV}svxH03%1U=F%GULGG~+rf-!O|yTH^zUTkaU?M?$v7qr#+$9?1MZh0W4WQ%iIyb&Y5 z*agvgjIXWm4rR8`%7PwvxCOh4-R2QW4k}h}zU5LrZSjnJQMAsk%g+57OmjqI$?zaj z;U72HChwVkk{-aE`PEfZpGf?1HiFAs~4mVk`SOPcOyD&R;FYG>`OS&wTza14M ztDGExyyrO|SP=ib9sjE|dA5~WHZ%@(u$&z4KsbelHThs7e#*GBqdf;gO(v2TcewK( zt#i1CTamczpPKJ=r?_r%Iiio8GnM|WX$sB*2Xnb7T&EH3ox!vlfeHp=0Glrg=m^w} z&NCU>K<3`cx|z_W4jjlh;~VfyO=V`CM)T0B?zWlpEB}ETjikBZr$Qlg&k5(~(9W}# zhDC=R2aM4{0s@j`Ju8)YR_DOx;dCb#Exbk(suK$@mNE zq7V2XGvhXHcm%(S8?-!V^`4U37R5hyc2Aa%y79?SWF}Y7;6}Ri-%c0`HI$f~=*#c> zh02nHr}p(GK^YE6>CPxqoJ!T8?Es8cNSp1FPP_TpZl~TimXOumc#pfj z{7{7l2D%AD$WEf(BONA-8cbMm@X4&KW-*v};DBs*K9)T_UB^UZ+x09f)%62)*W zBHN7DA*QTBHEWdbmHOA@rNj4+%qaUK?u`w~#`BS*WDX@2Wu3Z6^wmub&VumM+)Z|d zr{avB0ZK{+vRa)`cw&K+DOo6PVvxQX&(#f~uUeHu0)3T9rLw5IrMxGU{(SF^fm}*e z-kFHg4z*^CNI&M@3p{p!%KOab&cpXyx?95uEh_M0yf&80`hU1JP6`B zDKx~SfFPUtf~A0bg_l)YqW8Y^h`Uv5!59gA%j&6w zDU*74w8jChg$Y*d-B+3BRUS>zw4uW$0nPRaJOtIt)u>%gU+vb#BMVd?@#Ls{)*`Vi zA=@v?f}`~*0##denFQ7#Do{;V*pS7Hdkl-spswg+lTk4Q$C6l>%)-5f_gYzJmqZu` zugt=Qp=KGg7K$5BnO)LCVU0GFW2xIFjwn$c~f87jVQD;hA4SpJ38g;h)-Y;h343(QU z6VapoGyvW6)^I%{#~X~gbmq&QeZP3~!*Abzc=zV@_xgJKn}2=rf~dijKCW1_$M4(c z2gY0f@Hc;R_44OGfBUDae_jJ?7|rXAqod5s=kvc)9)B;te)InAAK!iZ=KU3g{Oo5& zzxm^DKK$Ds-dw%>ySMMYH}+rN{P4RE|8j-Rz53eFuiw4>;~$jq<$tTx_3!?zO7AMZ z;pca+e|Z0g*YDo^@a?}n_&qgt0sr(5zxmfU-+mwoKbQ|MfBEKrfA{U1uYdjXt6zNc zV)L(W-@o`@SY~T*+B-}4niM_$Es4rH{^+mLk0jkNjh8{6WF`}Yg(u@CBKQ=xDR(LT z6Y>|sTmD4xBYdv>+6do#D^dItYk-o`lIE}e^x@ave0crgP5u6>UH$KyzkmJye{N)_ ze?Ab+lHkLym%qM}=2-_G{&w=Omk9rFfB%PndHwOCM-@)W5MTvMOMa}lpZ%1M($zH;<-@SkF64w6m?Ti2V;t46Kz?RbCn5uF1HdX)a4?n#9@c!zb zr|Y%K|Ksc5z3JAx{QEb*{qFTo?Z#4!>7T!N`@@GfKTxN5FyKF`8-BPVDqhfrQ-Zn; z>eB!DyWc|WmD=$2)zJKlw|^w>&IGR(ya(Bo#PZFys808b*B@U0{_XFaSM7fP6cvAZ z_vU}R(9G*a_fP$oz}C(F<_g?@sz85NbX5L!_k_YBUw;eYdFMyaZqNAoFx8GH{2oKP zruR`QUN1a>cxC2Ms{7qzBJe_1#t-jafA{-0?_P+#|LK=7_b=bS{r=5gUH#>Ezx}Ib v@yoB@zJzW?z0-G}1N?w*%&_Amb8FMjn8fA@a?+5q>G diff --git a/DuckDuckGo/DaxOnboardingViewController.swift b/DuckDuckGo/DaxOnboardingViewController.swift deleted file mode 100644 index 9fda073b4e..0000000000 --- a/DuckDuckGo/DaxOnboardingViewController.swift +++ /dev/null @@ -1,206 +0,0 @@ -// -// DaxOnboardingViewController.swift -// DuckDuckGo -// -// Copyright © 2020 DuckDuckGo. All rights reserved. -// -// 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. -// - -import UIKit - -class DaxOnboardingViewController: UIViewController, Onboarding { - - struct Constants { - - static let animationDelay = 1.4 - static let animationDuration = 0.4 - - } - - weak var delegate: OnboardingDelegate? - weak var daxDialog: DaxDialogViewController? - - @IBOutlet weak var welcomeMessage: UILabel! - @IBOutlet weak var daxDialogContainer: UIView! - @IBOutlet weak var daxDialogContainerHeight: NSLayoutConstraint! - @IBOutlet weak var daxIcon: UIView! - @IBOutlet weak var onboardingIcon: UIView! - @IBOutlet weak var transitionalIcon: UIView! - @IBOutlet weak var button: UIButton! - @IBOutlet weak var backgroundView: UIView! - - override var supportedInterfaceOrientations: UIInterfaceOrientationMask { - return isPad ? super.supportedInterfaceOrientations : [ .portrait ] - } - - override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { - return isPad ? super.preferredInterfaceOrientationForPresentation : .portrait - } - - override var shouldAutorotate: Bool { - return true - } - - private let pixelReporting: OnboardingIntroImpressionReporting - - init?(coder: NSCoder, pixelReporting: OnboardingIntroImpressionReporting) { - self.pixelReporting = pixelReporting - super.init(coder: coder) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - welcomeMessage.setAttributedTextString(UserText.launchscreenWelcomeMessage) - daxDialog?.message = UserText.daxDialogOnboardingMessage - daxDialog?.reset() - daxDialogContainerHeight.constant = daxDialog?.calculateHeight() ?? 0 - button.displayDropShadow() - daxIcon.isHidden = true - - pixelReporting.trackOnboardingIntroImpression() - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - guard !view.isHidden else { return } - - daxDialogContainerHeight.constant = daxDialog?.calculateHeight() ?? 0 - self.daxDialog?.reset() - - DispatchQueue.main.asyncAfter(deadline: .now() + Constants.animationDelay) { - self.transitionFromOnboarding() - } - } - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - super.prepare(for: segue, sender: nil) - - if let daxDialog = segue.destination as? DaxDialogViewController { - self.daxDialog = daxDialog - view.addGestureRecognizer(daxDialog.tapToCompleteGestureRecognizer) - } else if let controller = segue.destination as? DaxOnboardingPadViewController { - controller.delegate = self - } else if let navController = segue.destination as? UINavigationController, - let controller = navController.viewControllers.first as? OnboardingViewController { - controller.delegate = self - } - - } - - func transitionFromOnboarding() { - - // using snapshots means the original views don't get messed up by their constraints when subsequent animations kick off - let transitionIconSS: UIView = self.transitionalIcon.snapshotView(afterScreenUpdates: true) ?? self.transitionalIcon - transitionIconSS.frame = self.transitionalIcon.frame - view.addSubview(transitionIconSS) - self.transitionalIcon.isHidden = true - - let onboardingIconSS: UIView = self.onboardingIcon.snapshotView(afterScreenUpdates: true) ?? self.onboardingIcon - onboardingIconSS.frame = self.onboardingIcon.frame - view.addSubview(onboardingIconSS) - self.onboardingIcon.isHidden = true - - UIView.animate(withDuration: 0.3, animations: { - - // the dax dialog icon is not exactly centered with or the same size as this icon so we need to account for this in the animation - onboardingIconSS.frame = CGRect(x: 0, y: 0, width: 76, height: 76) - onboardingIconSS.center = CGPoint(x: self.daxIcon.center.x, y: self.daxIcon.center.y - 2) - onboardingIconSS.alpha = 0.0 - - transitionIconSS.frame = self.daxIcon.frame - transitionIconSS.alpha = 1.0 - - self.backgroundView.alpha = 0.0 - }, completion: { _ in - self.daxIcon.isHidden = false - onboardingIconSS.isHidden = true - transitionIconSS.isHidden = true - - DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { - onboardingIconSS.removeFromSuperview() - transitionIconSS.removeFromSuperview() - self.transitionToDaxDialog() - } - - }) - - } - - func transitionToDaxDialog() { - - let snapshot: UIView = self.daxIcon.snapshotView(afterScreenUpdates: true) ?? self.daxIcon - snapshot.frame = self.daxIcon.frame - view.addSubview(snapshot) - self.daxIcon.isHidden = true - - UIView.animate(withDuration: Constants.animationDuration, animations: { - self.welcomeMessage.alpha = 0.0 - - if let frame = self.daxDialog?.icon.frame, - let localFrame = self.daxDialog?.icon.superview!.convert(frame, to: self.view) { - self.daxIcon.frame = localFrame - snapshot.frame = localFrame - } - - }, completion: { _ in - - // fade out while it's being shown again below, otherwise there's an abrupt change when the double dropshadow disappears - UIView.animate(withDuration: 1.0, animations: { - snapshot.alpha = 0.0 - }, completion: { _ in - snapshot.removeFromSuperview() - }) - - self.showDaxDialog { - self.daxDialog?.start() - } - }) - - } - - @IBAction func onTapButton() { - let segue = isPad ? "AddToHomeRow-iPad" : "AddToHomeRow" - performSegue(withIdentifier: segue, sender: self) - } - - func showDaxDialog(completion: @escaping () -> Void) { - daxDialogContainer.alpha = 0.0 - daxDialogContainer.isHidden = false - - button.alpha = 0.0 - button.isHidden = false - - UIView.animate(withDuration: Constants.animationDuration, animations: { - self.daxDialogContainer.alpha = 1.0 - self.button.alpha = 1.0 - }, completion: { _ in - completion() - }) - } - -} - -extension DaxOnboardingViewController: OnboardingDelegate { - func onboardingCompleted(controller: UIViewController) { - self.view.isHidden = true - controller.dismiss(animated: true) - self.delegate?.onboardingCompleted(controller: self) - } -} diff --git a/DuckDuckGo/MainViewController+Segues.swift b/DuckDuckGo/MainViewController+Segues.swift index bca512800e..8d91186009 100644 --- a/DuckDuckGo/MainViewController+Segues.swift +++ b/DuckDuckGo/MainViewController+Segues.swift @@ -33,19 +33,8 @@ extension MainViewController { Logger.lifecycle.debug(#function) hideAllHighlightsIfNeeded() - var controller: (Onboarding & UIViewController)? - - if DefaultVariantManager().isNewIntroFlow { - controller = OnboardingIntroViewController(onboardingPixelReporter: contextualOnboardingPixelReporter) - } else { - let storyboard = UIStoryboard(name: "DaxOnboarding", bundle: nil) - controller = storyboard.instantiateInitialViewController(creator: { coder in - DaxOnboardingViewController(coder: coder, pixelReporting: self.contextualOnboardingPixelReporter) - }) - } - - controller?.delegate = self - guard let controller else { return assertionFailure() } + let controller = OnboardingIntroViewController(onboardingPixelReporter: contextualOnboardingPixelReporter) + controller.delegate = self controller.modalPresentationStyle = .overFullScreen present(controller, animated: false) } diff --git a/DuckDuckGo/OnboardingExperiment/DefaultVariantManager+Onboarding.swift b/DuckDuckGo/OnboardingExperiment/DefaultVariantManager+Onboarding.swift index fa3701270a..528ff47fc8 100644 --- a/DuckDuckGo/OnboardingExperiment/DefaultVariantManager+Onboarding.swift +++ b/DuckDuckGo/OnboardingExperiment/DefaultVariantManager+Onboarding.swift @@ -22,10 +22,6 @@ import BrowserServicesKit extension VariantManager { - var isNewIntroFlow: Bool { - isSupported(feature: .newOnboardingIntro) || isSupported(feature: .newOnboardingIntroHighlights) - } - var isOnboardingHighlightsExperiment: Bool { isSupported(feature: .newOnboardingIntroHighlights) } diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index c526e40a7d..c0d006206f 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -221,7 +221,6 @@ public struct UserText { public static let favorite = NSLocalizedString("favorite", value: "Favorite", comment: "") - public static let launchscreenWelcomeMessage = NSLocalizedString("launchscreenWelcomeMessage", value: "Welcome to\nDuckDuckGo!", comment: "Please preserve newline character") public static let onboardingWelcomeHeader = NSLocalizedString("onboardingWelcomeHeader", value: "Welcome to DuckDuckGo!", comment: "") public static let onboardingContinue = NSLocalizedString("onboardingContinue", value: "Continue", comment: "") public static let onboardingSkip = NSLocalizedString("onboardingSkip", value: "Skip", comment: "") @@ -274,9 +273,6 @@ public struct UserText { public static let daxDialogFireButtonEducationConfirmAction = NSLocalizedString("dax.onboarding.fire.button.confirmAction", value: "Close Tabs and Clear Data", comment: "Encourage user to try clearing data with the fire button") public static let daxDialogFireButtonEducationCancelAction = NSLocalizedString("dax.onboarding.fire.button.cancelAction", value: "Cancel", comment: "Cancel action") - - public static let daxDialogOnboardingMessage = NSLocalizedString("dax.onboarding.message", value: "The Internet can be kinda creepy.\n\nNot to worry! Searching and browsing privately is easier than you think.", comment: "") - public static let daxDialogHideTitle = NSLocalizedString("dax.hide.title", value: "Hide remaining tips?", comment: "Title in Hide Dax dialog") public static let daxDialogHideMessage = NSLocalizedString("dax.hide.message", value: "There are only a few, and we tried to make them informative.", comment: "Subtitle in Hide Dax dialog") public static let daxDialogHideButton = NSLocalizedString("dax.hide.button", value: "Hide Tips Forever", comment: "") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 4ab56d6e1f..214e4328a4 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -962,9 +962,6 @@ /* ad = advertisment */ "dax.onboarding.home.subsequent" = "You’ve got this!\n\nRemember: Every time you browse with me, a creepy ad loses its wings. 👍"; -/* No comment provided by engineer. */ -"dax.onboarding.message" = "The Internet can be kinda creepy.\n\nNot to worry! Searching and browsing privately is easier than you think."; - /* Default string used if users device is not iPhone or iPad */ "device.type.default" = "device"; @@ -1565,9 +1562,6 @@ /* No comment provided by engineer. */ "keyCommandShowAllTabs" = "Show All Tabs"; -/* Please preserve newline character */ -"launchscreenWelcomeMessage" = "Welcome to\nDuckDuckGo!"; - /* Summary text for the macOS browser waitlist */ "mac-browser.waitlist.summary" = "DuckDuckGo for Mac has the speed you need, the browsing features you expect, and comes packed with our best-in-class privacy essentials."; diff --git a/DuckDuckGoTests/DefaultVariantManagerOnboardingTests.swift b/DuckDuckGoTests/DefaultVariantManagerOnboardingTests.swift index 23d5d06c5f..f9641c8fd1 100644 --- a/DuckDuckGoTests/DefaultVariantManagerOnboardingTests.swift +++ b/DuckDuckGoTests/DefaultVariantManagerOnboardingTests.swift @@ -24,41 +24,6 @@ import BrowserServicesKit final class DefaultVariantManagerOnboardingTests: XCTestCase { - // MARK: - Is New Intro Flow - - func testWhenIsNewIntroFlow_AndFeatureIsNewOnboardingIntro_ThenReturnTrue() { - // GIVEN - let sut = makeVariantManager(features: [.newOnboardingIntro]) - - // WHEN - let result = sut.isNewIntroFlow - - // THEN - XCTAssertTrue(result) - } - - func testWhenIsNewIntroFlow_AndFeaturesContainNewOnboardingIntroHighlights_ThenReturnTrue() { - // GIVEN - let sut = makeVariantManager(features: [.newOnboardingIntroHighlights]) - - // WHEN - let result = sut.isNewIntroFlow - - // THEN - XCTAssertTrue(result) - } - - func testWhenIsNewIntroFlow_AndFeaturesDoNotContainNewOnboardingIntroOrNewOnboardingIntroHighlights_ThenReturnFalse() { - // GIVEN - let sut = makeVariantManager(features: [.contextualDaxDialogs]) - - // WHEN - let result = sut.isNewIntroFlow - - // THEN - XCTAssertFalse(result) - } - // MARK: - Is Onboarding Highlights func testWhenIsOnboardingHighlights_AndFeaturesContainOnboardingHighlights_ThenReturnTrue() { From b020e7f9e67b02e55f4effd18283216c6a2b401d Mon Sep 17 00:00:00 2001 From: Alessandro Boron Date: Tue, 12 Nov 2024 15:03:23 +0100 Subject: [PATCH 09/56] Release 7.145.0-1 (#3567) --- DuckDuckGo.xcodeproj/project.pbxproj | 56 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 8b53f5f54e..520246d0be 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9191,7 +9191,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -9228,7 +9228,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9318,7 +9318,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9345,7 +9345,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9494,7 +9494,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9519,7 +9519,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9588,7 +9588,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -9622,7 +9622,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9655,7 +9655,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9685,7 +9685,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9995,7 +9995,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10026,7 +10026,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10054,7 +10054,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10087,7 +10087,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -10117,7 +10117,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -10150,11 +10150,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 0; + DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10387,7 +10387,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10414,7 +10414,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10446,7 +10446,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10483,7 +10483,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10518,7 +10518,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10553,11 +10553,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 0; + DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10730,11 +10730,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 0; + DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10763,10 +10763,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 0; + DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; From 67449e122815bd12282d72e6f7cf375e899593e9 Mon Sep 17 00:00:00 2001 From: Alessandro Boron Date: Tue, 12 Nov 2024 15:57:40 +0100 Subject: [PATCH 10/56] Import Add To Dock Translations (#3566) Task/Issue URL: https://app.asana.com/0/414235014887631/1208739475947574/f **Description**: Import Add To Dock translations --- DuckDuckGo/bg.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/cs.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/da.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/de.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/el.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/es.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/et.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/fi.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/fr.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/hr.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/hu.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/it.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/lt.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/lv.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/nb.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/nl.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/pl.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/pt.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/ro.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/ru.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/sk.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/sl.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/sv.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ DuckDuckGo/tr.lproj/Localizable.strings | 27 +++++++++++++++++++++++++ 24 files changed, 648 insertions(+) diff --git a/DuckDuckGo/bg.lproj/Localizable.strings b/DuckDuckGo/bg.lproj/Localizable.strings index df72ca960f..bab8e189f9 100644 --- a/DuckDuckGo/bg.lproj/Localizable.strings +++ b/DuckDuckGo/bg.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Да"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Пропускане"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Стартиране на сърфирането"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Покажи ми как"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Не забравяйте: всеки път когато сърфирате с мен, аз ще подрязвам крилцата на досадните реклами.\n\nЗатова ме дръжте в своя панел за ежедневното си сърфиране."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Ще се сгуша на удобно място да ви чакам, за да сърфирате с мен всеки ден."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Добавете ме към панела си!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Намерете иконата DuckDuckGo на своя начален екран. След това натиснете и я плъзнете на място. Това е всичко!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Лесно е да ме добавите към своя панел."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Изскачащият прозорец е скрит"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Разбрах"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Изберете своя браузър"; diff --git a/DuckDuckGo/cs.lproj/Localizable.strings b/DuckDuckGo/cs.lproj/Localizable.strings index 86a9a53eb4..a446d620d2 100644 --- a/DuckDuckGo/cs.lproj/Localizable.strings +++ b/DuckDuckGo/cs.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Ano"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Přeskočit"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Spustit procházení"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Ukaž mi jak"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Pamatuj: Když se mnou na webu surfuješ, příšerné reklamy zaženeš.\n\nDej si mě do Docku, ať mě můžeš denně používat."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Až budeš chtít brouzdat po internetu, budu na dosah křídla."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Přidej si mě do Docku!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Najdi ikonu DuckDuckGo na ploše. Pak ji podrž a přetáhni na místo. A je to!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Přidat si mě do Docku je hračka."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Skryté vyskakovací okno"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Mám to"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Vyber si prohlížeč"; diff --git a/DuckDuckGo/da.lproj/Localizable.strings b/DuckDuckGo/da.lproj/Localizable.strings index 3e89b7a158..115988f39b 100644 --- a/DuckDuckGo/da.lproj/Localizable.strings +++ b/DuckDuckGo/da.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Ja"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Spring over"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Start søgning"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Vis mig hvordan"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Husk: Hver gang du browser med mig, mister en uhyggelig annonce sine vinger.\n\nSå gem mig i din Dock til daglig browsing."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Jeg ligger lige ved hånden til al din daglige browsing."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Føj mig til din Dock!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Find DuckDuckGo-ikonet på din startskærm. Tryk og træk den derefter på plads. Det er det!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Det er nemt at tilføje mig til din Dock."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Pop op-vindue skjult"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Forstået"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Vælg din browser"; diff --git a/DuckDuckGo/de.lproj/Localizable.strings b/DuckDuckGo/de.lproj/Localizable.strings index 5f893a3166..6ca64593f9 100644 --- a/DuckDuckGo/de.lproj/Localizable.strings +++ b/DuckDuckGo/de.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Ja"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Überspringen"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Mit dem Browsen beginnen"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Anleitung"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Hinweis: Jedes Mal, wenn du mit mir browst, verliert eine aufdringliche Werbung ihren Schrecken.\n\nBehalte mich also zum täglichen Browsen in deinem Dock."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Ich niste in leicht erreichbarer Nähe für dein tägliches Browsen."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Füge mich zu deinem Dock hinzu!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Suche auf deinem Startbildschirm das DuckDuckGo-Symbol. Klicke es an und ziehe es dann an die richtige Stelle. Das war es schon!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Es ist ganz einfach, mich zu deinem Dock hinzuzufügen."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Pop-up ausgeblendet"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Verstanden"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Wähle deinen Browser"; diff --git a/DuckDuckGo/el.lproj/Localizable.strings b/DuckDuckGo/el.lproj/Localizable.strings index 5df4692edf..2fef03526b 100644 --- a/DuckDuckGo/el.lproj/Localizable.strings +++ b/DuckDuckGo/el.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Ναί"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Παράλειψη"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Έναρξη περιήγησης"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Δείξε μου πώς"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Να θυμάστε: κάθε φορά που περιηγείστε μαζί μου, μια ανατριχιαστική διαφήμιση χάνει τη δύναμή της!\n\nΓι' αυτό, διατηρήστε με στο Dock σας για καθημερινή περιήγηση."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Θα απολαμβάνω έτσι εύκολη πρόσβαση για όλη την καθημερινή περιήγησή σας."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Προσθέστε με στο Dock σας!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Βρείτε το εικονίδιο DuckDuckGo στην Αρχική οθόνη σας. Στη συνέχεια, πατήστε και μεταφέρετέ το στη θέση του. Αυτό είναι!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Η προσθήκη μου στο Dock σας είναι εύκολη."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Κρυφό αναδυόμενο παράθυρο"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Το κατάλαβα"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Επιλέξτε το πρόγραμμα περιήγησής σας"; diff --git a/DuckDuckGo/es.lproj/Localizable.strings b/DuckDuckGo/es.lproj/Localizable.strings index b7dff0c463..adc8c04a8a 100644 --- a/DuckDuckGo/es.lproj/Localizable.strings +++ b/DuckDuckGo/es.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Sí"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Omitir"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Empezar a navegar"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Muéstrame cómo"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Recuerda: cada vez que navegas conmigo corto las alas a un anuncio escalofriante.\n\nAsí que mantenme en tu Dock para la navegación diaria."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Estaré al alcance de la mano para toda tu navegación diaria."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "¡Añádeme a tu Dock!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Busca el icono de DuckDuckGo en tu pantalla de inicio. A continuación, selecciónalo y arrástralo a su ubicación. ¡Eso es todo!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Añadirme a tu Dock es fácil."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Ventana emergente oculta"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Entendido"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Elige tu navegador"; diff --git a/DuckDuckGo/et.lproj/Localizable.strings b/DuckDuckGo/et.lproj/Localizable.strings index b1376a0ab7..9d94f5047e 100644 --- a/DuckDuckGo/et.lproj/Localizable.strings +++ b/DuckDuckGo/et.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Jah"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Jäta vahele"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Alusta sirvimist"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Näita mulle, kuidas"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Pea meeles, iga kord, kui minuga sirvid, kaotab salakaval reklaam oma tiivad.\n\nNii et hoia mind igapäevaselt sirvides oma Dockis."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Olen hõlpsasti ligipääsetav kogu teie igapäevase sirvimise vältel."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Lisa mind oma Docki!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Leia oma avakuvalt DuckDuckGo ikoon. Seejärel vajuta ja lohista see oma kohale. See on kõik!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Minu lisamine teie Docki on lihtne."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Hüpikaken on peidetud"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Sain aru"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Vali oma brauser"; diff --git a/DuckDuckGo/fi.lproj/Localizable.strings b/DuckDuckGo/fi.lproj/Localizable.strings index c745173f5a..9c85d1a744 100644 --- a/DuckDuckGo/fi.lproj/Localizable.strings +++ b/DuckDuckGo/fi.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Kyllä"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Ohita"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Aloita selailu"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Näytä minulle miten"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Muista, että joka kerta kun käytät minua selaamiseen, rasittavat mainokset katoavat.\n\nJoten pidä minut Docissa helppoa selausta varten."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Olen helposti käden ulottuvilla päivittäistä selaamista varten."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Lisää minut telakkaasi!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Etsi DuckDuckGo-kuvake aloitusnäytöltäsi. Paina ja vedä se sitten paikalleen. Siinä kaikki!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Voit lisätä minut telakkaasi helposti."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Ponnahdusikkuna piilotettu"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Selvä"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Valitse selaimesi"; diff --git a/DuckDuckGo/fr.lproj/Localizable.strings b/DuckDuckGo/fr.lproj/Localizable.strings index 970ec2d762..f35339e3c8 100644 --- a/DuckDuckGo/fr.lproj/Localizable.strings +++ b/DuckDuckGo/fr.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Oui"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Ignorer"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Commencer la navigation"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Me montrer comment faire"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Pensez-y : chaque fois que vous naviguez avec moi, une publicité douteuse disparaît.\n\nAlors gardez-moi dans votre Dock pour naviguer au quotidien."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Je serai à portée de main pour toutes vos navigations quotidiennes."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Ajoutez-moi à votre Dock !"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Trouvez l'icône DuckDuckGo sur votre écran d'accueil. Appuyez ensuite dessus pour la faire glisser au bon endroit. Voilà !"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Facile de m'ajouter à votre Dock !"; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Fenêtre contextuelle masquée"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "J'ai compris"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Choisissez votre navigateur"; diff --git a/DuckDuckGo/hr.lproj/Localizable.strings b/DuckDuckGo/hr.lproj/Localizable.strings index 1e91cfa4d0..5bb618e15f 100644 --- a/DuckDuckGo/hr.lproj/Localizable.strings +++ b/DuckDuckGo/hr.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Da"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Preskoči"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Započni pretraživanje"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Pokaži mi kako"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Zapamti: svaki put kad pregledavaš sa mnom, grozna reklama gubi krila.\n\nZato me zadrži u svom Docku za svakodnevno pregledavanje."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Bit ću ti na dohvat ruke za svo tvoje svakodnevno pregledavanje."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Dodaj me na svoj Dock!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Pronađi ikonu DuckDuckGo na početnom zaslonu. Zatim je pritisni i povuci na mjesto. I to je sve!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Dodavanje mene na tvoj Dock je jednostavno."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Skočni prozor je sakriven"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Shvatio/la sam"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Odaberi preglednik"; diff --git a/DuckDuckGo/hu.lproj/Localizable.strings b/DuckDuckGo/hu.lproj/Localizable.strings index 6e011c1d33..dbfb665421 100644 --- a/DuckDuckGo/hu.lproj/Localizable.strings +++ b/DuckDuckGo/hu.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Igen"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Kihagyás"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Böngészés indítása"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Mutasd meg, hogyan"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Ne feledd, minden alkalommal, amikor velem böngészel, egy undok hirdetés elveszíti az erejét.\n\nTehát tarts a Dockban a napi böngészéshez."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Könnyen elérhetsz a napi böngészés során."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Adj hozzá a Dockhoz!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Keresd meg a DuckDuckGo ikont a kezdőképernyőn. Ezután az ikont nyomva tartva húzd a helyére. Ennyi az egész!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Egyszerűen hozzáadhatsz a Dockhoz."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Felugró ablak elrejtve"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Megvan"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Böngésző kiválasztása"; diff --git a/DuckDuckGo/it.lproj/Localizable.strings b/DuckDuckGo/it.lproj/Localizable.strings index aa975129cd..d9712c048d 100644 --- a/DuckDuckGo/it.lproj/Localizable.strings +++ b/DuckDuckGo/it.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Sì"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Salta"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Inizia a navigare"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Dammi indicazioni"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Ricorda: quando navighi con me gli annunci inquietanti non possono seguirti.\n\nQuindi tienimi nel tuo dock per la navigazione quotidiana."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Sarò a portata di mano per tutta la tua navigazione quotidiana."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Aggiungimi al tuo dock!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Trova l'icona di DuckDuckGo sulla tua schermata Home. Quindi premi e trascinala nella posizione desiderata. Ecco fatto!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Aggiungermi al tuo dock è facile."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Popup nascosto"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Fatto"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Scegli il tuo browser"; diff --git a/DuckDuckGo/lt.lproj/Localizable.strings b/DuckDuckGo/lt.lproj/Localizable.strings index aefc629f07..117b42027f 100644 --- a/DuckDuckGo/lt.lproj/Localizable.strings +++ b/DuckDuckGo/lt.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Taip"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Praleisti"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Pradėti naršyti"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Parodyti, kaip"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Įsidėmėkite: kiekvieną kartą, kai naršote su manimi, bauginantis skelbimas praranda galią.\n\nTaigi laikykite mane savo juostoje, kad galėtumėte kasdien naršyti."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Mane lengvai pasieksite savo kasdienei naršymo veiklai."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Įtraukite mane į savo juostą!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Pagrindiniame ekrane raskite „DuckDuckGo“ piktogramą. Tada paspauskite ir vilkite ją į vietą. Štai ir viskas!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Įtraukti mane į savo juostą paprasta."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Iškylantysis langas paslėptas"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Supratau"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Pasirinkite naršyklę"; diff --git a/DuckDuckGo/lv.lproj/Localizable.strings b/DuckDuckGo/lv.lproj/Localizable.strings index 53a83ff1b3..0760667d91 100644 --- a/DuckDuckGo/lv.lproj/Localizable.strings +++ b/DuckDuckGo/lv.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Jā"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Izlaist"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Sākt pārlūkošanu"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Parādiet, kā"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Atceries: kad pārlūko Internetu ar mani, uzmācīgās reklāmas zaudē savu spēku.\n\nTāpēc turi mani dokā ikdienas pārlūkošanai."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Es būšu viegli sasniedzamā vietā tavai ikdienas pārlūkošanai."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Pievieno mani dokam!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Atrodi DuckDuckGo ikonu sākuma ekrānā. Pēc tam piespied un ievelc vietā. Tik vienkārši!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Viegli pievieno mani dokam."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Uznirstošais logs paslēpts"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Sapratu"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Izvēlies pārlūku"; diff --git a/DuckDuckGo/nb.lproj/Localizable.strings b/DuckDuckGo/nb.lproj/Localizable.strings index 5c75a162e9..eb37f0908e 100644 --- a/DuckDuckGo/nb.lproj/Localizable.strings +++ b/DuckDuckGo/nb.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Ja"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Hopp over"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Begynn å surfe"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Vis meg hvordan"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Husk at hver gang du surfer med meg, klippes vingene på en slesk annonse.\n\nSå ha meg i docken din for daglig surfing."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Jeg ligger rede til å nettsurfe med deg hver dag."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Legg meg til i docken din!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Finn DuckDuckGo-ikonet på startskjermen. Trykk på det og dra det dit du vil ha det. Det er det hele!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Det er enkelt å legge meg til i docken din."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Popup-vindu skjult"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Den er grei"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Velg nettleseren din"; diff --git a/DuckDuckGo/nl.lproj/Localizable.strings b/DuckDuckGo/nl.lproj/Localizable.strings index 49b2ffc582..ac787a200c 100644 --- a/DuckDuckGo/nl.lproj/Localizable.strings +++ b/DuckDuckGo/nl.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Ja"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Overslaan"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Beginnen met browsen"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Tonen"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Vergeet niet: elke keer als je met mij browset, verliest een enge advertentie haar kracht.\n\nHoud me dus in je Dock voor dagelijks gebruik."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Ik heb alles wat je nodig hebt om dagelijks te browsen."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Voeg me toe aan je dock!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Zoek het DuckDuckGo-pictogram op je startscherm. Houd het ingedrukt en sleep het naar zijn plaats. Dat is alles!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Voeg me eenvoudig toe aan je Dock."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Pop-up verborgen"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Ik snap het"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Kies je browser"; diff --git a/DuckDuckGo/pl.lproj/Localizable.strings b/DuckDuckGo/pl.lproj/Localizable.strings index a82a482b04..7a65fbf6bf 100644 --- a/DuckDuckGo/pl.lproj/Localizable.strings +++ b/DuckDuckGo/pl.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Tak"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Pomiń"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Rozpocznij przeglądanie"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Pokaż, jak to zrobić"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Pamiętaj: za każdym razem, gdy przeglądasz ze mną Internet, jakaś wstrętna reklama przestaje działać.\n\nDlatego dodaj mnie do Docka na potrzeby codziennego przeglądania."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Będę w zasięgu ręki podczas codziennego przeglądania."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Dodaj mnie do Docka!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Znajdź ikonę DuckDuckGo na ekranie głównym. Następnie naciśnij i przeciągnij ją w odpowiednie miejsce. To wszystko!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Dodanie mnie do Docka jest łatwe."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Ukryte wyskakujące okienka"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Rozumiem"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Wybierz przeglądarkę"; diff --git a/DuckDuckGo/pt.lproj/Localizable.strings b/DuckDuckGo/pt.lproj/Localizable.strings index fbef6e16e2..f8b8487247 100644 --- a/DuckDuckGo/pt.lproj/Localizable.strings +++ b/DuckDuckGo/pt.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Sim"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Ignorar"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Iniciar a navegação"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Mostrar-me como"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Lembra-te: sempre que navegas comigo, um anúncio assustador perde as suas asas.\n\nPor isso, mantém-me na tua Dock para navegares diariamente."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Vou estar num lugar de fácil acesso para toda a tua navegação diária."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Adiciona-me à tua Dock!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Encontra o ícone do DuckDuckGo no ecrã inicial. Em seguida, prime e arrasta-o para o lugar certo. É só isto!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Adicionar-me à tua Dock é fácil."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Pop-up ocultado"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Entendi"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Escolhe o teu navegador"; diff --git a/DuckDuckGo/ro.lproj/Localizable.strings b/DuckDuckGo/ro.lproj/Localizable.strings index a0d15fec4e..95b88cf50a 100644 --- a/DuckDuckGo/ro.lproj/Localizable.strings +++ b/DuckDuckGo/ro.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Da"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Ignorare"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Începe navigarea"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Arată-mi cum"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Reține, de fiecare dată când navighezi cu mine, o reclamă sinistră își pierde aripile.\n\nAșa că ține-mă în rândul de jos de pictograme pentru a naviga zilnic."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Îmi voi face cuibul la îndemână, pentru toată navigarea ta zilnică."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Adaugă-mă în rândul tău de jos de pictograme!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Găsește pictograma DuckDuckGo pe ecranul de pornire. Apoi apas-o și trage-o în poziție. Gata!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Este simplu să mă adaugi în rândul de jos de pictograme."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Pop-up ascuns"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Am înțeles"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Alege browserul"; diff --git a/DuckDuckGo/ru.lproj/Localizable.strings b/DuckDuckGo/ru.lproj/Localizable.strings index 35e1e8e6da..33cb21334a 100644 --- a/DuckDuckGo/ru.lproj/Localizable.strings +++ b/DuckDuckGo/ru.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Да"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Пропустить"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Начать просмотр"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Показать, как"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Напоминаю: просматривая сайты с моей помощью, вы обезвреживаете коварную рекламу.\n\nПоэтому закрепите мой значок в док-панели."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Я устроюсь в удобном месте на каждый день."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Добавьте меня на док-панель!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Найдите значок DuckDuckGo на главном экране. Нажмите и перетащите его на панель. Все готово!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Добавить меня на док-панель очень просто."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Всплывающее окно скрыто"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Понятно"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Выбрать браузер"; diff --git a/DuckDuckGo/sk.lproj/Localizable.strings b/DuckDuckGo/sk.lproj/Localizable.strings index e3ef7a8a83..e695d5169d 100644 --- a/DuckDuckGo/sk.lproj/Localizable.strings +++ b/DuckDuckGo/sk.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Áno"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Preskočiť"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Začnite prehliadať"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Ukážte mi ako"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Pamätajte: zakaždým, keď prehliadate s nami, nepríjemnej reklame pristrihávate krídla.\n\nNechajte ma teda vo svojom Docku na každodenné prehliadanie."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Budem hniezdiť v ľahkom dosahu pre všetko vaše každodenné prehliadanie."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Pridajte ma do svojho Docku!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Nájdite ikonu DuckDuckGo na svojej domovskej obrazovke. Potom stlačte a potiahnite na miesto. To je všetko!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Pridanie ma do doku je jednoduché."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Kontextové okno je skryté"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Rozumiem"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Vyberte si prehliadač"; diff --git a/DuckDuckGo/sl.lproj/Localizable.strings b/DuckDuckGo/sl.lproj/Localizable.strings index 08fd2dde74..7e79dd1cbd 100644 --- a/DuckDuckGo/sl.lproj/Localizable.strings +++ b/DuckDuckGo/sl.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Da"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Preskoči"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Začni brskanje"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Pokaži mi, kako"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Ne pozabite: Vedno kadar brskate z mano, grozljivemu oglasu pristrižete krila.\n\nZato me imejte na domačem zaslonu za vsakodnevno brskanje."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Ugnezdil se bom na dosegu roke za vsakodnevno brskanje."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Dodajte me na svoj domači zaslon!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Poiščite ikono DuckDuckGo na domačem zaslonu. Nato jo pritisnite in povlecite na svoje mesto. To je to!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Na svoj domači zaslon me lahko dodate povsem preprosto"; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Pojavno okno je skrito"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Razumem"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Izberite brskalnik"; diff --git a/DuckDuckGo/sv.lproj/Localizable.strings b/DuckDuckGo/sv.lproj/Localizable.strings index 8b073384b5..4e82a701be 100644 --- a/DuckDuckGo/sv.lproj/Localizable.strings +++ b/DuckDuckGo/sv.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Ja"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Hoppa över"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Börja bläddra"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Visa mig hur"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Kom ihåg att varje gång du surfar med mig förlorar en påträngande annons sina vingar.\n\nSå spara mig i din Dock för ditt dagliga surfande."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Jag kommer att hålla mig nära för allt ditt dagliga surfande."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Lägg till mig i din Dock!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Leta upp DuckDuckGo-ikonen på hemskärmen. Tryck och dra den därefter på plats. Sen är det klart!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Det är enkelt att lägga till mig i din Dock."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Popup-fönster dolt"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Jag fattar"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Välj din webbläsare"; diff --git a/DuckDuckGo/tr.lproj/Localizable.strings b/DuckDuckGo/tr.lproj/Localizable.strings index abaf73d410..52e1dc4c0c 100644 --- a/DuckDuckGo/tr.lproj/Localizable.strings +++ b/DuckDuckGo/tr.lproj/Localizable.strings @@ -770,6 +770,30 @@ /* Button to answer question 'Did turning off protections resolve the issue on this site?' */ "broken.site.report.toggle.alert.yes.button" = "Evet"; +/* Button to continue the onboarding process */ +"contextual.onboarding.addToDock.buttons.skip" = "Atla"; + +/* Button on the last screen of the onboarding, it will dismiss the onboarding screen. */ +"contextual.onboarding.addToDock.buttons.startBrowsing" = "Gezinmeye Başla"; + +/* Button of the onboarding dialog. On click it shows a dialog with a tutorial video about how to add the DDG browser icon to the device dock. */ +"contextual.onboarding.addToDock.buttons.tutorial" = "Nasıl Yapılacağını Göster"; + +/* Message of the last screen of the onboarding that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.contextual.message" = "Unutmayın: Benimle her gezinti yaptığınızda rahatsız edici bir reklam kanatlarını kaybeder.\n\nO yüzden günlük gezintileriniz için beni Dock'unuzda tutun."; + +/* The message of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.intro.message" = "Tüm günlük gezinmeleriniz için kolay erişilebilir bir yere yuvalanacağım."; + +/* The title of the onboarding dialog popup that promotes adding the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.promo.title" = "Beni Dock'a ekleyin!"; + +/* The message of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.message" = "Ana Ekranınızda DuckDuckGo simgesini bulun. Daha sonra simgeye basıp sürükleyerek yerine sabitleyin. Hepsi bu kadar!"; + +/* The title of the onboarding dialog popup that explains how to add the DDG browser icon to the dock. */ +"contextual.onboarding.addToDock.tutorial.title" = "Beni Dock'unuza eklemek çok kolay."; + /* First parameter is a count of additional trackers, second and third are names of the tracker networks (strings) */ "contextual.onboarding.browsing.multiple.trackers" = "contextual.onboarding.browsing.multiple.trackers"; @@ -1784,6 +1808,9 @@ /* Text displayed on notification appearing in the address bar when the browser hides a cookie popup */ "omnibar.notification.popup-hidden" = "Açılır Pencere Gizli"; +/* Button on the Add to Dock tutorial screen of the onboarding, it will proceed to the next step of the onboarding. */ +"onboarding.addToDock.buttons.gotIt" = "Anladım"; + /* Button to change the default browser */ "onboarding.browsers.cta" = "Tarayıcınızı Seçin"; From d62e0c49f4e2b36e97e80d49a7fa3cc840a22dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Tue, 12 Nov 2024 18:06:37 +0100 Subject: [PATCH 11/56] Fix favorites grid layout issues on New Tab Page (#3568) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1206226850447395/1208709136086082/f Tech Design URL: CC: **Description**: Addresses feedback around updated favorites grid layout on New Tab Page. * Uses static column setup with 4 columns on iPhone and 5 on iPad when NTP customization is turned off. * Reduces the width of grid and makes it centered. * A special case handled for smaller screens so the static layout does not exceed margins. **Steps to test this PR**: For best baseline run 7.142.1 or earlier. 1. Add at least 5 favorites 2. Verify number of columns shown and their count does not change when rotated to landscape: a. 4 on iPhone b. 5 on iPad (unless in compact-sized Split View) **Definition of Done (Internal Only)**: * [x] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Orientation Testing**: * [x] Portrait * [x] Landscape **Device Testing**: * [x] iPhone SE (1st Gen) * [ ] iPhone 8 * [ ] iPhone X * [x] iPhone 16 Pro * [x] iPad **OS Testing**: * [x] iOS 15 * [ ] iOS 16 * [x] iOS 18 **Theme Testing**: * [x] Light theme * [x] Dark theme --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- DuckDuckGo/EditableShortcutsView.swift | 2 +- DuckDuckGo/FavoritesView.swift | 6 ++- DuckDuckGo/FavoritesViewModel.swift | 3 +- DuckDuckGo/NewTabPageGridView.swift | 56 +++++++++++++++++++++----- DuckDuckGo/ShortcutsView.swift | 2 +- DuckDuckGo/SimpleNewTabPageView.swift | 13 ++++-- 6 files changed, 63 insertions(+), 19 deletions(-) diff --git a/DuckDuckGo/EditableShortcutsView.swift b/DuckDuckGo/EditableShortcutsView.swift index 08ac409016..df40c9cbc8 100644 --- a/DuckDuckGo/EditableShortcutsView.swift +++ b/DuckDuckGo/EditableShortcutsView.swift @@ -28,7 +28,7 @@ struct EditableShortcutsView: View { private let haptics = UIImpactFeedbackGenerator() var body: some View { - NewTabPageGridView(geometry: geometry) { _ in + NewTabPageGridView(geometry: geometry, isUsingDynamicSpacing: true) { _ in ReorderableForEach(model.itemsSettings, id: \.item.id, isReorderingEnabled: true) { setting in let isEnabled = model.enabledItems.contains(setting.item) Button { diff --git a/DuckDuckGo/FavoritesView.swift b/DuckDuckGo/FavoritesView.swift index bb65db7939..a8a7620052 100644 --- a/DuckDuckGo/FavoritesView.swift +++ b/DuckDuckGo/FavoritesView.swift @@ -36,10 +36,12 @@ struct FavoritesView: View { var body: some View { VStack(alignment: .center, spacing: 24) { - let columns = NewTabPageGrid.columnsCount(for: horizontalSizeClass, isLandscape: isLandscape) + let columns = NewTabPageGrid.columnsCount(for: horizontalSizeClass, + isLandscape: isLandscape, + isDynamic: model.isNewTabPageCustomizationEnabled) let result = model.prefixedFavorites(for: columns) - NewTabPageGridView(geometry: geometry) { _ in + NewTabPageGridView(geometry: geometry, isUsingDynamicSpacing: model.isNewTabPageCustomizationEnabled) { _ in ReorderableForEach(result.items) { item in viewFor(item) .previewShape() diff --git a/DuckDuckGo/FavoritesViewModel.swift b/DuckDuckGo/FavoritesViewModel.swift index babd8e20c2..fac9571bd4 100644 --- a/DuckDuckGo/FavoritesViewModel.swift +++ b/DuckDuckGo/FavoritesViewModel.swift @@ -54,7 +54,8 @@ class FavoritesViewModel: ObservableObject { private let favoriteDataSource: NewTabPageFavoriteDataSource private let pixelFiring: PixelFiring.Type private let dailyPixelFiring: DailyPixelFiring.Type - private let isNewTabPageCustomizationEnabled: Bool + + let isNewTabPageCustomizationEnabled: Bool var isEmpty: Bool { allFavorites.filter(\.isFavorite).isEmpty diff --git a/DuckDuckGo/NewTabPageGridView.swift b/DuckDuckGo/NewTabPageGridView.swift index f2b75d76b5..ffcffc0e17 100644 --- a/DuckDuckGo/NewTabPageGridView.swift +++ b/DuckDuckGo/NewTabPageGridView.swift @@ -24,14 +24,15 @@ struct NewTabPageGridView: View { @Environment(\.isLandscapeOrientation) var isLandscape let geometry: GeometryProxy? + let isUsingDynamicSpacing: Bool @ViewBuilder var content: (_ columnsCount: Int) -> Content @State private var width: CGFloat = .zero var body: some View { - let columnsCount = NewTabPageGrid.columnsCount(for: horizontalSizeClass, isLandscape: isLandscape) + let columnsCount = NewTabPageGrid.columnsCount(for: horizontalSizeClass, isLandscape: isLandscape, isDynamic: isUsingDynamicSpacing) - LazyVGrid(columns: flexibleColumns(columnsCount, width: width), spacing: 24, content: { + LazyVGrid(columns: createColumns(columnsCount), spacing: 24, content: { content(columnsCount) }) .frame(maxWidth: .infinity) @@ -41,12 +42,14 @@ struct NewTabPageGridView: View { return geometry[anchor].width }) .onPreferenceChange(FramePreferenceKey.self, perform: { value in - width = value + if isUsingDynamicSpacing { + width = value + } }) .padding(0) } - private func flexibleColumns(_ count: Int, width: CGFloat) -> [GridItem] { + private func flexibleColumns(_ count: Int) -> [GridItem] { let spacing: CGFloat? if width != .zero { let columnsWidth = NewTabPageGrid.Item.edgeSize * Double(count) @@ -62,6 +65,17 @@ struct NewTabPageGridView: View { alignment: .top), count: count) } + + private func staticColumns(_ count: Int) -> [GridItem] { + return Array(repeating: GridItem(.fixed(NewTabPageGrid.Item.edgeSize), + spacing: NewTabPageGrid.Item.staticSpacing, + alignment: .top), + count: count) + } + + private func createColumns(_ count: Int) -> [GridItem] { + isUsingDynamicSpacing ? flexibleColumns(count) : staticColumns(count) + } } private struct FramePreferenceKey: PreferenceKey { @@ -72,17 +86,39 @@ private struct FramePreferenceKey: PreferenceKey { } enum NewTabPageGrid { - enum ColumnCount { - static let compact = 4 - static let regular = 6 + static func columnsCount(for sizeClass: UserInterfaceSizeClass?, isLandscape: Bool, isDynamic: Bool) -> Int { + if isDynamic { + let usesWideLayout = isLandscape || sizeClass == .regular + return usesWideLayout ? ColumnCount.regular : ColumnCount.compact + } else { + return staticGridColumnsCount(for: sizeClass) + } + } + + static func staticGridWidth(for sizeClass: UserInterfaceSizeClass?) -> CGFloat { + let columnsCount = CGFloat(staticGridColumnsCount(for: sizeClass)) + return columnsCount * Item.edgeSize + (columnsCount - 1) * Item.staticSpacing + } + + private static func staticGridColumnsCount(for sizeClass: UserInterfaceSizeClass?) -> Int { + let isPad = UIDevice.current.userInterfaceIdiom == .pad + + return isPad && sizeClass == .regular ? ColumnCount.staticWideLayout : ColumnCount.compact } enum Item { static let edgeSize = 64.0 } +} - static func columnsCount(for sizeClass: UserInterfaceSizeClass?, isLandscape: Bool) -> Int { - let usesWideLayout = isLandscape || sizeClass == .regular - return usesWideLayout ? ColumnCount.regular : ColumnCount.compact +private extension NewTabPageGrid { + enum ColumnCount { + static let compact = 4 + static let regular = 6 + static let staticWideLayout = 5 } } + +private extension NewTabPageGrid.Item { + static let staticSpacing = 32.0 +} diff --git a/DuckDuckGo/ShortcutsView.swift b/DuckDuckGo/ShortcutsView.swift index 230d2a5393..0b83fc7b22 100644 --- a/DuckDuckGo/ShortcutsView.swift +++ b/DuckDuckGo/ShortcutsView.swift @@ -26,7 +26,7 @@ struct ShortcutsView: View { let proxy: GeometryProxy? var body: some View { - NewTabPageGridView(geometry: proxy) { _ in + NewTabPageGridView(geometry: proxy, isUsingDynamicSpacing: true) { _ in ForEach(shortcuts) { shortcut in Button { model.openShortcut(shortcut) diff --git a/DuckDuckGo/SimpleNewTabPageView.swift b/DuckDuckGo/SimpleNewTabPageView.swift index cf31697226..d674e59e32 100644 --- a/DuckDuckGo/SimpleNewTabPageView.swift +++ b/DuckDuckGo/SimpleNewTabPageView.swift @@ -81,7 +81,7 @@ private extension SimpleNewTabPageView { favoritesSectionView(proxy: proxy) } - .padding(Metrics.largePadding) + .padding(sectionsViewPadding(in: proxy)) } .withScrollKeyboardDismiss() } @@ -99,7 +99,7 @@ private extension SimpleNewTabPageView { } .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top) } - .padding(Metrics.largePadding) + .padding(Metrics.regularPadding) } private var messagesSectionView: some View { @@ -115,6 +115,11 @@ private extension SimpleNewTabPageView { isAddingFavorite: .constant(false), geometry: proxy) } + + private func sectionsViewPadding(in geometry: GeometryProxy) -> CGFloat { + let requiredWidth = NewTabPageGrid.staticGridWidth(for: horizontalSizeClass) + Metrics.regularPadding + return geometry.frame(in: .local).width >= requiredWidth ? Metrics.regularPadding : Metrics.smallPadding + } } private extension View { @@ -130,8 +135,8 @@ private extension View { private struct Metrics { - static let regularPadding = 16.0 - static let largePadding = 24.0 + static let smallPadding = 12.0 + static let regularPadding = 24.0 static let sectionSpacing = 32.0 static let nonGridSectionTopPadding = -8.0 From 45cda431ea3de8946fb3cee64c3da0ec3f0f63cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Tue, 12 Nov 2024 19:03:27 +0100 Subject: [PATCH 12/56] Release 7.145.0-2 (#3570) Please make sure all GH checks passed before merging. It can take around 20 minutes. Briefly review this PR to see if there are no issues or red flags and then merge it. --- DuckDuckGo.xcodeproj/project.pbxproj | 56 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 520246d0be..6f8db18707 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9191,7 +9191,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -9228,7 +9228,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9318,7 +9318,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9345,7 +9345,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9494,7 +9494,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9519,7 +9519,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9588,7 +9588,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -9622,7 +9622,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9655,7 +9655,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9685,7 +9685,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9995,7 +9995,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10026,7 +10026,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10054,7 +10054,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10087,7 +10087,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -10117,7 +10117,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -10150,11 +10150,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10387,7 +10387,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10414,7 +10414,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10446,7 +10446,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10483,7 +10483,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10518,7 +10518,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10553,11 +10553,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10730,11 +10730,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10763,10 +10763,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; From 665770e7757592014cf5c72a2f3992c4676c9502 Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Wed, 13 Nov 2024 19:44:20 +0100 Subject: [PATCH 13/56] Update pr.yml Bumping timeout to 60m to allow job to run tests. --- .github/workflows/pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 2248bd73f8..d50d143b61 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -40,7 +40,7 @@ jobs: name: Unit Tests runs-on: macos-14-xlarge - timeout-minutes: 20 + timeout-minutes: 60 outputs: commit_author: ${{ steps.fetch_commit_author.outputs.commit_author }} From b645554e5a52d2b945fafb7d209eb8cc7888b50d Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Wed, 13 Nov 2024 19:47:13 +0100 Subject: [PATCH 14/56] Update pr.yml --- .github/workflows/pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d50d143b61..2248bd73f8 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -40,7 +40,7 @@ jobs: name: Unit Tests runs-on: macos-14-xlarge - timeout-minutes: 60 + timeout-minutes: 20 outputs: commit_author: ${{ steps.fetch_commit_author.outputs.commit_author }} From 1d14059835ad58450289f9da5d4d3648484785fd Mon Sep 17 00:00:00 2001 From: Daniel Bernal Date: Wed, 13 Nov 2024 19:52:33 +0100 Subject: [PATCH 15/56] [DuckPlayer] Overlay Usage Pixels (#3565) Task/Issue URL: https://app.asana.com/0/1204099484721401/1208739766555300/f Description: Unifies navigation tracking and pixel firing in a single method Adds temporary Overlay usage pixels --- .../DuckPlayerNavigationHandler.swift | 32 ++- .../DuckPlayerOverlayUsagePixels.swift | 116 ++++---- .../DuckPlayerOverlayUsagePixelsTests.swift | 247 ++++++------------ 3 files changed, 148 insertions(+), 247 deletions(-) diff --git a/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift b/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift index f64a61f558..609b1d3af8 100644 --- a/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift +++ b/DuckDuckGo/DuckPlayer/DuckPlayerNavigationHandler.swift @@ -117,7 +117,7 @@ final class DuckPlayerNavigationHandler: NSObject { pixelFiring: PixelFiring.Type = Pixel.self, dailyPixelFiring: DailyPixelFiring.Type = DailyPixel.self, tabNavigationHandler: DuckPlayerTabNavigationHandling? = nil, - duckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring? = nil) { + duckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring? = DuckPlayerOverlayUsagePixels()) { self.duckPlayer = duckPlayer self.featureFlagger = featureFlagger self.appSettings = appSettings @@ -575,8 +575,6 @@ final class DuckPlayerNavigationHandler: NSObject { // Watch in YT videos always open in new tab redirectToYouTubeVideo(url: url, webView: webView, forceNewTab: true) } - - } } @@ -638,7 +636,9 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling { // Before performing the simulated request DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { self.performRequest(request: newRequest, webView: webView) + self.duckPlayerOverlayUsagePixels?.handleNavigationAndFirePixels(url: url, duckPlayerMode: self.duckPlayerMode) self.fireDuckPlayerPixels(webView: webView) + } } else { redirectToYouTubeVideo(url: url, webView: webView) @@ -663,9 +663,6 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling { @MainActor func handleURLChange(webView: WKWebView) -> DuckPlayerNavigationHandlerURLChangeResult { - // Track overlayUsagePixels - duckPlayerOverlayUsagePixels?.registerNavigation(url: webView.url) - // We want to prevent multiple simultaneous redirects // This can be caused by Duplicate Nav events, and quick URL changes if let lastTimestamp = lastURLChangeHandling, @@ -683,6 +680,12 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling { return .notHandled(.duplicateNavigation) } + // Overlay Usage Pixel handling + if let url = webView.url { + duckPlayerOverlayUsagePixels?.handleNavigationAndFirePixels(url: url, duckPlayerMode: duckPlayerMode) + lastURLChangeHandling = Date() + } + // Check if DuckPlayer feature is enabled guard isDuckPlayerFeatureEnabled else { return .notHandled(.featureOff) @@ -735,7 +738,7 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling { @MainActor func handleGoBack(webView: WKWebView) { - guard isDuckPlayerFeatureEnabled else { + guard let url = webView.url, url.isDuckPlayer, isDuckPlayerFeatureEnabled else { webView.goBack() return } @@ -783,7 +786,7 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling { guard let url = webView.url else { return } - + if url.isDuckPlayer, duckPlayerMode != .disabled { redirectToDuckPlayerVideo(url: url, webView: webView, disableNewTab: true) return @@ -833,6 +836,17 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling { // Reset allowFirstVideo duckPlayer.settings.allowFirstVideo = false + // Overlay Usage Pixel handling for Direct Navigation + if let url = webView.url, !url.isYoutube { + duckPlayerOverlayUsagePixels?.handleNavigationAndFirePixels(url: url, duckPlayerMode: duckPlayerMode) + } + // Reset Overlay Last Fired pixel after the page is loaded + // A delay is required as Youtube sometimes performs an extra redirect on load + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + self.duckPlayerOverlayUsagePixels?.lastFiredPixel = nil + } + + } /// Resets settings when the web view starts loading a new page. @@ -890,7 +904,7 @@ extension DuckPlayerNavigationHandler: DuckPlayerNavigationHandling { guard isDuckPlayerFeatureEnabled else { return false } - + // Only account for in 'Always' mode if duckPlayerMode == .disabled { return false diff --git a/DuckDuckGo/DuckPlayer/DuckPlayerOverlayUsagePixels.swift b/DuckDuckGo/DuckPlayer/DuckPlayerOverlayUsagePixels.swift index 459b762f40..6f3339dd72 100644 --- a/DuckDuckGo/DuckPlayer/DuckPlayerOverlayUsagePixels.swift +++ b/DuckDuckGo/DuckPlayer/DuckPlayerOverlayUsagePixels.swift @@ -23,21 +23,16 @@ protocol DuckPlayerOverlayPixelFiring { var pixelFiring: PixelFiring.Type { get set } var navigationHistory: [URL] { get set } + var lastFiredPixel: Pixel.Event? { get set } - func registerNavigation(url: URL?) - func navigationBack(duckPlayerMode: DuckPlayerMode) - func navigationReload(duckPlayerMode: DuckPlayerMode) - func navigationWithinYoutube(duckPlayerMode: DuckPlayerMode) - func navigationOutsideYoutube(duckPlayerMode: DuckPlayerMode) - func navigationClosed(duckPlayerMode: DuckPlayerMode) - func overlayIdle(duckPlayerMode: DuckPlayerMode) - + func handleNavigationAndFirePixels(url: URL?, duckPlayerMode: DuckPlayerMode) } final class DuckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring { var pixelFiring: PixelFiring.Type var navigationHistory: [URL] = [] + var lastFiredPixel: Pixel.Event? private var idleTimer: Timer? private var idleTimeInterval: TimeInterval @@ -49,75 +44,64 @@ final class DuckPlayerOverlayUsagePixels: DuckPlayerOverlayPixelFiring { self.idleTimeInterval = timeoutInterval } - // Method to reset the idle timer - private func resetIdleTimer() { - idleTimer?.invalidate() - idleTimer = nil - } - - func registerNavigation(url: URL?) { + func handleNavigationAndFirePixels(url: URL?, duckPlayerMode: DuckPlayerMode) { guard let url = url else { return } - navigationHistory.append(url) - - // Cancel and reset the idle timer whenever a new navigation occurs - resetIdleTimer() - } - - func navigationBack(duckPlayerMode: DuckPlayerMode) { - guard duckPlayerMode == .alwaysAsk, - let lastURL = navigationHistory.last, - lastURL.isYoutubeWatch else { return } - - pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationBack, withAdditionalParameters: [:]) - } - - func navigationReload(duckPlayerMode: DuckPlayerMode) { - guard duckPlayerMode == .alwaysAsk, - let lastURL = navigationHistory.last, - lastURL.isYoutubeWatch else { return } + let comparisonURL = url.forComparison() - pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationRefresh, withAdditionalParameters: [:]) - } + // Only append the URL if it's different from the last entry in normalized form + navigationHistory.append(comparisonURL) - func navigationWithinYoutube(duckPlayerMode: DuckPlayerMode) { + // DuckPlayer is in Ask Mode, there's navigation history, and last URL is a YouTube Watch Video guard duckPlayerMode == .alwaysAsk, navigationHistory.count > 1, let currentURL = navigationHistory.last, let previousURL = navigationHistory.dropLast().last, - previousURL.isYoutubeWatch, - currentURL.isYoutube else { return } - - pixelFiring.fire(.duckPlayerYouTubeNavigationWithinYouTube, withAdditionalParameters: [:]) - } + previousURL.isYoutubeWatch else { return } + + var isReload = false + // Check for a reload condition: when current videoID is the same as Previous + if let currentVideoID = currentURL.youtubeVideoParams?.videoID, + let previousVideoID = previousURL.youtubeVideoParams?.videoID, + !previousURL.isDuckPlayer, !currentURL.isDuckPlayer { + isReload = currentVideoID == previousVideoID + } - func navigationOutsideYoutube(duckPlayerMode: DuckPlayerMode) { - guard duckPlayerMode == .alwaysAsk, - navigationHistory.count > 1, - let currentURL = navigationHistory.last, - let previousURL = navigationHistory.dropLast().last, - previousURL.isYoutubeWatch, - !currentURL.isYoutube else { return } + // Fire the reload pixel if this is a reload navigation + if isReload { + firePixel(.duckPlayerYouTubeOverlayNavigationRefresh) + } else { + // Determine if it’s a back navigation by looking further back in history + let isBackNavigation = navigationHistory.count > 2 && + navigationHistory[navigationHistory.count - 3].forComparison() == currentURL.forComparison() + + // Fire the appropriate pixel based on navigation type + if isBackNavigation { + firePixel(.duckPlayerYouTubeOverlayNavigationBack) + } else if previousURL.isYoutubeWatch && currentURL.isYoutube { + // Forward navigation within YouTube (including non-video URLs) + firePixel(.duckPlayerYouTubeNavigationWithinYouTube) + } else if previousURL.isYoutubeWatch && !currentURL.isYoutube && !currentURL.isDuckPlayer { + // Navigation outside YouTube + firePixel(.duckPlayerYouTubeOverlayNavigationOutsideYoutube) + navigationHistory.removeAll() + } + } - pixelFiring.fire(.duckPlayerYouTubeOverlayNavigationOutsideYoutube, withAdditionalParameters: [:]) + // Truncation logic: Remove all URLs up to the last occurrence of the current URL in normalized form + if navigationHistory.count > 0 { + if let lastOccurrenceIndex = (0.. Date: Wed, 13 Nov 2024 21:43:02 +0100 Subject: [PATCH 16/56] Add possibility to stop page loading (#3553) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1206226850447395/1206267785501484/f Tech Design URL: CC: **Description**: Adds an additional OmniBar state variation when the website is loading, allowing to stop the loading process. **Steps to test this PR**: 💡 It's helpful to test on a physical device (with link conditioner enabled to slow down loading) or using [link conditioner](https://nshipster.com/network-link-conditioner/) for simulator. 1. Start loading a website on 2 or more tabs. 2. Switch between them and observe if state is shown properly. (swiping on address bar is helpful to do it quickly). 3. Stop loading. 4. Verify omni bar state is valid (refresh is visible) and: a. if no valid resources were loaded error page should be presented b. if some resources were loaded and can be displayed, partially loaded website should be visible c. pixel is sent. **Definition of Done (Internal Only)**: * [x] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Orientation Testing**: * [x] Portrait * [x] Landscape **Device Testing**: * [ ] iPhone SE (1st Gen) * [ ] iPhone 8 * [ ] iPhone X * [x] iPhone 15 Pro * [x] iPad **OS Testing**: * [x] iOS 15 * [ ] iOS 16 * [x] iOS 18 **Theme Testing**: * [x] Light theme * [x] Dark theme --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- Core/PixelEvent.swift | 9 +- DuckDuckGo.xcodeproj/project.pbxproj | 4 + DuckDuckGo/Base.lproj/OmniBar.xib | 25 ++- DuckDuckGo/BlankSnapshotViewController.swift | 6 +- DuckDuckGo/LargeOmniBarState.swift | 102 +++++---- DuckDuckGo/MainViewController.swift | 21 +- DuckDuckGo/OmniBar.swift | 28 ++- DuckDuckGo/OmniBarDelegate.swift | 2 + DuckDuckGo/OmniBarState.swift | 44 +++- DuckDuckGo/SmallOmniBarState.swift | 113 ++++++---- DuckDuckGo/TabViewController.swift | 37 ++- DuckDuckGo/UniversalOmniBarState.swift | 30 ++- DuckDuckGoTests/LargeOmniBarStateTests.swift | 212 ++++++++++-------- .../OmniBarLoadingStateBearerTests.swift | 81 +++++++ DuckDuckGoTests/QuerySubmittedTests.swift | 3 + DuckDuckGoTests/SmallOmniBarStateTests.swift | 204 +++++++++-------- 16 files changed, 614 insertions(+), 307 deletions(-) create mode 100644 DuckDuckGoTests/OmniBarLoadingStateBearerTests.swift diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 2ddc0806ca..4fd41cf2f7 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -852,6 +852,9 @@ extension Pixel { case protectedDataUnavailableWhenBecomeActive case statisticsLoaderATBStateMismatch case adAttributionReportStateMismatch + + // MARK: Browsing + case stopPageLoad // MARK: - DuckPlayer Overlay Navigation case duckPlayerYouTubeOverlayNavigationBack @@ -1702,6 +1705,9 @@ extension Pixel.Event { case .protectedDataUnavailableWhenBecomeActive: return "m_protected_data_unavailable_when_become_active" case .statisticsLoaderATBStateMismatch: return "m_statistics_loader_atb_state_mismatch" case .adAttributionReportStateMismatch: return "m_ad_attribution_report_state_mismatch" + + // MARK: Browsing + case .stopPageLoad: return "m_stop-page-load" // MARK: - DuckPlayer Overlay Navigation case .duckPlayerYouTubeOverlayNavigationBack: return "duckplayer.youtube.overlay.navigation.back" @@ -1710,8 +1716,7 @@ extension Pixel.Event { case .duckPlayerYouTubeOverlayNavigationOutsideYoutube: return "duckplayer.youtube.overlay.navigation.outside-youtube" case .duckPlayerYouTubeOverlayNavigationClosed: return "duckplayer.youtube.overlay.navigation.closed" case .duckPlayerYouTubeNavigationIdle30: return "duckplayer.youtube.overlay.idle-30" - - + } } } diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 84113f95a0..401aeaa3e7 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -299,6 +299,7 @@ 6F04224D2CD2A3AD00729FA6 /* StorageInconsistencyMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F98573F2CD2933B001BE9A0 /* StorageInconsistencyMonitor.swift */; }; 6F0FEF6B2C516D540090CDE4 /* NewTabPageSettingsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0FEF6A2C516D540090CDE4 /* NewTabPageSettingsStorage.swift */; }; 6F0FEF6D2C52639E0090CDE4 /* ReorderableForEach.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0FEF6C2C52639E0090CDE4 /* ReorderableForEach.swift */; }; + 6F3529FF2CDCEDFF00A59170 /* OmniBarLoadingStateBearerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F3529FE2CDCEDF700A59170 /* OmniBarLoadingStateBearerTests.swift */; }; 6F35379E2C4AAF2E009F8717 /* NewTabPageSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F35379D2C4AAF2E009F8717 /* NewTabPageSettingsView.swift */; }; 6F3537A02C4AAFD2009F8717 /* NewTabPageSettingsSectionItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F35379F2C4AAFD2009F8717 /* NewTabPageSettingsSectionItemView.swift */; }; 6F3537A22C4AB97A009F8717 /* NewTabPageSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F3537A12C4AB97A009F8717 /* NewTabPageSettingsModel.swift */; }; @@ -1599,6 +1600,7 @@ 6F03CB082C32F331004179A8 /* PixelFiringAsync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelFiringAsync.swift; sourceTree = ""; }; 6F0FEF6A2C516D540090CDE4 /* NewTabPageSettingsStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageSettingsStorage.swift; sourceTree = ""; }; 6F0FEF6C2C52639E0090CDE4 /* ReorderableForEach.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReorderableForEach.swift; sourceTree = ""; }; + 6F3529FE2CDCEDF700A59170 /* OmniBarLoadingStateBearerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBarLoadingStateBearerTests.swift; sourceTree = ""; }; 6F35379D2C4AAF2E009F8717 /* NewTabPageSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageSettingsView.swift; sourceTree = ""; }; 6F35379F2C4AAFD2009F8717 /* NewTabPageSettingsSectionItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageSettingsSectionItemView.swift; sourceTree = ""; }; 6F3537A12C4AB97A009F8717 /* NewTabPageSettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageSettingsModel.swift; sourceTree = ""; }; @@ -6309,6 +6311,7 @@ F1D477C71F2139210031ED49 /* OmniBar */ = { isa = PBXGroup; children = ( + 6F3529FE2CDCEDF700A59170 /* OmniBarLoadingStateBearerTests.swift */, BBFF18B02C76448100C48D7D /* QuerySubmittedTests.swift */, 8588026424E4209900C24AB6 /* LargeOmniBarStateTests.swift */, 85F20005221702F7006BB258 /* AddressDisplayHelperTests.swift */, @@ -8107,6 +8110,7 @@ 9F4CC51D2C48D240006A96EB /* CoreDataDatabaseTestUtilities.swift in Sources */, C185ED672BD43DA100BAE9DC /* ImportPasswordsStatusHandlerTests.swift in Sources */, F198D7981E3A45D90088DA8A /* WKWebViewConfigurationExtensionTests.swift in Sources */, + 6F3529FF2CDCEDFF00A59170 /* OmniBarLoadingStateBearerTests.swift in Sources */, 564DE45E2C45218500D23241 /* OnboardingNavigationDelegateTests.swift in Sources */, C14E2F7729DE14EA002AC515 /* AutofillInterfaceUsernameTruncatorTests.swift in Sources */, 9F7CFF782C86E3E10012833E /* OnboardingManagerTests.swift in Sources */, diff --git a/DuckDuckGo/Base.lproj/OmniBar.xib b/DuckDuckGo/Base.lproj/OmniBar.xib index c0a18404df..0cd7d0a6c2 100644 --- a/DuckDuckGo/Base.lproj/OmniBar.xib +++ b/DuckDuckGo/Base.lproj/OmniBar.xib @@ -82,10 +82,10 @@ - + - + @@ -217,7 +217,7 @@ - + @@ -260,7 +260,7 @@ + @@ -398,6 +409,7 @@ + @@ -449,6 +461,7 @@ + diff --git a/DuckDuckGo/BlankSnapshotViewController.swift b/DuckDuckGo/BlankSnapshotViewController.swift index 9c55649c0d..0268aa3f2b 100644 --- a/DuckDuckGo/BlankSnapshotViewController.swift +++ b/DuckDuckGo/BlankSnapshotViewController.swift @@ -162,7 +162,7 @@ extension BlankSnapshotViewController: UICollectionViewDataSource { } extension BlankSnapshotViewController: OmniBarDelegate { - + func onVoiceSearchPressed() { // No-op } @@ -202,6 +202,10 @@ extension BlankSnapshotViewController: OmniBarDelegate { func onClearPressed() { // No-op } + + func onAbortPressed() { + // no-op + } } extension BlankSnapshotViewController: TabSwitcherButtonDelegate { diff --git a/DuckDuckGo/LargeOmniBarState.swift b/DuckDuckGo/LargeOmniBarState.swift index eb543f9f96..f80578a679 100644 --- a/DuckDuckGo/LargeOmniBarState.swift +++ b/DuckDuckGo/LargeOmniBarState.swift @@ -22,7 +22,7 @@ import Core struct LargeOmniBarState { - struct HomeEmptyEditingState: OmniBarState { + struct HomeEmptyEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = true let showBackButton: Bool = true let showForwardButton: Bool = true @@ -33,27 +33,37 @@ struct LargeOmniBarState { let showPrivacyIcon = false let showBackground = false let showClear = false + let showAbort = false let showRefresh = false let showMenu = false let showSettings = true let showCancel: Bool = false var name: String { return "Pad" + Type.name(self) } - var onEditingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEditingStartedState: OmniBarState { return self } var onTextClearedState: OmniBarState { return self } - var onTextEnteredState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper) } - var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onTextEnteredState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onBrowsingStoppedState: OmniBarState { return self } var onEnterPadState: OmniBarState { return self } - var onEnterPhoneState: OmniBarState { return SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onReloadState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEnterPhoneState: OmniBarState { return SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onReloadState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var showSearchLoupe: Bool { !voiceSearchHelper.isVoiceSearchEnabled } var showVoiceSearch: Bool { voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool + + func withLoading() -> LargeOmniBarState.HomeEmptyEditingState { + Self.init(voiceSearchHelper: voiceSearchHelper, isLoading: true) + } + + func withoutLoading() -> LargeOmniBarState.HomeEmptyEditingState { + Self.init(voiceSearchHelper: voiceSearchHelper, isLoading: false) + } } - struct HomeTextEditingState: OmniBarState { + struct HomeTextEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = true let showBackButton: Bool = true let showForwardButton: Bool = true @@ -64,27 +74,29 @@ struct LargeOmniBarState { let showPrivacyIcon = false let showBackground = false let showClear = true + let showAbort = false let showRefresh = false let showMenu = false let showSettings = true let showCancel: Bool = false var name: String { return "Pad" + Type.name(self) } - var onEditingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEditingStartedState: OmniBarState { return self } - var onTextClearedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onTextClearedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onTextEnteredState: OmniBarState { return self } - var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } - var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPadState: OmniBarState { return self } - var onEnterPhoneState: OmniBarState { return SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: voiceSearchHelper) } - var onReloadState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEnterPhoneState: OmniBarState { return SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onReloadState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var showSearchLoupe: Bool { !voiceSearchHelper.isVoiceSearchEnabled } var showVoiceSearch: Bool { voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct HomeNonEditingState: OmniBarState { + struct HomeNonEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = true let showBackButton: Bool = true let showForwardButton: Bool = true @@ -96,26 +108,28 @@ struct LargeOmniBarState { let showPrivacyIcon = false let showBackground = true let showClear = false + let showAbort = false let showRefresh = false let showMenu = false let showSettings = true let showCancel: Bool = false var name: String { return "Pad" + Type.name(self) } var onEditingStoppedState: OmniBarState { return self } - var onEditingStartedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onTextClearedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onTextEnteredState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper) } - var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } - var onBrowsingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStartedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onTextClearedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onTextEnteredState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onBrowsingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPadState: OmniBarState { return self } - var onEnterPhoneState: OmniBarState { return SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } - var onReloadState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEnterPhoneState: OmniBarState { return SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onReloadState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var showVoiceSearch: Bool { voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct BrowsingEmptyEditingState: OmniBarState { + struct BrowsingEmptyEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = true let showBackButton: Bool = true let showForwardButton: Bool = true @@ -126,27 +140,29 @@ struct LargeOmniBarState { let showPrivacyIcon = false let showBackground = false let showClear = false + let showAbort = false let showRefresh = false let showMenu = true let showSettings = false let showCancel: Bool = false var name: String { return "Pad" + Type.name(self) } - var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEditingStartedState: OmniBarState { return self } var onTextClearedState: OmniBarState { return self } - var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onBrowsingStartedState: OmniBarState { return self } - var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPadState: OmniBarState { return self } - var onEnterPhoneState: OmniBarState { return SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onReloadState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEnterPhoneState: OmniBarState { return SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onReloadState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var showSearchLoupe: Bool { !voiceSearchHelper.isVoiceSearchEnabled } var showVoiceSearch: Bool { voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct BrowsingTextEditingState: OmniBarState { + struct BrowsingTextEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = true let showBackButton: Bool = true let showForwardButton: Bool = true @@ -157,27 +173,29 @@ struct LargeOmniBarState { let showPrivacyIcon = false let showBackground = false let showClear = true + let showAbort = false let showRefresh = false let showMenu = true let showSettings = false let showCancel: Bool = false var name: String { return "Pad" + Type.name(self) } - var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEditingStartedState: OmniBarState { return self } - var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onTextEnteredState: OmniBarState { return self } var onBrowsingStartedState: OmniBarState { return self } - var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPadState: OmniBarState { return self } - var onEnterPhoneState: OmniBarState { return SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } - var onReloadState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEnterPhoneState: OmniBarState { return SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onReloadState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var showSearchLoupe: Bool { !voiceSearchHelper.isVoiceSearchEnabled } var showVoiceSearch: Bool { voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct BrowsingNonEditingState: OmniBarState { + struct BrowsingNonEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = true let showBackButton: Bool = true let showForwardButton: Bool = true @@ -189,23 +207,25 @@ struct LargeOmniBarState { let showPrivacyIcon = true let showBackground = true let showClear = false - let showRefresh = true + var showAbort: Bool { isLoading } + var showRefresh: Bool { !isLoading } let showMenu = true let showSettings = false let showCancel: Bool = false let showVoiceSearch = false var name: String { return "Pad" + Type.name(self) } var onEditingStoppedState: OmniBarState { return self } - var onEditingStartedState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } - var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStartedState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onBrowsingStartedState: OmniBarState { return self } - var onBrowsingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onBrowsingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPadState: OmniBarState { return self } - var onEnterPhoneState: OmniBarState { return SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } - var onReloadState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEnterPhoneState: OmniBarState { return SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onReloadState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } } diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index de806d9737..75c5777782 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -950,6 +950,10 @@ class MainViewController: UIViewController { loadUrl(url) } + func stopLoading() { + currentTab?.stopLoading() + } + func loadUrl(_ url: URL, fromExternalLink: Bool = false) { prepareTabForRequest { self.currentTab?.load(url: url) @@ -1072,6 +1076,8 @@ class MainViewController: UIViewController { } private func refreshOmniBar() { + updateOmniBarLoadingState() + guard let tab = currentTab, tab.link != nil else { viewCoordinator.omniBar.stopBrowsing() return @@ -1086,10 +1092,18 @@ class MainViewController: UIViewController { } else { viewCoordinator.omniBar.resetPrivacyIcon(for: tab.url) } - + viewCoordinator.omniBar.startBrowsing() } + private func updateOmniBarLoadingState() { + if currentTab?.isLoading == true { + omniBar.startLoading() + } else { + omniBar.stopLoading() + } + } + func dismissOmniBar() { viewCoordinator.omniBar.resignFirstResponder() hideSuggestionTray() @@ -1948,6 +1962,11 @@ extension MainViewController: OmniBarDelegate { performCancel() } + func onAbortPressed() { + Pixel.fire(pixel: .stopPageLoad) + stopLoading() + } + func onClearPressed() { fireControllerAwarePixel(ntp: .addressBarClearPressedOnNTP, serp: .addressBarClearPressedOnSERP, diff --git a/DuckDuckGo/OmniBar.swift b/DuckDuckGo/OmniBar.swift index c2b6877be7..91a1214bd4 100644 --- a/DuckDuckGo/OmniBar.swift +++ b/DuckDuckGo/OmniBar.swift @@ -50,7 +50,8 @@ class OmniBar: UIView { @IBOutlet weak var cancelButton: UIButton! @IBOutlet weak var refreshButton: UIButton! @IBOutlet weak var voiceSearchButton: UIButton! - + @IBOutlet weak var abortButton: UIButton! + @IBOutlet weak var bookmarksButton: UIButton! @IBOutlet weak var backButton: UIButton! @IBOutlet weak var forwardButton: UIButton! @@ -80,7 +81,7 @@ class OmniBar: UIView { static func loadFromXib(voiceSearchHelper: VoiceSearchHelperProtocol) -> OmniBar { let omniBar = OmniBar.load(nibName: "OmniBar") - omniBar.state = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) + omniBar.state = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: false) omniBar.refreshState(omniBar.state) return omniBar @@ -92,7 +93,7 @@ class OmniBar: UIView { // Tests require this init(voiceSearchHelper: VoiceSearchHelperProtocol, frame: CGRect) { - self.state = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) + self.state = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: false) super.init(frame: frame) } @@ -249,6 +250,14 @@ class OmniBar: UIView { refreshState(state.onBrowsingStoppedState) } + func startLoading() { + refreshState(state.withLoading()) + } + + func stopLoading() { + refreshState(state.withoutLoading()) + } + func removeTextSelection() { textField.selectedTextRange = nil } @@ -350,9 +359,9 @@ class OmniBar: UIView { textField.selectedTextRange = textField.textRange(from: fromPosition, to: textField.endOfDocument) } - fileprivate func refreshState(_ newState: OmniBarState) { - if state.name != newState.name { - Logger.general.debug("OmniBar entering \(newState.name) from \(self.state.name)") + fileprivate func refreshState(_ newState: any OmniBarState) { + if !newState.isEquivalent(to: state) { + Logger.general.debug("OmniBar entering \(newState.description) from \(self.state.description)") if newState.clearTextOnStart { clear() } @@ -370,6 +379,7 @@ class OmniBar: UIView { setVisibility(cancelButton, hidden: !state.showCancel) setVisibility(refreshButton, hidden: !state.showRefresh) setVisibility(voiceSearchButton, hidden: !state.showVoiceSearch) + setVisibility(abortButton, hidden: !state.showAbort) setVisibility(backButton, hidden: !state.showBackButton) setVisibility(forwardButton, hidden: !state.showForwardButton) @@ -462,7 +472,11 @@ class OmniBar: UIView { @IBAction func onVoiceSearchButtonPressed(_ sender: UIButton) { omniDelegate?.onVoiceSearchPressed() } - + + @IBAction func onAbortButtonPressed(_ sender: Any) { + omniDelegate?.onAbortPressed() + } + @IBAction func onClearButtonPressed(_ sender: Any) { omniDelegate?.onClearPressed() refreshState(state.onTextClearedState) diff --git a/DuckDuckGo/OmniBarDelegate.swift b/DuckDuckGo/OmniBarDelegate.swift index e1153fd7a3..d5122cac32 100644 --- a/DuckDuckGo/OmniBarDelegate.swift +++ b/DuckDuckGo/OmniBarDelegate.swift @@ -47,6 +47,8 @@ protocol OmniBarDelegate: AnyObject { func onClearPressed() + func onAbortPressed() + func onCancelPressed() func onEnterPressed() diff --git a/DuckDuckGo/OmniBarState.swift b/DuckDuckGo/OmniBarState.swift index db7330bd9c..3e486652c5 100644 --- a/DuckDuckGo/OmniBarState.swift +++ b/DuckDuckGo/OmniBarState.swift @@ -20,8 +20,10 @@ import Foundation import Core -protocol OmniBarState { - +protocol OmniBarState: CustomStringConvertible { + + var name: String { get } + var hasLargeWidth: Bool { get } var showBackButton: Bool { get } var showForwardButton: Bool { get } @@ -39,7 +41,8 @@ protocol OmniBarState { var showMenu: Bool { get } var showSettings: Bool { get } var showVoiceSearch: Bool { get } - var name: String { get } + var showAbort: Bool { get } + var onEditingStoppedState: OmniBarState { get } var onEditingSuspendedState: OmniBarState { get } var onEditingStartedState: OmniBarState { get } @@ -50,10 +53,43 @@ protocol OmniBarState { var onEnterPhoneState: OmniBarState { get } var onEnterPadState: OmniBarState { get } var onReloadState: OmniBarState { get } + + var voiceSearchHelper: VoiceSearchHelperProtocol { get } + + var isLoading: Bool { get } + + func withLoading() -> Self + func withoutLoading() -> Self + + func isEquivalent(to other: OmniBarState) -> Bool } extension OmniBarState { + func isEquivalent(to other: OmniBarState) -> Bool { + name == other.name && isLoading == other.isLoading + } + + var description: String { + "\(name)\(isLoading ? " (loading)" : "")" + } + var onEditingSuspendedState: OmniBarState { - UniversalOmniBarState.EditingSuspendedState(baseState: self.onEditingStartedState) + UniversalOmniBarState.EditingSuspendedState(baseState: onEditingStartedState, + voiceSearchHelper: voiceSearchHelper, + isLoading: isLoading) + } +} + +protocol OmniBarLoadingBearerStateCreating { + init(voiceSearchHelper: VoiceSearchHelperProtocol, isLoading: Bool) +} + +extension OmniBarLoadingBearerStateCreating where Self: OmniBarState { + func withLoading() -> Self { + Self.init(voiceSearchHelper: voiceSearchHelper, isLoading: true) + } + + func withoutLoading() -> Self { + Self.init(voiceSearchHelper: voiceSearchHelper, isLoading: false) } } diff --git a/DuckDuckGo/SmallOmniBarState.swift b/DuckDuckGo/SmallOmniBarState.swift index ee47e1af6d..f00abfac23 100644 --- a/DuckDuckGo/SmallOmniBarState.swift +++ b/DuckDuckGo/SmallOmniBarState.swift @@ -22,7 +22,7 @@ import Core struct SmallOmniBarState { - struct HomeEmptyEditingState: OmniBarState { + struct HomeEmptyEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = false let showBackButton: Bool = false let showForwardButton: Bool = false @@ -33,27 +33,29 @@ struct SmallOmniBarState { let showPrivacyIcon = false let showBackground = false let showClear = false + let showAbort = false let showRefresh = false let showMenu = false let showSettings = false let showCancel: Bool = true var name: String { return "Phone" + Type.name(self) } - var onEditingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEditingStartedState: OmniBarState { return self } var onTextClearedState: OmniBarState { return self } - var onTextEnteredState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper) } - var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onTextEnteredState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onBrowsingStoppedState: OmniBarState { return self } - var onEnterPadState: OmniBarState { return LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEnterPadState: OmniBarState { return LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPhoneState: OmniBarState { return self } - var onReloadState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onReloadState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var showSearchLoupe: Bool { !voiceSearchHelper.isSpeechRecognizerAvailable } var showVoiceSearch: Bool { voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct HomeTextEditingState: OmniBarState { + struct HomeTextEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = false let showBackButton: Bool = false let showForwardButton: Bool = false @@ -64,27 +66,29 @@ struct SmallOmniBarState { let showPrivacyIcon = false let showBackground = false let showClear = true + let showAbort = false let showRefresh = false let showMenu = false let showSettings = false let showCancel: Bool = true let showVoiceSearch = false var name: String { return "Phone" + Type.name(self) } - var onEditingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEditingStartedState: OmniBarState { return self } - var onTextClearedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onTextClearedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onTextEnteredState: OmniBarState { return self } - var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } - var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onEnterPadState: OmniBarState { return LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onEnterPadState: OmniBarState { return LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPhoneState: OmniBarState { return self } - var onReloadState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onReloadState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var showSearchLoupe: Bool { !voiceSearchHelper.isSpeechRecognizerAvailable } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct HomeNonEditingState: OmniBarState { + struct HomeNonEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = false let showBackButton: Bool = false let showForwardButton: Bool = false @@ -96,26 +100,29 @@ struct SmallOmniBarState { let showPrivacyIcon = false let showBackground = true let showClear = false + let showAbort = false let showRefresh = false let showMenu = false let showSettings = true let showCancel: Bool = false var name: String { return "Phone" + Type.name(self) } var onEditingStoppedState: OmniBarState { return self } - var onEditingStartedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onTextClearedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onTextEnteredState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper) } - var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } - var onBrowsingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } - var onEnterPadState: OmniBarState { return LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStartedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onTextClearedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onTextEnteredState: OmniBarState { return HomeTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onBrowsingStartedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onBrowsingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onEnterPadState: OmniBarState { return LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPhoneState: OmniBarState { return self } - var onReloadState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onReloadState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var showVoiceSearch: Bool { voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct BrowsingEmptyEditingState: OmniBarState { + struct BrowsingEmptyEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = false let showBackButton: Bool = false let showForwardButton: Bool = false @@ -126,27 +133,30 @@ struct SmallOmniBarState { let showPrivacyIcon = false let showBackground = false let showClear = false + let showAbort = false let showRefresh = false let showMenu = false let showSettings = false let showCancel: Bool = true var name: String { return "Phone" + Type.name(self) } - var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEditingStartedState: OmniBarState { return self } var onTextClearedState: OmniBarState { return self } - var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onBrowsingStartedState: OmniBarState { return self } - var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onEnterPadState: OmniBarState { return LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onEnterPadState: OmniBarState { return LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPhoneState: OmniBarState { return self } - var onReloadState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onReloadState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var showSearchLoupe: Bool { !voiceSearchHelper.isVoiceSearchEnabled } var showVoiceSearch: Bool { voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct BrowsingTextEditingState: OmniBarState { + struct BrowsingTextEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = false let showBackButton: Bool = false let showForwardButton: Bool = false @@ -157,27 +167,30 @@ struct SmallOmniBarState { let showPrivacyIcon = false let showBackground = false let showClear = true + let showAbort = false let showRefresh = false let showMenu = false let showSettings = false let showCancel: Bool = true let showVoiceSearch = false var name: String { return "Phone" + Type.name(self) } - var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEditingStartedState: OmniBarState { return self } - var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } + var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onTextEnteredState: OmniBarState { return self } var onBrowsingStartedState: OmniBarState { return self } - var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onEnterPadState: OmniBarState { return LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onEnterPadState: OmniBarState { return LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPhoneState: OmniBarState { return self } - var onReloadState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onReloadState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var showSearchLoupe: Bool { !voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct BrowsingNonEditingState: OmniBarState { + struct BrowsingNonEditingState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = false let showBackButton: Bool = false let showForwardButton: Bool = false @@ -189,26 +202,28 @@ struct SmallOmniBarState { let showPrivacyIcon = true let showBackground = true let showClear = false - let showRefresh = true + var showAbort: Bool { isLoading } + var showRefresh: Bool { !isLoading } let showMenu = false let showSettings = false let showCancel: Bool = false let showVoiceSearch = false var name: String { return "Phone" + Type.name(self) } var onEditingStoppedState: OmniBarState { return self } - var onEditingStartedState: OmniBarState { return BrowsingTextEditingStartedState(voiceSearchHelper: voiceSearchHelper) } - var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStartedState: OmniBarState { return BrowsingTextEditingStartedState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onBrowsingStartedState: OmniBarState { return self } - var onBrowsingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper) } - var onEnterPadState: OmniBarState { return LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onBrowsingStoppedState: OmniBarState { return HomeNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onEnterPadState: OmniBarState { return LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPhoneState: OmniBarState { return self } - var onReloadState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onReloadState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } - struct BrowsingTextEditingStartedState: OmniBarState { + struct BrowsingTextEditingStartedState: OmniBarState, OmniBarLoadingBearerStateCreating { let hasLargeWidth: Bool = false let showBackButton: Bool = false let showForwardButton: Bool = false @@ -219,23 +234,25 @@ struct SmallOmniBarState { let showPrivacyIcon = false let showBackground = false let showClear = true + let showAbort = false let showRefresh = false let showMenu = false let showSettings = false let showCancel: Bool = true var name: String { return "Phone" + Type.name(self) } - var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper) } + var onEditingStoppedState: OmniBarState { return BrowsingNonEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEditingStartedState: OmniBarState { return self } - var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onTextClearedState: OmniBarState { return BrowsingEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onTextEnteredState: OmniBarState { return BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onBrowsingStartedState: OmniBarState { return self } - var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper) } - var onEnterPadState: OmniBarState { return LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper) } + var onBrowsingStoppedState: OmniBarState { return HomeEmptyEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } + var onEnterPadState: OmniBarState { return LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var onEnterPhoneState: OmniBarState { return self } - var onReloadState: OmniBarState { return BrowsingTextEditingStartedState(voiceSearchHelper: voiceSearchHelper) } + var onReloadState: OmniBarState { return BrowsingTextEditingStartedState(voiceSearchHelper: voiceSearchHelper, isLoading: isLoading) } var showSearchLoupe: Bool { !voiceSearchHelper.isVoiceSearchEnabled } var showVoiceSearch: Bool { voiceSearchHelper.isVoiceSearchEnabled } let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool } } diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 6be661152c..5609aec797 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -66,7 +66,12 @@ class TabViewController: UIViewController { private let instrumentation = TabInstrumentation() var isLinkPreview = false - + + // A workaround for an issue when in some cases webview reports `isLoading == true` when it was stoppped. + var isLoading: Bool { + webView.isLoading && !wasLoadingStoppedExternally + } + var openedByPage = false weak var openingTab: TabViewController? { didSet { @@ -163,6 +168,9 @@ class TabViewController: UIViewController { // Temporary to gather some data. Fire a follow up if no trackers dax dialog was shown and then trackers appear. private var fireWoFollowUp = false + // Indicates if there was an external call to stop loading current request. Resets on new load request, refresh and failures. + private var wasLoadingStoppedExternally = false + // In certain conditions we try to present a dax dialog when one is already showing, so check to ensure we don't var isShowingFullScreenDaxDialog = false @@ -660,6 +668,7 @@ class TabViewController: UIViewController { } public func load(url: URL) { + wasLoadingStoppedExternally = false webView.stopLoading() dismissJSAlertIfNeeded() @@ -828,6 +837,7 @@ class TabViewController: UIViewController { } public func reload() { + wasLoadingStoppedExternally = false updateContentMode() cachedRuntimeConfigurationForDomain = [:] if let handler = duckPlayerNavigationHandler { @@ -835,6 +845,7 @@ class TabViewController: UIViewController { } else { webView.reload() } + delegate?.tabLoadingStateDidChange(tab: self) privacyDashboard?.dismiss(animated: true) } @@ -1168,6 +1179,14 @@ class TabViewController: UIViewController { UIPasteboard.general.string = text } + func stopLoading() { + webView.stopLoading() + wasLoadingStoppedExternally = true + + hideProgressIndicator() + delegate?.tabLoadingStateDidChange(tab: self) + } + private func cleanUpBeforeClosing() { let job = { [weak webView, userContentController] in userContentController.cleanUpBeforeClosing() @@ -1606,6 +1625,7 @@ extension TabViewController: WKNavigationDelegate { } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + Logger.general.debug("didFailNavigation; error: \(error)") adClickAttributionDetection.onDidFailNavigation() hideProgressIndicator() webpageDidFailToLoad() @@ -1617,6 +1637,9 @@ extension TabViewController: WKNavigationDelegate { private func webpageDidFailToLoad() { Logger.general.debug("webpageLoading failed") + + wasLoadingStoppedExternally = false + if isError { showBars(animated: true) privacyInfo = nil @@ -1627,6 +1650,7 @@ extension TabViewController: WKNavigationDelegate { } func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + Logger.general.debug("didFailProvisionalNavigation; error: \(error)") adClickAttributionDetection.onDidFailNavigation() hideProgressIndicator() linkProtection.setMainFrameUrl(nil) @@ -1639,7 +1663,7 @@ extension TabViewController: WKNavigationDelegate { if error.code == 102 && error.domain == "WebKitErrorDomain" { return } - + if let url = url, let domain = url.host, error.code == Constants.frameLoadInterruptedErrorCode { @@ -1650,6 +1674,15 @@ extension TabViewController: WKNavigationDelegate { self.url = webView.url } + // Bail out before showing error when navigation was cancelled by the user + if error.code == NSURLErrorCancelled && error.domain == NSURLErrorDomain { + webpageDidFailToLoad() + + // Reset url to current one, as navigation was not successful + self.url = webView.url + return + } + // wait before showing errors in case they recover automatically DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { self.showErrorNow() diff --git a/DuckDuckGo/UniversalOmniBarState.swift b/DuckDuckGo/UniversalOmniBarState.swift index 2e15892c02..3dd7fd48f7 100644 --- a/DuckDuckGo/UniversalOmniBarState.swift +++ b/DuckDuckGo/UniversalOmniBarState.swift @@ -36,19 +36,31 @@ enum UniversalOmniBarState { var showPrivacyIcon: Bool { baseState.showPrivacyIcon } var showBackground: Bool { baseState.showBackground } var showClear: Bool { false } + var showAbort: Bool { baseState.showAbort } var showRefresh: Bool { baseState.showRefresh } var showMenu: Bool { baseState.showMenu } var showSettings: Bool { baseState.showSettings } var showVoiceSearch: Bool { baseState.showVoiceSearch } var name: String { Type.name(self) } - var onEditingStoppedState: OmniBarState { baseState.onEditingStoppedState } - var onEditingStartedState: OmniBarState { baseState.onEditingStartedState } - var onTextClearedState: OmniBarState { baseState.onTextClearedState } - var onTextEnteredState: OmniBarState { baseState.onTextEnteredState } - var onBrowsingStartedState: OmniBarState { baseState.onBrowsingStartedState } - var onBrowsingStoppedState: OmniBarState { baseState.onBrowsingStoppedState } - var onEnterPhoneState: OmniBarState { baseState.onEnterPhoneState } - var onEnterPadState: OmniBarState { baseState.onEnterPadState } - var onReloadState: OmniBarState { baseState.onReloadState } + var onEditingStoppedState: any OmniBarState { baseState.onEditingStoppedState } + var onEditingStartedState: any OmniBarState { baseState.onEditingStartedState } + var onTextClearedState: any OmniBarState { baseState.onTextClearedState } + var onTextEnteredState: any OmniBarState { baseState.onTextEnteredState } + var onBrowsingStartedState: any OmniBarState { baseState.onBrowsingStartedState } + var onBrowsingStoppedState: any OmniBarState { baseState.onBrowsingStoppedState } + var onEnterPhoneState: any OmniBarState { baseState.onEnterPhoneState } + var onEnterPadState: any OmniBarState { baseState.onEnterPadState } + var onReloadState: any OmniBarState { baseState.onReloadState } + + let voiceSearchHelper: VoiceSearchHelperProtocol + let isLoading: Bool + + func withLoading() -> UniversalOmniBarState.EditingSuspendedState { + Self.init(baseState: baseState, voiceSearchHelper: voiceSearchHelper, isLoading: true) + } + + func withoutLoading() -> UniversalOmniBarState.EditingSuspendedState { + Self.init(baseState: baseState, voiceSearchHelper: voiceSearchHelper, isLoading: false) + } } } diff --git a/DuckDuckGoTests/LargeOmniBarStateTests.swift b/DuckDuckGoTests/LargeOmniBarStateTests.swift index f65af8ec0a..caeedfc75d 100644 --- a/DuckDuckGoTests/LargeOmniBarStateTests.swift +++ b/DuckDuckGoTests/LargeOmniBarStateTests.swift @@ -28,7 +28,7 @@ class LargeOmniBarStateTests: XCTestCase { let disabledVoiceSearchHelper = MockVoiceSearchHelper(isSpeechRecognizerAvailable: false) func testWhenInHomeEmptyEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) @@ -38,7 +38,9 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) - + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) + XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) XCTAssertTrue(testee.showForwardButton) @@ -47,7 +49,7 @@ class LargeOmniBarStateTests: XCTestCase { } func testWhenInHomeEmptyEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) @@ -57,7 +59,9 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) XCTAssertTrue(testee.showVoiceSearch) - + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) + XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) XCTAssertTrue(testee.showForwardButton) @@ -66,42 +70,42 @@ class LargeOmniBarStateTests: XCTestCase { } func testWhenEnteringHomeEmptyEditingStateThenTextIsCleared() { - let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.clearTextOnStart) } func testWhenInHomeEmptyEditingStateThenEditingStartedMaintainsState() { - let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenEditingStoppedTrainsitionsToNonEditingState() { - let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenEnteringTextTransitionsToTextEditingState() { - let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenClearingTextMaintainsState() { - let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenBrowsingStartedTransitionsToBrowsingNonEditingState() { - let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenBrowsingStoppedMaintainsState() { - let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) @@ -111,7 +115,9 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) - + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) + XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) XCTAssertTrue(testee.showForwardButton) @@ -120,7 +126,7 @@ class LargeOmniBarStateTests: XCTestCase { } func testWhenInHomeTextEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) @@ -130,7 +136,9 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) XCTAssertTrue(testee.showVoiceSearch) - + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) + XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) XCTAssertTrue(testee.showForwardButton) @@ -138,42 +146,42 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showShareButton) } func testWhenEnteringHomeTextEditingStateThenTextIsNotCleared() { - let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.clearTextOnStart) } func testWhenInHomeTextEditingStateThenEditingStartedMaintainsState() { - let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenEditingStoppedTrainsitionsToNonEditingState() { - let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenEnteringTextMaintainstState() { - let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenClearingTextTransitionsToEmptyEditingState() { - let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenBrowsingStartedTransitionsToBrowsingNonEditingState() { - let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenBrowsingStoppedTransitionsToHomeTextEditingState() { - let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -182,6 +190,8 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertTrue(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) @@ -189,9 +199,9 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertTrue(testee.showBookmarksButton) XCTAssertFalse(testee.showShareButton) } - + func testWhenInHomeNonEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -200,6 +210,8 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) @@ -209,42 +221,42 @@ class LargeOmniBarStateTests: XCTestCase { } func testWhenEnteringHomeNonEditingStateThenTextIsCleared() { - let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.clearTextOnStart) } func testWhenInHomeNonEditingStateThenEditingStartedTransitionsToEmptyEditingState() { - let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenEditingStoppedMaintainsState() { - let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenEnteringTextTransitionsToTextEditingState() { - let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenClearingTextTransitionsToEmptyEditingState() { - let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenBrowsingStartedTransitionsToBrowsingNonEditingState() { - let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenBrowsingStoppedTransitionsToHomeNonEditingState() { - let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowserEmptyEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -253,6 +265,8 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) @@ -262,7 +276,7 @@ class LargeOmniBarStateTests: XCTestCase { } func testWhenInBrowserEmptyEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -271,6 +285,8 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) XCTAssertTrue(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) @@ -280,42 +296,42 @@ class LargeOmniBarStateTests: XCTestCase { } func testWhenEnteringBrowserEmptyEditingStateThenTextIsCleared() { - let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.clearTextOnStart) } func testWhenInBrowsingEmptyEditingStateThenEditingStartedMaintainsState() { - let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenEditingStoppedTrainsitionsToBrowsingNonEditingState() { - let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenEnteringTextTransitionsToTextEditingState() { - let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenClearingMaintainsState() { - let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenBrowsingStartedMaintainsState() { - let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenBrowsingStoppedTransitionsToHomeEmptyEditingState() { - let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertTrue(testee.showClear) @@ -324,6 +340,8 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) XCTAssertTrue(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) @@ -333,7 +351,7 @@ class LargeOmniBarStateTests: XCTestCase { } func testWhenInBrowsingTextEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertTrue(testee.showClear) @@ -342,6 +360,8 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) @@ -351,42 +371,42 @@ class LargeOmniBarStateTests: XCTestCase { } func testWhenEnteringBrowsingTextEditingStateThenTextIsMaintained() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.clearTextOnStart) } func testWhenInBrowsingTextEditingStateThenEditingStartedMaintainsState() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenEditingStoppedTrainsitionsToNonEditingState() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenEnteringTextMaintainstState() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenClearingTextTransitionsToEmptyEditingState() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenBrowsingStartedMaintainsState() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenBrowsingStoppedTransitionsToHomeTextEditingState() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenCorrectButtonsAreShown() { - let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.showBackground) XCTAssertTrue(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -394,7 +414,9 @@ class LargeOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showSettings) XCTAssertFalse(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) - + XCTAssertFalse(testee.showAbort) + XCTAssertTrue(testee.showRefresh) + XCTAssertTrue(testee.hasLargeWidth) XCTAssertTrue(testee.showBackButton) XCTAssertTrue(testee.showForwardButton) @@ -403,37 +425,37 @@ class LargeOmniBarStateTests: XCTestCase { } func testWhenEnteringBrowsingNonEditingStateThenTextIsMaintained() { - let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.clearTextOnStart) } func testWhenInBrowsingNonEditingStateThenEditingStartedTransitionsToTextEditingState() { - let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenEditingStoppedMaintainsState() { - let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenEnteringTextTransitionsToTextEditingState() { - let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, LargeOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenClearingTextTransitionsToEmptyEditingState() { - let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, LargeOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenBrowsingStartedMaintainstState() { - let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenBrowsingStoppedTransitionsToHomeNonEditingState() { - let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = LargeOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, LargeOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } } diff --git a/DuckDuckGoTests/OmniBarLoadingStateBearerTests.swift b/DuckDuckGoTests/OmniBarLoadingStateBearerTests.swift new file mode 100644 index 0000000000..b8888ed716 --- /dev/null +++ b/DuckDuckGoTests/OmniBarLoadingStateBearerTests.swift @@ -0,0 +1,81 @@ +// +// OmniBarLoadingStateBearerTests.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import XCTest +@testable import DuckDuckGo + +final class OmniBarLoadingStateBearerTests: XCTestCase { + + static let unaffectedByLoadingStates: [(OmniBarState & OmniBarLoadingBearerStateCreating).Type] = [ + SmallOmniBarState.BrowsingEmptyEditingState.self, + SmallOmniBarState.BrowsingTextEditingStartedState.self, + SmallOmniBarState.BrowsingTextEditingState.self, + SmallOmniBarState.HomeEmptyEditingState.self, + SmallOmniBarState.HomeNonEditingState.self, + SmallOmniBarState.HomeTextEditingState.self, + LargeOmniBarState.BrowsingEmptyEditingState.self, + LargeOmniBarState.BrowsingTextEditingState.self, + LargeOmniBarState.HomeEmptyEditingState.self, + LargeOmniBarState.HomeNonEditingState.self, + LargeOmniBarState.HomeTextEditingState.self + ] + + static let affectedByLoadingStates: [(OmniBarState & OmniBarLoadingBearerStateCreating).Type] = [ + SmallOmniBarState.BrowsingNonEditingState.self, + LargeOmniBarState.BrowsingNonEditingState.self + ] + + func testUnaffectedByLoadingStatesDoNotShowAbortButtonWhenLoading() { + for state in Self.unaffectedByLoadingStates { + let state = state.init(voiceSearchHelper: MockVoiceSearchHelper(isSpeechRecognizerAvailable: false), isLoading: true) + + XCTAssertFalse(state.showAbort) + } + } + + func testAffectedByLoadingStatesShowAbortInPlaceOfRefreshButtonWhenLoading() { + for state in Self.affectedByLoadingStates { + let state = state.init(voiceSearchHelper: MockVoiceSearchHelper(isSpeechRecognizerAvailable: false), isLoading: true) + + XCTAssertTrue(state.showAbort) + XCTAssertFalse(state.showRefresh) + } + } + + func testLoadingStateIsPreservedAcrossStates() { + let initialState = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: MockVoiceSearchHelper(isSpeechRecognizerAvailable: false), isLoading: false) + + let lastState = initialState + .withLoading() + .onBrowsingStartedState + .onBrowsingStoppedState + .onEditingSuspendedState + .onEnterPadState + .onBrowsingStartedState + .onEditingStoppedState + .onTextClearedState + .onTextEnteredState + .onEnterPhoneState + .onTextClearedState + .onTextEnteredState + + XCTAssertTrue(lastState.isLoading) + XCTAssertFalse(lastState.withoutLoading().isLoading) + } +} diff --git a/DuckDuckGoTests/QuerySubmittedTests.swift b/DuckDuckGoTests/QuerySubmittedTests.swift index da37da1e9f..1ece6508c2 100644 --- a/DuckDuckGoTests/QuerySubmittedTests.swift +++ b/DuckDuckGoTests/QuerySubmittedTests.swift @@ -125,6 +125,9 @@ final class MockOmniBarDelegate: OmniBarDelegate { // MARK: - Unused methods + func onAbortPressed() { + } + func onEditingEnd() -> OmniBarEditingEndResult { return .dismissed } diff --git a/DuckDuckGoTests/SmallOmniBarStateTests.swift b/DuckDuckGoTests/SmallOmniBarStateTests.swift index 93941a66a2..3cc7f5bf49 100644 --- a/DuckDuckGoTests/SmallOmniBarStateTests.swift +++ b/DuckDuckGoTests/SmallOmniBarStateTests.swift @@ -28,7 +28,7 @@ class SmallOmniBarStateTests: XCTestCase { let disabledVoiceSearchHelper = MockVoiceSearchHelper(isSpeechRecognizerAvailable: false) func testWhenInHomeEmptyEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) @@ -38,6 +38,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertTrue(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -47,7 +49,7 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenInHomeEmptyEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) @@ -57,6 +59,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertTrue(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) XCTAssertTrue(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -66,42 +70,42 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenEnteringHomeEmptyEditingStateThenTextIsCleared() { - let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.clearTextOnStart) } func testWhenInHomeEmptyEditingStateThenEditingStartedMaintainsState() { - let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenEditingStoppedTrainsitionsToNonEditingState() { - let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenEnteringTextTransitionsToTextEditingState() { - let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenClearingTextMaintainsState() { - let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenBrowsingStartedTransitionsToBrowsingNonEditingState() { - let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeEmptyEditingStateThenBrowsingStoppedMaintainsState() { - let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertTrue(testee.showClear) @@ -110,6 +114,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertTrue(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -119,7 +125,7 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenInHomeTextEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertTrue(testee.showClear) @@ -128,6 +134,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertTrue(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -137,42 +145,42 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenEnteringHomeTextEditingStateThenTextIsNotCleared() { - let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.clearTextOnStart) } func testWhenInHomeTextEditingStateThenEditingStartedMaintainsState() { - let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenEditingStoppedTrainsitionsToNonEditingState() { - let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenEnteringTextMaintainsState() { - let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenClearingTextTransitionsToEmptyEditingState() { - let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenBrowsingStartedTransitionsToBrowsingNonEditingState() { - let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeTextEditingStateThenBrowsingStoppedTransitionsToHomeTextEditingState() { - let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -181,6 +189,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -190,7 +200,7 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenInHomeNonEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -199,6 +209,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertTrue(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -208,42 +220,42 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenEnteringHomeNonEditingStateThenTextIsCleared() { - let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.clearTextOnStart) } func testWhenInHomeNonEditingStateThenEditingStartedTransitionsToEmptyEditingState() { - let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenEditingStoppedMaintainsState() { - let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenEnteringTextTransitionsToTextEditingState() { - let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.HomeTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenClearingTextTransitionsToEmptyEditingState() { - let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenBrowsingStartedTransitionsToBrowsingNonEditingState() { - let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInHomeNonEditingStateThenBrowsingStoppedTransitionsToHomeNonEditingState() { - let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowserEmptyEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -252,6 +264,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertTrue(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -261,7 +275,7 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenInBrowserEmptyEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -270,6 +284,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertTrue(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) XCTAssertTrue(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -279,42 +295,42 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenEnteringBrowserEmptyEditingStateThenTextIsCleared() { - let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.clearTextOnStart) } func testWhenInBrowsingEmptyEditingStateThenEditingStartedMaintainsState() { - let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenEditingStoppedTrainsitionsToBrowsingNonEditingState() { - let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenEnteringTextTransitionsToTextEditingState() { - let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenClearingMaintainsState() { - let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenBrowsingStartedMaintainsState() { - let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEmptyEditingStateThenBrowsingStoppedTransitionsToHomeEmptyEditingState() { - let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateWithoutVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: disabledVoiceSearchHelper) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: disabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertTrue(testee.showClear) @@ -323,6 +339,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertTrue(testee.showCancel) XCTAssertTrue(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -332,7 +350,7 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenInBrowsingTextEditingStateWithVoiceSearchThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.showBackground) XCTAssertFalse(testee.showPrivacyIcon) XCTAssertTrue(testee.showClear) @@ -341,6 +359,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertTrue(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) XCTAssertFalse(testee.showVoiceSearch) + XCTAssertFalse(testee.showAbort) + XCTAssertFalse(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -350,42 +370,42 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenEnteringBrowsingTextEditingStateThenTextIsMaintained() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.clearTextOnStart) } func testWhenInBrowsingTextEditingStateThenEditingStartedMaintainsState() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenEditingStoppedTrainsitionsToNonEditingState() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenEnteringTextMaintainstState() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenClearingTextTransitionsToEmptyEditingState() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenBrowsingStartedMaintainsState() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingTextEditingStateThenBrowsingStoppedTransitionsToHomeTextEditingState() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenCorrectButtonsAreShown() { - let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertTrue(testee.showBackground) XCTAssertTrue(testee.showPrivacyIcon) XCTAssertFalse(testee.showClear) @@ -393,6 +413,8 @@ class SmallOmniBarStateTests: XCTestCase { XCTAssertFalse(testee.showSettings) XCTAssertFalse(testee.showCancel) XCTAssertFalse(testee.showSearchLoupe) + XCTAssertFalse(testee.showAbort) + XCTAssertTrue(testee.showRefresh) XCTAssertFalse(testee.hasLargeWidth) XCTAssertFalse(testee.showBackButton) @@ -402,42 +424,42 @@ class SmallOmniBarStateTests: XCTestCase { } func testWhenEnteringBrowsingNonEditingStateThenTextIsMaintained() { - let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper) + let testee = SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) XCTAssertFalse(testee.clearTextOnStart) } func testWhenInBrowsingNonEditingStateThenToBrowsingTextEditingStartedState() { - let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.BrowsingTextEditingStartedState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStartedState.name, SmallOmniBarState.BrowsingTextEditingStartedState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingEditingStartedStateThenEnteringTextTransitionsToTextEditingState() { - let testee = SmallOmniBarState.BrowsingTextEditingStartedState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingTextEditingStartedState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenEditingStoppedMaintainsState() { - let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onEditingStoppedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenEnteringTextTransitionsToTextEditingState() { - let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextEnteredState.name, SmallOmniBarState.BrowsingTextEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenClearingTextTransitionsToEmptyEditingState() { - let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onTextClearedState.name, SmallOmniBarState.BrowsingEmptyEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenBrowsingStartedMaintainstState() { - let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStartedState.name, SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } func testWhenInBrowsingNonEditingStateThenBrowsingStoppedTransitionsToHomeNonEditingState() { - let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper) - XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper).name) + let testee = SmallOmniBarState.BrowsingNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false) + XCTAssertEqual(testee.onBrowsingStoppedState.name, SmallOmniBarState.HomeNonEditingState(voiceSearchHelper: enabledVoiceSearchHelper, isLoading: false).name) } } From 8739310ac4f9506a67c45eed4d3cf847b23bf3e6 Mon Sep 17 00:00:00 2001 From: Maxim Tsoy Date: Wed, 13 Nov 2024 22:19:55 +0100 Subject: [PATCH 17/56] Sync BSK with macos (#3561) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1206594217714678/1208738322889179/f Tech Design URL: CC: **Description**: **Steps to test this PR**: 1. 2. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Copy Testing**: * [ ] Use of correct apostrophes in new copy, ie `’` rather than `'` **Orientation Testing**: * [ ] Portrait * [ ] Landscape **Device Testing**: * [ ] iPhone SE (1st Gen) * [ ] iPhone 8 * [ ] iPhone X * [ ] iPhone 14 Pro * [ ] iPad **OS Testing**: * [ ] iOS 15 * [ ] iOS 16 * [ ] iOS 17 **Theme Testing**: * [ ] Light theme * [ ] Dark theme --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 401aeaa3e7..e73881c3aa 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10996,7 +10996,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 209.0.0; + version = 209.1.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c542bb4b81..16e6bef221 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "614ea57db48db644ce7f3a3de9c20c9a7fbb08ff", - "version" : "209.0.0" + "revision" : "948420e704ea4d9412a4fc3e2c2ab0d5ea5fe5d7", + "version" : "209.1.0" } }, { From 95897a71d6c75ed877c1baad334df8a902083f17 Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Thu, 14 Nov 2024 10:32:20 +0000 Subject: [PATCH 18/56] pixels for bookmarks > favorites tab (#3572) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/392891325557410/1208733952836859/f Tech Design URL: CC: **Description**: Pixels for bookmarks > favorites tab. **Steps to test this PR**: 1. Change DailyPixel.swift so that `hasBeenFiredToday` returns false 2. Add some favorites 3. Go to the bookmarks UI and tap on the favourites tab 4. Tap on manage -> pixel should fire `m_bookmarks_ui_favorites_manage_daily` 6. Exit edit mode 7. Edit a favorite -> pixel should fire `m_bookmarks_ui_favorites_action_daily` 8. Move a favorite -> pixel should fire `m_bookmarks_ui_favorites_action_daily` 9. Remove a favorite -> pixel should fire `m_bookmarks_ui_favorites_action_daily` 10. Check that actions on the new tab page do not fire the above pixels 11. Check the overlay does not trigger these pixels to fire --------- Co-authored-by: Mariusz Śpiewak --- Core/PixelEvent.swift | 6 ++++++ DuckDuckGo/BookmarksViewController.swift | 4 ++++ DuckDuckGo/FavoritesHomeViewSectionRenderer.swift | 12 ++++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 4fd41cf2f7..969bf6f637 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -207,6 +207,9 @@ extension Pixel { case bookmarkAddFavoriteBySwipe case bookmarkDeletedFromBookmark + case bookmarksUIFavoritesAction + case bookmarksUIFavoritesManage + case bookmarkImportSuccess case bookmarkImportFailure case bookmarkImportFailureParsingDL @@ -968,6 +971,9 @@ extension Pixel.Event { case .bookmarkAddFavoriteBySwipe: return "m_add_favorite_by_swipe" case .bookmarkDeletedFromBookmark: return "m_bookmark_deleted_from_bookmark" + case .bookmarksUIFavoritesAction: return "m_bookmarks_ui_favorites_action_daily" + case .bookmarksUIFavoritesManage: return "m_bookmarks_ui_favorites_manage_daily" + case .homeScreenShown: return "mh" case .homeScreenEditFavorite: return "mh_ef" case .homeScreenDeleteFavorite: return "mh_df" diff --git a/DuckDuckGo/BookmarksViewController.swift b/DuckDuckGo/BookmarksViewController.swift index 8d5f56f5ea..235afcd895 100644 --- a/DuckDuckGo/BookmarksViewController.swift +++ b/DuckDuckGo/BookmarksViewController.swift @@ -787,6 +787,10 @@ class BookmarksViewController: UIViewController, UITableViewDelegate { changeEditButtonToDone() configureToolbarMoreItem() refreshFooterView() + + if !favoritesContainer.isHidden { + DailyPixel.fireDaily(.bookmarksUIFavoritesManage) + } } private func finishEditing() { diff --git a/DuckDuckGo/FavoritesHomeViewSectionRenderer.swift b/DuckDuckGo/FavoritesHomeViewSectionRenderer.swift index e4cf90c408..0d1646f259 100644 --- a/DuckDuckGo/FavoritesHomeViewSectionRenderer.swift +++ b/DuckDuckGo/FavoritesHomeViewSectionRenderer.swift @@ -156,6 +156,7 @@ class FavoritesHomeViewSectionRenderer { guard let indexPath = collectionView.indexPath(for: cell), let favorite = viewModel.favorite(at: indexPath.row) else { return } Pixel.fire(pixel: .homeScreenDeleteFavorite) + fireActionPixel() viewModel.removeFavorite(favorite) WidgetCenter.shared.reloadAllTimelines() collectionView.performBatchUpdates { @@ -168,6 +169,7 @@ class FavoritesHomeViewSectionRenderer { guard let indexPath = collectionView.indexPath(for: cell), let favorite = viewModel.favorite(at: indexPath.row) else { return } Pixel.fire(pixel: .homeScreenEditFavorite) + fireActionPixel() controller?.favoritesRenderer(self, didRequestEdit: favorite) } @@ -272,7 +274,7 @@ class FavoritesHomeViewSectionRenderer { let dragItem = coordinator.items.first?.dragItem, let sourcePath = coordinator.items.first?.sourceIndexPath, let destinationPath = coordinator.destinationIndexPath, - let cell = self.collectionView(collectionView, cellForItemAt: sourcePath) as? FavoriteHomeCell, + let cell = collectionView.cellForItem(at: sourcePath) as? FavoriteHomeCell, let favorite = cell.favorite else { return } @@ -285,10 +287,11 @@ class FavoritesHomeViewSectionRenderer { coordinator.drop(dragItem, toItemAt: destinationPath) + fireActionPixel() } func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { - guard let cell = self.collectionView(collectionView, cellForItemAt: indexPath) as? FavoriteHomeCell else { return [] } + guard let cell = collectionView.cellForItem(at: indexPath) as? FavoriteHomeCell else { return [] } if let size = cell.iconImage.image?.size.width, size <= 32 { cell.iconBackground.backgroundColor = ThemeManager.shared.currentTheme.backgroundColor @@ -314,4 +317,9 @@ class FavoritesHomeViewSectionRenderer { return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath) } + /// Actions are only available from the bookmarks UI, so this is safe to send from here. + func fireActionPixel() { + DailyPixel.fire(pixel: .bookmarksUIFavoritesAction) + } + } From 3feecaf480d15ad12b2c80a88279ba8d2f2d8804 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Thu, 14 Nov 2024 12:55:23 +0100 Subject: [PATCH 19/56] Add support for local overrides for feature flags (#3571) Task/Issue URL: https://app.asana.com/0/72649045549333/1208716221426945/f Tech Design URL: https://app.asana.com/0/481882893211075/1208716218352496/f Description: This change is currently transparent to iOS because no feature flags support local overriding. --- Core/FeatureFlag.swift | 8 ++++++-- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- DuckDuckGoTests/DuckPlayerMocks.swift | 5 ++++- DuckDuckGoTests/MockFeatureFlagger.swift | 6 ++++-- .../NewTabPageShortcutsSettingsModelTests.swift | 5 ++++- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Core/FeatureFlag.swift b/Core/FeatureFlag.swift index de9c1df97e..eff7ca49c4 100644 --- a/Core/FeatureFlag.swift +++ b/Core/FeatureFlag.swift @@ -54,7 +54,11 @@ public enum FeatureFlag: String { case networkProtectionEnforceRoutes } -extension FeatureFlag: FeatureFlagSourceProviding { +extension FeatureFlag: FeatureFlagDescribing { + public var supportsLocalOverriding: Bool { + false + } + public var source: FeatureFlagSource { switch self { case .debugMenu: @@ -117,6 +121,6 @@ extension FeatureFlag: FeatureFlagSourceProviding { extension FeatureFlagger { public func isFeatureOn(_ featureFlag: FeatureFlag) -> Bool { - return isFeatureOn(forProvider: featureFlag) + return isFeatureOn(for: featureFlag) } } diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index e73881c3aa..e43e2b1e62 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10996,7 +10996,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 209.1.0; + version = 210.0.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 16e6bef221..ea6d72ec5a 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "948420e704ea4d9412a4fc3e2c2ab0d5ea5fe5d7", - "version" : "209.1.0" + "revision" : "cfb178099738bc6cd0c3a3d73df717420ef4a59f", + "version" : "210.0.0" } }, { diff --git a/DuckDuckGoTests/DuckPlayerMocks.swift b/DuckDuckGoTests/DuckPlayerMocks.swift index f593fa4dd9..7806c9d874 100644 --- a/DuckDuckGoTests/DuckPlayerMocks.swift +++ b/DuckDuckGoTests/DuckPlayerMocks.swift @@ -242,13 +242,16 @@ enum MockFeatureFlag: Hashable { } final class MockDuckPlayerFeatureFlagger: FeatureFlagger { + var internalUserDecider: InternalUserDecider = DefaultInternalUserDecider(store: MockInternalUserStoring()) + var localOverrides: FeatureFlagLocalOverriding? + var enabledFeatures: Set = [] func isFeatureOn(_ feature: MockFeatureFlag) -> Bool { return enabledFeatures.contains(feature) } - func isFeatureOn(forProvider provider: F) -> Bool where F: FeatureFlagSourceProviding { + func isFeatureOn(for featureFlag: Flag, allowOverride: Bool) -> Bool { return !enabledFeatures.isEmpty } } diff --git a/DuckDuckGoTests/MockFeatureFlagger.swift b/DuckDuckGoTests/MockFeatureFlagger.swift index 5434453927..9125dc769f 100644 --- a/DuckDuckGoTests/MockFeatureFlagger.swift +++ b/DuckDuckGoTests/MockFeatureFlagger.swift @@ -21,11 +21,13 @@ import BrowserServicesKit import Core final class MockFeatureFlagger: FeatureFlagger { + var internalUserDecider: InternalUserDecider = DefaultInternalUserDecider(store: MockInternalUserStoring()) + var localOverrides: FeatureFlagLocalOverriding? var enabledFeatureFlags: [FeatureFlag] = [] - func isFeatureOn(forProvider provider: F) -> Bool where F: BrowserServicesKit.FeatureFlagSourceProviding { - guard let flag = provider as? FeatureFlag else { + func isFeatureOn(for featureFlag: Flag, allowOverride: Bool) -> Bool { + guard let flag = featureFlag as? FeatureFlag else { return false } guard enabledFeatureFlags.contains(flag) else { diff --git a/DuckDuckGoTests/NewTabPageShortcutsSettingsModelTests.swift b/DuckDuckGoTests/NewTabPageShortcutsSettingsModelTests.swift index 62964ea0ef..9f3affb257 100644 --- a/DuckDuckGoTests/NewTabPageShortcutsSettingsModelTests.swift +++ b/DuckDuckGoTests/NewTabPageShortcutsSettingsModelTests.swift @@ -67,7 +67,10 @@ final class NewTabPageShortcutsSettingsModelTests: XCTestCase { } private final class AlwaysTrueFeatureFlagger: FeatureFlagger { - func isFeatureOn(forProvider: F) -> Bool where F: FeatureFlagSourceProviding { + var internalUserDecider: InternalUserDecider = DefaultInternalUserDecider(store: MockInternalUserStoring()) + var localOverrides: FeatureFlagLocalOverriding? + + func isFeatureOn(for featureFlag: Flag, allowOverride: Bool) -> Bool { true } } From c40417771879348634a45d01b89d18219c725f01 Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Thu, 14 Nov 2024 13:18:05 +0000 Subject: [PATCH 20/56] text zoom improvements (#3509) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/392891325557410/1206268893832417/f Tech Design URL: CC: **Description**: Makes it easier to access text zoom and allows per page state. **Steps to test this PR**: See test scenarios in Ship Review: https://app.asana.com/0/0/1208685664909495/f **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Copy Testing**: * [ ] Use of correct apostrophes in new copy, ie `’` rather than `'` **Orientation Testing**: * [ ] Portrait * [ ] Landscape **Device Testing**: * [ ] iPhone SE (1st Gen) * [ ] iPhone 8 * [ ] iPhone X * [ ] iPhone 14 Pro * [ ] iPad **OS Testing**: * [ ] iOS 15 * [ ] iOS 16 * [ ] iOS 17 **Theme Testing**: * [ ] Light theme * [ ] Dark theme --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- Core/FeatureFlag.swift | 3 + Core/Pixel.swift | 5 +- Core/PixelEvent.swift | 21 +- Core/TextSizeUserScript.swift | 58 ----- Core/UserDefaultsPropertyWrapper.swift | 7 +- Core/textsize.js | 154 ------------ DuckDuckGo.xcodeproj/project.pbxproj | 68 ++++-- .../xcshareddata/swiftpm/Package.resolved | 4 +- DuckDuckGo/AppDelegate.swift | 13 +- DuckDuckGo/AppSettings.swift | 2 +- DuckDuckGo/AppUserDefaults.swift | 19 +- .../TextSizeLarger.imageset/Contents.json | 15 -- .../Font-Larger-24.pdf | Bin 1058 -> 0 bytes .../TextSizeSmaller.imageset/Contents.json | 15 -- .../Font-Smaller-24.pdf | Bin 1054 -> 0 bytes DuckDuckGo/Base.lproj/Settings.storyboard | 165 +------------ DuckDuckGo/ContentBlockingUpdating.swift | 1 - DuckDuckGo/IntervalSlider.swift | 62 ++++- DuckDuckGo/MainViewController+Segues.swift | 3 +- DuckDuckGo/MainViewController.swift | 21 +- DuckDuckGo/SettingsAccessibilityView.swift | 44 ++-- DuckDuckGo/SettingsGeneralView.swift | 30 +-- DuckDuckGo/SettingsLegacyViewProvider.swift | 2 - DuckDuckGo/SettingsState.swift | 8 +- DuckDuckGo/SettingsViewModel.swift | 38 ++- DuckDuckGo/TabManager.swift | 23 +- DuckDuckGo/TabViewController.swift | 32 ++- ...bViewControllerBrowsingMenuExtension.swift | 6 +- ...ViewControllerLongPressMenuExtension.swift | 25 +- .../TextSizeSettingsViewController.swift | 221 ------------------ DuckDuckGo/TextZoomController.swift | 38 +++ DuckDuckGo/TextZoomCoordinator.swift | 181 ++++++++++++++ DuckDuckGo/TextZoomEditorModel.swift | 73 ++++++ DuckDuckGo/TextZoomEditorView.swift | 95 ++++++++ DuckDuckGo/TextZoomLevel.swift | 39 ++++ DuckDuckGo/TextZoomStorage.swift | 60 +++++ DuckDuckGo/UserScripts.swift | 5 +- DuckDuckGo/UserText.swift | 20 +- DuckDuckGo/en.lproj/Localizable.strings | 13 +- DuckDuckGoTests/AppSettingsMock.swift | 1 + .../ContentBlockingUpdatingTests.swift | 25 -- DuckDuckGoTests/MockFeatureFlagger.swift | 4 + DuckDuckGoTests/MockTabDelegate.swift | 3 +- DuckDuckGoTests/MockTextZoomCoordinator.swift | 55 +++++ .../OnboardingDaxFavouritesTests.swift | 4 +- .../OnboardingNavigationDelegateTests.swift | 4 +- DuckDuckGoTests/TextZoomTests.swift | 192 +++++++++++++++ 47 files changed, 1092 insertions(+), 785 deletions(-) delete mode 100644 Core/TextSizeUserScript.swift delete mode 100644 Core/textsize.js delete mode 100644 DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Contents.json delete mode 100644 DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Font-Larger-24.pdf delete mode 100644 DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Contents.json delete mode 100644 DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Font-Smaller-24.pdf delete mode 100644 DuckDuckGo/TextSizeSettingsViewController.swift create mode 100644 DuckDuckGo/TextZoomController.swift create mode 100644 DuckDuckGo/TextZoomCoordinator.swift create mode 100644 DuckDuckGo/TextZoomEditorModel.swift create mode 100644 DuckDuckGo/TextZoomEditorView.swift create mode 100644 DuckDuckGo/TextZoomLevel.swift create mode 100644 DuckDuckGo/TextZoomStorage.swift create mode 100644 DuckDuckGoTests/MockTextZoomCoordinator.swift create mode 100644 DuckDuckGoTests/TextZoomTests.swift diff --git a/Core/FeatureFlag.swift b/Core/FeatureFlag.swift index eff7ca49c4..81e9b34dd4 100644 --- a/Core/FeatureFlag.swift +++ b/Core/FeatureFlag.swift @@ -45,6 +45,7 @@ public enum FeatureFlag: String { case onboardingAddToDock case autofillSurveys case autcompleteTabs + case textZoom case adAttributionReporting /// https://app.asana.com/0/72649045549333/1208231259093710/f @@ -111,6 +112,8 @@ extension FeatureFlag: FeatureFlagDescribing { return .remoteReleasable(.feature(.autocompleteTabs)) case .networkProtectionUserTips: return .remoteReleasable(.subfeature(NetworkProtectionSubfeature.userTips)) + case .textZoom: + return .remoteReleasable(.feature(.textZoom)) case .networkProtectionEnforceRoutes: return .remoteDevelopment(.subfeature(NetworkProtectionSubfeature.enforceRoutes)) case .adAttributionReporting: diff --git a/Core/Pixel.swift b/Core/Pixel.swift index b0796afe64..fc2e7f3945 100644 --- a/Core/Pixel.swift +++ b/Core/Pixel.swift @@ -86,8 +86,9 @@ public struct PixelParameters { public static let count = "count" public static let source = "source" - public static let textSizeInitial = "text_size_initial" - public static let textSizeUpdated = "text_size_updated" + // Text size is the legacy name + public static let textZoomInitial = "text_size_initial" + public static let textZoomUpdated = "text_size_updated" public static let canAutoPreviewMIMEType = "can_auto_preview_mime_type" public static let mimeType = "mime_type" diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 969bf6f637..85416a001c 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -80,6 +80,7 @@ extension Pixel { case browsingMenuCopy case browsingMenuPrint case browsingMenuFindInPage + case browsingMenuZoom case browsingMenuDisableProtection case browsingMenuEnableProtection case browsingMenuReportBrokenSite @@ -220,8 +221,10 @@ extension Pixel { case bookmarkExportSuccess case bookmarkExportFailure - case textSizeSettingsChanged - + case textZoomSettingsChanged + case textZoomChangedOnPage + case textZoomChangedOnPageDaily + case downloadStarted case downloadStartedDueToUnhandledMIMEType case downloadTriedToPresentPreviewWithoutTab @@ -748,7 +751,7 @@ extension Pixel { case settingsRecentlyVisitedOff case settingsAddressBarSelectorPressed case settingsAccessibilityOpen - case settingsAccessiblityTextSize + case settingsAccessiblityTextZoom // Web pixels case privacyProOfferMonthlyPriceClick @@ -927,6 +930,7 @@ extension Pixel.Event { case .browsingMenuCopy: return "mb_cp" case .browsingMenuPrint: return "mb_pr" case .browsingMenuFindInPage: return "mb_fp" + case .browsingMenuZoom: return "m_menu_page_zoom_taps" case .browsingMenuDisableProtection: return "mb_wla" case .browsingMenuEnableProtection: return "mb_wlr" case .browsingMenuReportBrokenSite: return "mb_rb" @@ -1063,8 +1067,11 @@ extension Pixel.Event { case .bookmarkExportSuccess: return "m_be_a" case .bookmarkExportFailure: return "m_be_e" - case .textSizeSettingsChanged: return "m_text_size_settings_changed" - + // Text size is the legacy name + case .textZoomSettingsChanged: return "m_text_size_settings_changed" + case .textZoomChangedOnPageDaily: return "m_menu_page_zoom_changed_daily" + case .textZoomChangedOnPage: return "m_menu_page_zoom_changed" + case .downloadStarted: return "m_download_started" case .downloadStartedDueToUnhandledMIMEType: return "m_download_started_due_to_unhandled_mime_type" case .downloadTriedToPresentPreviewWithoutTab: return "m_download_tried_to_present_preview_without_tab" @@ -1590,7 +1597,9 @@ extension Pixel.Event { case .settingsRecentlyVisitedOff: return "m_settings_autocomplete_recently-visited_off" case .settingsAddressBarSelectorPressed: return "m_settings_address_bar_selector_pressed" case .settingsAccessibilityOpen: return "m_settings_accessibility_open" - case .settingsAccessiblityTextSize: return "m_settings_accessiblity_text_size" + + // legacy name is text size + case .settingsAccessiblityTextZoom: return "m_settings_accessiblity_text_size" // Web case .privacyProOfferMonthlyPriceClick: return "m_privacy-pro_offer_monthly-price_click" diff --git a/Core/TextSizeUserScript.swift b/Core/TextSizeUserScript.swift deleted file mode 100644 index a246d48e63..0000000000 --- a/Core/TextSizeUserScript.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// TextSizeUserScript.swift -// DuckDuckGo -// -// Copyright © 2021 DuckDuckGo. All rights reserved. -// -// 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. -// - -import Foundation -import WebKit -import UserScript - -public class TextSizeUserScript: NSObject, UserScript { - - public static let knownDynamicTypeExceptions: [String] = ["wikipedia.org"] - public var textSizeAdjustmentInPercents: Int = 100 - - public var source: String { TextSizeUserScript.makeSource(for: textSizeAdjustmentInPercents) } - - public var injectionTime: WKUserScriptInjectionTime = .atDocumentStart - public var forMainFrameOnly: Bool = false - public var messageNames: [String] = [] - - public init(textSizeAdjustmentInPercents: Int) { - self.textSizeAdjustmentInPercents = textSizeAdjustmentInPercents - } - - public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { } - - fileprivate static func makeSource(for textSizeAdjustmentInPercents: Int) -> String { - let dynamicTypeScalePercentage = UIFontMetrics.default.scaledValue(for: 100) - - return loadJS("textsize", from: Bundle.core, withReplacements: [ - "$KNOWN_DYNAMIC_TYPE_EXCEPTIONS$": knownDynamicTypeExceptions.joined(separator: "\n"), - "$TEXT_SIZE_ADJUSTMENT_IN_PERCENTS$": "\(textSizeAdjustmentInPercents)", - "$DYNAMIC_TYPE_SCALE_PERCENTAGE$": "\(dynamicTypeScalePercentage)" - ]) - } -} - -public extension WKWebView { - - func adjustTextSize(_ percentage: Int) { - let jsString = TextSizeUserScript.makeSource(for: percentage) - evaluateJavaScript(jsString, completionHandler: nil) - } -} diff --git a/Core/UserDefaultsPropertyWrapper.swift b/Core/UserDefaultsPropertyWrapper.swift index eae3ee9842..ac6a5a6bdf 100644 --- a/Core/UserDefaultsPropertyWrapper.swift +++ b/Core/UserDefaultsPropertyWrapper.swift @@ -75,7 +75,9 @@ public struct UserDefaultsWrapper { case downloadedSurrogatesCount = "com.duckduckgo.app.downloadedSurrogatesCount" case downloadedTrackerDataSetCount = "com.duckduckgo.app.downloadedTrackerDataSetCount" case downloadedPrivacyConfigurationCount = "com.duckduckgo.app.downloadedPrivacyConfigurationCount" - case textSize = "com.duckduckgo.ios.textSize" + + // Text size is the legacy name and this key is still in use + case textZoom = "com.duckduckgo.ios.textSize" case emailWaitlistShouldReceiveNotifications = "com.duckduckgo.ios.showWaitlistNotification" case unseenDownloadsAvailable = "com.duckduckgo.app.unseenDownloadsAvailable" @@ -179,6 +181,9 @@ public struct UserDefaultsWrapper { case duckPlayerPixelExperimentLastVideoIDRendered = "com.duckduckgo.ios.duckplayer.pixel.experiment.last.videoID.rendered.v2" case duckPlayerPixelExperimentOverride = "com.duckduckgo.ios.duckplayer.pixel.experiment.override.v2" + // Domain specific text zoom + case domainTextZoomStorage = "com.duckduckgo.ios.domainTextZoomStorage" + // TipKit case resetTipKitOnNextLaunch = "com.duckduckgo.ios.tipKit.resetOnNextLaunch" } diff --git a/Core/textsize.js b/Core/textsize.js deleted file mode 100644 index 98a434ad82..0000000000 --- a/Core/textsize.js +++ /dev/null @@ -1,154 +0,0 @@ -// -// textsize.js -// DuckDuckGo -// -// Copyright © 2021 DuckDuckGo. All rights reserved. -// -// 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. -// - -(function() { - let hostname = getTopLevelURL().hostname; - - let knownDynamicTypeExceptions = `$KNOWN_DYNAMIC_TYPE_EXCEPTIONS$`.split("\n"); - - let shouldAdjustForDynamicType = isURLMatchingAnyOfDomains(hostname, knownDynamicTypeExceptions); - let isDDG = isURLMatchingDomain(hostname, "duckduckgo.com"); - - let currentTextSizeAdjustment = $TEXT_SIZE_ADJUSTMENT_IN_PERCENTS$; - - if (document.readyState === "complete" - || document.readyState === "loaded" - || document.readyState === "interactive") { - // DOM should have been parsed - adjustTextSize(currentTextSizeAdjustment); - } else { - // DOM not yet ready, add a listener instead - if ((shouldAdjustForDynamicType) || (isDDG) || (currentTextSizeAdjustment != 100)) { - document.addEventListener("DOMContentLoaded", function(event) { - adjustTextSize(currentTextSizeAdjustment); - }, false) - } - } - - function getTopLevelURL() { - try { - // FROM: https://stackoverflow.com/a/7739035/73479 - // FIX: Better capturing of top level URL so that trackers in embedded documents are not considered first party - return new URL(window.location != window.parent.location ? document.referrer : document.location.href) - } catch(error) { - return new URL(location.href) - } - } - - function isURLMatchingDomain(url, domain) { - var urlParts = url.split('.'); - - while (urlParts.length > 1) { - if (domain === urlParts.join('.')) { - return true; - } - - urlParts.shift(); - } - - return false; - } - - function isURLMatchingAnyOfDomains(url, domains) { - for (const domain of domains) { - if (isURLMatchingDomain(url, domain)) { - return true - } - } - - return false - } - - function adjustTextSize(percentage) { - if (shouldAdjustForDynamicType) { - adjustTextSizeForDynamicType(percentage); - } else if (isDDG && (typeof DDG !== 'undefined')) { - adjustTextSizeForDDG(percentage); - } else { - document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust=percentage+"%"; - } - } - - function adjustTextSizeForDynamicType(percentage) { - let dynamicTypeAdjustment = $DYNAMIC_TYPE_SCALE_PERCENTAGE$; - var adjustedPercentage = percentage * 100/dynamicTypeAdjustment; - - document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust=adjustedPercentage+"%"; - } - - function adjustTextSizeForDDG(percentage) { - var adjustedPercentage = 100; - - // Fix for side menu sliding in when growing due to increased text - let menu = document.getElementsByClassName('nav-menu--slideout')[0]; - let previousLeft = menu.style.left; - menu.style.left="-100%"; - - // Force re-painting of the menu: https://stackoverflow.com/a/3485654 - menu.style.display='none'; - menu.offsetHeight; // no need to store this anywhere, the reference is enough - menu.style.display='block'; - - switch(percentage) { - case 80: - DDG.settings.set('ks', 's'); - break; - case 90: - DDG.settings.set('ks', 'm'); - break; - case 100: - DDG.settings.set('ks', 'n'); - break; - case 110: - DDG.settings.set('ks', 'n'); - adjustedPercentage = 105; - break; - case 120: - DDG.settings.set('ks', 'l'); - break; - case 130: - DDG.settings.set('ks', 'l'); - adjustedPercentage = 105; - break; - case 140: - DDG.settings.set('ks', 'l'); - adjustedPercentage = 110; - break; - case 150: - DDG.settings.set('ks', 't'); - break; - case 160: - DDG.settings.set('ks', 't'); - adjustedPercentage = 105; - break; - case 170: - DDG.settings.set('ks', 't'); - adjustedPercentage = 110; - break; - default: - DDG.settings.set('ks', 'n'); - break; - } - - document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust=adjustedPercentage+"%"; - - menu.style.left = previousLeft; - } - -}) (); diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index e43e2b1e62..310c116fad 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -78,7 +78,6 @@ 1E60989B290009C700A508F9 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 1E7060BD28F88EE200E4CCDB /* Common */; }; 1E60989D290011E600A508F9 /* ContentBlocking in Frameworks */ = {isa = PBXBuildFile; productRef = 1E60989C290011E600A508F9 /* ContentBlocking */; }; 1E6098A1290011E600A508F9 /* UserScript in Frameworks */ = {isa = PBXBuildFile; productRef = 1E6098A0290011E600A508F9 /* UserScript */; }; - 1E61BC2A27074BED00B2854D /* TextSizeUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E61BC2927074BED00B2854D /* TextSizeUserScript.swift */; }; 1E6A4D692984208800A371D3 /* LocaleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E6A4D682984208800A371D3 /* LocaleExtension.swift */; }; 1E722729292EB24D003B5F53 /* AppSettingsMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AD9E3C28D46FD50019CDE9 /* AppSettingsMock.swift */; }; 1E7A71172934EB6400B7EA19 /* OmniBarNotificationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7A71162934EB6400B7EA19 /* OmniBarNotificationAnimator.swift */; }; @@ -86,7 +85,6 @@ 1E7A711C2934EEBC00B7EA19 /* OmniBarNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7A711B2934EEBC00B7EA19 /* OmniBarNotification.swift */; }; 1E8146AD28C8ABF000D1AF63 /* TrackerAnimationLogicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E8146A728C8AB3F00D1AF63 /* TrackerAnimationLogicTests.swift */; }; 1E8146AE28C8ABF400D1AF63 /* PrivacyIconLogicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E8146A928C8AB8200D1AF63 /* PrivacyIconLogicTests.swift */; }; - 1E865AF0272042DB001C74F3 /* TextSizeSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E865AEF272042DB001C74F3 /* TextSizeSettingsViewController.swift */; }; 1E87615928A1517200C7C5CE /* PrivacyDashboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E87615828A1517200C7C5CE /* PrivacyDashboardViewController.swift */; }; 1E8AD1C727BE9B2900ABA377 /* DownloadsListDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E8AD1C627BE9B2900ABA377 /* DownloadsListDataSource.swift */; }; 1E8AD1C927BFAD1500ABA377 /* DirectoryMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E8AD1C827BFAD1500ABA377 /* DirectoryMonitor.swift */; }; @@ -126,7 +124,6 @@ 1EEF12532851D32B003DDE57 /* trackers-2.json in Resources */ = {isa = PBXBuildFile; fileRef = 1EEF12512851D32A003DDE57 /* trackers-2.json */; }; 1EEF12542851D32B003DDE57 /* trackers-1.json in Resources */ = {isa = PBXBuildFile; fileRef = 1EEF12522851D32A003DDE57 /* trackers-1.json */; }; 1EEF387D285B1A1100383393 /* TrackerImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EEF387C285B1A1100383393 /* TrackerImageCache.swift */; }; - 1EEFD2D52758E31600B1393B /* textsize.js in Resources */ = {isa = PBXBuildFile; fileRef = 1EEFD2D42758E31600B1393B /* textsize.js */; }; 1EF24235273BB9D200DE3D02 /* IntervalSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EF24234273BB9D200DE3D02 /* IntervalSlider.swift */; }; 1EFDCBC127D2393C00916BC5 /* DownloadsDeleteHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EFDCBC027D2393C00916BC5 /* DownloadsDeleteHelper.swift */; }; 22CB1ED8203DDD2C00D2C724 /* AppDeepLinksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22CB1ED7203DDD2C00D2C724 /* AppDeepLinksTests.swift */; }; @@ -525,6 +522,14 @@ 8596C30D2B7EB1800058EF90 /* DataStoreWarmup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8596C30C2B7EB1800058EF90 /* DataStoreWarmup.swift */; }; 8598F67B2405EB8D00FBC70C /* KeyboardSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8598F6792405EB8600FBC70C /* KeyboardSettingsTests.swift */; }; 8599690F29D2F1C100DBF9FA /* DDGSync in Frameworks */ = {isa = PBXBuildFile; productRef = 8599690E29D2F1C100DBF9FA /* DDGSync */; }; + 859DB8132CE6263C001F7210 /* TextZoomStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DB80D2CE6263B001F7210 /* TextZoomStorage.swift */; }; + 859DB8142CE6263C001F7210 /* TextZoomController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DB80E2CE6263B001F7210 /* TextZoomController.swift */; }; + 859DB8152CE6263C001F7210 /* TextZoomEditorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DB80F2CE6263C001F7210 /* TextZoomEditorModel.swift */; }; + 859DB8162CE6263C001F7210 /* TextZoomEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DB8102CE6263C001F7210 /* TextZoomEditorView.swift */; }; + 859DB8172CE6263C001F7210 /* TextZoomLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DB8112CE6263C001F7210 /* TextZoomLevel.swift */; }; + 859DB8182CE6263C001F7210 /* TextZoomCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DB8122CE6263C001F7210 /* TextZoomCoordinator.swift */; }; + 859DB81C2CE6268C001F7210 /* MockTextZoomCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DB81A2CE6268C001F7210 /* MockTextZoomCoordinator.swift */; }; + 859DB81E2CE62766001F7210 /* TextZoomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DB81B2CE6268C001F7210 /* TextZoomTests.swift */; }; 85A1B3B220C6CD9900C18F15 /* CookieStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A1B3B120C6CD9900C18F15 /* CookieStorage.swift */; }; 85A313972028E78A00327D00 /* release_notes.txt in Resources */ = {isa = PBXBuildFile; fileRef = 85A313962028E78A00327D00 /* release_notes.txt */; }; 85A9C37920E0E00C00073340 /* HomeRow.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 85A9C37820E0E00C00073340 /* HomeRow.xcassets */; }; @@ -1396,7 +1401,6 @@ 1E4FAA6327D8DFB900ADC5B3 /* OngoingDownloadRowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OngoingDownloadRowViewModel.swift; sourceTree = ""; }; 1E4FAA6527D8DFC800ADC5B3 /* CompleteDownloadRowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompleteDownloadRowViewModel.swift; sourceTree = ""; }; 1E53508E2C7C9A1F00818DAA /* DefaultSubscriptionManager+AccountManagerKeychainAccessDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DefaultSubscriptionManager+AccountManagerKeychainAccessDelegate.swift"; sourceTree = ""; }; - 1E61BC2927074BED00B2854D /* TextSizeUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextSizeUserScript.swift; sourceTree = ""; }; 1E6A4D682984208800A371D3 /* LocaleExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocaleExtension.swift; sourceTree = ""; }; 1E7A71162934EB6400B7EA19 /* OmniBarNotificationAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBarNotificationAnimator.swift; sourceTree = ""; }; 1E7A71182934EC6100B7EA19 /* OmniBarNotificationContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBarNotificationContainerView.swift; sourceTree = ""; }; @@ -1443,7 +1447,6 @@ 1EEF12512851D32A003DDE57 /* trackers-2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "trackers-2.json"; sourceTree = ""; }; 1EEF12522851D32A003DDE57 /* trackers-1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "trackers-1.json"; sourceTree = ""; }; 1EEF387C285B1A1100383393 /* TrackerImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackerImageCache.swift; sourceTree = ""; }; - 1EEFD2D42758E31600B1393B /* textsize.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = textsize.js; sourceTree = ""; }; 1EF24234273BB9D200DE3D02 /* IntervalSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntervalSlider.swift; sourceTree = ""; }; 1EFDCBC027D2393C00916BC5 /* DownloadsDeleteHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsDeleteHelper.swift; sourceTree = ""; }; 22CB1ED7203DDD2C00D2C724 /* AppDeepLinksTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDeepLinksTests.swift; sourceTree = ""; }; @@ -1832,6 +1835,14 @@ 8590CB68268A4E190089F6BF /* DebugEtagStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugEtagStorage.swift; sourceTree = ""; }; 8596C30C2B7EB1800058EF90 /* DataStoreWarmup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStoreWarmup.swift; sourceTree = ""; }; 8598F6792405EB8600FBC70C /* KeyboardSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardSettingsTests.swift; sourceTree = ""; }; + 859DB80D2CE6263B001F7210 /* TextZoomStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextZoomStorage.swift; sourceTree = ""; }; + 859DB80E2CE6263B001F7210 /* TextZoomController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextZoomController.swift; sourceTree = ""; }; + 859DB80F2CE6263C001F7210 /* TextZoomEditorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextZoomEditorModel.swift; sourceTree = ""; }; + 859DB8102CE6263C001F7210 /* TextZoomEditorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextZoomEditorView.swift; sourceTree = ""; }; + 859DB8112CE6263C001F7210 /* TextZoomLevel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextZoomLevel.swift; sourceTree = ""; }; + 859DB8122CE6263C001F7210 /* TextZoomCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextZoomCoordinator.swift; sourceTree = ""; }; + 859DB81A2CE6268C001F7210 /* MockTextZoomCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockTextZoomCoordinator.swift; sourceTree = ""; }; + 859DB81B2CE6268C001F7210 /* TextZoomTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextZoomTests.swift; sourceTree = ""; }; 85A1B3B120C6CD9900C18F15 /* CookieStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CookieStorage.swift; sourceTree = ""; }; 85A313962028E78A00327D00 /* release_notes.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = release_notes.txt; path = fastlane/metadata/default/release_notes.txt; sourceTree = ""; }; 85A53EC9200D1FA20010D13F /* FileStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileStore.swift; sourceTree = ""; }; @@ -4230,21 +4241,22 @@ 37CF915E2BB4735F00BADCAE /* Crashes */, D6E0C1812B7A2B0700D5E1E9 /* DesktopDownloads */, 310D09192799EF5C00DC0060 /* Downloads */, - D63FF8922C1B67D1006DE24D /* DuckPlayer */, F143C2C51E4A08F300CFDE3A /* DuckDuckGo.entitlements */, EE3B98EA2A9634CC002F63A0 /* DuckDuckGoAlpha.entitlements */, + D63FF8922C1B67D1006DE24D /* DuckPlayer */, C159DF052A430B36007834BB /* EmailProtection */, 3157B43627F4C8380042D3D7 /* Favicons */, 839F119520DBC489007CD8C2 /* Feedback */, 85F2FFFE2215C163006BB258 /* FindInPage */, - F13B4BF31F18C73A00814661 /* NewTabPage */, 84E341A11E2F7EFB00BDBA6F /* Info.plist */, 98B001B1251EABB40090EC07 /* InfoPlist.strings */, 85DFEDEB24C7CC7600973FE7 /* iPad */, F1C5ECFA1E37B15B00C599A4 /* Main */, EECD94B22A28B8580085C66E /* NetworkProtection */, + F13B4BF31F18C73A00814661 /* NewTabPage */, 85AE668C20971FCA0014CF04 /* Notifications */, F1C4A70C1E5771F800A6CA1B /* OmniBar */, + CB48D32F2B90CE8500631D8B /* PageRefreshMonitor */, F1AE54DB1F0425BB00D9A700 /* Privacy */, F1DF09502B039E6E008CC908 /* PrivacyDashboard */, 02ECEC602A965074009F0654 /* PrivacyInfo.xcprivacy */, @@ -4255,10 +4267,10 @@ 85F98F8C296F0ED100742F4A /* Sync */, F13B4BF41F18C74500814661 /* Tabs */, F1386BA21E6846320062FC3C /* TabSwitcher */, + 859DB80C2CE6262A001F7210 /* TextZoom */, 98F3A1D6217B36EE0011A0D4 /* Themes */, 7BF78E002CA2CC100026A1FC /* TipKit */, F11CEF581EBB66C80088E4D7 /* Tutorials */, - CB48D32F2B90CE8500631D8B /* PageRefreshMonitor */, F1D796ED1E7AE4090019D451 /* UserInterface */, 84E341E31E2FC0E400BDBA6F /* UserInterfaceResources */, 3151F0E827357F8F00226F58 /* VoiceSearch */, @@ -4466,7 +4478,6 @@ isa = PBXGroup; children = ( 4B60AC96252EC07B00E8D219 /* fullscreenvideo.js */, - 1EEFD2D42758E31600B1393B /* textsize.js */, ); name = "ios-js-support"; sourceTree = ""; @@ -4479,6 +4490,28 @@ name = FireAnimation; sourceTree = ""; }; + 859DB80C2CE6262A001F7210 /* TextZoom */ = { + isa = PBXGroup; + children = ( + 859DB80E2CE6263B001F7210 /* TextZoomController.swift */, + 859DB8122CE6263C001F7210 /* TextZoomCoordinator.swift */, + 859DB80F2CE6263C001F7210 /* TextZoomEditorModel.swift */, + 859DB8102CE6263C001F7210 /* TextZoomEditorView.swift */, + 859DB8112CE6263C001F7210 /* TextZoomLevel.swift */, + 859DB80D2CE6263B001F7210 /* TextZoomStorage.swift */, + ); + name = TextZoom; + sourceTree = ""; + }; + 859DB8192CE6265F001F7210 /* TextZoom */ = { + isa = PBXGroup; + children = ( + 859DB81A2CE6268C001F7210 /* MockTextZoomCoordinator.swift */, + 859DB81B2CE6268C001F7210 /* TextZoomTests.swift */, + ); + name = TextZoom; + sourceTree = ""; + }; 85AE668C20971FCA0014CF04 /* Notifications */ = { isa = PBXGroup; children = ( @@ -5764,10 +5797,10 @@ F12D98401F266B30003C2EE3 /* DuckDuckGo */ = { isa = PBXGroup; children = ( - 851952692CE2569600578553 /* Autocomplete */, 6FF9157F2B88E04F0042AC87 /* AdAttribution */, F17669A21E411D63003D3222 /* Application */, 981FED7222045FFA008488D7 /* AutoClear */, + 851952692CE2569600578553 /* Autocomplete */, 1E1D8B5B2994FF7800C96994 /* Autoconsent */, F40F843228C92B1C0081AE75 /* Autofill */, 98559FD0267099F400A83094 /* ContentBlocker */, @@ -5784,6 +5817,7 @@ F1BDDBFC2C340D9C00459306 /* Subscription */, 569437222BDD402600C0881B /* Sync */, F13B4BF71F18C9E800814661 /* Tabs */, + 859DB8192CE6265F001F7210 /* TextZoom */, 98EA2C3A218B9A880023E1DC /* Themes */, F12790DD1EBBDDF3001D3AEC /* Tutorials */, F194FAF91F14E605009B4DF8 /* UserInterface */, @@ -5979,7 +6013,6 @@ 850559CF23CF647C0055C0D5 /* PreserveLogins.swift */, 4B75EA9126A266CB00018634 /* PrintingUserScript.swift */, 988F3DCE237D5C0F00AEE34C /* SchemeHandler.swift */, - 1E61BC2927074BED00B2854D /* TextSizeUserScript.swift */, 836A941C247F23C600BF8EF5 /* UserAgentManager.swift */, F1A886771F29394E0096251E /* WebCacheManager.swift */, 83004E7F2193BB8200DA013C /* WKNavigationExtension.swift */, @@ -7177,7 +7210,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1EEFD2D52758E31600B1393B /* textsize.js in Resources */, 83E2D2B4253CC16B005605F5 /* httpsMobileV2BloomSpec.json in Resources */, 98B001B0251EABB40090EC07 /* InfoPlist.strings in Resources */, 02BA15B126A89ECA00472DD7 /* ios-config.json in Resources */, @@ -7471,6 +7503,7 @@ 853C5F6121C277C7001F7A05 /* global.swift in Sources */, EE9D68D82AE15AD600B55EF4 /* UIApplicationExtension.swift in Sources */, 566B73702BECD46800FF1959 /* MainViewController+SyncAlerts.swift in Sources */, + 859DB8182CE6263C001F7210 /* TextZoomCoordinator.swift in Sources */, 6F0FEF6B2C516D540090CDE4 /* NewTabPageSettingsStorage.swift in Sources */, F13B4BD31F1822C700814661 /* Tab.swift in Sources */, BDFF031D2BA3D2BD00F324C9 /* DefaultNetworkProtectionVisibility.swift in Sources */, @@ -7513,9 +7546,11 @@ 1E1626072968413B0004127F /* ViewExtension.swift in Sources */, 31A42566285A0A6300049386 /* FaviconViewModel.swift in Sources */, 6F691CCA2C4979EC002E9553 /* FavoritesTooltip.swift in Sources */, + 859DB8132CE6263C001F7210 /* TextZoomStorage.swift in Sources */, D65625952C22D382006EF297 /* TabViewController.swift in Sources */, 8C4838B5221C8F7F008A6739 /* GestureToolbarButton.swift in Sources */, 310ECFDD282A8BB0005029B3 /* EnableAutofillSettingsTableViewCell.swift in Sources */, + 859DB8172CE6263C001F7210 /* TextZoomLevel.swift in Sources */, BDE91CD62C6294020005CB74 /* FeedbackCategoryProviding.swift in Sources */, 6F9FFE2A2C57ADB100A238BE /* EditableShortcutsView.swift in Sources */, 1E908BF329827C480008C8F3 /* AutoconsentManagement.swift in Sources */, @@ -7538,6 +7573,7 @@ CB258D1329A4F24E00DEBA24 /* ConfigurationStore.swift in Sources */, 85058370219F424500ED4EDB /* SearchBarExtension.swift in Sources */, 310D09212799FD1A00DC0060 /* MIMEType.swift in Sources */, + 859DB8152CE6263C001F7210 /* TextZoomEditorModel.swift in Sources */, D668D9292B69681C008E2FF2 /* IdentityTheftRestorationPagesUserScript.swift in Sources */, D64648AD2B59936B0033090B /* SubscriptionEmailView.swift in Sources */, BD862E032B30DA170073E2EE /* VPNFeedbackFormViewModel.swift in Sources */, @@ -7596,6 +7632,7 @@ C1641EAF2BC2F5140012607A /* ImportPasswordsViewController.swift in Sources */, D63FF8982C1B6A45006DE24D /* DuckPlayer.swift in Sources */, 85B9CB8921AEBDD5009001F1 /* FavoriteHomeCell.swift in Sources */, + 859DB81C2CE6268C001F7210 /* MockTextZoomCoordinator.swift in Sources */, 1E39BEB02CC9477200496FBA /* SubscriptionCookieManageEventPixelMapping.swift in Sources */, C1935A102C88D131001AD72D /* AutofillSurveyManager.swift in Sources */, 7B1604EE2CB68D2600A44EC6 /* TipKitDebugOptionsUIActionHandling.swift in Sources */, @@ -7641,6 +7678,7 @@ D66F683D2BB333C100AE93E2 /* SubscriptionContainerView.swift in Sources */, 851B128822200575004781BC /* Onboarding.swift in Sources */, 9FB027192C26BC29009EA190 /* BrowsersComparisonModel.swift in Sources */, + 859DB8142CE6263C001F7210 /* TextZoomController.swift in Sources */, F1EFB0062C5B8B8E009AB44B /* StatusIndicatorView.swift in Sources */, EE5929622C5A8AF40029380B /* AutofillUsageMonitor.swift in Sources */, 3151F0EE2735800800226F58 /* VoiceSearchFeedbackView.swift in Sources */, @@ -7843,6 +7881,7 @@ 4B5C462A2AF2A6E6002A4432 /* VPNIntents.swift in Sources */, 310742A62848CD780012660B /* BackForwardMenuHistoryItem.swift in Sources */, 9FDEC7B82C9004D600C7A692 /* OnboardingIntroViewModel+Copy.swift in Sources */, + 859DB8162CE6263C001F7210 /* TextZoomEditorView.swift in Sources */, 858566FB252E55D6007501B8 /* ImageCacheDebugViewController.swift in Sources */, D6E0C1832B7A2B1E00D5E1E9 /* DesktopDownloadView.swift in Sources */, 1E7A71172934EB6400B7EA19 /* OmniBarNotificationAnimator.swift in Sources */, @@ -7934,7 +7973,6 @@ 1E8AD1D727C2E24E00ABA377 /* DownloadsListRowViewModel.swift in Sources */, 9FEA222E2C324ECD006B03BF /* ViewVisibility.swift in Sources */, BD10B8AA2C7629740033115D /* Logger+Subscription.swift in Sources */, - 1E865AF0272042DB001C74F3 /* TextSizeSettingsViewController.swift in Sources */, D6E0C1892B7A2E0D00D5E1E9 /* DesktopDownloadViewModel.swift in Sources */, 8524CC9A246DA81700E59D45 /* FullscreenDaxDialogViewController.swift in Sources */, 9F23B8012C2BC94400950875 /* OnboardingBackground.swift in Sources */, @@ -8006,6 +8044,7 @@ 1E722729292EB24D003B5F53 /* AppSettingsMock.swift in Sources */, 8536A1C8209AF2410050739E /* MockVariantManager.swift in Sources */, C1B7B53428944EFA0098FD6A /* CoreDataTestUtilities.swift in Sources */, + 859DB81E2CE62766001F7210 /* TextZoomTests.swift in Sources */, 1DE384E42BC41E2500871AF6 /* PixelExperimentTests.swift in Sources */, CBDD5DE129A6741300832877 /* MockBundle.swift in Sources */, C158AC7B297AB5DC0008723A /* MockSecureVault.swift in Sources */, @@ -8348,7 +8387,6 @@ 85CA53A824BB343700A6288C /* Favicons.swift in Sources */, F143C3181E4A99D200CFDE3A /* Link.swift in Sources */, 6F03CB092C32F331004179A8 /* PixelFiringAsync.swift in Sources */, - 1E61BC2A27074BED00B2854D /* TextSizeUserScript.swift in Sources */, 37CEFCAC2A673B90001EF741 /* CredentialsCleanupErrorHandling.swift in Sources */, CB2A7EF128410DF700885F67 /* PixelEvent.swift in Sources */, 85D2187624BF6164004373D2 /* FaviconSourcesProvider.swift in Sources */, @@ -10996,7 +11034,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 210.0.0; + version = 210.0.1; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ea6d72ec5a..3234f8630b 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "cfb178099738bc6cd0c3a3d73df717420ef4a59f", - "version" : "210.0.0" + "revision" : "183b9c111176fd7821cd17d01c01ddb38486c9ac", + "version" : "210.0.1" } }, { diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index 52bc2e1ac9..4305c5b418 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -355,7 +355,9 @@ import os.log contextualOnboardingPixelReporter: onboardingPixelReporter, subscriptionFeatureAvailability: subscriptionFeatureAvailability, voiceSearchHelper: voiceSearchHelper, - subscriptionCookieManager: subscriptionCookieManager) + featureFlagger: AppDependencyProvider.shared.featureFlagger, + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: makeTextZoomCoordinator()) main.loadViewIfNeeded() syncErrorHandler.alertPresenter = main @@ -408,6 +410,15 @@ import os.log return true } + private func makeTextZoomCoordinator() -> TextZoomCoordinator { + let provider = AppDependencyProvider.shared + let storage = TextZoomStorage() + + return TextZoomCoordinator(appSettings: provider.appSettings, + storage: storage, + featureFlagger: provider.featureFlagger) + } + private func makeSubscriptionCookieManager() -> SubscriptionCookieManaging { let subscriptionCookieManager = SubscriptionCookieManager(subscriptionManager: AppDependencyProvider.shared.subscriptionManager, currentCookieStore: { [weak self] in diff --git a/DuckDuckGo/AppSettings.swift b/DuckDuckGo/AppSettings.swift index af3f91b5a4..4c7c9d8991 100644 --- a/DuckDuckGo/AppSettings.swift +++ b/DuckDuckGo/AppSettings.swift @@ -60,7 +60,7 @@ protocol AppSettings: AnyObject, AppDebugSettings { var currentAddressBarPosition: AddressBarPosition { get set } var showFullSiteAddress: Bool { get set } - var textSize: Int { get set } + var defaultTextZoomLevel: TextZoomLevel { get set } var favoritesDisplayMode: FavoritesDisplayMode { get set } diff --git a/DuckDuckGo/AppUserDefaults.swift b/DuckDuckGo/AppUserDefaults.swift index 4cd79c3e0b..559a521900 100644 --- a/DuckDuckGo/AppUserDefaults.swift +++ b/DuckDuckGo/AppUserDefaults.swift @@ -27,7 +27,7 @@ public class AppUserDefaults: AppSettings { public struct Notifications { public static let doNotSellStatusChange = Notification.Name("com.duckduckgo.app.DoNotSellStatusChange") public static let currentFireButtonAnimationChange = Notification.Name("com.duckduckgo.app.CurrentFireButtonAnimationChange") - public static let textSizeChange = Notification.Name("com.duckduckgo.app.TextSizeChange") + public static let textZoomChange = Notification.Name("com.duckduckgo.app.TextZoomChange") public static let favoritesDisplayModeChange = Notification.Name("com.duckduckgo.app.FavoritesDisplayModeChange") public static let syncPausedStateChanged = SyncBookmarksAdapter.syncBookmarksPausedStateChanged public static let syncCredentialsPausedStateChanged = SyncCredentialsAdapter.syncCredentialsPausedStateChanged @@ -235,8 +235,21 @@ public class AppUserDefaults: AppSettings { } } - @UserDefaultsWrapper(key: .textSize, defaultValue: 100) - var textSize: Int + @UserDefaultsWrapper(key: .textZoom, defaultValue: 100) + private var textZoom: Int { + didSet { + NotificationCenter.default.post(name: Notifications.textZoomChange, object: textZoom) + } + } + + var defaultTextZoomLevel: TextZoomLevel { + get { + return TextZoomLevel(rawValue: textZoom) ?? .percent100 + } + set { + textZoom = newValue.rawValue + } + } public var favoritesDisplayMode: FavoritesDisplayMode { get { diff --git a/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Contents.json deleted file mode 100644 index 172e1f8799..0000000000 --- a/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "Font-Larger-24.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Font-Larger-24.pdf b/DuckDuckGo/Assets.xcassets/TextSizeLarger.imageset/Font-Larger-24.pdf deleted file mode 100644 index 4f9ffc74208d7c97791bdcfd51839e5570d438ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1058 zcmZvb&2H2%5P zjX%%-Ojg^?-4!DWfFZ^9`wu|8zQ&syu+7e2fiHRT(Kh?x2~!7iuhkEoEe?=u?C+|y z`MXjf?2_F2HTkIfimZi|zC%Zf)|R+PPHGSCC_fvu>ZA zEj!Ds%iI>hk0!0PWn)@$iQl=6eo)4oqO4vk{x;*_k zB1z2|N?mtOwG=%wR7yv!p)0D|cHpP?e&gD4(YFVCi5J!Ga%xJFx9xzw;IYBUef8J6 U?8o1^=!UTzohn$Z-hRIO2NeG5(*OVf diff --git a/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Contents.json deleted file mode 100644 index aee39a9607..0000000000 --- a/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "filename" : "Font-Smaller-24.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Font-Smaller-24.pdf b/DuckDuckGo/Assets.xcassets/TextSizeSmaller.imageset/Font-Smaller-24.pdf deleted file mode 100644 index 4f76f020d0defb17e1762c56aa79ecf9859b3116..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1054 zcmZuw$!^;)5WUY=%*8-*2*sT=5CmxKrYPE?uF_l3gDNwQ3N5Xq6luRcq%G2llQ{^F zkDQq|ix!*p%>^R{fFZ^1=Py9Kyu_<3aP2l6fzSEuvuk(b0}4;(;ngtqu4o`zyT4WG z@(x-JN6%9*lr2~yjpf=)k3J2sgcGPi5yP~y z8X1o-YmkInA(?zZCZ_~yuU~Oy#PXP?22QkHa>h^)DWvkC215j+#xCdFYl$^H_|!|G zlrDnwUm6$y%8}ax`!6NK^W#VsW{d! z!Na&EQ)$>Tv3?1%cWv8^1K$1cOW`g1{_nTLY*XyqM0|1Es<`f+@b1`})Hg0;tB)u~ z%H7aC_N5yztX)2ZTXpT|TAwlOTqHL|?>STxHQUTUrH#!#Ra-9=Lj^g;Jge@}`?6R1 z2hYqR=@*d>Wv+^`sJq?d8j2p?67kf#d!T6Gu;Ss1S}CE>(~~iZdxUMGgx4ADNGa;; zIia{YrHpqud1cHo*4P(S?Rp5)`?&V)I2*dgo#R=xJwG%h%e!vGQ1HIN*=_aTdG-5W Rx#-7zIaUZ*EZ%>;c?S0O>8t<% diff --git a/DuckDuckGo/Base.lproj/Settings.storyboard b/DuckDuckGo/Base.lproj/Settings.storyboard index b0decd8ad5..39927df63a 100644 --- a/DuckDuckGo/Base.lproj/Settings.storyboard +++ b/DuckDuckGo/Base.lproj/Settings.storyboard @@ -1,162 +1,14 @@ - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -174,7 +26,7 @@ - + @@ -962,7 +814,7 @@ - + @@ -1066,16 +918,7 @@ - - - - - - - - - diff --git a/DuckDuckGo/ContentBlockingUpdating.swift b/DuckDuckGo/ContentBlockingUpdating.swift index 95e70dbcf6..95002bca9e 100644 --- a/DuckDuckGo/ContentBlockingUpdating.swift +++ b/DuckDuckGo/ContentBlockingUpdating.swift @@ -87,7 +87,6 @@ public final class ContentBlockingUpdating { .combineLatest(onNotificationWithInitial(PreserveLogins.Notifications.loginDetectionStateChanged), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.doNotSellStatusChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.autofillEnabledChange), combine) - .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.textSizeChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.didVerifyInternalUser), combine) .combineLatest(onNotificationWithInitial(ConfigurationManager.didUpdateTrackerDependencies) .receive(on: DispatchQueue.main), combine) diff --git a/DuckDuckGo/IntervalSlider.swift b/DuckDuckGo/IntervalSlider.swift index 37ced4bea3..e338daae7f 100644 --- a/DuckDuckGo/IntervalSlider.swift +++ b/DuckDuckGo/IntervalSlider.swift @@ -18,6 +18,7 @@ // import UIKit +import SwiftUI class IntervalSlider: UISlider { @@ -40,14 +41,8 @@ class IntervalSlider: UISlider { let thumbRect = thumbRect(forBounds: rect, trackRect: trackRect, value: 1.0) let thumbOffset = Darwin.round(thumbRect.width/2) - 3 - - let newTrackRect = trackRect.inset(by: UIEdgeInsets(top: 0.0, left: thumbOffset, bottom: 0.0, right: thumbOffset)) - - let color: UIColor = UIColor.cornflowerBlue - let bpath: UIBezierPath = UIBezierPath(rect: newTrackRect) - color.set() - bpath.fill() + let newTrackRect = trackRect.inset(by: UIEdgeInsets(top: 0.0, left: thumbOffset, bottom: 0.0, right: thumbOffset)) guard steps.count > 1 else { return } for i in 0...steps.count-1 { @@ -58,8 +53,13 @@ class IntervalSlider: UISlider { width: Constants.markWidth, height: Constants.markHeight) let markPath: UIBezierPath = UIBezierPath(roundedRect: markRect, cornerRadius: Constants.markCornerRadius) - color.set() - + + if Int(self.value) >= i { + minimumTrackTintColor?.set() + } else { + maximumTrackTintColor?.set() + } + markPath.fill() } } @@ -74,3 +74,47 @@ class IntervalSlider: UISlider { } } + +struct IntervalSliderRepresentable: UIViewRepresentable { + + @Binding var value: Int + + let steps: [Int] + + func makeUIView(context: Context) -> IntervalSlider { + let slider = IntervalSlider(frame: .zero) + slider.minimumTrackTintColor = UIColor(designSystemColor: .accent) + slider.maximumTrackTintColor = UIColor.systemGray3 + slider.steps = steps + slider.minimumValue = Float(0) + slider.maximumValue = Float(steps.count - 1) + slider.addTarget(context.coordinator, action: #selector(Coordinator.valueChanged(_:)), for: .valueChanged) + return slider + } + + func updateUIView(_ uiView: IntervalSlider, context: Context) { + uiView.value = Float(value) + uiView.setNeedsDisplay() + } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject { + var parent: IntervalSliderRepresentable + + init(_ parent: IntervalSliderRepresentable) { + self.parent = parent + } + + @objc func valueChanged(_ sender: IntervalSlider) { + let roundedValue = round(sender.value) + sender.value = roundedValue + if Int(roundedValue) != parent.value { + parent.value = Int(roundedValue) + sender.setNeedsDisplay() + } + } + } +} diff --git a/DuckDuckGo/MainViewController+Segues.swift b/DuckDuckGo/MainViewController+Segues.swift index 8d91186009..3ab8722e7f 100644 --- a/DuckDuckGo/MainViewController+Segues.swift +++ b/DuckDuckGo/MainViewController+Segues.swift @@ -301,7 +301,8 @@ extension MainViewController { deepLink: deepLinkTarget, historyManager: historyManager, syncPausedStateManager: syncPausedStateManager, - privacyProDataReporter: privacyProDataReporter) + privacyProDataReporter: privacyProDataReporter, + textZoomCoordinator: textZoomCoordinator) Pixel.fire(pixel: .settingsPresented) if let navigationController = self.presentedViewController as? UINavigationController, diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 75c5777782..29364843b7 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -177,6 +177,9 @@ class MainViewController: UIViewController { fatalError("Use init?(code:") } + let preserveLogins: PreserveLogins + let textZoomCoordinator: TextZoomCoordinating + var historyManager: HistoryManaging var viewCoordinator: MainViewCoordinator! @@ -200,7 +203,10 @@ class MainViewController: UIViewController { statisticsStore: StatisticsStore = StatisticsUserDefaults(), subscriptionFeatureAvailability: SubscriptionFeatureAvailability, voiceSearchHelper: VoiceSearchHelperProtocol, - subscriptionCookieManager: SubscriptionCookieManaging + featureFlagger: FeatureFlagger, + preserveLogins: PreserveLogins = .shared, + subscriptionCookieManager: SubscriptionCookieManaging, + textZoomCoordinator: TextZoomCoordinating ) { self.bookmarksDatabase = bookmarksDatabase self.bookmarksDatabaseCleaner = bookmarksDatabaseCleaner @@ -223,7 +229,10 @@ class MainViewController: UIViewController { contextualOnboardingPresenter: contextualOnboardingPresenter, contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: contextualOnboardingPixelReporter, - subscriptionCookieManager: subscriptionCookieManager) + featureFlagger: featureFlagger, + subscriptionCookieManager: subscriptionCookieManager, + appSettings: appSettings, + textZoomCoordinator: textZoomCoordinator) self.syncPausedStateManager = syncPausedStateManager self.privacyProDataReporter = privacyProDataReporter self.homeTabManager = NewTabPageManager() @@ -234,7 +243,9 @@ class MainViewController: UIViewController { self.statisticsStore = statisticsStore self.subscriptionFeatureAvailability = subscriptionFeatureAvailability self.voiceSearchHelper = voiceSearchHelper + self.preserveLogins = preserveLogins self.subscriptionCookieManager = subscriptionCookieManager + self.textZoomCoordinator = textZoomCoordinator super.init(nibName: nil, bundle: nil) @@ -2659,6 +2670,7 @@ extension MainViewController: AutoClearWorker { self.bookmarksDatabaseCleaner?.cleanUpDatabaseNow() } + self.forgetTextZoom() await historyManager.removeAllHistory() self.clearInProgress = false @@ -2736,6 +2748,11 @@ extension MainViewController: AutoClearWorker { viewCoordinator.omniBar.dismissOnboardingPrivacyIconAnimation() } + private func forgetTextZoom() { + let allowedDomains = preserveLogins.allowedDomains + textZoomCoordinator.resetTextZoomLevels(excludingDomains: allowedDomains) + } + } extension MainViewController { diff --git a/DuckDuckGo/SettingsAccessibilityView.swift b/DuckDuckGo/SettingsAccessibilityView.swift index ad0141d69f..f801ae83d0 100644 --- a/DuckDuckGo/SettingsAccessibilityView.swift +++ b/DuckDuckGo/SettingsAccessibilityView.swift @@ -28,35 +28,33 @@ struct SettingsAccessibilityView: View { var body: some View { List { - Section { - // Text Size - if viewModel.state.textSize.enabled { - SettingsCellView(label: UserText.settingsText, - action: { viewModel.presentLegacyView(.textSize) }, - accessory: .rightDetail("\(viewModel.state.textSize.size)%"), - disclosureIndicator: true, - isButton: true) + if viewModel.state.textZoom.enabled { + Section(footer: Text(UserText.textZoomDescription)) { + // Text Size + SettingsPickerCellView(label: UserText.settingsText, + options: TextZoomLevel.allCases, + selectedOption: viewModel.textZoomLevelBinding) } } - Section(footer: Text(UserText.voiceSearchFooter)) { - // Private Voice Search - if viewModel.state.speechRecognitionAvailable { + if viewModel.state.speechRecognitionAvailable { + Section(footer: Text(UserText.voiceSearchFooter)) { + // Private Voice Search SettingsCellView(label: UserText.settingsVoiceSearch, accessory: .toggle(isOn: viewModel.voiceSearchEnabledBinding)) } - } - .alert(isPresented: $shouldShowNoMicrophonePermissionAlert) { - Alert(title: Text(UserText.noVoicePermissionAlertTitle), - message: Text(UserText.noVoicePermissionAlertMessage), - dismissButton: .default(Text(UserText.noVoicePermissionAlertOKbutton), - action: { - viewModel.shouldShowNoMicrophonePermissionAlert = false - }) - ) - } - .onChange(of: viewModel.shouldShowNoMicrophonePermissionAlert) { value in - shouldShowNoMicrophonePermissionAlert = value + .alert(isPresented: $shouldShowNoMicrophonePermissionAlert) { + Alert(title: Text(UserText.noVoicePermissionAlertTitle), + message: Text(UserText.noVoicePermissionAlertMessage), + dismissButton: .default(Text(UserText.noVoicePermissionAlertOKbutton), + action: { + viewModel.shouldShowNoMicrophonePermissionAlert = false + }) + ) + } + .onChange(of: viewModel.shouldShowNoMicrophonePermissionAlert) { value in + shouldShowNoMicrophonePermissionAlert = value + } } } .applySettingsListModifiers(title: UserText.accessibility, diff --git a/DuckDuckGo/SettingsGeneralView.swift b/DuckDuckGo/SettingsGeneralView.swift index 2307c092f7..427ec3bfc3 100644 --- a/DuckDuckGo/SettingsGeneralView.swift +++ b/DuckDuckGo/SettingsGeneralView.swift @@ -49,24 +49,24 @@ struct SettingsGeneralView: View { } } - Section(footer: Text(UserText.voiceSearchFooter)) { - // Private Voice Search - if viewModel.state.speechRecognitionAvailable { + if viewModel.state.speechRecognitionAvailable { + Section(footer: Text(UserText.voiceSearchFooter)) { + // Private Voice Search SettingsCellView(label: UserText.settingsVoiceSearch, accessory: .toggle(isOn: viewModel.voiceSearchEnabledBinding)) } - } - .alert(isPresented: $shouldShowNoMicrophonePermissionAlert) { - Alert(title: Text(UserText.noVoicePermissionAlertTitle), - message: Text(UserText.noVoicePermissionAlertMessage), - dismissButton: .default(Text(UserText.noVoicePermissionAlertOKbutton), - action: { - viewModel.shouldShowNoMicrophonePermissionAlert = false - }) - ) - } - .onChange(of: viewModel.shouldShowNoMicrophonePermissionAlert) { value in - shouldShowNoMicrophonePermissionAlert = value + .alert(isPresented: $shouldShowNoMicrophonePermissionAlert) { + Alert(title: Text(UserText.noVoicePermissionAlertTitle), + message: Text(UserText.noVoicePermissionAlertMessage), + dismissButton: .default(Text(UserText.noVoicePermissionAlertOKbutton), + action: { + viewModel.shouldShowNoMicrophonePermissionAlert = false + }) + ) + } + .onChange(of: viewModel.shouldShowNoMicrophonePermissionAlert) { value in + shouldShowNoMicrophonePermissionAlert = value + } } Section(header: Text(UserText.settingsCustomizeSection), diff --git a/DuckDuckGo/SettingsLegacyViewProvider.swift b/DuckDuckGo/SettingsLegacyViewProvider.swift index 736e81f8e5..dee451e380 100644 --- a/DuckDuckGo/SettingsLegacyViewProvider.swift +++ b/DuckDuckGo/SettingsLegacyViewProvider.swift @@ -53,7 +53,6 @@ class SettingsLegacyViewProvider: ObservableObject { case addToDock, sync, logins, - textSize, appIcon, gpc, autoconsent, @@ -72,7 +71,6 @@ class SettingsLegacyViewProvider: ObservableObject { // Legacy UIKit Views (Pushed unmodified) var addToDock: UIViewController { instantiate( "instructions", fromStoryboard: "HomeRow") } - var textSettings: UIViewController { return instantiate("TextSize", fromStoryboard: "Settings") } var appIcon: UIViewController { instantiate("AppIcon", fromStoryboard: "Settings") } var gpc: UIViewController { instantiate("DoNotSell", fromStoryboard: "Settings") } var autoConsent: UIViewController { instantiate("AutoconsentSettingsViewController", fromStoryboard: "Settings") } diff --git a/DuckDuckGo/SettingsState.swift b/DuckDuckGo/SettingsState.swift index 299cfeba21..665077e29d 100644 --- a/DuckDuckGo/SettingsState.swift +++ b/DuckDuckGo/SettingsState.swift @@ -31,9 +31,9 @@ struct SettingsState { var position: AddressBarPosition } - struct TextSize { + struct TextZoom { var enabled: Bool - var size: Int + var level: TextZoomLevel } struct Subscription: Codable { @@ -57,7 +57,7 @@ struct SettingsState { var appTheme: ThemeName var appIcon: AppIcon var fireButtonAnimation: FireButtonAnimationType - var textSize: TextSize + var textZoom: TextZoom var addressBar: AddressBar var showsFullURL: Bool @@ -107,7 +107,7 @@ struct SettingsState { appTheme: .systemDefault, appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: .fireRising, - textSize: TextSize(enabled: false, size: 100), + textZoom: TextZoom(enabled: false, level: .percent100), addressBar: AddressBar(enabled: false, position: .top), showsFullURL: false, sendDoNotSell: true, diff --git a/DuckDuckGo/SettingsViewModel.swift b/DuckDuckGo/SettingsViewModel.swift index e008a34ab6..5f96ce0215 100644 --- a/DuckDuckGo/SettingsViewModel.swift +++ b/DuckDuckGo/SettingsViewModel.swift @@ -43,6 +43,8 @@ final class SettingsViewModel: ObservableObject { var emailManager: EmailManager { EmailManager() } private let historyManager: HistoryManaging let privacyProDataReporter: PrivacyProDataReporting? + let textZoomCoordinator: TextZoomCoordinating + // Subscription Dependencies private let subscriptionManager: SubscriptionManager let subscriptionFeatureAvailability: SubscriptionFeatureAvailability @@ -63,7 +65,8 @@ final class SettingsViewModel: ObservableObject { // App Data State Notification Observer private var appDataClearingObserver: Any? - + private var textZoomObserver: Any? + // Closures to interact with legacy view controllers through the container var onRequestPushLegacyView: ((UIViewController) -> Void)? var onRequestPresentLegacyView: ((UIViewController, _ modal: Bool) -> Void)? @@ -77,7 +80,7 @@ final class SettingsViewModel: ObservableObject { enum Features { case sync case autofillAccessCredentialManagement - case textSize + case zoomLevel case voiceSearch case addressbarPosition case speechRecognition @@ -256,6 +259,20 @@ final class SettingsViewModel: ObservableObject { ) } + var textZoomLevelBinding: Binding { + Binding( + get: { self.state.textZoom.level }, + set: { newValue in + Pixel.fire(.settingsAccessiblityTextZoom, withAdditionalParameters: [ + PixelParameters.textZoomInitial: String(self.appSettings.defaultTextZoomLevel.rawValue), + PixelParameters.textZoomUpdated: String(newValue.rawValue), + ]) + self.appSettings.defaultTextZoomLevel = newValue + self.state.textZoom.level = newValue + } + ) + } + var duckPlayerModeBinding: Binding { Binding( get: { @@ -368,7 +385,8 @@ final class SettingsViewModel: ObservableObject { deepLink: SettingsDeepLinkSection? = nil, historyManager: HistoryManaging, syncPausedStateManager: any SyncPausedStateManaging, - privacyProDataReporter: PrivacyProDataReporting) { + privacyProDataReporter: PrivacyProDataReporting, + textZoomCoordinator: TextZoomCoordinating) { self.state = SettingsState.defaults self.legacyViewProvider = legacyViewProvider @@ -379,6 +397,7 @@ final class SettingsViewModel: ObservableObject { self.historyManager = historyManager self.syncPausedStateManager = syncPausedStateManager self.privacyProDataReporter = privacyProDataReporter + self.textZoomCoordinator = textZoomCoordinator setupNotificationObservers() updateRecentlyVisitedSitesVisibility() @@ -387,6 +406,7 @@ final class SettingsViewModel: ObservableObject { deinit { subscriptionSignOutObserver = nil appDataClearingObserver = nil + textZoomObserver = nil } } @@ -402,7 +422,7 @@ extension SettingsViewModel { appTheme: appSettings.currentThemeName, appIcon: AppIconManager.shared.appIcon, fireButtonAnimation: appSettings.currentFireButtonAnimation, - textSize: SettingsState.TextSize(enabled: !isPad, size: appSettings.textSize), + textZoom: SettingsState.TextZoom(enabled: textZoomCoordinator.isEnabled, level: appSettings.defaultTextZoomLevel), addressBar: SettingsState.AddressBar(enabled: !isPad, position: appSettings.currentAddressBarPosition), showsFullURL: appSettings.showFullSiteAddress, sendDoNotSell: appSettings.sendDoNotSell, @@ -605,10 +625,6 @@ extension SettingsViewModel { pushViewController(legacyViewProvider.loginSettings(delegate: self, selectedAccount: state.activeWebsiteAccount)) - case .textSize: - firePixel(.settingsAccessiblityTextSize) - pushViewController(legacyViewProvider.textSettings) - case .gpc: firePixel(.settingsDoNotSellShown) pushViewController(legacyViewProvider.gpc) @@ -771,6 +787,12 @@ extension SettingsViewModel { self?.state.autoclearDataEnabled = (AutoClearSettingsModel(settings: settings) != nil) } + textZoomObserver = NotificationCenter.default.addObserver(forName: AppUserDefaults.Notifications.textZoomChange, + object: nil, + queue: .main, using: { [weak self] _ in + guard let self = self else { return } + self.state.textZoom = SettingsState.TextZoom(enabled: true, level: self.appSettings.defaultTextZoomLevel) + }) } func restoreAccountPurchase() async { diff --git a/DuckDuckGo/TabManager.swift b/DuckDuckGo/TabManager.swift index 46efdc1369..9f9786fecb 100644 --- a/DuckDuckGo/TabManager.swift +++ b/DuckDuckGo/TabManager.swift @@ -42,7 +42,10 @@ class TabManager { private let contextualOnboardingPresenter: ContextualOnboardingPresenting private let contextualOnboardingLogic: ContextualOnboardingLogic private let onboardingPixelReporter: OnboardingPixelReporting + private let featureFlagger: FeatureFlagger + private let textZoomCoordinator: TextZoomCoordinating private let subscriptionCookieManager: SubscriptionCookieManaging + private let appSettings: AppSettings weak var delegate: TabDelegate? @@ -60,7 +63,10 @@ class TabManager { contextualOnboardingPresenter: ContextualOnboardingPresenting, contextualOnboardingLogic: ContextualOnboardingLogic, onboardingPixelReporter: OnboardingPixelReporting, - subscriptionCookieManager: SubscriptionCookieManaging) { + featureFlagger: FeatureFlagger, + subscriptionCookieManager: SubscriptionCookieManaging, + appSettings: AppSettings, + textZoomCoordinator: TextZoomCoordinating) { self.model = model self.previewsSource = previewsSource self.bookmarksDatabase = bookmarksDatabase @@ -71,7 +77,10 @@ class TabManager { self.contextualOnboardingPresenter = contextualOnboardingPresenter self.contextualOnboardingLogic = contextualOnboardingLogic self.onboardingPixelReporter = onboardingPixelReporter + self.featureFlagger = featureFlagger self.subscriptionCookieManager = subscriptionCookieManager + self.appSettings = appSettings + self.textZoomCoordinator = textZoomCoordinator registerForNotifications() } @@ -84,6 +93,7 @@ class TabManager { @MainActor private func buildController(forTab tab: Tab, url: URL?, inheritedAttribution: AdClickAttributionLogic.State?) -> TabViewController { let configuration = WKWebViewConfiguration.persistent() + let controller = TabViewController.loadFromStoryboard(model: tab, bookmarksDatabase: bookmarksDatabase, historyManager: historyManager, @@ -93,8 +103,9 @@ class TabManager { contextualOnboardingPresenter: contextualOnboardingPresenter, contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: onboardingPixelReporter, - featureFlagger: AppDependencyProvider.shared.featureFlagger, - subscriptionCookieManager: subscriptionCookieManager) + featureFlagger: featureFlagger, + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: textZoomCoordinator) controller.applyInheritedAttribution(inheritedAttribution) controller.attachWebView(configuration: configuration, andLoadRequest: url == nil ? nil : URLRequest.userInitiated(url!), @@ -172,8 +183,9 @@ class TabManager { contextualOnboardingPresenter: contextualOnboardingPresenter, contextualOnboardingLogic: contextualOnboardingLogic, onboardingPixelReporter: onboardingPixelReporter, - featureFlagger: AppDependencyProvider.shared.featureFlagger, - subscriptionCookieManager: subscriptionCookieManager) + featureFlagger: featureFlagger, + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: textZoomCoordinator) controller.attachWebView(configuration: configCopy, andLoadRequest: request, consumeCookies: !model.hasActiveTabs, @@ -356,4 +368,5 @@ extension TabManager { TabPreviewsCleanup.shared.startCleanup(with: model, source: previewsSource) } } + } diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 5609aec797..7e4bb51b8c 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -197,7 +197,6 @@ class TabViewController: UIViewController { var failedURL: URL? var storedSpecialErrorPageUserScript: SpecialErrorPageUserScript? var isSpecialErrorPageVisible: Bool = false - let syncService: DDGSyncing private let daxDialogsDebouncer = Debouncer(mode: .common) @@ -332,7 +331,9 @@ class TabViewController: UIViewController { onboardingPixelReporter: OnboardingCustomInteractionPixelReporting, urlCredentialCreator: URLCredentialCreating = URLCredentialCreator(), featureFlagger: FeatureFlagger, - subscriptionCookieManager: SubscriptionCookieManaging) -> TabViewController { + subscriptionCookieManager: SubscriptionCookieManaging, + textZoomCoordinator: TextZoomCoordinating) -> TabViewController { + let storyboard = UIStoryboard(name: "Tab", bundle: nil) let controller = storyboard.instantiateViewController(identifier: "TabViewController", creator: { coder in TabViewController(coder: coder, @@ -348,7 +349,8 @@ class TabViewController: UIViewController { onboardingPixelReporter: onboardingPixelReporter, urlCredentialCreator: urlCredentialCreator, featureFlagger: featureFlagger, - subscriptionCookieManager: subscriptionCookieManager + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: textZoomCoordinator ) }) return controller @@ -367,6 +369,7 @@ class TabViewController: UIViewController { let contextualOnboardingPresenter: ContextualOnboardingPresenting let contextualOnboardingLogic: ContextualOnboardingLogic let onboardingPixelReporter: OnboardingCustomInteractionPixelReporting + let textZoomCoordinator: TextZoomCoordinating required init?(coder aDecoder: NSCoder, tabModel: Tab, @@ -382,7 +385,8 @@ class TabViewController: UIViewController { onboardingPixelReporter: OnboardingCustomInteractionPixelReporting, urlCredentialCreator: URLCredentialCreating = URLCredentialCreator(), featureFlagger: FeatureFlagger, - subscriptionCookieManager: SubscriptionCookieManaging) { + subscriptionCookieManager: SubscriptionCookieManaging, + textZoomCoordinator: TextZoomCoordinating) { self.tabModel = tabModel self.appSettings = appSettings self.bookmarksDatabase = bookmarksDatabase @@ -402,6 +406,8 @@ class TabViewController: UIViewController { self.urlCredentialCreator = urlCredentialCreator self.featureFlagger = featureFlagger self.subscriptionCookieManager = subscriptionCookieManager + self.textZoomCoordinator = textZoomCoordinator + super.init(coder: aDecoder) // Assign itself as tabNavigationHandler for DuckPlayer @@ -418,7 +424,7 @@ class TabViewController: UIViewController { preserveLoginsWorker = PreserveLoginsWorker(controller: self) initAttributionLogic() decorate() - addTextSizeObserver() + addTextZoomObserver() subscribeToEmailProtectionSignOutNotification() registerForDownloadsNotifications() registerForAddressBarLocationNotifications() @@ -542,6 +548,7 @@ class TabViewController: UIViewController { } else { webView = WKWebView(frame: view.bounds, configuration: configuration) } + textZoomCoordinator.onWebViewCreated(applyToWebView: webView) webView.allowsLinkPreview = true webView.allowsBackForwardNavigationGestures = true @@ -958,10 +965,10 @@ class TabViewController: UIViewController { breakageAdditionalInfo: makeBreakageAdditionalInfo()) } - private func addTextSizeObserver() { + private func addTextZoomObserver() { NotificationCenter.default.addObserver(self, - selector: #selector(onTextSizeChange), - name: AppUserDefaults.Notifications.textSizeChange, + selector: #selector(onTextZoomChange), + name: AppUserDefaults.Notifications.textZoomChange, object: nil) } @@ -974,8 +981,8 @@ class TabViewController: UIViewController { } } - @objc func onTextSizeChange() { - webView.adjustTextSize(appSettings.textSize) + @objc func onTextZoomChange() { + textZoomCoordinator.onTextZoomChange(applyToWebView: webView) } @objc func onDuckDuckGoEmailSignOut(_ notification: Notification) { @@ -1310,6 +1317,7 @@ extension TabViewController: WKNavigationDelegate { let tld = storageCache.tld let httpsForced = tld.domain(lastUpgradedURL?.host) == tld.domain(webView.url?.host) onWebpageDidStartLoading(httpsForced: httpsForced) + textZoomCoordinator.onNavigationCommitted(applyToWebView: webView) } private func onWebpageDidStartLoading(httpsForced: Bool) { @@ -1439,6 +1447,7 @@ extension TabViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { self.currentlyLoadedURL = webView.url + onTextZoomChange() adClickAttributionDetection.onDidFinishNavigation(url: webView.url) adClickAttributionLogic.onDidFinishNavigation(host: webView.url?.host) hideProgressIndicator() @@ -2167,7 +2176,7 @@ extension TabViewController { */ private func setupOrClearTemporaryDownload(for response: URLResponse) -> WKNavigationResponsePolicy? { let downloadManager = AppDependencyProvider.shared.downloadManager - guard let url = response.url, + guard response.url != nil, let downloadMetaData = downloadManager.downloadMetaData(for: response), !downloadMetaData.mimeType.isHTML else { @@ -2544,7 +2553,6 @@ extension TabViewController: UserContentControllerDelegate { userScripts.autofillUserScript.vaultDelegate = vaultManager userScripts.faviconScript.delegate = faviconUpdater userScripts.printingUserScript.delegate = self - userScripts.textSizeUserScript.textSizeAdjustmentInPercents = appSettings.textSize userScripts.loginFormDetectionScript?.delegate = self userScripts.autoconsentUserScript.delegate = self userScripts.specialErrorPageUserScript?.delegate = self diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index 8e8d715052..fe193e42a0 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -156,6 +156,10 @@ extension TabViewController { entries.append(entry) } + if let entry = textZoomCoordinator.makeBrowsingMenuEntry(forLink: link, inController: self, forWebView: self.webView) { + entries.append(entry) + } + let title = self.tabModel.isDesktop ? UserText.actionRequestMobileSite : UserText.actionRequestDesktopSite let image = self.tabModel.isDesktop ? UIImage(named: "Device-Mobile-16")! : UIImage(named: "Device-Desktop-16")! entries.append(BrowsingMenuEntry.regular(name: title, image: image, action: { [weak self] in @@ -166,7 +170,7 @@ extension TabViewController { return entries } - + private func buildKeepSignInEntry(forLink link: Link) -> BrowsingMenuEntry? { guard let domain = link.url.host, !link.url.isDuckDuckGo else { return nil } let isFireproofed = PreserveLogins.shared.isAllowed(cookieDomain: domain) diff --git a/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift b/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift index 8de6d3de6c..974fbbf895 100644 --- a/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerLongPressMenuExtension.swift @@ -102,17 +102,20 @@ extension TabViewController { fileprivate func buildOpenLinkPreview(for url: URL) -> UIViewController? { let tab = Tab(link: Link(title: nil, url: url)) - let tabController = TabViewController.loadFromStoryboard(model: tab, - bookmarksDatabase: bookmarksDatabase, - historyManager: historyManager, - syncService: syncService, - duckPlayer: duckPlayer, - privacyProDataReporter: privacyProDataReporter, - contextualOnboardingPresenter: contextualOnboardingPresenter, - contextualOnboardingLogic: contextualOnboardingLogic, - onboardingPixelReporter: onboardingPixelReporter, - featureFlagger: AppDependencyProvider.shared.featureFlagger, - subscriptionCookieManager: subscriptionCookieManager) + let tabController = TabViewController.loadFromStoryboard( + model: tab, + bookmarksDatabase: bookmarksDatabase, + historyManager: historyManager, + syncService: syncService, + duckPlayer: duckPlayer, + privacyProDataReporter: privacyProDataReporter, + contextualOnboardingPresenter: contextualOnboardingPresenter, + contextualOnboardingLogic: contextualOnboardingLogic, + onboardingPixelReporter: onboardingPixelReporter, + featureFlagger: featureFlagger, + subscriptionCookieManager: subscriptionCookieManager, + textZoomCoordinator: textZoomCoordinator) + tabController.isLinkPreview = true let configuration = WKWebViewConfiguration.nonPersistent() tabController.attachWebView(configuration: configuration, andLoadRequest: URLRequest.userInitiated(url), consumeCookies: false) diff --git a/DuckDuckGo/TextSizeSettingsViewController.swift b/DuckDuckGo/TextSizeSettingsViewController.swift deleted file mode 100644 index c28cfd61be..0000000000 --- a/DuckDuckGo/TextSizeSettingsViewController.swift +++ /dev/null @@ -1,221 +0,0 @@ -// -// TextSizeSettingsViewController.swift -// DuckDuckGo -// -// Copyright © 2021 DuckDuckGo. All rights reserved. -// -// 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. -// - -import Foundation -import UIKit -import Core - -class TextSizeSettingsViewController: UITableViewController { - - @IBOutlet var customBackBarButtonItem: UIBarButtonItem! - @IBOutlet weak var customBackInnerButton: UIButton! - @IBOutlet weak var descriptionLabel: UILabel! - @IBOutlet weak var textSizeSlider: IntervalSlider! - @IBOutlet weak var smallerTextIcon: UIImageView! - @IBOutlet weak var largerTextIcon: UIImageView! - @IBOutlet weak var currentSelectedValueLabel: UILabel! - - private let predefinedPercentages = [80, 90, 100, 110, 120, 130, 140, 150, 160, 170] - - private let initialTextSizePercentage: Int = AppDependencyProvider.shared.appSettings.textSize - private var currentTextSizePercentage: Int = AppDependencyProvider.shared.appSettings.textSize - - private var hasAdjustedDetent: Bool = false - - override func viewDidLoad() { - super.viewDidLoad() - - navigationItem.leftBarButtonItem = nil - - configureCustomBackButtonTitle() - configureDescriptionLabel() - configureSlider() - updateTextSizeFooterLabel() - - decorate() - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - adjustDetentOnPresentation() - } - - private func adjustDetentOnPresentation() { - if !hasAdjustedDetent, let sheetController = navigationController?.presentationController as? UISheetPresentationController { - sheetController.detents = [.medium(), .large()] - sheetController.delegate = self - sheetController.preferredCornerRadius = 16 - - sheetController.animateChanges { - sheetController.selectedDetentIdentifier = .medium - } - - navigationItem.leftBarButtonItem = customBackBarButtonItem - - hasAdjustedDetent = true - } - } - - override func willMove(toParent parent: UIViewController?) { - super.willMove(toParent: parent) - - if parent == nil { - firePixelForTextSizeChange() - } - } - - override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - let theme = ThemeManager.shared.currentTheme - cell.decorate(with: theme) - } - - private func configureCustomBackButtonTitle() { - let topViewController = navigationController?.topViewController - let previousViewController = navigationController?.viewControllers.last(where: { $0 != topViewController }) - let backTitle = previousViewController?.navigationItem.title ?? "" - - customBackInnerButton.setTitle(backTitle, for: .normal) - } - - private func configureDescriptionLabel() { - descriptionLabel.text = UserText.textSizeDescription - adjustDescriptionLabelHeight() - } - - private func adjustDescriptionLabelHeight() { - guard let headerView = tableView.tableHeaderView else { return } - - let adjustedSize = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) - - if headerView.frame.size.height != adjustedSize.height { - headerView.frame.size.height = adjustedSize.height - } - } - - private func configureSlider() { - textSizeSlider.minimumValue = 0 - textSizeSlider.maximumValue = Float(predefinedPercentages.count - 1) - - textSizeSlider.steps = predefinedPercentages - - configureSliderCurrentSelection() - } - - private func configureSliderCurrentSelection() { - let currentSelectionIndex = predefinedPercentages.firstIndex(of: currentTextSizePercentage) ?? 0 - textSizeSlider.value = Float(currentSelectionIndex) - } - - private func updateTextSizeFooterLabel() { - let percentageString = "\(currentTextSizePercentage)%" - currentSelectedValueLabel.text = UserText.textSizeFooter(for: percentageString) - - } - - @IBAction func customBackButtonTapped(_ sender: AnyObject) { - var shouldPopViewController: Bool = true - - if let sheetController = navigationController?.presentationController as? UISheetPresentationController { - sheetController.detents = [.large()] - - // We recreate two-step detent animation, like on push but in reverse - if sheetController.selectedDetentIdentifier != .large { - shouldPopViewController = false - - // First step is to animate detent to large - sheetController.animateChanges { - sheetController.selectedDetentIdentifier = .large - } - - // Second step is to actually pop the view controller - DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) { - self.navigationItem.leftBarButtonItem = nil - self.navigationController?.popViewController(animated: true) - } - } - } - - if shouldPopViewController { - navigationItem.leftBarButtonItem = nil - navigationController?.popViewController(animated: true) - } - } - - @IBAction func onSliderValueChanged(_ sender: Any) { - let roundedValue = round(textSizeSlider.value) - - // make the slider snap - textSizeSlider.value = roundedValue - - let index = Int(roundedValue) - let newTextSizePercentage = predefinedPercentages[index] - - if newTextSizePercentage != currentTextSizePercentage { - currentTextSizePercentage = newTextSizePercentage - - updateTextSizeFooterLabel() - storeTextSizeInAppSettings(currentTextSizePercentage) - } - } - - private func storeTextSizeInAppSettings(_ percentage: Int) { - let appSettings = AppDependencyProvider.shared.appSettings - appSettings.textSize = percentage - - NotificationCenter.default.post(name: AppUserDefaults.Notifications.textSizeChange, object: self) - } - - private func firePixelForTextSizeChange() { - guard initialTextSizePercentage != currentTextSizePercentage else { return } - - Pixel.fire(pixel: .textSizeSettingsChanged, withAdditionalParameters: [PixelParameters.textSizeInitial: "\(initialTextSizePercentage)", - PixelParameters.textSizeUpdated: "\(currentTextSizePercentage)"]) - } -} - -extension TextSizeSettingsViewController: UISheetPresentationControllerDelegate { - - func sheetPresentationControllerDidChangeSelectedDetentIdentifier(_ sheetPresentationController: UISheetPresentationController) { - navigationItem.leftBarButtonItem = sheetPresentationController.selectedDetentIdentifier == .medium ? customBackBarButtonItem : nil - } -} - -extension TextSizeSettingsViewController: UIAdaptivePresentationControllerDelegate { - - func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { - firePixelForTextSizeChange() - } -} - -extension TextSizeSettingsViewController { - - private func decorate() { - let theme = ThemeManager.shared.currentTheme - descriptionLabel.textColor = theme.tableCellTextColor - smallerTextIcon.tintColor = theme.tableCellTextColor - largerTextIcon.tintColor = theme.tableCellTextColor - currentSelectedValueLabel.textColor = theme.tableHeaderTextColor - - tableView.backgroundColor = theme.backgroundColor - tableView.separatorColor = theme.tableCellSeparatorColor - - tableView.reloadData() - } -} diff --git a/DuckDuckGo/TextZoomController.swift b/DuckDuckGo/TextZoomController.swift new file mode 100644 index 0000000000..e175c81d2a --- /dev/null +++ b/DuckDuckGo/TextZoomController.swift @@ -0,0 +1,38 @@ +// +// TextZoomController.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import UIKit +import SwiftUI + +class TextZoomController: UIHostingController { + + let coordinator: TextZoomCoordinating + let model: TextZoomEditorModel + + @MainActor init(domain: String, coordinator: TextZoomCoordinating, defaultTextZoom: TextZoomLevel) { + self.coordinator = coordinator + self.model = TextZoomEditorModel(domain: domain, coordinator: coordinator, defaultTextZoom: defaultTextZoom) + super.init(rootView: TextZoomEditorView(model: model)) + } + + @MainActor required dynamic init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/DuckDuckGo/TextZoomCoordinator.swift b/DuckDuckGo/TextZoomCoordinator.swift new file mode 100644 index 0000000000..3aec4d1ae2 --- /dev/null +++ b/DuckDuckGo/TextZoomCoordinator.swift @@ -0,0 +1,181 @@ +// +// TextZoomCoordinator.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation +import WebKit +import Common +import BrowserServicesKit +import Core + +/// Central point for coordinating text zoom activities. +/// * Host is used to represent unaltered host from a URL. Domain is a normalised host. +protocol TextZoomCoordinating { + + /// Based on .textZoom feature flag + var isEnabled: Bool { get } + + /// @return The zoom level for a host or the current default if there isn't one. Uses eTLDplus1 to determine the domain. + func textZoomLevel(forHost host: String?) -> TextZoomLevel + + /// Sets the text zoom level for a host. Uses eLTDplus1 to determine the domain. + /// If the level matches the global default then this specific level for the host is forgotten. + func set(textZoomLevel level: TextZoomLevel, forHost host: String?) + + /// Reset, ie 'forget', the saved zoom levels for all domains except the ones specified. + func resetTextZoomLevels(excludingDomains: [String]) + + /// Applies appropriate text zoom to webview on creation,. Does nothing if feature is disabled. + func onWebViewCreated(applyToWebView webView: WKWebView) + + /// Applies appropriate text zoom when navigation is committed. Does nothing if feature is disabled. + func onNavigationCommitted(applyToWebView webView: WKWebView) + + /// Applies appropriate text zoom to webview when the text zoom has changed (e.g. in settings or for the current tab). + /// Does nothing if feature is disabled. + func onTextZoomChange(applyToWebView webView: WKWebView) + + /// Shows a text zoom editor for the current webview. Does nothing if the feature is disabled. + func showTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) + + /// Creates a browsing menu entry for the given link. Returns nil if the feature is disabled. + func makeBrowsingMenuEntry(forLink: Link, inController controller: UIViewController, forWebView webView: WKWebView) -> BrowsingMenuEntry? + +} + +final class TextZoomCoordinator: TextZoomCoordinating { + + let appSettings: AppSettings + let storage: TextZoomStoring + let featureFlagger: FeatureFlagger + + var isEnabled: Bool { + featureFlagger.isFeatureOn(.textZoom) + } + + init(appSettings: AppSettings, storage: TextZoomStoring, featureFlagger: FeatureFlagger) { + self.appSettings = appSettings + self.storage = storage + self.featureFlagger = featureFlagger + } + + func textZoomLevel(forHost host: String?) -> TextZoomLevel { + let domain = TLD().eTLDplus1(host) ?? "" + // If the webview returns no host then there won't be a setting for a blank string anyway. + return storage.textZoomLevelForDomain(domain) + // And if there's no setting for whatever domain is passed in, use the app default + ?? appSettings.defaultTextZoomLevel + } + + func set(textZoomLevel level: TextZoomLevel, forHost host: String?) { + guard let domain = TLD().eTLDplus1(host) else { return } + if level == appSettings.defaultTextZoomLevel { + storage.removeTextZoomLevel(forDomain: domain) + } else { + storage.set(textZoomLevel: level, forDomain: domain) + } + } + + func resetTextZoomLevels(excludingDomains domains: [String]) { + storage.resetTextZoomLevels(excludingDomains: domains) + } + + func onWebViewCreated(applyToWebView webView: WKWebView) { + applyTextZoom(webView) + } + + func onNavigationCommitted(applyToWebView webView: WKWebView) { + applyTextZoom(webView) + } + + func onTextZoomChange(applyToWebView webView: WKWebView) { + applyTextZoom(webView) + } + + private func applyTextZoom(_ webView: WKWebView) { + guard isEnabled else { return } + let level = textZoomLevel(forHost: webView.url?.host) + let dynamicTypeScalePercentage = UIFontMetrics.default.scaledValue(for: 1.0) + let viewScale = CGFloat(level.rawValue) / 100 * dynamicTypeScalePercentage + webView.applyViewScale(viewScale) + } + + @MainActor + func showTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) { + guard isEnabled else { return } + + guard let domain = TLD().eTLDplus1(webView.url?.host) else { return } + let zoomController = TextZoomController( + domain: domain, + coordinator: self, + defaultTextZoom: appSettings.defaultTextZoomLevel + ) + + zoomController.modalPresentationStyle = .formSheet + if #available(iOS 16.0, *) { + zoomController.sheetPresentationController?.detents = [.custom(resolver: { _ in + return 152 + })] + + zoomController.sheetPresentationController?.prefersScrollingExpandsWhenScrolledToEdge = false + zoomController.sheetPresentationController?.prefersEdgeAttachedInCompactHeight = true + zoomController.sheetPresentationController?.widthFollowsPreferredContentSizeWhenEdgeAttached = true + } else { + zoomController.sheetPresentationController?.detents = [.medium()] + } + + controller.present(zoomController, animated: true) + } + + func makeBrowsingMenuEntry(forLink link: Link, + inController controller: UIViewController, + forWebView webView: WKWebView) -> BrowsingMenuEntry? { + guard isEnabled else { return nil } + + let label: String + if let domain = TLD().eTLDplus1(link.url.host), + let level = storage.textZoomLevelForDomain(domain) { + label = UserText.textZoomWithPercentForMenuItem(level.rawValue) + } else { + label = UserText.textZoomMenuItem + } + + return BrowsingMenuEntry.regular(name: label, + image: UIImage(named: "Type-Size-16")!, + showNotificationDot: false) { [weak self, weak controller, weak webView] in + guard let self = self, let controller = controller, let webView = webView else { return } + Task { @MainActor in + self.showTextZoomEditor(inController: controller, forWebView: webView) + Pixel.fire(pixel: .browsingMenuZoom) + } + } + } +} + +extension WKWebView { + + func applyViewScale(_ scale: CGFloat) { + let key = "viewScale" + guard responds(to: NSSelectorFromString("_\(key)")) else { + assertionFailure("viewScale API has changed") + return + } + setValue(scale, forKey: key) + } + +} diff --git a/DuckDuckGo/TextZoomEditorModel.swift b/DuckDuckGo/TextZoomEditorModel.swift new file mode 100644 index 0000000000..44e187d762 --- /dev/null +++ b/DuckDuckGo/TextZoomEditorModel.swift @@ -0,0 +1,73 @@ +// +// TextZoomEditorModel.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import SwiftUI +import Core + +class TextZoomEditorModel: ObservableObject { + + let domain: String + let coordinator: TextZoomCoordinating + let initialValue: TextZoomLevel + + var valueAsPercent: Int { + TextZoomLevel.allCases[value].rawValue + } + + @Published var value: Int = 0 { + didSet { + valueWasSet() + } + } + + @Published var title: String = "" + + init(domain: String, coordinator: TextZoomCoordinating, defaultTextZoom: TextZoomLevel) { + self.domain = domain + self.coordinator = coordinator + self.initialValue = coordinator.textZoomLevel(forHost: domain) + value = TextZoomLevel.allCases.firstIndex(of: initialValue) ?? 0 + } + + func increment() { + value = min(TextZoomLevel.allCases.count - 1, value + 1) + } + + func decrement() { + value = max(0, value - 1) + } + + private func valueWasSet() { + title = UserText.textZoomWithPercentSheetTitle(TextZoomLevel.allCases[value].rawValue) + coordinator.set(textZoomLevel: TextZoomLevel.allCases[value], forHost: domain) + NotificationCenter.default.post( + name: AppUserDefaults.Notifications.textZoomChange, + object: nil) + DailyPixel.fire(pixel: .textZoomChangedOnPageDaily) + } + + func onDismiss() { + guard initialValue.rawValue != TextZoomLevel.allCases[value].rawValue else { return } + Pixel.fire(.textZoomChangedOnPage, withAdditionalParameters: [ + PixelParameters.textZoomInitial: String(initialValue.rawValue), + PixelParameters.textZoomUpdated: String(TextZoomLevel.allCases[value].rawValue), + ]) + } + +} diff --git a/DuckDuckGo/TextZoomEditorView.swift b/DuckDuckGo/TextZoomEditorView.swift new file mode 100644 index 0000000000..acc28235b8 --- /dev/null +++ b/DuckDuckGo/TextZoomEditorView.swift @@ -0,0 +1,95 @@ +// +// TextZoomEditorView.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import SwiftUI + +struct TextZoomEditorView: View { + + @ObservedObject var model: TextZoomEditorModel + + @Environment(\.dismiss) var dismiss + + @ViewBuilder + func header() -> some View { + ZStack(alignment: .center) { + Text(model.title) + .font(Font(uiFont: .daxHeadline())) + .frame(alignment: .center) + .foregroundStyle(Color(designSystemColor: .textPrimary)) + + Button { + model.onDismiss() + dismiss() + } label: { + Text(UserText.navigationTitleDone) + .font(Font(uiFont: .daxHeadline())) + } + .buttonStyle(.plain) + .padding(0) + .frame(maxWidth: .infinity, alignment: .trailing) + .foregroundStyle(Color(designSystemColor: .textPrimary)) + } + .padding(.horizontal, 16) + .frame(height: 56) + } + + func slider() -> some View { + HStack(spacing: 6) { + Button { + model.decrement() + } label: { + Image("Font-Smaller-24") + } + .foregroundColor(Color(designSystemColor: .textPrimary)) + .padding(12) + .padding(.leading, 8) + + IntervalSliderRepresentable( + value: $model.value, + steps: TextZoomLevel.allCases.map { $0.rawValue }) + .padding(.vertical) + + Button { + model.increment() + } label: { + Image("Font-Larger-24") + } + .foregroundColor(Color(designSystemColor: .textPrimary)) + .padding(12) + .padding(.trailing, 8) + } + .background(RoundedRectangle(cornerRadius: 8) + .foregroundColor(Color(designSystemColor: .surface))) + .frame(height: 64) + .padding(.horizontal, 16) + + } + + var body: some View { + VStack { + header() + Spacer() + slider() + Spacer() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color(designSystemColor: .background)) + } + +} diff --git a/DuckDuckGo/TextZoomLevel.swift b/DuckDuckGo/TextZoomLevel.swift new file mode 100644 index 0000000000..ef0ba39812 --- /dev/null +++ b/DuckDuckGo/TextZoomLevel.swift @@ -0,0 +1,39 @@ +// +// TextZoomLevel.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation + +enum TextZoomLevel: Int, CaseIterable, CustomStringConvertible { + + var description: String { + return "\(self.rawValue)%" + } + + case percent80 = 80 + case percent90 = 90 + case percent100 = 100 + case percent110 = 110 + case percent120 = 120 + case percent130 = 130 + case percent140 = 140 + case percent150 = 150 + case percent160 = 160 + case percent170 = 170 + +} diff --git a/DuckDuckGo/TextZoomStorage.swift b/DuckDuckGo/TextZoomStorage.swift new file mode 100644 index 0000000000..80920b380c --- /dev/null +++ b/DuckDuckGo/TextZoomStorage.swift @@ -0,0 +1,60 @@ +// +// TextZoomStorage.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation +import Core +import Common + +protocol TextZoomStoring { + func textZoomLevelForDomain(_ domain: String) -> TextZoomLevel? + func set(textZoomLevel: TextZoomLevel, forDomain domain: String) + func removeTextZoomLevel(forDomain domain: String) + func resetTextZoomLevels(excludingDomains: [String]) +} + +class TextZoomStorage: TextZoomStoring { + + @UserDefaultsWrapper(key: .domainTextZoomStorage, defaultValue: [:]) + var textZoomLevels: [String: Int] + + func textZoomLevelForDomain(_ domain: String) -> TextZoomLevel? { + guard let zoomLevel = textZoomLevels[domain] else { + return nil + } + return TextZoomLevel(rawValue: zoomLevel) + } + + func set(textZoomLevel: TextZoomLevel, forDomain domain: String) { + textZoomLevels[domain] = textZoomLevel.rawValue + } + + func removeTextZoomLevel(forDomain domain: String) { + textZoomLevels.removeValue(forKey: domain) + } + + func resetTextZoomLevels(excludingDomains: [String]) { + let tld = TLD() + textZoomLevels = textZoomLevels.filter { level in + excludingDomains.contains(where: { + tld.eTLDplus1($0) == level.key + }) + } + } + +} diff --git a/DuckDuckGo/UserScripts.swift b/DuckDuckGo/UserScripts.swift index 144686acb9..eb69b13057 100644 --- a/DuckDuckGo/UserScripts.swift +++ b/DuckDuckGo/UserScripts.swift @@ -50,10 +50,10 @@ final class UserScripts: UserScriptsProvider { private(set) var findInPageScript = FindInPageUserScript() private(set) var fullScreenVideoScript = FullScreenVideoUserScript() private(set) var printingUserScript = PrintingUserScript() - private(set) var textSizeUserScript = TextSizeUserScript(textSizeAdjustmentInPercents: AppDependencyProvider.shared.appSettings.textSize) private(set) var debugScript = DebugUserScript() - init(with sourceProvider: ScriptSourceProviding) { + init(with sourceProvider: ScriptSourceProviding, appSettings: AppSettings = AppDependencyProvider.shared.appSettings) { + contentBlockerUserScript = ContentBlockerRulesUserScript(configuration: sourceProvider.contentBlockerRulesConfig) surrogatesScript = SurrogatesUserScript(configuration: sourceProvider.surrogatesConfig) autofillUserScript = AutofillUserScript(scriptSourceProvider: sourceProvider.autofillSourceProvider) @@ -79,7 +79,6 @@ final class UserScripts: UserScriptsProvider { lazy var userScripts: [UserScript] = [ debugScript, - textSizeUserScript, autoconsentUserScript, findInPageScript, navigatorPatchScript, diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index c0d006206f..43e48a8762 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -326,8 +326,10 @@ public struct UserText { public static let voiceSearchCancelButton = NSLocalizedString("voiceSearch.cancel", value: "Cancel", comment: "Cancel button for voice search") public static let voiceSearchFooterOld = NSLocalizedString("voiceSearch.footer.note.old", value: "Audio is processed on-device. It's not stored or shared with anyone, including DuckDuckGo.", comment: "Voice-search footer note with on-device privacy warning") public static let voiceSearchFooter = NSLocalizedString("voiceSearch.footer.note", value: "Add Private Voice Search option to the address bar. Audio is not stored or shared with anyone, including DuckDuckGo.", comment: "Voice-search footer note with on-device privacy warning") - public static let textSizeDescription = NSLocalizedString("textSize.description", value: "Choose your preferred text size. Websites you view in DuckDuckGo will adjust to it.", comment: "Description text for the text size adjustment setting") - public static func textSizeFooter(for percentage: String) -> String { + + // Legacy name is text size - don't want to mess up translations by changing it. + public static let textZoomDescription = NSLocalizedString("textSize.description", value: "Increase or decrease text size across all sites.", comment: "Description text for the text size adjustment setting") + public static func textZoomFooter(for percentage: String) -> String { let message = NSLocalizedString("textSize.footer", value: "Text Size - %@", comment: "Replacement string is a current percent value e.g. '120%'") return message.format(arguments: percentage) } @@ -354,6 +356,18 @@ public struct UserText { } public static let messageAllFilesDeleted = NSLocalizedString("downloads.message.all-files-deleted", value: "All files deleted", comment: "Message confirming that all files on the downloads list have been deleted") + public static let textZoomMenuItem = NSLocalizedString("action.text-zoom-sheet-menu-item", value: "Zoom", comment: "Text zoom menu item") + + public static func textZoomWithPercentSheetTitle(_ percent: Int) -> String { + let message = NSLocalizedString("action.text-zoom-sheet-title", value: "Text Zoom (%d%%)", comment: "Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please.") + return message.format(arguments: percent) + } + + public static func textZoomWithPercentForMenuItem(_ percent: Int) -> String { + let message = NSLocalizedString("action.text-zoom-menu-item", value: "Zoom (%d%%)", comment: "Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please.") + return message.format(arguments: percent) + } + public static let actionGenericShow = NSLocalizedString("action.generic.show", value: "Show", comment: "Button label for a generic show action") public static let actionDownloads = NSLocalizedString("action.title.downloads", value: "Downloads", comment: "Downloads menu item opening the downlods list") public static let downloadsScreenTitle = NSLocalizedString("downloads.downloads-list.title", value: "Downloads", comment: "Downloads list screen title") @@ -1051,7 +1065,7 @@ But if you *do* want a peek under the hood, you can find more information about public static let settingsTheme = NSLocalizedString("settings.theme", value: "Theme", comment: "Settings screen cell text for theme") public static let settingsIcon = NSLocalizedString("settings.icon", value: "App Icon", comment: "Settings screen cell text for app icon selection") public static let settingsFirebutton = NSLocalizedString("settings.firebutton", value: "Fire Button Animation", comment: "Settings screen cell text for fire button animation") - public static let settingsText = NSLocalizedString("settings.text.size", value: "Text Size", comment: "Settings screen cell text for text size") + public static let settingsText = NSLocalizedString("settings.text.size", value: "Default Text Zoom", comment: "Settings screen cell text for text size") public static let settingsAddressBar = NSLocalizedString("settings.address.bar", value: "Address Bar Position", comment: "Settings screen cell text for addess bar position") public static let settingsFullURL = NSLocalizedString("settings.address.full.url", value: "Show Full Site Address", comment: "Settings screen cell title for toggling full URL visibility in address bar") diff --git a/DuckDuckGo/en.lproj/Localizable.strings b/DuckDuckGo/en.lproj/Localizable.strings index 214e4328a4..fc7d856f4a 100644 --- a/DuckDuckGo/en.lproj/Localizable.strings +++ b/DuckDuckGo/en.lproj/Localizable.strings @@ -13,6 +13,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Text Zoom (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Add"; @@ -2374,7 +2383,7 @@ But if you *do* want a peek under the hood, you can find more information about "settings.sync" = "Sync & Backup"; /* Settings screen cell text for text size */ -"settings.text.size" = "Text Size"; +"settings.text.size" = "Default Text Zoom"; /* Settings screen cell text for theme */ "settings.theme" = "Theme"; @@ -2728,7 +2737,7 @@ But if you *do* want a peek under the hood, you can find more information about "tab.switcher.accessibility.label" = "Tab Switcher"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Choose your preferred text size. Websites you view in DuckDuckGo will adjust to it."; +"textSize.description" = "Increase or decrease text size across all sites."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Text Size - %@"; diff --git a/DuckDuckGoTests/AppSettingsMock.swift b/DuckDuckGoTests/AppSettingsMock.swift index 585d936cd9..4d9b09321e 100644 --- a/DuckDuckGoTests/AppSettingsMock.swift +++ b/DuckDuckGoTests/AppSettingsMock.swift @@ -22,6 +22,7 @@ import Foundation @testable import DuckDuckGo class AppSettingsMock: AppSettings { + var defaultTextZoomLevel: DuckDuckGo.TextZoomLevel = .percent100 var recentlyVisitedSites: Bool = false diff --git a/DuckDuckGoTests/ContentBlockingUpdatingTests.swift b/DuckDuckGoTests/ContentBlockingUpdatingTests.swift index b57c10b1b3..dc68adcd9e 100644 --- a/DuckDuckGoTests/ContentBlockingUpdatingTests.swift +++ b/DuckDuckGoTests/ContentBlockingUpdatingTests.swift @@ -171,31 +171,6 @@ final class ContentBlockingUpdatingTests: XCTestCase { } } - func testWhenTextSizeChangeNotificationSentThenUserScriptsAreRebuild() { - let e1 = expectation(description: "should post initial update") - var e2: XCTestExpectation! - var ruleList: WKContentRuleList! - let c = updating.userContentBlockingAssets.sink { assets in - if ruleList == nil { - ruleList = assets.rules(withName: "test") - e1.fulfill() - } else { - // ruleList should not be recompiled - XCTAssertTrue(assets.rules(withName: "test") === ruleList) - XCTAssertTrue(assets.isValid) - e2.fulfill() - } - } - - rulesManager.updatesSubject.send(Self.testUpdate()) - withExtendedLifetime(c) { - waitForExpectations(timeout: 1, handler: nil) - e2 = expectation(description: "should rebuild user scripts") - NotificationCenter.default.post(name: AppUserDefaults.Notifications.textSizeChange, object: nil) - waitForExpectations(timeout: 1, handler: nil) - } - } - func testWhenDidVerifyInternalUserNotificationSentThenUserScriptsAreRebuild() { let e1 = expectation(description: "should post initial update") var e2: XCTestExpectation! diff --git a/DuckDuckGoTests/MockFeatureFlagger.swift b/DuckDuckGoTests/MockFeatureFlagger.swift index 9125dc769f..7a8f568486 100644 --- a/DuckDuckGoTests/MockFeatureFlagger.swift +++ b/DuckDuckGoTests/MockFeatureFlagger.swift @@ -26,6 +26,10 @@ final class MockFeatureFlagger: FeatureFlagger { var enabledFeatureFlags: [FeatureFlag] = [] + init(enabledFeatureFlags: [FeatureFlag] = []) { + self.enabledFeatureFlags = enabledFeatureFlags + } + func isFeatureOn(for featureFlag: Flag, allowOverride: Bool) -> Bool { guard let flag = featureFlag as? FeatureFlag else { return false diff --git a/DuckDuckGoTests/MockTabDelegate.swift b/DuckDuckGoTests/MockTabDelegate.swift index b37a63a332..fefb80faa7 100644 --- a/DuckDuckGoTests/MockTabDelegate.swift +++ b/DuckDuckGoTests/MockTabDelegate.swift @@ -137,7 +137,8 @@ extension TabViewController { onboardingPixelReporter: contextualOnboardingPixelReporter, urlCredentialCreator: MockCredentialCreator(), featureFlagger: featureFlagger, - subscriptionCookieManager: SubscriptionCookieManagerMock() + subscriptionCookieManager: SubscriptionCookieManagerMock(), + textZoomCoordinator: MockTextZoomCoordinator() ) tab.attachWebView(configuration: .nonPersistent(), andLoadRequest: nil, consumeCookies: false, customWebView: customWebView) return tab diff --git a/DuckDuckGoTests/MockTextZoomCoordinator.swift b/DuckDuckGoTests/MockTextZoomCoordinator.swift new file mode 100644 index 0000000000..1fcaed95c3 --- /dev/null +++ b/DuckDuckGoTests/MockTextZoomCoordinator.swift @@ -0,0 +1,55 @@ +// +// MockTextZoomCoordinator.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation +@testable import DuckDuckGo +import Core +import WebKit + +class MockTextZoomCoordinator: TextZoomCoordinating { + + let isEnabled: Bool = true + + func textZoomLevel(forHost host: String?) -> TextZoomLevel { + return .percent100 + } + + func set(textZoomLevel level: DuckDuckGo.TextZoomLevel, forHost host: String?) { + } + + func onWebViewCreated(applyToWebView webView: WKWebView) { + } + + func onNavigationCommitted(applyToWebView webView: WKWebView) { + } + + func onTextZoomChange(applyToWebView webView: WKWebView) { + } + + func showTextZoomEditor(inController controller: UIViewController, forWebView webView: WKWebView) { + } + + func makeBrowsingMenuEntry(forLink: Link, inController controller: UIViewController, forWebView webView: WKWebView) -> BrowsingMenuEntry? { + return nil + } + + func resetTextZoomLevels(excludingDomains: [String]) { + } + +} diff --git a/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift b/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift index ff93a30198..99ad0e1b60 100644 --- a/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift +++ b/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift @@ -80,7 +80,9 @@ final class OnboardingDaxFavouritesTests: XCTestCase { tutorialSettings: tutorialSettingsMock, subscriptionFeatureAvailability: SubscriptionFeatureAvailabilityMock.enabled, voiceSearchHelper: MockVoiceSearchHelper(isSpeechRecognizerAvailable: true, voiceSearchEnabled: true), - subscriptionCookieManager: SubscriptionCookieManagerMock() + featureFlagger: MockFeatureFlagger(), + subscriptionCookieManager: SubscriptionCookieManagerMock(), + textZoomCoordinator: MockTextZoomCoordinator() ) let window = UIWindow(frame: UIScreen.main.bounds) window.rootViewController = UIViewController() diff --git a/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift b/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift index 7ccd6d49b9..3f1762975b 100644 --- a/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift +++ b/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift @@ -78,7 +78,9 @@ final class OnboardingNavigationDelegateTests: XCTestCase { contextualOnboardingPixelReporter: onboardingPixelReporter, subscriptionFeatureAvailability: SubscriptionFeatureAvailabilityMock.enabled, voiceSearchHelper: MockVoiceSearchHelper(isSpeechRecognizerAvailable: true, voiceSearchEnabled: true), - subscriptionCookieManager: SubscriptionCookieManagerMock()) + featureFlagger: MockFeatureFlagger(), + subscriptionCookieManager: SubscriptionCookieManagerMock(), + textZoomCoordinator: MockTextZoomCoordinator()) let window = UIWindow(frame: UIScreen.main.bounds) window.rootViewController = UIViewController() window.makeKeyAndVisible() diff --git a/DuckDuckGoTests/TextZoomTests.swift b/DuckDuckGoTests/TextZoomTests.swift new file mode 100644 index 0000000000..ca4974ee10 --- /dev/null +++ b/DuckDuckGoTests/TextZoomTests.swift @@ -0,0 +1,192 @@ +// +// TextZoomTests.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation +@testable import DuckDuckGo +import BrowserServicesKit +import Core +import XCTest +import WebKit + +final class TextZoomTests: XCTestCase { + + let viewScaleKey = "viewScale" + + func testZoomLevelAppliedToWebView() { + let storage = TextZoomStorage() + storage.textZoomLevels = [:] + + let coordinator: TextZoomCoordinating = makeTextZoomCoordinator(storage: storage) + let webView = URLFixedWebView(frame: .zero, configuration: .nonPersistent()) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onNavigationCommitted(applyToWebView: webView) + XCTAssertEqual(1.0, webView.value(forKey: viewScaleKey) as? Double) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onTextZoomChange(applyToWebView: webView) + XCTAssertEqual(1.0, webView.value(forKey: viewScaleKey) as? Double) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onWebViewCreated(applyToWebView: webView) + XCTAssertEqual(1.0, webView.value(forKey: viewScaleKey) as? Double) + + let host = "example.com" + webView.fixed = URL(string: "https://\(host)") + coordinator.set(textZoomLevel: .percent120, forHost: host) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onNavigationCommitted(applyToWebView: webView) + XCTAssertEqual(1.2, webView.value(forKey: viewScaleKey) as? Double) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onTextZoomChange(applyToWebView: webView) + XCTAssertEqual(1.2, webView.value(forKey: viewScaleKey) as? Double) + + webView.setValue(0.1, forKey: viewScaleKey) + coordinator.onWebViewCreated(applyToWebView: webView) + XCTAssertEqual(1.2, webView.value(forKey: viewScaleKey) as? Double) + + // When reset to the default then "forget" + coordinator.set(textZoomLevel: .percent100, forHost: host) + XCTAssertEqual(storage.textZoomLevels, [:]) + } + + func testMenuItemCreation() { + let host = "example.com" + + let storage = TextZoomStorage() + storage.textZoomLevels = [:] + + let coordinator: TextZoomCoordinating = makeTextZoomCoordinator(storage: storage) + coordinator.set(textZoomLevel: .percent120, forHost: host) + + let controller = UIViewController() + let webView = WKWebView(frame: .zero, configuration: .nonPersistent()) + + let item1 = coordinator.makeBrowsingMenuEntry( + forLink: makeLink(url: URL(string: "https://other.org")!), + inController: controller, + forWebView: webView) + + // Expecting the 'default' value + if case .regular(let name, _, _, _, _) = item1 { + XCTAssertEqual(UserText.textZoomMenuItem, name) + } else { + XCTFail("Unexpected menu item type") + } + + let item2 = coordinator.makeBrowsingMenuEntry( + forLink: makeLink(url: URL(string: "https://\(host)")!), + inController: controller, + forWebView: webView) + + // Expecting the menu item to include the percent + if case .regular(let name, _, _, _, _) = item2 { + XCTAssertEqual(UserText.textZoomWithPercentForMenuItem(120), name) + } else { + XCTFail("Unexpected menu item type") + } + + } + + func testSettingAndResetingDomainTextZoomLevels() { + let host1 = "example.com" + let host2 = "another.org" + + let storage = TextZoomStorage() + storage.textZoomLevels = [:] + + let coordinator: TextZoomCoordinating = makeTextZoomCoordinator(storage: storage) + coordinator.set(textZoomLevel: .percent120, forHost: host1) + XCTAssertEqual(coordinator.textZoomLevel(forHost: host1), .percent120) + + coordinator.set(textZoomLevel: .percent140, forHost: host2) + XCTAssertEqual(coordinator.textZoomLevel(forHost: host2), .percent140) + + coordinator.resetTextZoomLevels(excludingDomains: [host1]) + XCTAssertEqual(coordinator.textZoomLevel(forHost: host1), .percent120) + XCTAssertEqual(coordinator.textZoomLevel(forHost: host2), AppSettingsMock().defaultTextZoomLevel) + } + + func testWhenFeatureFlagEnabled_ThenCoordinatorIsEnabled() { + let controller = UIViewController() + let webView = WKWebView(frame: .zero, configuration: .nonPersistent()) + webView.setValue(0.1, forKey: viewScaleKey) + XCTAssertEqual(0.1, webView.value(forKey: viewScaleKey) as? Double) + + let featureFlagger = MockFeatureFlagger() + featureFlagger.enabledFeatureFlags = [.textZoom] + let coordinator: TextZoomCoordinating = makeTextZoomCoordinator(featureFlagger: featureFlagger) + XCTAssertTrue(coordinator.isEnabled) + + featureFlagger.enabledFeatureFlags = [] + XCTAssertFalse(coordinator.isEnabled) + + coordinator.onNavigationCommitted(applyToWebView: webView) + coordinator.onTextZoomChange(applyToWebView: webView) + coordinator.onWebViewCreated(applyToWebView: webView) + XCTAssertNil(coordinator.makeBrowsingMenuEntry(forLink: makeLink(), inController: controller, forWebView: webView)) + + XCTAssertEqual(0.1, webView.value(forKey: viewScaleKey) as? Double) + } + + private func makeTextZoomCoordinator( + appSettings: AppSettings = AppSettingsMock(), + storage: TextZoomStoring = MockTextZoomStorage(), + featureFlagger: FeatureFlagger = MockFeatureFlagger(enabledFeatureFlags: [.textZoom]) + ) -> TextZoomCoordinating { + return TextZoomCoordinator(appSettings: appSettings, + storage: storage, + featureFlagger: featureFlagger) + } + + private func makeLink(title: String? = "title", url: URL = .ddg, localPath: URL? = nil) -> Link { + return Link(title: title, url: url, localPath: localPath) + } + +} + +/// Nothing else should be using storage directly so just keeping it here out of the way. +private class MockTextZoomStorage: TextZoomStoring { + + func textZoomLevelForDomain(_ domain: String) -> DuckDuckGo.TextZoomLevel? { + return nil + } + + func set(textZoomLevel: DuckDuckGo.TextZoomLevel, forDomain domain: String) { + } + + func removeTextZoomLevel(forDomain domain: String) { + } + + func resetTextZoomLevels(excludingDomains: [String]) { + } + +} + +private class URLFixedWebView: WKWebView { + + var fixed: URL? + + override var url: URL? { + fixed + } + +} From 81c9a099288146d049b5867731855d88b98a8925 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Thu, 14 Nov 2024 08:36:15 -0800 Subject: [PATCH 21/56] Remove the `ld_classic` build setting (#3575) Task/Issue URL: https://app.asana.com/0/1199333091098016/1208760941595237/f Tech Design URL: CC: Description: This PR removes the legacy linker setting. --- DuckDuckGo.xcodeproj/project.pbxproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 310c116fad..bf8faaab9a 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9477,7 +9477,6 @@ IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-ld_classic"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -9533,7 +9532,6 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; - OTHER_LDFLAGS = "-ld_classic"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; SWIFT_COMPILATION_MODE = wholemodule; @@ -10428,7 +10426,6 @@ IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = "-ld_classic"; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ALPHA; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; From d1c3a62a77e5e7a2ab6dcbc45a9df08b4e03450f Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Thu, 14 Nov 2024 18:51:59 -0800 Subject: [PATCH 22/56] Upgrade to Xcode 16 (#3573) Task/Issue URL: https://app.asana.com/0/1203301625297703/1208329354262556/f This PR upgrades the app to support Xcode 16. Steps to test this PR: Check that CI is green and that this branch works locally when running on Xcode 16 --- .github/workflows/end-to-end.yml | 2 +- .github/workflows/nightly.yml | 4 ++-- .github/workflows/pr.yml | 8 ++++---- .github/workflows/sync-end-to-end.yml | 2 +- .../{01_fire_proofing.yml => 01_fire_proofing.yaml} | 0 ...uckduckgo_settings.yml => 02_duckduckgo_settings.yaml} | 0 .maestro/setup_ui_tests.sh | 6 +++--- .maestro/shared/remove_local_logins.yaml | 4 +++- .xcode-version | 2 +- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift | 2 +- 12 files changed, 21 insertions(+), 19 deletions(-) rename .maestro/data_clearing_tests/{01_fire_proofing.yml => 01_fire_proofing.yaml} (100%) rename .maestro/data_clearing_tests/{02_duckduckgo_settings.yml => 02_duckduckgo_settings.yaml} (100%) diff --git a/.github/workflows/end-to-end.yml b/.github/workflows/end-to-end.yml index 094b1826b6..cd3cbe1299 100644 --- a/.github/workflows/end-to-end.yml +++ b/.github/workflows/end-to-end.yml @@ -42,7 +42,7 @@ jobs: run: | set -o pipefail && xcodebuild \ -scheme "DuckDuckGo" \ - -destination "platform=iOS Simulator,name=iPhone 15,OS=17.2" \ + -destination "platform=iOS Simulator,name=iPhone 16,OS=18.1" \ -derivedDataPath "DerivedData" \ -skipPackagePluginValidation \ -skipMacroValidation \ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index c68371f73e..2bff554068 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -44,7 +44,7 @@ jobs: run: | set -o pipefail && xcodebuild test \ -scheme "AtbUITests" \ - -destination "platform=iOS Simulator,name=iPhone 15,OS=17.2" \ + -destination "platform=iOS Simulator,name=iPhone 16,OS=18.1" \ -derivedDataPath "DerivedData" \ -skipPackagePluginValidation \ -skipMacroValidation \ @@ -87,7 +87,7 @@ jobs: run: | set -o pipefail && xcodebuild test \ -scheme "FingerprintingUITests" \ - -destination "platform=iOS Simulator,name=iPhone 15,OS=17.2" \ + -destination "platform=iOS Simulator,name=iPhone 16,OS=18.1" \ -derivedDataPath "DerivedData" \ -skipPackagePluginValidation \ -skipMacroValidation \ diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 2248bd73f8..763e3d8c21 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -39,7 +39,7 @@ jobs: name: Unit Tests - runs-on: macos-14-xlarge + runs-on: macos-15 timeout-minutes: 20 outputs: @@ -79,7 +79,7 @@ jobs: run: | set -o pipefail && xcodebuild test \ -scheme "DuckDuckGo" \ - -destination "platform=iOS Simulator,name=iPhone 15,OS=17.2" \ + -destination "platform=iOS Simulator,name=iPhone 16,OS=18.1" \ -derivedDataPath "DerivedData" \ -skipPackagePluginValidation \ -skipMacroValidation \ @@ -132,7 +132,7 @@ jobs: # Dependabot doesn't have access to all secrets, so we skip this job if: github.actor != 'dependabot[bot]' - runs-on: macos-14-xlarge + runs-on: macos-15 timeout-minutes: 30 steps: @@ -185,7 +185,7 @@ jobs: set -o pipefail && xcodebuild \ -scheme "DuckDuckGo" \ - -destination "platform=iOS Simulator,name=iPhone 15" \ + -destination "platform=iOS Simulator,name=iPhone 16" \ -derivedDataPath "DerivedData" \ -configuration "Release" \ -skipPackagePluginValidation \ diff --git a/.github/workflows/sync-end-to-end.yml b/.github/workflows/sync-end-to-end.yml index fc7d66c5d8..b2ea9a8661 100644 --- a/.github/workflows/sync-end-to-end.yml +++ b/.github/workflows/sync-end-to-end.yml @@ -42,7 +42,7 @@ jobs: run: | set -o pipefail && xcodebuild \ -scheme "DuckDuckGo" \ - -destination "platform=iOS Simulator,name=iPhone 15" \ + -destination "platform=iOS Simulator,name=iPhone 16" \ -derivedDataPath "DerivedData" \ -skipPackagePluginValidation \ -skipMacroValidation \ diff --git a/.maestro/data_clearing_tests/01_fire_proofing.yml b/.maestro/data_clearing_tests/01_fire_proofing.yaml similarity index 100% rename from .maestro/data_clearing_tests/01_fire_proofing.yml rename to .maestro/data_clearing_tests/01_fire_proofing.yaml diff --git a/.maestro/data_clearing_tests/02_duckduckgo_settings.yml b/.maestro/data_clearing_tests/02_duckduckgo_settings.yaml similarity index 100% rename from .maestro/data_clearing_tests/02_duckduckgo_settings.yml rename to .maestro/data_clearing_tests/02_duckduckgo_settings.yaml diff --git a/.maestro/setup_ui_tests.sh b/.maestro/setup_ui_tests.sh index 50cc291db7..d47d106b1a 100755 --- a/.maestro/setup_ui_tests.sh +++ b/.maestro/setup_ui_tests.sh @@ -7,8 +7,8 @@ source $(dirname $0)/common.sh ## Constants # The simulator command requires the hyphens -target_device="iPhone-15" -target_os="iOS-17-0" +target_device="iPhone-16" +target_os="iOS-18-1" ## Functions @@ -50,7 +50,7 @@ build_app() { echo "⏲️ Building the app" set -o pipefail && xcodebuild -project "$project_root"/DuckDuckGo.xcodeproj \ -scheme "DuckDuckGo" \ - -destination "platform=iOS Simulator,name=iPhone 15,OS=17.2" \ + -destination "platform=iOS Simulator,name=iPhone 16,OS=18.1" \ -derivedDataPath "$derived_data_path" \ -skipPackagePluginValidation \ -skipMacroValidation \ diff --git a/.maestro/shared/remove_local_logins.yaml b/.maestro/shared/remove_local_logins.yaml index e830ee3ec3..3abdf45299 100644 --- a/.maestro/shared/remove_local_logins.yaml +++ b/.maestro/shared/remove_local_logins.yaml @@ -2,6 +2,8 @@ appId: com.duckduckgo.mobile.ios --- - tapOn: Settings +- scrollUntilVisible: + element: Passwords - tapOn: Passwords - tapOn: Passcode field - inputText: "0000" @@ -10,4 +12,4 @@ appId: com.duckduckgo.mobile.ios - tapOn: Delete Password - tapOn: Delete Password - tapOn: Settings -- tapOn: Done \ No newline at end of file +- tapOn: Done diff --git a/.xcode-version b/.xcode-version index 232a7fc1a6..c32b0ec5ab 100644 --- a/.xcode-version +++ b/.xcode-version @@ -1 +1 @@ -15.4 +16.1 diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index bf8faaab9a..5f400e5844 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -11031,7 +11031,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 210.0.1; + version = 210.0.2; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 3234f8630b..69f1229996 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "183b9c111176fd7821cd17d01c01ddb38486c9ac", - "version" : "210.0.1" + "revision" : "07af4d672e003cc247e28a01b9fe3e77abaf49f9", + "version" : "210.0.2" } }, { @@ -68,8 +68,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/GRDB.swift.git", "state" : { - "revision" : "4225b85c9a0c50544e413a1ea1e502c802b44b35", - "version" : "2.4.0" + "revision" : "5b2f6a81099d26ae0f9e38788f51490cd6a4b202", + "version" : "2.4.2" } }, { diff --git a/DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift b/DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift index 1b3906eea1..f1c406cea8 100644 --- a/DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift +++ b/DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift @@ -452,7 +452,7 @@ extension ContextualDaxDialogsFactoryTests { XCTAssertNotNil(host.view) // THEN - waitForExpectations(timeout: 2.0) + waitForExpectations(timeout: 10.0) completionHandler() } From e9bec32b8d0e0c2474cc45682289706f0640baeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Fri, 15 Nov 2024 17:26:21 +0100 Subject: [PATCH 23/56] Prevent sending duplicate home tab pixel (#3580) Task/Issue URL: https://app.asana.com/0/414235014887631/1208773981053518/f Tech Design URL: CC: **Description**: Re-applies a fix from https://github.com/duckduckgo/iOS/pull/2503 on the `NewTabPageViewController` fixing a regression of firing duplicate `mh` pixels. **Steps to test this PR**: #### Cold start scenario 1. Turn off automatic data clearing (see https://app.asana.com/0/0/1208749384570653/f for context). 2. Clear all tabs or make sure New Tab page is the active tab. 3. Cold launch the app, verify single instance of `mh` pixel is sent. #### Tab switcher scenario 1. Open multiple tabs, make sure there's at least one New Tab. 2. In the tab switcher close some of tabs except New Tab. 3. `mh` pixel **should not** be fired. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- DuckDuckGo.xcodeproj/project.pbxproj | 4 + DuckDuckGo/NewTabPageViewController.swift | 18 +++- .../NewTabPageControllerPixelTests.swift | 93 +++++++++++++++++++ .../NewTabPageMessagesModelTests.swift | 2 +- 4 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 DuckDuckGoTests/NewTabPageControllerPixelTests.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 5f400e5844..e50ecf690b 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -364,6 +364,7 @@ 6FEC0B852C999352006B4F6E /* FavoriteItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FEC0B842C999352006B4F6E /* FavoriteItem.swift */; }; 6FEC0B882C999961006B4F6E /* FavoritesListInteractingAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FEC0B872C999961006B4F6E /* FavoritesListInteractingAdapter.swift */; }; 6FF915822B88E07A0042AC87 /* AdAttributionFetcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF915802B88E0750042AC87 /* AdAttributionFetcherTests.swift */; }; + 6FF9AD452CE766F700C5A406 /* NewTabPageControllerPixelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF9AD442CE766F700C5A406 /* NewTabPageControllerPixelTests.swift */; }; 7B1604E82CB685B400A44EC6 /* Logger+TipKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1604E72CB685B400A44EC6 /* Logger+TipKit.swift */; }; 7B1604EC2CB68BDA00A44EC6 /* TipKitController+ConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1604EB2CB68BDA00A44EC6 /* TipKitController+ConvenienceInitializers.swift */; }; 7B1604EE2CB68D2600A44EC6 /* TipKitDebugOptionsUIActionHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1604ED2CB68D2600A44EC6 /* TipKitDebugOptionsUIActionHandling.swift */; }; @@ -1673,6 +1674,7 @@ 6FEC0B842C999352006B4F6E /* FavoriteItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteItem.swift; sourceTree = ""; }; 6FEC0B872C999961006B4F6E /* FavoritesListInteractingAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesListInteractingAdapter.swift; sourceTree = ""; }; 6FF915802B88E0750042AC87 /* AdAttributionFetcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdAttributionFetcherTests.swift; sourceTree = ""; }; + 6FF9AD442CE766F700C5A406 /* NewTabPageControllerPixelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageControllerPixelTests.swift; sourceTree = ""; }; 7B1604E72CB685B400A44EC6 /* Logger+TipKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+TipKit.swift"; sourceTree = ""; }; 7B1604EB2CB68BDA00A44EC6 /* TipKitController+ConvenienceInitializers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TipKitController+ConvenienceInitializers.swift"; sourceTree = ""; }; 7B1604ED2CB68D2600A44EC6 /* TipKitDebugOptionsUIActionHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TipKitDebugOptionsUIActionHandling.swift; sourceTree = ""; }; @@ -3851,6 +3853,7 @@ 6F03CAFF2C32ED22004179A8 /* NewTabPage */ = { isa = PBXGroup; children = ( + 6FF9AD442CE766F700C5A406 /* NewTabPageControllerPixelTests.swift */, 6F03CB002C32ED42004179A8 /* NewTabPageMessagesModelTests.swift */, 6F40D15C2C34436200BF22F0 /* HomePageDisplayDailyPixelBucketTests.swift */, 6F934F852C58DB00008364E4 /* NewTabPageSettingsPersistentStorageTests.swift */, @@ -8148,6 +8151,7 @@ 987130C8294AAB9F00AB05E0 /* BookmarksTestHelpers.swift in Sources */, 9F4CC51D2C48D240006A96EB /* CoreDataDatabaseTestUtilities.swift in Sources */, C185ED672BD43DA100BAE9DC /* ImportPasswordsStatusHandlerTests.swift in Sources */, + 6FF9AD452CE766F700C5A406 /* NewTabPageControllerPixelTests.swift in Sources */, F198D7981E3A45D90088DA8A /* WKWebViewConfigurationExtensionTests.swift in Sources */, 6F3529FF2CDCEDFF00A59170 /* OmniBarLoadingStateBearerTests.swift in Sources */, 564DE45E2C45218500D23241 /* OnboardingNavigationDelegateTests.swift in Sources */, diff --git a/DuckDuckGo/NewTabPageViewController.swift b/DuckDuckGo/NewTabPageViewController.swift index b67eb9ac0f..02c0009e75 100644 --- a/DuckDuckGo/NewTabPageViewController.swift +++ b/DuckDuckGo/NewTabPageViewController.swift @@ -42,6 +42,8 @@ final class NewTabPageViewController: UIHostingController, NewTabPage { private weak var daxDialogViewController: DaxDialogViewController? private var daxDialogHeightConstraint: NSLayoutConstraint? + private let pixelFiring: PixelFiring.Type + var isDaxDialogVisible: Bool { daxDialogViewController?.view.isHidden == false } @@ -54,12 +56,14 @@ final class NewTabPageViewController: UIHostingController, NewTabPage { variantManager: VariantManager, newTabDialogFactory: any NewTabDaxDialogProvider, newTabDialogTypeProvider: NewTabDialogSpecProvider, - faviconLoader: FavoritesFaviconLoading) { + faviconLoader: FavoritesFaviconLoading, + pixelFiring: PixelFiring.Type = Pixel.self) { self.associatedTab = tab self.variantManager = variantManager self.newTabDialogFactory = newTabDialogFactory self.newTabDialogTypeProvider = newTabDialogTypeProvider + self.pixelFiring = pixelFiring newTabPageViewModel = NewTabPageViewModel() shortcutsSettingsModel = NewTabPageShortcutsSettingsModel() @@ -96,14 +100,20 @@ final class NewTabPageViewController: UIHostingController, NewTabPage { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) + view.backgroundColor = UIColor(designSystemColor: .background) + + // If there's no tab switcher then this will be true, if there is a tabswitcher then only allow the + // stuff below to happen if it's being dismissed + guard presentedViewController?.isBeingDismissed ?? true else { + return + } + associatedTab.viewed = true presentNextDaxDialog() - Pixel.fire(pixel: .homeScreenShown) + pixelFiring.fire(.homeScreenShown, withAdditionalParameters: [:]) sendDailyDisplayPixel() - - view.backgroundColor = UIColor(designSystemColor: .background) } private func setUpDaxDialog() { diff --git a/DuckDuckGoTests/NewTabPageControllerPixelTests.swift b/DuckDuckGoTests/NewTabPageControllerPixelTests.swift new file mode 100644 index 0000000000..be66b23ad0 --- /dev/null +++ b/DuckDuckGoTests/NewTabPageControllerPixelTests.swift @@ -0,0 +1,93 @@ +// +// NewTabPageControllerPixelTests.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import XCTest +import Core +@testable import DuckDuckGo +import SwiftUI + +final class NewTabPageControllerPixelTests: XCTestCase { + + override func setUp() { + super.setUp() + + PixelFiringMock.tearDown() + } + + override func tearDown() { + super.tearDown() + + PixelFiringMock.tearDown() + } + + func testHomeScreenPixelIsFiredOnAppear() { + let sut = createSUT() + sut.loadViewIfNeeded() + + sut.viewDidAppear(false) + + let count = PixelFiringMock.allPixelsFired.filter { $0.pixelName == Pixel.Event.homeScreenShown.name }.count + + XCTAssertEqual(count, 1) + } + + func testHomeScreenPixelIsNotFired_WhenPresentingOtherController() { + let expectation = XCTestExpectation(description: "View loaded") + let sut = createSUT() + + let window = UIWindow(frame: UIScreen.main.bounds) + let presentedVC = UIViewController() + window.rootViewController = sut + window.makeKeyAndVisible() + window.rootViewController?.present(presentedVC, animated: false, completion: nil) + + DispatchQueue.main.async { + XCTAssertTrue(sut.isViewLoaded) + XCTAssertTrue(presentedVC.isViewLoaded) + XCTAssertNotNil(sut.presentedViewController) + expectation.fulfill() + } + + wait(for: [expectation], timeout: 1) + + sut.viewDidAppear(false) + + let count = PixelFiringMock.allPixelsFired.filter { $0.pixelName == Pixel.Event.homeScreenShown.name }.count + + XCTAssertEqual(count, 0) + } + + private func createSUT() -> NewTabPageViewController { + NewTabPageViewController(tab: Tab(), + isNewTabPageCustomizationEnabled: false, + interactionModel: MockFavoritesListInteracting(), + homePageMessagesConfiguration: HomePageMessagesConfigurationMock(homeMessages: []), + variantManager: MockVariantManager(), + newTabDialogFactory: MockDaxDialogFactory(), + newTabDialogTypeProvider: MockNewTabDialogSpecProvider(), + faviconLoader: EmptyFaviconLoading(), + pixelFiring: PixelFiringMock.self) + } +} + +private class MockDaxDialogFactory: NewTabDaxDialogProvider { + func createDaxDialog(for homeDialog: DaxDialogs.HomeScreenSpec, onDismiss: @escaping () -> Void) -> EmptyView { + EmptyView() + } +} diff --git a/DuckDuckGoTests/NewTabPageMessagesModelTests.swift b/DuckDuckGoTests/NewTabPageMessagesModelTests.swift index d24d9edfa8..6ca484a5f1 100644 --- a/DuckDuckGoTests/NewTabPageMessagesModelTests.swift +++ b/DuckDuckGoTests/NewTabPageMessagesModelTests.swift @@ -250,7 +250,7 @@ final class NewTabPageMessagesModelTests: XCTestCase { } } -private class HomePageMessagesConfigurationMock: HomePageMessagesConfiguration { +class HomePageMessagesConfigurationMock: HomePageMessagesConfiguration { var homeMessages: [HomeMessage] init(homeMessages: [HomeMessage]) { From a255082e6ec90ba75a2ba497435ac8a11e7d7a58 Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Fri, 15 Nov 2024 18:36:24 +0000 Subject: [PATCH 24/56] apply translations for zoom text (#3583) Task/Issue URL: https://app.asana.com/0/392891325557410/1208623380535818/f Tech Design URL: CC: **Description**: Applies translations for the zoom text feature. **Steps to test this PR**: 1. Run the app and check a few different languages. 2. Smoke text zoom text functionality: * Change the zoom text from the browsing menu * Change the zoom text in settings --- DuckDuckGo/bg.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/cs.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/da.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/de.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/el.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/es.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/et.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/fi.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/fr.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/hr.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/hu.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/it.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/lt.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/lv.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/nb.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/nl.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/pl.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/ro.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/ru.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/sk.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/sl.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/sv.lproj/Localizable.strings | 13 +++++++++++-- DuckDuckGo/tr.lproj/Localizable.strings | 13 +++++++++++-- 23 files changed, 253 insertions(+), 46 deletions(-) diff --git a/DuckDuckGo/bg.lproj/Localizable.strings b/DuckDuckGo/bg.lproj/Localizable.strings index bab8e189f9..16bb673761 100644 --- a/DuckDuckGo/bg.lproj/Localizable.strings +++ b/DuckDuckGo/bg.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "ОК"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Мащабиране (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Мащабиране"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Мащабиране на текста (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Добавяне"; @@ -2253,7 +2262,7 @@ "settings.sync" = "Синхронизиране и архивиране"; /* Settings screen cell text for text size */ -"settings.text.size" = "Размер на текста"; +"settings.text.size" = "Мащабиране на текста по подразбиране"; /* Settings screen cell text for theme */ "settings.theme" = "Тема"; @@ -2601,7 +2610,7 @@ "tab.switcher.accessibility.label" = "Превключване на раздели"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Изберете предпочитания размер на текста. Уебсайтът, който разглеждате в DuckDuckGo, ще се регулира спрямо него."; +"textSize.description" = "Увеличете или намалете размера на текста във всички сайтове."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Размер на текста - %@"; diff --git a/DuckDuckGo/cs.lproj/Localizable.strings b/DuckDuckGo/cs.lproj/Localizable.strings index a446d620d2..83b208d86a 100644 --- a/DuckDuckGo/cs.lproj/Localizable.strings +++ b/DuckDuckGo/cs.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "DOBŘE"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zvětšení (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zvětšení"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Zvětšení textu (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Přidat"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synchronizace a zálohování"; /* Settings screen cell text for text size */ -"settings.text.size" = "Velikost textu"; +"settings.text.size" = "Výchozí velikost textu"; /* Settings screen cell text for theme */ "settings.theme" = "Téma"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Přepínač karet"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Vyberte preferovanou velikost textu. Webové stránky, které zobrazíte v DuckDuckGo, se tomu přizpůsobí."; +"textSize.description" = "Zvětši nebo zmenši text na všech webech."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Velikost textu – %@"; diff --git a/DuckDuckGo/da.lproj/Localizable.strings b/DuckDuckGo/da.lproj/Localizable.strings index 115988f39b..0f9f20718b 100644 --- a/DuckDuckGo/da.lproj/Localizable.strings +++ b/DuckDuckGo/da.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "Okay"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Tekst-zoom (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Tilføj"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synkronisering og sikkerhedskopiering"; /* Settings screen cell text for text size */ -"settings.text.size" = "Tekststørrelse"; +"settings.text.size" = "Standard tekstzoom"; /* Settings screen cell text for theme */ "settings.theme" = "Tema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Faneskifter"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Vælg din foretrukne tekststørrelse. Websteder, som du ser i DuckDuckGo, tilpasser sig denne."; +"textSize.description" = "Forøg eller formindsk tekststørrelsen på tværs af alle websteder."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Tekststørrelse - %@"; diff --git a/DuckDuckGo/de.lproj/Localizable.strings b/DuckDuckGo/de.lproj/Localizable.strings index 6ca64593f9..0c992c1ffd 100644 --- a/DuckDuckGo/de.lproj/Localizable.strings +++ b/DuckDuckGo/de.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Textzoom (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Hinzufügen"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synchronisieren und sichern"; /* Settings screen cell text for text size */ -"settings.text.size" = "Textgröße"; +"settings.text.size" = "Standardmäßiger Textzoom"; /* Settings screen cell text for theme */ "settings.theme" = "Design"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Tabwechsel-Bildschirm"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Wähle die gewünschte Textgröße aus. In DuckDuckGo angezeigte Websites werden sich daran anpassen."; +"textSize.description" = "Erhöhe oder verringere die Textgröße auf allen Seiten."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Textgröße – %@"; diff --git a/DuckDuckGo/el.lproj/Localizable.strings b/DuckDuckGo/el.lproj/Localizable.strings index 2fef03526b..41f550e73d 100644 --- a/DuckDuckGo/el.lproj/Localizable.strings +++ b/DuckDuckGo/el.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "Εντάξει"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Ζουμ (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Ζουμ"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Ζουμ κειμένου (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Προσθήκη"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Συγχρονισμός και δημιουργία αντιγράφων ασφαλείας"; /* Settings screen cell text for text size */ -"settings.text.size" = "Μέγεθος κειμένου"; +"settings.text.size" = "Προεπιλεγμένο ζουμ κειμένου"; /* Settings screen cell text for theme */ "settings.theme" = "Θέμα"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Εναλλαγή καρτελών"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Επιλέξτε το προτιμώμενο μέγεθος κειμένου. Οι ιστότοποι που βλέπετε στο DuckDuckGo θα προσαρμοστούν σε αυτό."; +"textSize.description" = "Αυξήστε ή μειώστε το μέγεθος του κειμένου σε όλους τους ιστότοπους."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Μέγεθος κειμένου - %@"; diff --git a/DuckDuckGo/es.lproj/Localizable.strings b/DuckDuckGo/es.lproj/Localizable.strings index adc8c04a8a..15968c7091 100644 --- a/DuckDuckGo/es.lproj/Localizable.strings +++ b/DuckDuckGo/es.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "De acuerdo"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Zoom de texto (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Añadir"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Sincronización y copia de seguridad"; /* Settings screen cell text for text size */ -"settings.text.size" = "Tamaño del texto"; +"settings.text.size" = "Zoom de texto predeterminado"; /* Settings screen cell text for theme */ "settings.theme" = "Tema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Cambiar pestañas"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Elige tu tamaño de texto preferido. Los sitios web que veas en DuckDuckGo se ajustarán a él."; +"textSize.description" = "Aumenta o disminuye el tamaño del texto en todos los sitios."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Tamaño del texto - %@"; diff --git a/DuckDuckGo/et.lproj/Localizable.strings b/DuckDuckGo/et.lproj/Localizable.strings index 9d94f5047e..66bfb39f19 100644 --- a/DuckDuckGo/et.lproj/Localizable.strings +++ b/DuckDuckGo/et.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Suurendus (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Suurendus"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Teksti suumimine (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Lisa"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Sünkroonimine ja varundamine"; /* Settings screen cell text for text size */ -"settings.text.size" = "Teksti suurus"; +"settings.text.size" = "Vaikimisi teksti suumimine"; /* Settings screen cell text for theme */ "settings.theme" = "Teema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Vahekaardi vahetaja"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Valige soovitud teksti suurus. Veebisaidid, mida DuckDuckGos vaatate, kohanduvad sellega."; +"textSize.description" = "Suurendage või vähendage teksti suurust kõigil saitidel."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Teksti suurus - %@"; diff --git a/DuckDuckGo/fi.lproj/Localizable.strings b/DuckDuckGo/fi.lproj/Localizable.strings index 9c85d1a744..f4793f560b 100644 --- a/DuckDuckGo/fi.lproj/Localizable.strings +++ b/DuckDuckGo/fi.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoomaus (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoomaus"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Tekstin zoomaus (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Lisää"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synkronoi ja varmuuskopioi"; /* Settings screen cell text for text size */ -"settings.text.size" = "Tekstin koko"; +"settings.text.size" = "Tekstin oletuszoomaus"; /* Settings screen cell text for theme */ "settings.theme" = "Teema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Välilehtien vaihtotyökalu"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Valitse tekstin koko. DuckDuckGossa tarkastelemasi verkkosivustot käyttävät sitä."; +"textSize.description" = "Suurenna tai pienennä tekstin kokoa kaikilla sivustoilla."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Tekstin koko - %@"; diff --git a/DuckDuckGo/fr.lproj/Localizable.strings b/DuckDuckGo/fr.lproj/Localizable.strings index f35339e3c8..623a9d5afc 100644 --- a/DuckDuckGo/fr.lproj/Localizable.strings +++ b/DuckDuckGo/fr.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Zoom du texte (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Ajouter"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synchronisation et sauvegarde"; /* Settings screen cell text for text size */ -"settings.text.size" = "Taille du texte"; +"settings.text.size" = "Zoom par défaut du texte"; /* Settings screen cell text for theme */ "settings.theme" = "Thème"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Outil de changement d'onglet"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Choisissez la taille du texte par défaut. La taille des polices des sites Web que vous consultez à partir de Duckduckgo sera ajustée en conséquence."; +"textSize.description" = "Augmentez ou diminuez la taille du texte sur tous les sites."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Taille du texte – %@"; diff --git a/DuckDuckGo/hr.lproj/Localizable.strings b/DuckDuckGo/hr.lproj/Localizable.strings index 5bb618e15f..cae52c7a73 100644 --- a/DuckDuckGo/hr.lproj/Localizable.strings +++ b/DuckDuckGo/hr.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "U redu"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zumiranje (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zumiranje"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Zumiranje teksta (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Dodaj"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Sinkronizacija i sigurnosno kopiranje"; /* Settings screen cell text for text size */ -"settings.text.size" = "Veličina teksta"; +"settings.text.size" = "Zadano zumiranje teksta"; /* Settings screen cell text for theme */ "settings.theme" = "Tema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Mjenjač kartica"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Odaberite željenu veličinu teksta. Web stranice koje pregledavate u DuckDuckGou prilagodit će se ovoj postavci."; +"textSize.description" = "Povećajte ili smanjite veličinu teksta na svim web-mjestima."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Veličina teksta: %@"; diff --git a/DuckDuckGo/hu.lproj/Localizable.strings b/DuckDuckGo/hu.lproj/Localizable.strings index dbfb665421..ef68e71d66 100644 --- a/DuckDuckGo/hu.lproj/Localizable.strings +++ b/DuckDuckGo/hu.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Nagyítás (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Nagyítás"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Szöveg nagyítása (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Hozzáadás"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Szinkronizálás és biztonsági mentés"; /* Settings screen cell text for text size */ -"settings.text.size" = "Szövegméret"; +"settings.text.size" = "Alapértelmezett szövegnagyítás"; /* Settings screen cell text for theme */ "settings.theme" = "Kinézet"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Lapváltó"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Válaszd ki a kívánt szövegméretet. A DuckDuckGo ennek használatával jeleníti meg a webhelyeket."; +"textSize.description" = "Növeld vagy csökkentsd a szöveg méretét az összes webhelyen."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Szövegméret: %@"; diff --git a/DuckDuckGo/it.lproj/Localizable.strings b/DuckDuckGo/it.lproj/Localizable.strings index d9712c048d..8c8191f7f5 100644 --- a/DuckDuckGo/it.lproj/Localizable.strings +++ b/DuckDuckGo/it.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Zoom testo (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Aggiungi"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Sincronizzazione e backup"; /* Settings screen cell text for text size */ -"settings.text.size" = "Dimensione testo"; +"settings.text.size" = "Zoom testo predefinito"; /* Settings screen cell text for theme */ "settings.theme" = "Tema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Selettore schede"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Scegli le dimensioni del testo che preferisci. I siti web che visualizzi su DuckDuckGo si adatteranno a questa impostazione."; +"textSize.description" = "Aumenta o diminuisci la dimensione del testo in tutti i siti."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Dimensione testo - %@"; diff --git a/DuckDuckGo/lt.lproj/Localizable.strings b/DuckDuckGo/lt.lproj/Localizable.strings index 117b42027f..a4a5da7f0e 100644 --- a/DuckDuckGo/lt.lproj/Localizable.strings +++ b/DuckDuckGo/lt.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "GERAI"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Padidinimas (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Padidinti"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Teksto mastelio keitimas (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Papildyti"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Sinchronizuoti ir kurti atsarginę kopiją"; /* Settings screen cell text for text size */ -"settings.text.size" = "Teksto dydis"; +"settings.text.size" = "Numatytasis teksto mastelio keitimas"; /* Settings screen cell text for theme */ "settings.theme" = "Tema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Skirtukų perjungiklis"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Pasirinkite norimą teksto dydį. „DuckDuckGo“ rodomos svetainės atitiks šį nustatymą."; +"textSize.description" = "Padidinti arba sumažinti teksto dydį visose svetainėse."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Teksto dydis – %@"; diff --git a/DuckDuckGo/lv.lproj/Localizable.strings b/DuckDuckGo/lv.lproj/Localizable.strings index 0760667d91..8d5a6c5dfb 100644 --- a/DuckDuckGo/lv.lproj/Localizable.strings +++ b/DuckDuckGo/lv.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "Labi"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Tālummaiņa (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Tālummaiņa"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Teksta tālummaiņa (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Pievienot"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Sinhronizācija un dublēšana"; /* Settings screen cell text for text size */ -"settings.text.size" = "Burtu izmērs"; +"settings.text.size" = "Noklusējuma teksta tālummaiņa"; /* Settings screen cell text for theme */ "settings.theme" = "Motīvs"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Ciļņu pārslēdzējs"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Izvēlies burtu izmēru. Vietnes tavā DuckDuckGo tam pielāgosies."; +"textSize.description" = "Palielini vai samazini teksta lielumu visās vietnēs."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Burtu izmērs — %@"; diff --git a/DuckDuckGo/nb.lproj/Localizable.strings b/DuckDuckGo/nb.lproj/Localizable.strings index eb37f0908e..8a1e7d1bd6 100644 --- a/DuckDuckGo/nb.lproj/Localizable.strings +++ b/DuckDuckGo/nb.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Tekstzoom (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Legg til"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synkronisering og sikkerhetskopiering"; /* Settings screen cell text for text size */ -"settings.text.size" = "Tekststørrelse"; +"settings.text.size" = "Standard tekstzoom"; /* Settings screen cell text for theme */ "settings.theme" = "Utseende"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Fanebytter"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Velg ønsket tekststørrelse. Nettsteder du ser på i DuckDuckGo tilpasser seg den."; +"textSize.description" = "Øk eller reduser tekststørrelsen på alle nettsteder."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Tekststørrelse – %@"; diff --git a/DuckDuckGo/nl.lproj/Localizable.strings b/DuckDuckGo/nl.lproj/Localizable.strings index ac787a200c..c86a8c2907 100644 --- a/DuckDuckGo/nl.lproj/Localizable.strings +++ b/DuckDuckGo/nl.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "In-/uitzoomen (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoomniveau"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Tekstgrootte (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Toevoegen"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synchronisatie en back-up"; /* Settings screen cell text for text size */ -"settings.text.size" = "Lettergrootte"; +"settings.text.size" = "Standaard tekstgrootte"; /* Settings screen cell text for theme */ "settings.theme" = "Thema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Wisselen tussen tabbladen"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Kies de gewenste tekstgrootte. Websites die je in DuckDuckGo bekijkt, worden aan de tekstgrootte aangepast."; +"textSize.description" = "Vergroot of verklein de tekstgrootte op alle sites."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Lettergrootte - %@"; diff --git a/DuckDuckGo/pl.lproj/Localizable.strings b/DuckDuckGo/pl.lproj/Localizable.strings index 7a65fbf6bf..3ed633cac8 100644 --- a/DuckDuckGo/pl.lproj/Localizable.strings +++ b/DuckDuckGo/pl.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Powiększenie (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Powiększenie"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Powiększenie tekstu (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Dodaj"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synchronizacja i kopia zapasowa"; /* Settings screen cell text for text size */ -"settings.text.size" = "Rozmiar tekstu"; +"settings.text.size" = "Domyślne powiększenie tekstu"; /* Settings screen cell text for theme */ "settings.theme" = "Motyw"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Przełącznik kart"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Wybierz preferowany rozmiar tekstu. Ustawienie będzie miało wpływ na witryny wyświetlane w przeglądarce DuckDuckGo."; +"textSize.description" = "Zwiększ lub zmniejsz rozmiar tekstu na wszystkich stronach."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Rozmiar tekstu – %@"; diff --git a/DuckDuckGo/ro.lproj/Localizable.strings b/DuckDuckGo/ro.lproj/Localizable.strings index 95b88cf50a..1444305508 100644 --- a/DuckDuckGo/ro.lproj/Localizable.strings +++ b/DuckDuckGo/ro.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Zoom text (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Adăugați"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Sincronizare și copiere de rezervă"; /* Settings screen cell text for text size */ -"settings.text.size" = "Dimensiune text"; +"settings.text.size" = "Zoom text implicit"; /* Settings screen cell text for theme */ "settings.theme" = "Temă"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Comutator între file"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Alege dimensiunea preferată a textului. Site-urile pe care le vizitezi în DuckDuckGo se vor adapta la aceasta."; +"textSize.description" = "Mărește sau micșorează dimensiunea textului pe toate site-urile."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Dimensiune text - %@"; diff --git a/DuckDuckGo/ru.lproj/Localizable.strings b/DuckDuckGo/ru.lproj/Localizable.strings index 33cb21334a..8d3dec89b8 100644 --- a/DuckDuckGo/ru.lproj/Localizable.strings +++ b/DuckDuckGo/ru.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "Хорошо"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Масштаб (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Масштаб"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Масштаб текста (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Добавить"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Синхронизация и резервное копирование"; /* Settings screen cell text for text size */ -"settings.text.size" = "Размер текста"; +"settings.text.size" = "Масштаб текста по умолчанию"; /* Settings screen cell text for theme */ "settings.theme" = "Тема"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Переключатель вкладок"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Выберите удобный для вас размер шрифта. DuckDuckGo настроит вид сайтов автоматически."; +"textSize.description" = "Масштаб текста любого сайта можно отрегулировать."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Размер текста — %@"; diff --git a/DuckDuckGo/sk.lproj/Localizable.strings b/DuckDuckGo/sk.lproj/Localizable.strings index e695d5169d..86e801f76e 100644 --- a/DuckDuckGo/sk.lproj/Localizable.strings +++ b/DuckDuckGo/sk.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zväčšenie (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zväčšenie"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Zväčšenie textu (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Pridať"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synchronizácia a zálohovanie"; /* Settings screen cell text for text size */ -"settings.text.size" = "Veľkosť textu"; +"settings.text.size" = "Predvolené zväčšenie textu"; /* Settings screen cell text for theme */ "settings.theme" = "Motív"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Prepínač kariet"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Vyberte si preferovanú veľkosť textu. Webové stránky zobrazené v DuckDuckGo sa tomu prispôsobia."; +"textSize.description" = "Zväčšite alebo zmenšite veľkosť textu na všetkých stránkach."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Veľkosť textu - %@"; diff --git a/DuckDuckGo/sl.lproj/Localizable.strings b/DuckDuckGo/sl.lproj/Localizable.strings index 7e79dd1cbd..6a279a7f42 100644 --- a/DuckDuckGo/sl.lproj/Localizable.strings +++ b/DuckDuckGo/sl.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "V REDU"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Povečava (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Povečava"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Povečava besedila (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Dodaj"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Sinhronizacija in varnostno kopiranje"; /* Settings screen cell text for text size */ -"settings.text.size" = "Velikost besedila"; +"settings.text.size" = "Privzeta povečava besedila"; /* Settings screen cell text for theme */ "settings.theme" = "Tema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Preklopi med zavihki"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Izberite želeno velikost besedila. Spletna mesta, ki se prikazujejo v iskalniku DuckDuckGo, se temu prilagodijo."; +"textSize.description" = "Povečajte ali zmanjšajte velikost besedila na vseh spletnih mestih."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Velikost besedila - %@"; diff --git a/DuckDuckGo/sv.lproj/Localizable.strings b/DuckDuckGo/sv.lproj/Localizable.strings index 4e82a701be..0f5c7a6eb4 100644 --- a/DuckDuckGo/sv.lproj/Localizable.strings +++ b/DuckDuckGo/sv.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "OK"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Zoom (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Zoom"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Textzoom (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Lägg till"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Synkronisering och säkerhetskopiering"; /* Settings screen cell text for text size */ -"settings.text.size" = "Textstorlek"; +"settings.text.size" = "Standardzoom för text"; /* Settings screen cell text for theme */ "settings.theme" = "Tema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Flikväxlare"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Välj önskad textstorlek. Webbplatser som du visar i DuckDuckGo anpassas efter din inställning."; +"textSize.description" = "Öka eller minska textstorleken på alla webbplatser."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Textstorlek – %@"; diff --git a/DuckDuckGo/tr.lproj/Localizable.strings b/DuckDuckGo/tr.lproj/Localizable.strings index 52e1dc4c0c..7612f8efaf 100644 --- a/DuckDuckGo/tr.lproj/Localizable.strings +++ b/DuckDuckGo/tr.lproj/Localizable.strings @@ -19,6 +19,15 @@ /* Button label for OK action */ "action.ok" = "Tamam"; +/* Title for text zoom menu item. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-menu-item" = "Yakınlaştır (%d%%)"; + +/* Text zoom menu item */ +"action.text-zoom-sheet-menu-item" = "Yakınlaştır"; + +/* Title for text zoom sheet view. %d%% is replaced with percent, e.g. 56% so do not change that please. */ +"action.text-zoom-sheet-title" = "Metin Yakınlaştırma (%d%%)"; + /* Add action - button shown in alert */ "action.title.add" = "Ekle"; @@ -2251,7 +2260,7 @@ "settings.sync" = "Senkronizasyon ve Yedekleme"; /* Settings screen cell text for text size */ -"settings.text.size" = "Metin Boyutu"; +"settings.text.size" = "Varsayılan Metin Yakınlaştırma"; /* Settings screen cell text for theme */ "settings.theme" = "Tema"; @@ -2599,7 +2608,7 @@ "tab.switcher.accessibility.label" = "Sekme Değiştirici"; /* Description text for the text size adjustment setting */ -"textSize.description" = "Tercih ettiğiniz metin boyutunu seçin. DuckDuckGo'da görüntülediğiniz web siteleri bu boyuta ayarlanır."; +"textSize.description" = "Tüm sitelerde metin boyutunu artırın veya azaltın."; /* Replacement string is a current percent value e.g. '120%' */ "textSize.footer" = "Metin Boyutu - %@"; From 260b44ba864e439c88ce9e1e563e63c5ad456d21 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Fri, 15 Nov 2024 18:43:31 -0800 Subject: [PATCH 25/56] Set `dryRun` for VPN and alpha pixels (#3578) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/414235014887631/1208771566285225/f Tech Design URL: CC: Description: This PR updates the dryRun check to be set for all debug builds. Previously, it was only being set for non-alpha builds, meaning that if you ran a debug alpha build, you were firing real pixels (and in one case, causing a pixel anomaly 😬). This changes was originally done since the alpha build was always setting DEBUG, but that's no longer true so the dryRun check can be simplified. --- DuckDuckGo/AppDelegate.swift | 2 +- .../NetworkProtectionPacketTunnelProvider.swift | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index 4305c5b418..185cf88fa1 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -138,7 +138,7 @@ import os.log } #endif -#if DEBUG && !ALPHA +#if DEBUG Pixel.isDryRun = true #else Pixel.isDryRun = false diff --git a/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift b/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift index 4399848fc6..5f8d7d5f19 100644 --- a/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift +++ b/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift @@ -395,6 +395,10 @@ final class NetworkProtectionPacketTunnelProvider: PacketTunnelProvider { } @objc init() { +#if DEBUG + Pixel.isDryRun = true +#endif + APIRequest.Headers.setUserAgent(DefaultUserAgentManager.duckDuckGoUserAgent) let settings = VPNSettings(defaults: .networkProtectionGroupDefaults) From 700dcec529cae87789168d64431939b126a194cc Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Fri, 15 Nov 2024 18:44:40 -0800 Subject: [PATCH 26/56] Wrap subscription-related navigation links in `LazyView` (#3576) Task/Issue URL: https://app.asana.com/0/414235014887631/1208761754194252/f Tech Design URL: CC: Description: This PR fixes an issue where subscription views were being fully initialized from the settings screen, rather than initializing when being navigated to. This isn't a problem for most of the subscription views, but the VPN view was having all of its various subscribers etc. spun up and reacting to state when they shouldn't have been. --- DuckDuckGo/SettingsSubscriptionView.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DuckDuckGo/SettingsSubscriptionView.swift b/DuckDuckGo/SettingsSubscriptionView.swift index 6c22e97d9d..b2414c2855 100644 --- a/DuckDuckGo/SettingsSubscriptionView.swift +++ b/DuckDuckGo/SettingsSubscriptionView.swift @@ -157,7 +157,7 @@ struct SettingsSubscriptionView: View { private var subscriptionDetailsView: some View { if settingsViewModel.state.subscription.entitlements.contains(.networkProtection) { - NavigationLink(destination: NetworkProtectionRootView(), isActive: $isShowingVPN) { + NavigationLink(destination: LazyView(NetworkProtectionRootView()), isActive: $isShowingVPN) { SettingsCellView( label: UserText.settingsPProVPNTitle, image: Image("SettingsPrivacyProVPN"), @@ -167,7 +167,7 @@ struct SettingsSubscriptionView: View { } if settingsViewModel.state.subscription.entitlements.contains(.dataBrokerProtection) { - NavigationLink(destination: SubscriptionPIRView(), isActive: $isShowingDBP) { + NavigationLink(destination: LazyView(SubscriptionPIRView()), isActive: $isShowingDBP) { SettingsCellView( label: UserText.settingsPProDBPTitle, image: Image("SettingsPrivacyProPIR"), @@ -178,7 +178,7 @@ struct SettingsSubscriptionView: View { if settingsViewModel.state.subscription.entitlements.contains(.identityTheftRestoration) { NavigationLink( - destination: SubscriptionITPView(), + destination: LazyView(SubscriptionITPView()), isActive: $isShowingITP) { SettingsCellView( label: UserText.settingsPProITRTitle, @@ -188,7 +188,7 @@ struct SettingsSubscriptionView: View { } } - NavigationLink(destination: SubscriptionSettingsView(configuration: .subscribed, settingsViewModel: settingsViewModel) + NavigationLink(destination: LazyView(SubscriptionSettingsView(configuration: .subscribed, settingsViewModel: settingsViewModel)) .environmentObject(subscriptionNavigationCoordinator) ) { SettingsCustomCell(content: { manageSubscriptionView }) From 5f89b4be78522cd0d801be35defc7815b333cef1 Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Mon, 18 Nov 2024 11:18:44 +0100 Subject: [PATCH 27/56] Temporarily disable TipKit (#3564) **IMPORTANT:** Before merging, please update the target branch to internal. I haven't done that yet because the internal branch isn't yet available. Task/Issue URL: https://app.asana.com/0/1207603085593419/1208724397684354/f ## Description TipKit's `configure` call is causing crashes in iOS. --- DuckDuckGo/TipKit/TipKitAppEventHandling.swift | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/DuckDuckGo/TipKit/TipKitAppEventHandling.swift b/DuckDuckGo/TipKit/TipKitAppEventHandling.swift index 572427579a..d747af3fd4 100644 --- a/DuckDuckGo/TipKit/TipKitAppEventHandling.swift +++ b/DuckDuckGo/TipKit/TipKitAppEventHandling.swift @@ -39,10 +39,15 @@ struct TipKitAppEventHandler: TipKitAppEventHandling { func appDidFinishLaunching() { if #available(iOS 17.0, *) { - controller.configureTipKit([ - .displayFrequency(.immediate), - .datastoreLocation(.applicationDefault) - ]) + // TipKit is temporarily disabled. + // See https://app.asana.com/0/inbox/1203108348814444/1208724397684354/1208739407931826 + // for more information + logger.log("TipKit is temporarily disabled.") + + // controller.configureTipKit([ + // .displayFrequency(.immediate), + // .datastoreLocation(.applicationDefault) + // ]) } else { logger.log("TipKit initialization skipped: iOS 17.0 or later is required.") } From f8bf08eb04cd021db522b3ef22f6143beded4725 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Mon, 18 Nov 2024 11:23:30 +0100 Subject: [PATCH 28/56] Fix button shapes on New Tab Page (#3586) Task/Issue URL: https://app.asana.com/0/1206226850447395/1208777193348112/f Tech Design URL: CC: **Description**: Default button style in SwiftUI is defining a border shape which is visible when "Button Shapes" are enabled in _Accessibility -> Display & Text Size_. This sets custom button styles to plain in order to prevent them from appearing. **Steps to test this PR**: 1. Enable _Accessibility -> Display & Text Size -> Button Shapes_ 2. Make sure there is no gray-ish shape around Favorites 3. Enable NTP Sections in Debug settings 4. Check there's no border around shortcuts on New Tab Page and in Customize view. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Device Testing**: * [ ] iPhone SE (1st Gen) * [ ] iPhone 8 * [ ] iPhone X * [ ] iPhone 14 Pro * [ ] iPad **OS Testing**: * [ ] iOS 15 * [ ] iOS 16 * [ ] iOS 17 **Theme Testing**: * [ ] Light theme * [ ] Dark theme --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- DuckDuckGo/EditableShortcutsView.swift | 1 + DuckDuckGo/FavoritesView.swift | 1 + DuckDuckGo/ShortcutsView.swift | 1 + 3 files changed, 3 insertions(+) diff --git a/DuckDuckGo/EditableShortcutsView.swift b/DuckDuckGo/EditableShortcutsView.swift index df40c9cbc8..40a00a6e73 100644 --- a/DuckDuckGo/EditableShortcutsView.swift +++ b/DuckDuckGo/EditableShortcutsView.swift @@ -37,6 +37,7 @@ struct EditableShortcutsView: View { ShortcutItemView(shortcut: setting.item, accessoryType: isEnabled ? .selected : .add) .frame(width: NewTabPageGrid.Item.edgeSize) } + .buttonStyle(.plain) .padding([.horizontal, .top], 6) // Adjust for the accessory being cut-off when lifting for preview .previewShape() } preview: { setting in diff --git a/DuckDuckGo/FavoritesView.swift b/DuckDuckGo/FavoritesView.swift index a8a7620052..b12123857f 100644 --- a/DuckDuckGo/FavoritesView.swift +++ b/DuckDuckGo/FavoritesView.swift @@ -108,6 +108,7 @@ struct FavoritesView: View { .background(.clear) .frame(width: NewTabPageGrid.Item.edgeSize) }) + .buttonStyle(.plain) case .addFavorite: Button(action: { isAddingFavorite = true diff --git a/DuckDuckGo/ShortcutsView.swift b/DuckDuckGo/ShortcutsView.swift index 0b83fc7b22..867461fb42 100644 --- a/DuckDuckGo/ShortcutsView.swift +++ b/DuckDuckGo/ShortcutsView.swift @@ -33,6 +33,7 @@ struct ShortcutsView: View { } label: { ShortcutItemView(shortcut: shortcut, accessoryType: nil) } + .buttonStyle(.plain) } } } From 52b2b79c511498e5fe44b9e98a2ee270b278cd7a Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Mon, 18 Nov 2024 03:06:01 -0800 Subject: [PATCH 29/56] Update VPN auth token check logic (#3585) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1207603085593419/1208194658564979/f Tech Design URL: CC: **Description**: This PR updates the auth token check logic. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index e50ecf690b..49a05c4c5e 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -11035,7 +11035,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 210.0.2; + version = 210.0.3; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 69f1229996..ce3cd40e6c 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "07af4d672e003cc247e28a01b9fe3e77abaf49f9", - "version" : "210.0.2" + "revision" : "a296f015a572fdfe53a81de653efb9a6d7fc3eba", + "version" : "210.0.3" } }, { From 79366f2996f69018047e37a7244087af7a66b3a7 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Mon, 18 Nov 2024 07:13:11 -0800 Subject: [PATCH 30/56] Fix alpha build compilation (#3584) Task/Issue URL: https://app.asana.com/0/414235014887631/1208782910427477/f Tech Design URL: CC: Description: This PR fixes alpha build compilation. --- .github/workflows/alpha.yml | 7 ------- DuckDuckGo.xcodeproj/project.pbxproj | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 763f15db1e..ff6cda27e6 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -40,13 +40,6 @@ jobs: steps: - - name: Assert main branch - run: | - case "${{ github.ref }}" in - *main) ;; - *) echo "👎 Not main branch"; exit 1 ;; - esac - - name: Register SSH keys for access to certificates uses: webfactory/ssh-agent@v0.7.0 with: diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 49a05c4c5e..3506b3cf5f 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -10456,6 +10456,7 @@ "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.mobile.ios.alpha; + PRODUCT_MODULE_NAME = DuckDuckGo; PRODUCT_NAME = "$(TARGET_NAME)-Alpha"; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.duckduckgo.mobile.ios.alpha"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ALPHA; From 7b35da416872908aaf1a7e68336db546aa52872d Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Tue, 19 Nov 2024 11:18:35 +0100 Subject: [PATCH 31/56] Limits TipKit availability to iOS 18+ (#3589) ### Important: this is open for review, but DO NOT MERGE until we can point at the internal release branch. Task/Issue URL: https://app.asana.com/0/1206580121312550/1208786321276837/f ## Description Two changes are introduces here: - We're improving how we handle the TipKit remote feature flag to include the `setup` call at startup. - We're limiting TipKit support to iOS 18+ because of the high amount of crashes we saw on iOS 17. --- DuckDuckGo/NetworkProtectionStatusView.swift | 12 +++++----- .../TipKit/TipKitAppEventHandling.swift | 24 +++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/DuckDuckGo/NetworkProtectionStatusView.swift b/DuckDuckGo/NetworkProtectionStatusView.swift index 21e79aa654..88e6768dea 100644 --- a/DuckDuckGo/NetworkProtectionStatusView.swift +++ b/DuckDuckGo/NetworkProtectionStatusView.swift @@ -148,13 +148,13 @@ struct NetworkProtectionStatusView: View { .listRowBackground(Color(designSystemColor: .surface)) Section { - if #available(iOS 17.0, *) { + if #available(iOS 18.0, *) { widgetTipView() .tipImageSize(Self.defaultImageSize) .padding(.horizontal, 3) } - if #available(iOS 17.0, *) { + if #available(iOS 18.0, *) { snoozeTipView() .tipImageSize(Self.defaultImageSize) .padding(.horizontal, 3) @@ -256,7 +256,7 @@ struct NetworkProtectionStatusView: View { .listRowBackground(Color(designSystemColor: .surface)) Section { - if #available(iOS 17.0, *) { + if #available(iOS 18.0, *) { geoswitchingTipView() .tipImageSize(Self.defaultImageSize) .padding(.horizontal, 3) @@ -351,7 +351,7 @@ struct NetworkProtectionStatusView: View { // MARK: - Tips - @available(iOS 17.0, *) + @available(iOS 18.0, *) @ViewBuilder private func geoswitchingTipView() -> some View { if statusModel.canShowTips { @@ -363,7 +363,7 @@ struct NetworkProtectionStatusView: View { } } - @available(iOS 17.0, *) + @available(iOS 18.0, *) @ViewBuilder private func snoozeTipView() -> some View { if statusModel.canShowTips, @@ -376,7 +376,7 @@ struct NetworkProtectionStatusView: View { } } - @available(iOS 17.0, *) + @available(iOS 18.0, *) @ViewBuilder private func widgetTipView() -> some View { if statusModel.canShowTips, diff --git a/DuckDuckGo/TipKit/TipKitAppEventHandling.swift b/DuckDuckGo/TipKit/TipKitAppEventHandling.swift index d747af3fd4..1fb5e851bc 100644 --- a/DuckDuckGo/TipKit/TipKitAppEventHandling.swift +++ b/DuckDuckGo/TipKit/TipKitAppEventHandling.swift @@ -18,6 +18,7 @@ // import Core +import BrowserServicesKit import Foundation import os.log @@ -28,26 +29,29 @@ protocol TipKitAppEventHandling { struct TipKitAppEventHandler: TipKitAppEventHandling { private let controller: TipKitController + private let featureFlagger: FeatureFlagger private let logger: Logger init(controller: TipKitController = .make(), + featureFlagger: FeatureFlagger = AppDependencyProvider.shared.featureFlagger, logger: Logger = .tipKit) { self.controller = controller + self.featureFlagger = featureFlagger self.logger = logger } func appDidFinishLaunching() { - if #available(iOS 17.0, *) { - // TipKit is temporarily disabled. - // See https://app.asana.com/0/inbox/1203108348814444/1208724397684354/1208739407931826 - // for more information - logger.log("TipKit is temporarily disabled.") - - // controller.configureTipKit([ - // .displayFrequency(.immediate), - // .datastoreLocation(.applicationDefault) - // ]) + guard featureFlagger.isFeatureOn(.networkProtectionUserTips) else { + logger.log("TipKit disabled by remote feature flag.") + return + } + + if #available(iOS 18.0, *) { + controller.configureTipKit([ + .displayFrequency(.immediate), + .datastoreLocation(.applicationDefault) + ]) } else { logger.log("TipKit initialization skipped: iOS 17.0 or later is required.") } From b8f782f27ad2a39011421cee3ed4dd9ecc0d9e0d Mon Sep 17 00:00:00 2001 From: Michal Smaga Date: Tue, 19 Nov 2024 12:00:10 +0100 Subject: [PATCH 32/56] Update subtitle (#3592) Task/Issue URL: https://app.asana.com/0/414709148257752/1208697680588906/f **Description**: Update app metadata. It was already included in https://github.com/duckduckgo/iOS/releases/tag/7.144.0 but the change was never merged back to `main`. --- fastlane/metadata/en-CA/subtitle.txt | 2 +- fastlane/metadata/en-GB/subtitle.txt | 2 +- fastlane/metadata/en-US/subtitle.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fastlane/metadata/en-CA/subtitle.txt b/fastlane/metadata/en-CA/subtitle.txt index 5d60b334ee..fa81d8347f 100644 --- a/fastlane/metadata/en-CA/subtitle.txt +++ b/fastlane/metadata/en-CA/subtitle.txt @@ -1 +1 @@ -Privacy, simplified. \ No newline at end of file +Your protection, our priority. \ No newline at end of file diff --git a/fastlane/metadata/en-GB/subtitle.txt b/fastlane/metadata/en-GB/subtitle.txt index 5d60b334ee..fa81d8347f 100644 --- a/fastlane/metadata/en-GB/subtitle.txt +++ b/fastlane/metadata/en-GB/subtitle.txt @@ -1 +1 @@ -Privacy, simplified. \ No newline at end of file +Your protection, our priority. \ No newline at end of file diff --git a/fastlane/metadata/en-US/subtitle.txt b/fastlane/metadata/en-US/subtitle.txt index 5d60b334ee..fa81d8347f 100644 --- a/fastlane/metadata/en-US/subtitle.txt +++ b/fastlane/metadata/en-US/subtitle.txt @@ -1 +1 @@ -Privacy, simplified. \ No newline at end of file +Your protection, our priority. \ No newline at end of file From 38b2d673bba0de4ea5c87242a1e5a5690586300c Mon Sep 17 00:00:00 2001 From: Shane Osbourne Date: Tue, 19 Nov 2024 18:11:52 +0000 Subject: [PATCH 33/56] deps: Bump CSS@6.36.0 and BSK@211 (#3588) Task/Issue URL: https://app.asana.com/0/1201141132935289/1208785705095083/f Description: Just a BSK bump, no functional changes on iOS --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 14 +++++++------- DuckDuckGo/EmailSignupViewController.swift | 1 + DuckDuckGo/ScriptSourceProviding.swift | 4 ++++ DuckDuckGo/TabViewController.swift | 1 + 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 3506b3cf5f..1581ebb322 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -11036,7 +11036,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 210.0.3; + version = 211.0.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ce3cd40e6c..cdb32f0f44 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "a296f015a572fdfe53a81de653efb9a6d7fc3eba", - "version" : "210.0.3" + "revision" : "7033b0d6f166ac8152cff602f1a1301641f4da60", + "version" : "211.0.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "adca39c379b1a124f9990e9d0308c374f32f5018", - "version" : "6.32.0" + "revision" : "f2caf4ff814f4714d07d6fc2cf02498cb54a1389", + "version" : "6.36.0" } }, { @@ -122,8 +122,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/privacy-dashboard", "state" : { - "revision" : "53fd1a0f8d91fcf475d9220f810141007300dffd", - "version" : "7.1.1" + "revision" : "757bbbae1e2afbb421caee9bfca04ee5c56c3af8", + "version" : "7.2.0" } }, { @@ -138,7 +138,7 @@ { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-argument-parser.git", + "location" : "https://github.com/apple/swift-argument-parser", "state" : { "revision" : "0fbc8848e389af3bb55c182bc19ca9d5dc2f255b", "version" : "1.4.0" diff --git a/DuckDuckGo/EmailSignupViewController.swift b/DuckDuckGo/EmailSignupViewController.swift index e0c405ec61..056f861310 100644 --- a/DuckDuckGo/EmailSignupViewController.swift +++ b/DuckDuckGo/EmailSignupViewController.swift @@ -425,6 +425,7 @@ extension EmailSignupViewController: SecureVaultManagerDelegate { func secureVaultManager(_: SecureVaultManager, didRequestRuntimeConfigurationForDomain domain: String, completionHandler: @escaping (String?) -> Void) { let contentScopeProperties = ContentScopeProperties(gpcEnabled: AppDependencyProvider.shared.appSettings.sendDoNotSell, sessionKey: "", + messageSecret: "", featureToggles: ContentScopeFeatureToggles.supportedFeaturesOniOS) let runtimeConfig = DefaultAutofillSourceProvider.Builder(privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager, diff --git a/DuckDuckGo/ScriptSourceProviding.swift b/DuckDuckGo/ScriptSourceProviding.swift index 99ed069329..9d1d79a2c4 100644 --- a/DuckDuckGo/ScriptSourceProviding.swift +++ b/DuckDuckGo/ScriptSourceProviding.swift @@ -32,6 +32,7 @@ protocol ScriptSourceProviding { var autofillSourceProvider: AutofillUserScriptSourceProvider { get } var contentScopeProperties: ContentScopeProperties { get } var sessionKey: String { get } + var messageSecret: String { get } } @@ -45,6 +46,7 @@ struct DefaultScriptSourceProvider: ScriptSourceProviding { let autofillSourceProvider: AutofillUserScriptSourceProvider let contentScopeProperties: ContentScopeProperties let sessionKey: String + let messageSecret: String let privacyConfigurationManager: PrivacyConfigurationManaging let contentBlockingManager: ContentBlockerRulesManagerProtocol @@ -63,8 +65,10 @@ struct DefaultScriptSourceProvider: ScriptSourceProviding { surrogatesConfig = Self.buildSurrogatesConfig(contentBlockingManager: contentBlockingManager, privacyConfigurationManager: privacyConfigurationManager) sessionKey = Self.generateSessionKey() + messageSecret = Self.generateSessionKey() contentScopeProperties = ContentScopeProperties(gpcEnabled: appSettings.sendDoNotSell, sessionKey: sessionKey, + messageSecret: messageSecret, featureToggles: ContentScopeFeatureToggles.supportedFeaturesOniOS) autofillSourceProvider = Self.makeAutofillSource(privacyConfigurationManager: privacyConfigurationManager, properties: contentScopeProperties) diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 7e4bb51b8c..2f8e8f90b8 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -2976,6 +2976,7 @@ extension TabViewController: SecureVaultManagerDelegate { return ContentScopeProperties(gpcEnabled: appSettings.sendDoNotSell, sessionKey: autofillUserScript?.sessionKey ?? "", + messageSecret: autofillUserScript?.messageSecret ?? "", featureToggles: supportedFeatures) } From fbdb90ba126f5953e677a32c8bc60816a5e7e16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20=C5=81yp?= Date: Tue, 19 Nov 2024 21:07:04 +0100 Subject: [PATCH 34/56] Release 7.146.0-0 (#3594) --- Configuration/Version.xcconfig | 2 +- .../AppPrivacyConfigurationDataProvider.swift | 4 +- Core/ios-config.json | 110 ++++++++++++++---- DuckDuckGo.xcodeproj/project.pbxproj | 56 ++++----- DuckDuckGo/Settings.bundle/Root.plist | 2 +- fastlane/metadata/default/release_notes.txt | 1 - 6 files changed, 118 insertions(+), 57 deletions(-) diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig index a31bce32d5..daea147db4 100644 --- a/Configuration/Version.xcconfig +++ b/Configuration/Version.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 7.145.0 +MARKETING_VERSION = 7.146.0 diff --git a/Core/AppPrivacyConfigurationDataProvider.swift b/Core/AppPrivacyConfigurationDataProvider.swift index b83c4fa194..e9ffce7241 100644 --- a/Core/AppPrivacyConfigurationDataProvider.swift +++ b/Core/AppPrivacyConfigurationDataProvider.swift @@ -23,8 +23,8 @@ import BrowserServicesKit final public class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider { public struct Constants { - public static let embeddedDataETag = "\"bd1f5490770791f68fa9667d530758a9\"" - public static let embeddedDataSHA = "86b8c31a53f781d66dbc16eb09578d28149fee6c0e280fc75ddafeed8a4b46ac" + public static let embeddedDataETag = "\"d4536be677d4324aa872d0e59d6fd4fa\"" + public static let embeddedDataSHA = "a9cce4d5c3430bc3bbca33ad26aa980dcc1c0e792b71ce2696f4483401efbf72" } public var embeddedDataEtag: String { diff --git a/Core/ios-config.json b/Core/ios-config.json index d04ad45857..1d46138c7b 100644 --- a/Core/ios-config.json +++ b/Core/ios-config.json @@ -1,7 +1,16 @@ { "readme": "https://github.com/duckduckgo/privacy-configuration", - "version": 1731320660413, + "version": 1732039368165, "features": { + "adAttributionReporting": { + "state": "disabled", + "exceptions": [], + "minSupportedVersion": "7.145.0", + "settings": { + "includeToken": false + }, + "hash": "1da4782852f0317459b4465d801eda1f" + }, "adClickAttribution": { "readme": "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#3rd-party-tracker-loading-protection", "state": "enabled", @@ -159,6 +168,9 @@ { "domain": "eurostar.com" }, + { + "domain": "geo.fr" + }, { "domain": "ksta.de" }, @@ -261,9 +273,6 @@ { "domain": "motorsport.com" }, - { - "domain": "paypal.com" - }, { "domain": "elmundotoday.com" }, @@ -408,7 +417,8 @@ ], "settings": { "disabledCMPs": [ - "healthline-media" + "healthline-media", + "bing.com" ] }, "state": "enabled", @@ -431,7 +441,7 @@ } } }, - "hash": "c2885a67db26958bdb316564d5c94878" + "hash": "730dcd99d488f1a4ae6f633a7574f8e3" }, "autofillBreakageReporter": { "state": "enabled", @@ -1421,12 +1431,6 @@ { "domain": "instructure.com" }, - { - "domain": "humana.com" - }, - { - "domain": "centerwellpharmacy.com" - }, { "domain": "marvel.com" }, @@ -1444,7 +1448,7 @@ } ], "state": "disabled", - "hash": "33c2d56a2a9dd43c88a353d8a57dfa72" + "hash": "fce0a9ccd7ae060d25e7debe4d8905fb" }, "customUserAgent": { "settings": { @@ -1465,10 +1469,6 @@ { "domain": "ihg.com", "reason": "https://github.com/duckduckgo/privacy-configuration/pull/2383" - }, - { - "domain": "humana.com", - "reason": "https://github.com/duckduckgo/privacy-configuration/pull/2408" } ], "ddgDefaultSites": [ @@ -1498,7 +1498,7 @@ }, "exceptions": [], "state": "enabled", - "hash": "345d837217e74afd3f9e5fd04b208fa7" + "hash": "e577ccb473bdb7ada49c4d3c6e79cf01" }, "dbp": { "state": "disabled", @@ -1526,7 +1526,8 @@ "state": "disabled" }, "openInNewTab": { - "state": "internal" + "state": "enabled", + "minSupportedVersion": "7.144.0" }, "enableDuckPlayer": { "state": "enabled", @@ -1619,7 +1620,7 @@ ] }, "state": "enabled", - "hash": "c21895584fc5a38e4290c7941ec7d5f8" + "hash": "0181fe3479adc4db0b7dd140eb1bcc2e" }, "elementHiding": { "exceptions": [ @@ -2315,6 +2316,15 @@ } ] }, + { + "domain": "androidauthority.com", + "rules": [ + { + "selector": "div[data-ad-type]", + "type": "closest-empty" + } + ] + }, { "domain": "androidpolice.com", "rules": [ @@ -2913,6 +2923,14 @@ } ] }, + { + "domain": "expressnews.com", + "rules": [ + { + "type": "disable-default" + } + ] + }, { "domain": "fandom.com", "rules": [ @@ -3709,6 +3727,10 @@ { "selector": "[class^='ads__right-rail']", "type": "hide-empty" + }, + { + "selector": ".atf_mobile-scroll-ad", + "type": "hide" } ] }, @@ -4981,7 +5003,7 @@ ] }, "state": "enabled", - "hash": "2fa4c7c9bfd50585ee22d6c2d3bd3279" + "hash": "16e64ea4c926bdf7c865a8b7cbde1b2b" }, "exceptionHandler": { "exceptions": [ @@ -5212,6 +5234,15 @@ { "domain": "xfinity.com" }, + { + "domain": "centerwellpharmacy.com" + }, + { + "domain": "go365.com" + }, + { + "domain": "humana.com" + }, { "domain": "marvel.com" }, @@ -5232,7 +5263,7 @@ } ], "state": "enabled", - "hash": "cd4a8461973d1c1648dd20e6d1f532a7" + "hash": "b1f406c6ff87e27244d26289c0e383f9" }, "fingerprintingScreenSize": { "settings": { @@ -5615,6 +5646,15 @@ "state": "disabled", "hash": "728493ef7a1488e4781656d3f9db84aa" }, + "messageBridge": { + "exceptions": [], + "settings": { + "aiChat": "disabled", + "domains": [] + }, + "state": "disabled", + "hash": "cec85d8cf7db4b2abcbc450c66dd63fc" + }, "navigatorInterface": { "exceptions": [ { @@ -6898,6 +6938,7 @@ "ah.nl", "applesfera.com", "goplay.be", + "itsthevibe.com", "nytimes.com", "realmadrid.com", "rocketnews24.com", @@ -6940,6 +6981,7 @@ "rule": "securepubads.g.doubleclick.net/pagead/managed/js/gpt", "domains": [ "applesfera.com", + "itsthevibe.com", "triblive.com" ] }, @@ -7606,6 +7648,7 @@ "siouxlandnews.com", "southernoregoncw.com", "star64.tv", + "stockcharts.com", "thecw38.com", "thecw46.com", "thecwtc.com", @@ -8553,6 +8596,7 @@ "domains": [ "signupgenius.com", "smithsonianmag.com", + "stockcharts.com", "titantv.com" ] }, @@ -9254,6 +9298,12 @@ "" ] }, + { + "rule": "runtime.strm.yandex.ru/player/video/", + "domains": [ + "yandex.cloud" + ] + }, { "rule": "strm.yandex.ru/vh-special-converted/vod-content/", "domains": [ @@ -9427,7 +9477,7 @@ "domain": "instructure.com" } ], - "hash": "b7c276ffe1417313a46c0d13fbc9fcd9" + "hash": "f2f8b046c4ff4b5afb77a427106619da" }, "trackingCookies1p": { "settings": { @@ -9485,6 +9535,18 @@ { "domain": "axs.com" }, + { + "domain": "urldefense.com" + }, + { + "domain": "centerwellpharmacy.com" + }, + { + "domain": "go365.com" + }, + { + "domain": "humana.com" + }, { "domain": "marvel.com" }, @@ -9534,7 +9596,7 @@ ] }, "state": "enabled", - "hash": "3805ecfb8a129f70a99e73a364b38f38" + "hash": "3792a4970c07fe00da08f77e7dcf01ed" }, "userAgentRotation": { "settings": { diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 1581ebb322..d1904a4881 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9253,7 +9253,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -9290,7 +9290,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9380,7 +9380,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9407,7 +9407,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9554,7 +9554,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9579,7 +9579,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9648,7 +9648,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -9682,7 +9682,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9715,7 +9715,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9745,7 +9745,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10055,7 +10055,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10086,7 +10086,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10114,7 +10114,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10147,7 +10147,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -10177,7 +10177,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -10210,11 +10210,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10446,7 +10446,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10474,7 +10474,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10506,7 +10506,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10543,7 +10543,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10578,7 +10578,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10613,11 +10613,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10790,11 +10790,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10823,10 +10823,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/DuckDuckGo/Settings.bundle/Root.plist b/DuckDuckGo/Settings.bundle/Root.plist index cac348ca4f..917c98e508 100644 --- a/DuckDuckGo/Settings.bundle/Root.plist +++ b/DuckDuckGo/Settings.bundle/Root.plist @@ -6,7 +6,7 @@ DefaultValue - 7.145.0 + 7.146.0 Key version Title diff --git a/fastlane/metadata/default/release_notes.txt b/fastlane/metadata/default/release_notes.txt index a380910cf1..098fd1666f 100644 --- a/fastlane/metadata/default/release_notes.txt +++ b/fastlane/metadata/default/release_notes.txt @@ -1,2 +1 @@ -- Videos in Duck Player now open in a new tab by default, making it easier to navigate between YouTube and Duck Player. This setting can also be turned off in Settings > Duck Player. - Bug fixes and other improvements. \ No newline at end of file From 6642b4beda85cae80d193ce6f81117ee4119e154 Mon Sep 17 00:00:00 2001 From: Dax Mobile <44842493+daxmobile@users.noreply.github.com> Date: Wed, 20 Nov 2024 08:55:10 +1100 Subject: [PATCH 35/56] Update autoconsent to v11.5.0 (#3581) Task/Issue URL: https://app.asana.com/0/1208781796802514/1208781796802514 Autoconsent Release: https://github.com/duckduckgo/autoconsent/releases/tag/v11.5.0 ## Description Updates Autoconsent to version [v11.5.0](https://github.com/duckduckgo/autoconsent/releases/tag/v11.5.0). ### Autoconsent v11.5.0 release notes See release notes [here](https://github.com/duckduckgo/autoconsent/blob/v11.5.0/CHANGELOG.md) --- DuckDuckGo/Autoconsent/autoconsent-bundle.js | 446 ++++++++++++++++++- package-lock.json | 98 +++- package.json | 2 +- 3 files changed, 532 insertions(+), 14 deletions(-) diff --git a/DuckDuckGo/Autoconsent/autoconsent-bundle.js b/DuckDuckGo/Autoconsent/autoconsent-bundle.js index 1b1f441b79..a30f1e9d51 100644 --- a/DuckDuckGo/Autoconsent/autoconsent-bundle.js +++ b/DuckDuckGo/Autoconsent/autoconsent-bundle.js @@ -1 +1,445 @@ -!function(){"use strict";var e=class e{static setBase(t){e.base=t}static findElement(t,o=null,i=!1){let c=null;return c=null!=o?Array.from(o.querySelectorAll(t.selector)):null!=e.base?Array.from(e.base.querySelectorAll(t.selector)):Array.from(document.querySelectorAll(t.selector)),null!=t.textFilter&&(c=c.filter((e=>{const o=e.textContent.toLowerCase();if(Array.isArray(t.textFilter)){let e=!1;for(const i of t.textFilter)if(-1!==o.indexOf(i.toLowerCase())){e=!0;break}return e}if(null!=t.textFilter)return-1!==o.indexOf(t.textFilter.toLowerCase())}))),null!=t.styleFilters&&(c=c.filter((e=>{const o=window.getComputedStyle(e);let i=!0;for(const e of t.styleFilters){const t=o[e.option];i=e.negated?i&&t!==e.value:i&&t===e.value}return i}))),null!=t.displayFilter&&(c=c.filter((e=>t.displayFilter?0!==e.offsetHeight:0===e.offsetHeight))),null!=t.iframeFilter&&(c=c.filter((()=>t.iframeFilter?window.location!==window.parent.location:window.location===window.parent.location))),null!=t.childFilter&&(c=c.filter((o=>{const i=e.base;e.setBase(o);const c=e.find(t.childFilter);return e.setBase(i),null!=c.target}))),i?c:(c.length>1&&console.warn("Multiple possible targets: ",c,t,o),c[0])}static find(t,o=!1){const i=[];if(null!=t.parent){const c=e.findElement(t.parent,null,o);if(null!=c){if(c instanceof Array)return c.forEach((c=>{const n=e.findElement(t.target,c,o);n instanceof Array?n.forEach((e=>{i.push({parent:c,target:e})})):i.push({parent:c,target:n})})),i;{const n=e.findElement(t.target,c,o);n instanceof Array?n.forEach((e=>{i.push({parent:c,target:e})})):i.push({parent:c,target:n})}}}else{const c=e.findElement(t.target,null,o);c instanceof Array?c.forEach((e=>{i.push({parent:null,target:e})})):i.push({parent:null,target:c})}return 0===i.length&&i.push({parent:null,target:null}),o?i:(1!==i.length&&console.warn("Multiple results found, even though multiple false",i),i[0])}};e.base=null;var t=e;function o(e){const o=t.find(e);return"css"===e.type?!!o.target:"checkbox"===e.type?!!o.target&&o.target.checked:void 0}async function i(e,a){switch(e.type){case"click":return async function(e){const o=t.find(e);null!=o.target&&o.target.click();return n(c)}(e);case"list":return async function(e,t){for(const o of e.actions)await i(o,t)}(e,a);case"consent":return async function(e,t){for(const c of e.consents){const e=-1!==t.indexOf(c.type);if(c.matcher&&c.toggleAction){o(c.matcher)!==e&&await i(c.toggleAction)}else e?await i(c.trueAction):await i(c.falseAction)}}(e,a);case"ifcss":return async function(e,o){const c=t.find(e);c.target?e.falseAction&&await i(e.falseAction,o):e.trueAction&&await i(e.trueAction,o)}(e,a);case"waitcss":return async function(e){await new Promise((o=>{let i=e.retries||10;const c=e.waitTime||250,n=()=>{const a=t.find(e);(e.negated&&a.target||!e.negated&&!a.target)&&i>0?(i-=1,setTimeout(n,c)):o()};n()}))}(e);case"foreach":return async function(e,o){const c=t.find(e,!0),n=t.base;for(const n of c)n.target&&(t.setBase(n.target),await i(e.action,o));t.setBase(n)}(e,a);case"hide":return async function(e){const o=t.find(e);o.target&&o.target.classList.add("Autoconsent-Hidden")}(e);case"slide":return async function(e){const o=t.find(e),i=t.find(e.dragTarget);if(o.target){const e=o.target.getBoundingClientRect(),t=i.target.getBoundingClientRect();let c=t.top-e.top,n=t.left-e.left;"y"===this.config.axis.toLowerCase()&&(n=0),"x"===this.config.axis.toLowerCase()&&(c=0);const a=window.screenX+e.left+e.width/2,s=window.screenY+e.top+e.height/2,r=e.left+e.width/2,l=e.top+e.height/2,p=document.createEvent("MouseEvents");p.initMouseEvent("mousedown",!0,!0,window,0,a,s,r,l,!1,!1,!1,!1,0,o.target);const d=document.createEvent("MouseEvents");d.initMouseEvent("mousemove",!0,!0,window,0,a+n,s+c,r+n,l+c,!1,!1,!1,!1,0,o.target);const u=document.createEvent("MouseEvents");u.initMouseEvent("mouseup",!0,!0,window,0,a+n,s+c,r+n,l+c,!1,!1,!1,!1,0,o.target),o.target.dispatchEvent(p),await this.waitTimeout(10),o.target.dispatchEvent(d),await this.waitTimeout(10),o.target.dispatchEvent(u)}}(e);case"close":return async function(){window.close()}();case"wait":return async function(e){await n(e.waitTime)}(e);case"eval":return async function(e){return console.log("eval!",e.code),new Promise((t=>{try{e.async?(window.eval(e.code),setTimeout((()=>{t(window.eval("window.__consentCheckResult"))}),e.timeout||250)):t(window.eval(e.code))}catch(o){console.warn("eval error",o,e.code),t(!1)}}))}(e);default:throw"Unknown action type: "+e.type}}var c=0;function n(e){return new Promise((t=>{setTimeout((()=>{t()}),e)}))}function a(){return crypto&&void 0!==crypto.randomUUID?crypto.randomUUID():Math.random().toString()}var s=class{constructor(e,t=1e3){this.id=e,this.promise=new Promise(((e,t)=>{this.resolve=e,this.reject=t})),this.timer=window.setTimeout((()=>{this.reject(new Error("timeout"))}),t)}},r={pending:new Map,sendContentMessage:null};var l={EVAL_0:()=>console.log(1),EVAL_CONSENTMANAGER_1:()=>window.__cmp&&"object"==typeof __cmp("getCMPData"),EVAL_CONSENTMANAGER_2:()=>!__cmp("consentStatus").userChoiceExists,EVAL_CONSENTMANAGER_3:()=>__cmp("setConsent",0),EVAL_CONSENTMANAGER_4:()=>__cmp("setConsent",1),EVAL_CONSENTMANAGER_5:()=>__cmp("consentStatus").userChoiceExists,EVAL_COOKIEBOT_1:()=>!!window.Cookiebot,EVAL_COOKIEBOT_2:()=>!window.Cookiebot.hasResponse&&!0===window.Cookiebot.dialog?.visible,EVAL_COOKIEBOT_3:()=>window.Cookiebot.withdraw()||!0,EVAL_COOKIEBOT_4:()=>window.Cookiebot.hide()||!0,EVAL_COOKIEBOT_5:()=>!0===window.Cookiebot.declined,EVAL_KLARO_1:()=>{const e=globalThis.klaroConfig||globalThis.klaro?.getManager&&globalThis.klaro.getManager().config;if(!e)return!0;const t=(e.services||e.apps).filter((e=>!e.required)).map((e=>e.name));if(klaro&&klaro.getManager){const e=klaro.getManager();return t.every((t=>!e.consents[t]))}if(klaroConfig&&"cookie"===klaroConfig.storageMethod){const e=klaroConfig.cookieName||klaroConfig.storageName,o=JSON.parse(decodeURIComponent(document.cookie.split(";").find((t=>t.trim().startsWith(e))).split("=")[1]));return Object.keys(o).filter((e=>t.includes(e))).every((e=>!1===o[e]))}},EVAL_KLARO_OPEN_POPUP:()=>{klaro.show(void 0,!0)},EVAL_KLARO_TRY_API_OPT_OUT:()=>{if(window.klaro&&"function"==typeof klaro.show&&"function"==typeof klaro.getManager)try{return klaro.getManager().changeAll(!1),klaro.getManager().saveAndApplyConsents(),!0}catch(e){return console.warn(e),!1}return!1},EVAL_ONETRUST_1:()=>window.OnetrustActiveGroups.split(",").filter((e=>e.length>0)).length<=1,EVAL_TRUSTARC_TOP:()=>window&&window.truste&&"0"===window.truste.eu.bindMap.prefCookie,EVAL_TRUSTARC_FRAME_TEST:()=>window&&window.QueryString&&"0"===window.QueryString.preferences,EVAL_TRUSTARC_FRAME_GTM:()=>window&&window.QueryString&&"1"===window.QueryString.gtm,EVAL_ABC_TEST:()=>document.cookie.includes("trackingconsent"),EVAL_ADROLL_0:()=>!document.cookie.includes("__adroll_fpc"),EVAL_ALMACMP_0:()=>document.cookie.includes('"name":"Google","consent":false'),EVAL_AFFINITY_SERIF_COM_0:()=>document.cookie.includes("serif_manage_cookies_viewed")&&!document.cookie.includes("serif_allow_analytics"),EVAL_ARBEITSAGENTUR_TEST:()=>document.cookie.includes("cookie_consent=denied"),EVAL_AXEPTIO_0:()=>document.cookie.includes("axeptio_authorized_vendors=%2C%2C"),EVAL_BAHN_TEST:()=>1===utag.gdpr.getSelectedCategories().length,EVAL_BING_0:()=>document.cookie.includes("AL=0")&&document.cookie.includes("AD=0")&&document.cookie.includes("SM=0"),EVAL_BLOCKSY_0:()=>document.cookie.includes("blocksy_cookies_consent_accepted=no"),EVAL_BORLABS_0:()=>!JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>-1!==e.indexOf("borlabs-cookie"))).split("=",2)[1])).consents.statistics,EVAL_BUNDESREGIERUNG_DE_0:()=>document.cookie.match("cookie-allow-tracking=0"),EVAL_CANVA_0:()=>!document.cookie.includes("gtm_fpc_engagement_event"),EVAL_CC_BANNER2_0:()=>!!document.cookie.match(/sncc=[^;]+D%3Dtrue/),EVAL_CLICKIO_0:()=>document.cookie.includes("__lxG__consent__v2_daisybit="),EVAL_CLINCH_0:()=>document.cookie.includes("ctc_rejected=1"),EVAL_COOKIECONSENT2_TEST:()=>document.cookie.includes("cc_cookie="),EVAL_COOKIECONSENT3_TEST:()=>document.cookie.includes("cc_cookie="),EVAL_COINBASE_0:()=>JSON.parse(decodeURIComponent(document.cookie.match(/cm_(eu|default)_preferences=([0-9a-zA-Z\\{\\}\\[\\]%:]*);?/)[2])).consent.length<=1,EVAL_COMPLIANZ_BANNER_0:()=>document.cookie.includes("cmplz_banner-status=dismissed"),EVAL_COOKIE_LAW_INFO_0:()=>CLI.disableAllCookies()||CLI.reject_close()||!0,EVAL_COOKIE_LAW_INFO_1:()=>-1===document.cookie.indexOf("cookielawinfo-checkbox-non-necessary=yes"),EVAL_COOKIE_LAW_INFO_DETECT:()=>!!window.CLI,EVAL_COOKIE_MANAGER_POPUP_0:()=>!1===JSON.parse(document.cookie.split(";").find((e=>e.trim().startsWith("CookieLevel"))).split("=")[1]).social,EVAL_COOKIEALERT_0:()=>document.querySelector("body").removeAttribute("style")||!0,EVAL_COOKIEALERT_1:()=>document.querySelector("body").removeAttribute("style")||!0,EVAL_COOKIEALERT_2:()=>!0===window.CookieConsent.declined,EVAL_COOKIEFIRST_0:()=>{return!1===(e=JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>-1!==e.indexOf("cookiefirst"))).trim()).split("=")[1])).performance&&!1===e.functional&&!1===e.advertising;var e},EVAL_COOKIEFIRST_1:()=>document.querySelectorAll("button[data-cookiefirst-accent-color=true][role=checkbox]:not([disabled])").forEach((e=>"true"==e.getAttribute("aria-checked")&&e.click()))||!0,EVAL_COOKIEINFORMATION_0:()=>CookieInformation.declineAllCategories()||!0,EVAL_COOKIEINFORMATION_1:()=>CookieInformation.submitAllCategories()||!0,EVAL_COOKIEINFORMATION_2:()=>document.cookie.includes("CookieInformationConsent="),EVAL_COOKIEYES_0:()=>document.cookie.includes("advertisement:no"),EVAL_DAILYMOTION_0:()=>!!document.cookie.match("dm-euconsent-v2"),EVAL_DNDBEYOND_TEST:()=>document.cookie.includes("cookie-consent=denied"),EVAL_DSGVO_0:()=>!document.cookie.includes("sp_dsgvo_cookie_settings"),EVAL_DUNELM_0:()=>document.cookie.includes("cc_functional=0")&&document.cookie.includes("cc_targeting=0"),EVAL_ETSY_0:()=>document.querySelectorAll(".gdpr-overlay-body input").forEach((e=>{e.checked=!1}))||!0,EVAL_ETSY_1:()=>document.querySelector(".gdpr-overlay-view button[data-wt-overlay-close]").click()||!0,EVAL_EU_COOKIE_COMPLIANCE_0:()=>-1===document.cookie.indexOf("cookie-agreed=2"),EVAL_EU_COOKIE_LAW_0:()=>!document.cookie.includes("euCookie"),EVAL_EZOIC_0:()=>ezCMP.handleAcceptAllClick(),EVAL_EZOIC_1:()=>!!document.cookie.match(/ez-consent-tcf/),EVAL_FIDES_DETECT_POPUP:()=>window.Fides?.initialized,EVAL_GOOGLE_0:()=>!!document.cookie.match(/SOCS=CAE/),EVAL_HEMA_TEST_0:()=>document.cookie.includes("cookies_rejected=1"),EVAL_IUBENDA_0:()=>document.querySelectorAll(".purposes-item input[type=checkbox]:not([disabled])").forEach((e=>{e.checked&&e.click()}))||!0,EVAL_IUBENDA_1:()=>!!document.cookie.match(/_iub_cs-\d+=/),EVAL_IWINK_TEST:()=>document.cookie.includes("cookie_permission_granted=no"),EVAL_JQUERY_COOKIEBAR_0:()=>!document.cookie.includes("cookies-state=accepted"),EVAL_KETCH_TEST:()=>document.cookie.includes("_ketch_consent_v1_"),EVAL_MEDIAVINE_0:()=>document.querySelectorAll('[data-name="mediavine-gdpr-cmp"] input[type=checkbox]').forEach((e=>e.checked&&e.click()))||!0,EVAL_MICROSOFT_0:()=>Array.from(document.querySelectorAll("div > button")).filter((e=>e.innerText.match("Reject|Ablehnen")))[0].click()||!0,EVAL_MICROSOFT_1:()=>Array.from(document.querySelectorAll("div > button")).filter((e=>e.innerText.match("Accept|Annehmen")))[0].click()||!0,EVAL_MICROSOFT_2:()=>!!document.cookie.match("MSCC|GHCC"),EVAL_MOOVE_0:()=>document.querySelectorAll("#moove_gdpr_cookie_modal input").forEach((e=>{e.disabled||(e.checked="moove_gdpr_strict_cookies"===e.name||"moove_gdpr_strict_cookies"===e.id)}))||!0,EVAL_ONENINETWO_0:()=>document.cookie.includes("CC_ADVERTISING=NO")&&document.cookie.includes("CC_ANALYTICS=NO"),EVAL_OPENAI_TEST:()=>document.cookie.includes("oai-allow-ne=false"),EVAL_OPERA_0:()=>document.cookie.includes("cookie_consent_essential=true")&&!document.cookie.includes("cookie_consent_marketing=true"),EVAL_PAYPAL_0:()=>!0===document.cookie.includes("cookie_prefs"),EVAL_PRIMEBOX_0:()=>!document.cookie.includes("cb-enabled=accepted"),EVAL_PUBTECH_0:()=>document.cookie.includes("euconsent-v2")&&(document.cookie.match(/.YAAAAAAAAAAA/)||document.cookie.match(/.aAAAAAAAAAAA/)||document.cookie.match(/.YAAACFgAAAAA/)),EVAL_REDDIT_0:()=>document.cookie.includes("eu_cookie={%22opted%22:true%2C%22nonessential%22:false}"),EVAL_ROBLOX_TEST:()=>document.cookie.includes("RBXcb"),EVAL_SIRDATA_UNBLOCK_SCROLL:()=>(document.documentElement.classList.forEach((e=>{e.startsWith("sd-cmp-")&&document.documentElement.classList.remove(e)})),!0),EVAL_SNIGEL_0:()=>!!document.cookie.match("snconsent"),EVAL_STEAMPOWERED_0:()=>2===JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>e.trim().startsWith("cookieSettings"))).split("=")[1])).preference_state,EVAL_SVT_TEST:()=>document.cookie.includes('cookie-consent-1={"optedIn":true,"functionality":false,"statistics":false}'),EVAL_TAKEALOT_0:()=>document.body.classList.remove("freeze")||(document.body.style="")||!0,EVAL_TARTEAUCITRON_0:()=>tarteaucitron.userInterface.respondAll(!1)||!0,EVAL_TARTEAUCITRON_1:()=>tarteaucitron.userInterface.respondAll(!0)||!0,EVAL_TARTEAUCITRON_2:()=>document.cookie.match(/tarteaucitron=[^;]*/)?.[0].includes("false"),EVAL_TAUNTON_TEST:()=>document.cookie.includes("taunton_user_consent_submitted=true"),EVAL_TEALIUM_0:()=>void 0!==window.utag&&"object"==typeof utag.gdpr,EVAL_TEALIUM_1:()=>utag.gdpr.setConsentValue(!1)||!0,EVAL_TEALIUM_DONOTSELL:()=>utag.gdpr.dns?.setDnsState(!1)||!0,EVAL_TEALIUM_2:()=>utag.gdpr.setConsentValue(!0)||!0,EVAL_TEALIUM_3:()=>1!==utag.gdpr.getConsentState(),EVAL_TEALIUM_DONOTSELL_CHECK:()=>1!==utag.gdpr.dns?.getDnsState(),EVAL_TESLA_TEST:()=>document.cookie.includes("tsla-cookie-consent=rejected"),EVAL_TESTCMP_0:()=>"button_clicked"===window.results.results[0],EVAL_TESTCMP_COSMETIC_0:()=>"banner_hidden"===window.results.results[0],EVAL_THEFREEDICTIONARY_0:()=>cmpUi.showPurposes()||cmpUi.rejectAll()||!0,EVAL_THEFREEDICTIONARY_1:()=>cmpUi.allowAll()||!0,EVAL_THEVERGE_0:()=>document.cookie.includes("_duet_gdpr_acknowledged=1"),EVAL_TWCC_TEST:()=>document.cookie.includes("twCookieConsent="),EVAL_UBUNTU_COM_0:()=>document.cookie.includes("_cookies_accepted=essential"),EVAL_UK_COOKIE_CONSENT_0:()=>!document.cookie.includes("catAccCookies"),EVAL_USERCENTRICS_API_0:()=>"object"==typeof UC_UI,EVAL_USERCENTRICS_API_1:()=>!!UC_UI.closeCMP(),EVAL_USERCENTRICS_API_2:()=>!!UC_UI.denyAllConsents(),EVAL_USERCENTRICS_API_3:()=>!!UC_UI.acceptAllConsents(),EVAL_USERCENTRICS_API_4:()=>!!UC_UI.closeCMP(),EVAL_USERCENTRICS_API_5:()=>!0===UC_UI.areAllConsentsAccepted(),EVAL_USERCENTRICS_API_6:()=>!1===UC_UI.areAllConsentsAccepted(),EVAL_USERCENTRICS_BUTTON_0:()=>JSON.parse(localStorage.getItem("usercentrics")).consents.every((e=>e.isEssential||!e.consentStatus)),EVAL_WAITROSE_0:()=>Array.from(document.querySelectorAll("label[id$=cookies-deny-label]")).forEach((e=>e.click()))||!0,EVAL_WAITROSE_1:()=>document.cookie.includes("wtr_cookies_advertising=0")&&document.cookie.includes("wtr_cookies_analytics=0"),EVAL_WP_COOKIE_NOTICE_0:()=>document.cookie.includes("wpl_viewed_cookie=no"),EVAL_XE_TEST:()=>document.cookie.includes("xeConsentState={%22performance%22:false%2C%22marketing%22:false%2C%22compliance%22:false}"),EVAL_XING_0:()=>document.cookie.includes("userConsent=%7B%22marketing%22%3Afalse"),EVAL_YOUTUBE_DESKTOP_0:()=>!!document.cookie.match(/SOCS=CAE/),EVAL_YOUTUBE_MOBILE_0:()=>!!document.cookie.match(/SOCS=CAE/)};var p={main:!0,frame:!1,urlPattern:""},d=class{constructor(e){this.runContext=p,this.autoconsent=e}get hasSelfTest(){throw new Error("Not Implemented")}get isIntermediate(){throw new Error("Not Implemented")}get isCosmetic(){throw new Error("Not Implemented")}mainWorldEval(e){const t=l[e];if(!t)return console.warn("Snippet not found",e),Promise.resolve(!1);const o=this.autoconsent.config.logs;if(this.autoconsent.config.isMainWorld){o.evals&&console.log("inline eval:",e,t);let i=!1;try{i=!!t.call(globalThis)}catch(t){o.evals&&console.error("error evaluating rule",e,t)}return Promise.resolve(i)}const i=`(${t.toString()})()`;return o.evals&&console.log("async eval:",e,i),function(e,t){const o=a();r.sendContentMessage({type:"eval",id:o,code:e,snippetId:t});const i=new s(o);return r.pending.set(i.id,i),i.promise}(i,e).catch((t=>(o.evals&&console.error("error evaluating rule",e,t),!1)))}checkRunContext(){const e={...p,...this.runContext},t=window.top===window;return!(t&&!e.main)&&(!(!t&&!e.frame)&&!(e.urlPattern&&!window.location.href.match(e.urlPattern)))}detectCmp(){throw new Error("Not Implemented")}async detectPopup(){return!1}optOut(){throw new Error("Not Implemented")}optIn(){throw new Error("Not Implemented")}openCmp(){throw new Error("Not Implemented")}async test(){return Promise.resolve(!0)}click(e,t=!1){return this.autoconsent.domActions.click(e,t)}elementExists(e){return this.autoconsent.domActions.elementExists(e)}elementVisible(e,t){return this.autoconsent.domActions.elementVisible(e,t)}waitForElement(e,t){return this.autoconsent.domActions.waitForElement(e,t)}waitForVisible(e,t,o){return this.autoconsent.domActions.waitForVisible(e,t,o)}waitForThenClick(e,t,o){return this.autoconsent.domActions.waitForThenClick(e,t,o)}wait(e){return this.autoconsent.domActions.wait(e)}hide(e,t){return this.autoconsent.domActions.hide(e,t)}prehide(e){return this.autoconsent.domActions.prehide(e)}undoPrehide(){return this.autoconsent.domActions.undoPrehide()}querySingleReplySelector(e,t){return this.autoconsent.domActions.querySingleReplySelector(e,t)}querySelectorChain(e){return this.autoconsent.domActions.querySelectorChain(e)}elementSelector(e){return this.autoconsent.domActions.elementSelector(e)}},u=class extends d{constructor(e,t){super(t),this.rule=e,this.name=e.name,this.runContext=e.runContext||p}get hasSelfTest(){return!!this.rule.test}get isIntermediate(){return!!this.rule.intermediate}get isCosmetic(){return!!this.rule.cosmetic}get prehideSelectors(){return this.rule.prehideSelectors}async detectCmp(){return!!this.rule.detectCmp&&this._runRulesParallel(this.rule.detectCmp)}async detectPopup(){return!!this.rule.detectPopup&&this._runRulesSequentially(this.rule.detectPopup)}async optOut(){const e=this.autoconsent.config.logs;return!!this.rule.optOut&&(e.lifecycle&&console.log("Initiated optOut()",this.rule.optOut),this._runRulesSequentially(this.rule.optOut))}async optIn(){const e=this.autoconsent.config.logs;return!!this.rule.optIn&&(e.lifecycle&&console.log("Initiated optIn()",this.rule.optIn),this._runRulesSequentially(this.rule.optIn))}async openCmp(){return!!this.rule.openCmp&&this._runRulesSequentially(this.rule.openCmp)}async test(){return this.hasSelfTest?this._runRulesSequentially(this.rule.test):super.test()}async evaluateRuleStep(e){const t=[],o=this.autoconsent.config.logs;if(e.exists&&t.push(this.elementExists(e.exists)),e.visible&&t.push(this.elementVisible(e.visible,e.check)),e.eval){const o=this.mainWorldEval(e.eval);t.push(o)}if(e.waitFor&&t.push(this.waitForElement(e.waitFor,e.timeout)),e.waitForVisible&&t.push(this.waitForVisible(e.waitForVisible,e.timeout,e.check)),e.click&&t.push(this.click(e.click,e.all)),e.waitForThenClick&&t.push(this.waitForThenClick(e.waitForThenClick,e.timeout,e.all)),e.wait&&t.push(this.wait(e.wait)),e.hide&&t.push(this.hide(e.hide,e.method)),e.if){if(!e.if.exists&&!e.if.visible)return console.error("invalid conditional rule",e.if),!1;const i=await this.evaluateRuleStep(e.if);o.rulesteps&&console.log("Condition is",i),i?t.push(this._runRulesSequentially(e.then)):e.else?t.push(this._runRulesSequentially(e.else)):t.push(!0)}if(e.any){for(const t of e.any)if(await this.evaluateRuleStep(t))return!0;return!1}if(0===t.length)return o.errors&&console.warn("Unrecognized rule",e),!1;return(await Promise.all(t)).reduce(((e,t)=>e&&t),!0)}async _runRulesParallel(e){const t=e.map((e=>this.evaluateRuleStep(e)));return(await Promise.all(t)).every((e=>!!e))}async _runRulesSequentially(e){const t=this.autoconsent.config.logs;for(const o of e){t.rulesteps&&console.log("Running rule...",o);const e=await this.evaluateRuleStep(o);if(t.rulesteps&&console.log("...rule result",e),!e&&!o.optional)return!1}return!0}},m=class{constructor(e,t){this.name=e,this.config=t,this.methods=new Map,this.runContext=p,this.isCosmetic=!1,t.methods.forEach((e=>{e.action&&this.methods.set(e.name,e.action)})),this.hasSelfTest=!1}get isIntermediate(){return!1}checkRunContext(){return!0}async detectCmp(){return this.config.detectors.map((e=>o(e.presentMatcher))).some((e=>!!e))}async detectPopup(){return this.config.detectors.map((e=>o(e.showingMatcher))).some((e=>!!e))}async executeAction(e,t){return!this.methods.has(e)||i(this.methods.get(e),t)}async optOut(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),await this.executeAction("HIDE_CMP"),await this.executeAction("DO_CONSENT",[]),await this.executeAction("SAVE_CONSENT"),!0}async optIn(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),await this.executeAction("HIDE_CMP"),await this.executeAction("DO_CONSENT",["D","A","B","E","F","X"]),await this.executeAction("SAVE_CONSENT"),!0}async openCmp(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),!0}async test(){return!0}};function h(e="autoconsent-css-rules"){const t=`style#${e}`,o=document.querySelector(t);if(o&&o instanceof HTMLStyleElement)return o;{const t=document.head||document.getElementsByTagName("head")[0]||document.documentElement,o=document.createElement("style");return o.id=e,t.appendChild(o),o}}function k(e,t,o="display"){const i=`${t} { ${"opacity"===o?"opacity: 0":"display: none"} !important; z-index: -1 !important; pointer-events: none !important; } `;return e instanceof HTMLStyleElement&&(e.innerText+=i,t.length>0)}async function b(e,t,o){const i=await e();return!i&&t>0?new Promise((i=>{setTimeout((async()=>{i(b(e,t-1,o))}),o)})):Promise.resolve(i)}function _(e){if(!e)return!1;if(null!==e.offsetParent)return!0;{const t=window.getComputedStyle(e);if("fixed"===t.position&&"none"!==t.display)return!0}return!1}function g(e){const t={enabled:!0,autoAction:"optOut",disabledCmps:[],enablePrehide:!0,enableCosmeticRules:!0,detectRetries:20,isMainWorld:!1,prehideTimeout:2e3,logs:{lifecycle:!1,rulesteps:!1,evals:!1,errors:!0,messages:!1}},o=(i=t,globalThis.structuredClone?structuredClone(i):JSON.parse(JSON.stringify(i)));var i;for(const i of Object.keys(t))void 0!==e[i]&&(o[i]=e[i]);return o}var y="#truste-show-consent",w="#truste-consent-track",C=[class extends d{constructor(e){super(e),this.name="TrustArc-top",this.prehideSelectors=[".trustarc-banner-container",`.truste_popframe,.truste_overlay,.truste_box_overlay,${w}`],this.runContext={main:!0,frame:!1},this._shortcutButton=null,this._optInDone=!1}get hasSelfTest(){return!0}get isIntermediate(){return!this._optInDone&&!this._shortcutButton}get isCosmetic(){return!1}async detectCmp(){const e=this.elementExists(`${y},${w}`);return e&&(this._shortcutButton=document.querySelector("#truste-consent-required")),e}async detectPopup(){return this.elementVisible(`#truste-consent-content,#trustarc-banner-overlay,${w}`,"all")}openFrame(){this.click(y)}async optOut(){return this._shortcutButton?(this._shortcutButton.click(),!0):(k(h(),`.truste_popframe, .truste_overlay, .truste_box_overlay, ${w}`),this.click(y),setTimeout((()=>{h().remove()}),1e4),!0)}async optIn(){return this._optInDone=!0,this.click("#truste-consent-button")}async openCmp(){return!0}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_TRUSTARC_TOP")}},class extends d{constructor(){super(...arguments),this.name="TrustArc-frame",this.runContext={main:!1,frame:!0,urlPattern:"^https://consent-pref\\.trustarc\\.com/\\?"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return!0}async detectPopup(){return this.elementVisible("#defaultpreferencemanager","any")&&this.elementVisible(".mainContent","any")}async navigateToSettings(){return await b((async()=>this.elementExists(".shp")||this.elementVisible(".advance","any")||this.elementExists(".switch span:first-child")),10,500),this.elementExists(".shp")&&this.click(".shp"),await this.waitForElement(".prefPanel",5e3),this.elementVisible(".advance","any")&&this.click(".advance"),await b((()=>this.elementVisible(".switch span:first-child","any")),5,1e3)}async optOut(){if(await this.mainWorldEval("EVAL_TRUSTARC_FRAME_TEST"))return!0;let e=3e3;return await this.mainWorldEval("EVAL_TRUSTARC_FRAME_GTM")&&(e=1500),await b((()=>"complete"===document.readyState),20,100),await this.waitForElement(".mainContent[aria-hidden=false]",e),!!this.click(".rejectAll")||(this.elementExists(".prefPanel")&&await this.waitForElement('.prefPanel[style="visibility: visible;"]',e),this.click("#catDetails0")?(this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",e),!0):this.click(".required")?(this.waitForThenClick("#gwt-debug-close_id",e),!0):(await this.navigateToSettings(),this.click(".switch span:nth-child(1):not(.active)",!0),this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",10*e),!0))}async optIn(){return this.click(".call")||(await this.navigateToSettings(),this.click(".switch span:nth-child(2)",!0),this.click(".submit"),this.waitForElement("#gwt-debug-close_id",3e5).then((()=>{this.click("#gwt-debug-close_id")}))),!0}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_TRUSTARC_FRAME_TEST")}},class extends d{constructor(){super(...arguments),this.name="Cybotcookiebot",this.prehideSelectors=["#CybotCookiebotDialog,#CybotCookiebotDialogBodyUnderlay,#dtcookie-container,#cookiebanner,#cb-cookieoverlay,.modal--cookie-banner,#cookiebanner_outer,#CookieBanner"]}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return await this.mainWorldEval("EVAL_COOKIEBOT_1")}async detectPopup(){return this.mainWorldEval("EVAL_COOKIEBOT_2")}async optOut(){await this.wait(500);let e=await this.mainWorldEval("EVAL_COOKIEBOT_3");return await this.wait(500),e=e&&await this.mainWorldEval("EVAL_COOKIEBOT_4"),e}async optIn(){return this.elementExists("#dtcookie-container")?this.click(".h-dtcookie-accept"):(this.click(".CybotCookiebotDialogBodyLevelButton:not(:checked):enabled",!0),this.click("#CybotCookiebotDialogBodyLevelButtonAccept"),this.click("#CybotCookiebotDialogBodyButtonAccept"),!0)}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_COOKIEBOT_5")}},class extends d{constructor(){super(...arguments),this.name="Sourcepoint-frame",this.prehideSelectors=["div[id^='sp_message_container_'],.message-overlay","#sp_privacy_manager_container"],this.ccpaNotice=!1,this.ccpaPopup=!1,this.runContext={main:!0,frame:!0}}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){const e=new URL(location.href);return e.searchParams.has("message_id")&&"ccpa-notice.sp-prod.net"===e.hostname?(this.ccpaNotice=!0,!0):"ccpa-pm.sp-prod.net"===e.hostname?(this.ccpaPopup=!0,!0):("/index.html"===e.pathname||"/privacy-manager/index.html"===e.pathname||"/ccpa_pm/index.html"===e.pathname)&&(e.searchParams.has("message_id")||e.searchParams.has("requestUUID")||e.searchParams.has("consentUUID"))}async detectPopup(){return!!this.ccpaNotice||(this.ccpaPopup?await this.waitForElement(".priv-save-btn",2e3):(await this.waitForElement(".sp_choice_type_11,.sp_choice_type_12,.sp_choice_type_13,.sp_choice_type_ACCEPT_ALL,.sp_choice_type_SAVE_AND_EXIT",2e3),!this.elementExists(".sp_choice_type_9")))}async optIn(){return await this.waitForElement(".sp_choice_type_11,.sp_choice_type_ACCEPT_ALL",2e3),!!this.click(".sp_choice_type_11")||!!this.click(".sp_choice_type_ACCEPT_ALL")}isManagerOpen(){return"/privacy-manager/index.html"===location.pathname||"/ccpa_pm/index.html"===location.pathname}async optOut(){const e=this.autoconsent.config.logs;if(this.ccpaPopup){const e=document.querySelectorAll(".priv-purpose-container .sp-switch-arrow-block a.neutral.on .right");for(const t of e)t.click();const t=document.querySelectorAll(".priv-purpose-container .sp-switch-arrow-block a.switch-bg.on");for(const e of t)e.click();return this.click(".priv-save-btn")}if(!this.isManagerOpen()){if(!await this.waitForElement(".sp_choice_type_12,.sp_choice_type_13"))return!1;if(!this.elementExists(".sp_choice_type_12"))return this.click(".sp_choice_type_13");this.click(".sp_choice_type_12"),await b((()=>this.isManagerOpen()),200,100)}await this.waitForElement(".type-modal",2e4),this.waitForThenClick(".ccpa-stack .pm-switch[aria-checked=true] .slider",500,!0);try{const e=".sp_choice_type_REJECT_ALL",t=".reject-toggle",o=await Promise.race([this.waitForElement(e,2e3).then((e=>e?0:-1)),this.waitForElement(t,2e3).then((e=>e?1:-1)),this.waitForElement(".pm-features",2e3).then((e=>e?2:-1))]);if(0===o)return await this.waitForVisible(e),this.click(e);1===o?this.click(t):2===o&&(await this.waitForElement(".pm-features",1e4),this.click(".checked > span",!0),this.click(".chevron"))}catch(t){e.errors&&console.warn(t)}return this.click(".sp_choice_type_SAVE_AND_EXIT")}},class extends d{constructor(){super(...arguments),this.name="consentmanager.net",this.prehideSelectors=["#cmpbox,#cmpbox2"],this.apiAvailable=!1}get hasSelfTest(){return this.apiAvailable}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.apiAvailable=await this.mainWorldEval("EVAL_CONSENTMANAGER_1"),!!this.apiAvailable||this.elementExists("#cmpbox")}async detectPopup(){return this.apiAvailable?(await this.wait(500),await this.mainWorldEval("EVAL_CONSENTMANAGER_2")):this.elementVisible("#cmpbox .cmpmore","any")}async optOut(){return await this.wait(500),this.apiAvailable?await this.mainWorldEval("EVAL_CONSENTMANAGER_3"):!!this.click(".cmpboxbtnno")||(this.elementExists(".cmpwelcomeprpsbtn")?(this.click(".cmpwelcomeprpsbtn > a[aria-checked=true]",!0),this.click(".cmpboxbtnsave"),!0):(this.click(".cmpboxbtncustom"),await this.waitForElement(".cmptblbox",2e3),this.click(".cmptdchoice > a[aria-checked=true]",!0),this.click(".cmpboxbtnyescustomchoices"),this.hide("#cmpwrapper,#cmpbox","display"),!0))}async optIn(){return this.apiAvailable?await this.mainWorldEval("EVAL_CONSENTMANAGER_4"):this.click(".cmpboxbtnyes")}async test(){if(this.apiAvailable)return await this.mainWorldEval("EVAL_CONSENTMANAGER_5")}},class extends d{constructor(){super(...arguments),this.name="Evidon"}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("#_evidon_banner")}async detectPopup(){return this.elementVisible("#_evidon_banner","any")}async optOut(){return this.click("#_evidon-decline-button")||(k(h(),"#evidon-prefdiag-overlay,#evidon-prefdiag-background,#_evidon-background"),await this.waitForThenClick("#_evidon-option-button"),await this.waitForElement("#evidon-prefdiag-overlay",5e3),await this.wait(500),await this.waitForThenClick("#evidon-prefdiag-decline")),!0}async optIn(){return this.click("#_evidon-accept-button")}},class extends d{constructor(){super(...arguments),this.name="Onetrust",this.prehideSelectors=["#onetrust-banner-sdk,#onetrust-consent-sdk,.onetrust-pc-dark-filter,.js-consent-banner"],this.runContext={urlPattern:"^(?!.*https://www\\.nba\\.com/)"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("#onetrust-banner-sdk,#onetrust-pc-sdk")}async detectPopup(){return this.elementVisible("#onetrust-banner-sdk,#onetrust-pc-sdk","any")}async optOut(){return this.elementVisible("#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies","any")?this.click("#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies"):(this.elementExists("#onetrust-pc-btn-handler")?this.click("#onetrust-pc-btn-handler"):this.click(".ot-sdk-show-settings,button.js-cookie-settings"),await this.waitForElement("#onetrust-consent-sdk",2e3),await this.wait(1e3),this.click("#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked",!0),await this.wait(1e3),await this.waitForElement(".save-preference-btn-handler,.js-consent-save",2e3),this.click(".save-preference-btn-handler,.js-consent-save"),await this.waitForVisible("#onetrust-banner-sdk",5e3,"none"),!0)}async optIn(){return this.click("#onetrust-accept-btn-handler,#accept-recommended-btn-handler,.js-accept-cookies")}async test(){return await b((()=>this.mainWorldEval("EVAL_ONETRUST_1")),10,500)}},class extends d{constructor(){super(...arguments),this.name="Klaro",this.prehideSelectors=[".klaro"],this.settingsOpen=!1}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".klaro > .cookie-modal")?(this.settingsOpen=!0,!0):this.elementExists(".klaro > .cookie-notice")}async detectPopup(){return this.elementVisible(".klaro > .cookie-notice,.klaro > .cookie-modal","any")}async optOut(){return!!await this.mainWorldEval("EVAL_KLARO_TRY_API_OPT_OUT")||(!!this.click(".klaro .cn-decline")||(await this.mainWorldEval("EVAL_KLARO_OPEN_POPUP"),!!this.click(".klaro .cn-decline")||(this.click(".cm-purpose:not(.cm-toggle-all) > input:not(.half-checked,.required,.only-required),.cm-purpose:not(.cm-toggle-all) > div > input:not(.half-checked,.required,.only-required)",!0),this.click(".cm-btn-accept,.cm-button"))))}async optIn(){return!!this.click(".klaro .cm-btn-accept-all")||(this.settingsOpen?(this.click(".cm-purpose:not(.cm-toggle-all) > input.half-checked",!0),this.click(".cm-btn-accept")):this.click(".klaro .cookie-notice .cm-btn-success"))}async test(){return await this.mainWorldEval("EVAL_KLARO_1")}},class extends d{constructor(){super(...arguments),this.name="Uniconsent"}get prehideSelectors(){return[".unic",".modal:has(.unic)"]}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".unic .unic-box,.unic .unic-bar,.unic .unic-modal")}async detectPopup(){return this.elementVisible(".unic .unic-box,.unic .unic-bar,.unic .unic-modal","any")}async optOut(){if(await this.waitForElement(".unic button",1e3),document.querySelectorAll(".unic button").forEach((e=>{const t=e.textContent;(t.includes("Manage Options")||t.includes("Optionen verwalten"))&&e.click()})),await this.waitForElement(".unic input[type=checkbox]",1e3)){await this.waitForElement(".unic button",1e3),document.querySelectorAll(".unic input[type=checkbox]").forEach((e=>{e.checked&&e.click()}));for(const e of document.querySelectorAll(".unic button")){const t=e.textContent;for(const o of["Confirm Choices","Save Choices","Auswahl speichern"])if(t.includes(o))return e.click(),await this.wait(500),!0}}return!1}async optIn(){return this.waitForThenClick(".unic #unic-agree")}async test(){await this.wait(1e3);return!this.elementExists(".unic .unic-box,.unic .unic-bar")}},class extends d{constructor(){super(...arguments),this.prehideSelectors=[".cmp-root"],this.name="Conversant"}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".cmp-root .cmp-receptacle")}async detectPopup(){return this.elementVisible(".cmp-root .cmp-receptacle","any")}async optOut(){if(!await this.waitForThenClick(".cmp-main-button:not(.cmp-main-button--primary)"))return!1;if(!await this.waitForElement(".cmp-view-tab-tabs"))return!1;await this.waitForThenClick(".cmp-view-tab-tabs > :first-child"),await this.waitForThenClick(".cmp-view-tab-tabs > .cmp-view-tab--active:first-child");for(const e of Array.from(document.querySelectorAll(".cmp-accordion-item"))){e.querySelector(".cmp-accordion-item-title").click(),await b((()=>!!e.querySelector(".cmp-accordion-item-content.cmp-active")),10,50);const t=e.querySelector(".cmp-accordion-item-content.cmp-active");t.querySelectorAll(".cmp-toggle-actions .cmp-toggle-deny:not(.cmp-toggle-deny--active)").forEach((e=>e.click())),t.querySelectorAll(".cmp-toggle-actions .cmp-toggle-checkbox:not(.cmp-toggle-checkbox--active)").forEach((e=>e.click()))}return await this.click(".cmp-main-button:not(.cmp-main-button--primary)"),!0}async optIn(){return this.waitForThenClick(".cmp-main-button.cmp-main-button--primary")}async test(){return document.cookie.includes("cmp-data=0")}},class extends d{constructor(){super(...arguments),this.name="tiktok.com",this.runContext={urlPattern:"tiktok"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}getShadowRoot(){const e=document.querySelector("tiktok-cookie-banner");return e?e.shadowRoot:null}async detectCmp(){return this.elementExists("tiktok-cookie-banner")}async detectPopup(){return _(this.getShadowRoot().querySelector(".tiktok-cookie-banner"))}async optOut(){const e=this.autoconsent.config.logs,t=this.getShadowRoot().querySelector(".button-wrapper button:first-child");return t?(e.rulesteps&&console.log("[clicking]",t),t.click(),!0):(e.errors&&console.log("no decline button found"),!1)}async optIn(){const e=this.autoconsent.config.logs,t=this.getShadowRoot().querySelector(".button-wrapper button:last-child");return t?(e.rulesteps&&console.log("[clicking]",t),t.click(),!0):(e.errors&&console.log("no accept button found"),!1)}async test(){const e=document.cookie.match(/cookie-consent=([^;]+)/);if(!e)return!1;const t=JSON.parse(decodeURIComponent(e[1]));return Object.values(t).every((e=>"boolean"!=typeof e||!1===e))}},class extends d{constructor(){super(...arguments),this.runContext={urlPattern:"^https://(www\\.)?airbnb\\.[^/]+/"},this.prehideSelectors=["div[data-testid=main-cookies-banner-container]",'div:has(> div:first-child):has(> div:last-child):has(> section [data-testid="strictly-necessary-cookies"])']}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("div[data-testid=main-cookies-banner-container]")}async detectPopup(){return this.elementVisible("div[data-testid=main-cookies-banner-container","any")}async optOut(){let e;for(await this.waitForThenClick("div[data-testid=main-cookies-banner-container] button._snbhip0");e=document.querySelector("[data-testid=modal-container] button[aria-checked=true]:not([disabled])");)e.click();return this.waitForThenClick("button[data-testid=save-btn]")}async optIn(){return this.waitForThenClick("div[data-testid=main-cookies-banner-container] button._148dgdpk")}async test(){return await b((()=>!!document.cookie.match("OptanonAlertBoxClosed")),20,200)}},class extends d{constructor(){super(...arguments),this.name="tumblr-com",this.runContext={urlPattern:"^https://(www\\.)?tumblr\\.com/"}}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}get prehideSelectors(){return["#cmp-app-container"]}async detectCmp(){return this.elementExists("#cmp-app-container")}async detectPopup(){return this.elementVisible("#cmp-app-container","any")}async optOut(){let e=document.querySelector("#cmp-app-container iframe"),t=e.contentDocument?.querySelector(".cmp-components-button.is-secondary");return!!t&&(t.click(),await b((()=>{const e=document.querySelector("#cmp-app-container iframe");return!!e.contentDocument?.querySelector(".cmp__dialog input")}),5,500),e=document.querySelector("#cmp-app-container iframe"),t=e.contentDocument?.querySelector(".cmp-components-button.is-secondary"),!!t&&(t.click(),!0))}async optIn(){const e=document.querySelector("#cmp-app-container iframe").contentDocument.querySelector(".cmp-components-button.is-primary");return!!e&&(e.click(),!0)}},class extends d{constructor(){super(...arguments),this.name="Admiral"}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("div > div[class*=Card] > div[class*=Frame] > div[class*=Pills] > button[class*=Pills__StyledPill]")}async detectPopup(){return this.elementVisible("div > div[class*=Card] > div[class*=Frame] > div[class*=Pills] > button[class*=Pills__StyledPill]","any")}async optOut(){const e="xpath///button[contains(., 'Afvis alle') or contains(., 'Reject all') or contains(., 'Odbaci sve') or contains(., 'Rechazar todo') or contains(., 'Atmesti visus') or contains(., 'Odmítnout vše') or contains(., 'Απόρριψη όλων') or contains(., 'Rejeitar tudo') or contains(., 'Tümünü reddet') or contains(., 'Отклонить все') or contains(., 'Noraidīt visu') or contains(., 'Avvisa alla') or contains(., 'Odrzuć wszystkie') or contains(., 'Alles afwijzen') or contains(., 'Отхвърляне на всички') or contains(., 'Rifiuta tutto') or contains(., 'Zavrni vse') or contains(., 'Az összes elutasítása') or contains(., 'Respingeți tot') or contains(., 'Alles ablehnen') or contains(., 'Tout rejeter') or contains(., 'Odmietnuť všetko') or contains(., 'Lükka kõik tagasi') or contains(., 'Hylkää kaikki')]";if(await this.waitForElement(e,500))return this.click(e);const t="xpath///button[contains(., 'Spara & avsluta') or contains(., 'Save & exit') or contains(., 'Uložit a ukončit') or contains(., 'Enregistrer et quitter') or contains(., 'Speichern & Verlassen') or contains(., 'Tallenna ja poistu') or contains(., 'Išsaugoti ir išeiti') or contains(., 'Opslaan & afsluiten') or contains(., 'Guardar y salir') or contains(., 'Shrani in zapri') or contains(., 'Uložiť a ukončiť') or contains(., 'Kaydet ve çıkış yap') or contains(., 'Сохранить и выйти') or contains(., 'Salvesta ja välju') or contains(., 'Salva ed esci') or contains(., 'Gem & afslut') or contains(., 'Αποθήκευση και έξοδος') or contains(., 'Saglabāt un iziet') or contains(., 'Mentés és kilépés') or contains(., 'Guardar e sair') or contains(., 'Zapisz & zakończ') or contains(., 'Salvare și ieșire') or contains(., 'Spremi i izađi') or contains(., 'Запазване и изход')]";if(await this.waitForThenClick("xpath///button[contains(., 'Zwecke') or contains(., 'Σκοποί') or contains(., 'Purposes') or contains(., 'Цели') or contains(., 'Eesmärgid') or contains(., 'Tikslai') or contains(., 'Svrhe') or contains(., 'Cele') or contains(., 'Účely') or contains(., 'Finalidades') or contains(., 'Mērķi') or contains(., 'Scopuri') or contains(., 'Fines') or contains(., 'Ändamål') or contains(., 'Finalités') or contains(., 'Doeleinden') or contains(., 'Tarkoitukset') or contains(., 'Scopi') or contains(., 'Amaçlar') or contains(., 'Nameni') or contains(., 'Célok') or contains(., 'Formål')]")&&await this.waitForVisible(t)){return this.elementSelector(t)[0].parentElement.parentElement.querySelectorAll("input[type=checkbox]:checked").forEach((e=>e.click())),this.click(t)}return!1}async optIn(){return this.click("xpath///button[contains(., 'Sprejmi vse') or contains(., 'Prihvati sve') or contains(., 'Godkänn alla') or contains(., 'Prijať všetko') or contains(., 'Принять все') or contains(., 'Aceptar todo') or contains(., 'Αποδοχή όλων') or contains(., 'Zaakceptuj wszystkie') or contains(., 'Accetta tutto') or contains(., 'Priimti visus') or contains(., 'Pieņemt visu') or contains(., 'Tümünü kabul et') or contains(., 'Az összes elfogadása') or contains(., 'Accept all') or contains(., 'Приемане на всички') or contains(., 'Accepter alle') or contains(., 'Hyväksy kaikki') or contains(., 'Tout accepter') or contains(., 'Alles accepteren') or contains(., 'Aktsepteeri kõik') or contains(., 'Přijmout vše') or contains(., 'Alles akzeptieren') or contains(., 'Aceitar tudo') or contains(., 'Acceptați tot')]")}}],v=class{constructor(e){this.autoconsentInstance=e}click(e,t=!1){const o=this.elementSelector(e);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[click]",e,t,o),o.length>0&&(t?o.forEach((e=>e.click())):o[0].click()),o.length>0}elementExists(e){return this.elementSelector(e).length>0}elementVisible(e,t){const o=this.elementSelector(e),i=new Array(o.length);return o.forEach(((e,t)=>{i[t]=_(e)})),"none"===t?i.every((e=>!e)):0!==i.length&&("any"===t?i.some((e=>e)):i.every((e=>e)))}waitForElement(e,t=1e4){const o=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForElement]",e),b((()=>this.elementSelector(e).length>0),o,200)}waitForVisible(e,t=1e4,o="any"){const i=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForVisible]",e),b((()=>this.elementVisible(e,o)),i,200)}async waitForThenClick(e,t=1e4,o=!1){return await this.waitForElement(e,t),this.click(e,o)}wait(e){return this.autoconsentInstance.config.logs.rulesteps&&console.log("[wait]",e),new Promise((t=>{setTimeout((()=>{t(!0)}),e)}))}hide(e,t){this.autoconsentInstance.config.logs.rulesteps&&console.log("[hide]",e);return k(h(),e,t)}prehide(e){const t=h("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[prehide]",t,location.href),k(t,e,"opacity")}undoPrehide(){const e=h("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[undoprehide]",e,location.href),e&&e.remove(),!!e}querySingleReplySelector(e,t=document){if(e.startsWith("aria/"))return[];if(e.startsWith("xpath/")){const o=e.slice(6),i=document.evaluate(o,t,null,XPathResult.ANY_TYPE,null);let c=null;const n=[];for(;c=i.iterateNext();)n.push(c);return n}return e.startsWith("text/")||e.startsWith("pierce/")?[]:t.shadowRoot?Array.from(t.shadowRoot.querySelectorAll(e)):Array.from(t.querySelectorAll(e))}querySelectorChain(e){let t,o=document;for(const i of e){if(t=this.querySingleReplySelector(i,o),0===t.length)return[];o=t[0]}return t}elementSelector(e){return"string"==typeof e?this.querySingleReplySelector(e):this.querySelectorChain(e)}};var f=[{name:"192.com",detectCmp:[{exists:".ont-cookies"}],detectPopup:[{visible:".ont-cookies"}],optIn:[{click:".ont-btn-main.ont-cookies-btn.js-ont-btn-ok2"}],optOut:[{click:".ont-cookes-btn-manage"},{click:".ont-btn-main.ont-cookies-btn.js-ont-btn-choose"}],test:[{eval:"EVAL_ONENINETWO_0"}]},{name:"1password-com",cosmetic:!0,prehideSelectors:['footer #footer-root [aria-label="Cookie Consent"]'],detectCmp:[{exists:'footer #footer-root [aria-label="Cookie Consent"]'}],detectPopup:[{visible:'footer #footer-root [aria-label="Cookie Consent"]'}],optIn:[{click:'footer #footer-root [aria-label="Cookie Consent"] button'}],optOut:[{hide:'footer #footer-root [aria-label="Cookie Consent"]'}]},{name:"aa",vendorUrl:"https://aa.com",prehideSelectors:[],cosmetic:!0,detectCmp:[{exists:"#aa_optoutmulti-Modal,#cookieBannerMessage"}],detectPopup:[{visible:"#aa_optoutmulti-Modal,#cookieBannerMessage"}],optIn:[{hide:"#aa_optoutmulti-Modal,#cookieBannerMessage"},{waitForThenClick:"#aa_optoutmulti_checkBox"},{waitForThenClick:"#aa_optoutmulti-Modal button.optoutmulti_button"}],optOut:[{hide:"#aa_optoutmulti-Modal,#cookieBannerMessage"}]},{name:"abc",vendorUrl:"https://abc.net.au",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?abc\\.net\\.au/"},prehideSelectors:[],detectCmp:[{exists:"[data-component=CookieBanner]"}],detectPopup:[{visible:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptAll]"}],optIn:[{waitForThenClick:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptAll]"}],optOut:[{waitForThenClick:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptABCRequired]"}],test:[{eval:"EVAL_ABC_TEST"}]},{name:"abconcerts.be",vendorUrl:"https://unknown",intermediate:!1,prehideSelectors:["dialog.cookie-consent"],detectCmp:[{exists:"dialog.cookie-consent form.cookie-consent__form"}],detectPopup:[{visible:"dialog.cookie-consent form.cookie-consent__form"}],optIn:[{waitForThenClick:"dialog.cookie-consent form.cookie-consent__form button[value=yes]"}],optOut:[{if:{exists:"dialog.cookie-consent form.cookie-consent__form button[value=no]"},then:[{click:"dialog.cookie-consent form.cookie-consent__form button[value=no]"}],else:[{click:"dialog.cookie-consent form.cookie-consent__form button.cookie-consent__options-toggle"},{waitForThenClick:'dialog.cookie-consent form.cookie-consent__form button[value="save_options"]'}]}]},{name:"acris",prehideSelectors:["div.acris-cookie-consent"],detectCmp:[{exists:"[data-acris-cookie-consent]"}],detectPopup:[{visible:".acris-cookie-consent.is--modal"}],optIn:[{waitForVisible:"#ccConsentAcceptAllButton",check:"any"},{wait:500},{waitForThenClick:"#ccConsentAcceptAllButton"}],optOut:[{waitForVisible:"#ccAcceptOnlyFunctional",check:"any"},{wait:500},{waitForThenClick:"#ccAcceptOnlyFunctional"}]},{name:"activobank.pt",runContext:{urlPattern:"^https://(www\\.)?activobank\\.pt"},prehideSelectors:["aside#cookies,.overlay-cookies"],detectCmp:[{exists:"#cookies .cookies-btn"}],detectPopup:[{visible:"#cookies #submitCookies"}],optIn:[{waitForThenClick:"#cookies #submitCookies"}],optOut:[{waitForThenClick:"#cookies #rejectCookies"}]},{name:"Adroll",prehideSelectors:["#adroll_consent_container"],detectCmp:[{exists:"#adroll_consent_container"}],detectPopup:[{visible:"#adroll_consent_container"}],optIn:[{waitForThenClick:"#adroll_consent_accept"}],optOut:[{waitForThenClick:"#adroll_consent_reject"}],test:[{eval:"EVAL_ADROLL_0"}]},{name:"affinity.serif.com",detectCmp:[{exists:".c-cookie-banner button[data-qa='allow-all-cookies']"}],detectPopup:[{visible:".c-cookie-banner"}],optIn:[{click:'button[data-qa="allow-all-cookies"]'}],optOut:[{click:'button[data-qa="manage-cookies"]'},{waitFor:'.c-cookie-banner ~ [role="dialog"]'},{waitForThenClick:'.c-cookie-banner ~ [role="dialog"] input[type="checkbox"][value="true"]',all:!0},{click:'.c-cookie-banner ~ [role="dialog"] .c-modal__action button'}],test:[{wait:500},{eval:"EVAL_AFFINITY_SERIF_COM_0"}]},{name:"agolde.com",cosmetic:!0,prehideSelectors:["#modal-1 div[data-micromodal-close]"],detectCmp:[{exists:"#modal-1 div[aria-labelledby=modal-1-title]"}],detectPopup:[{exists:"#modal-1 div[data-micromodal-close]"}],optIn:[{click:'button[aria-label="Close modal"]'}],optOut:[{hide:"#modal-1 div[data-micromodal-close]"}]},{name:"aliexpress",vendorUrl:"https://aliexpress.com/",runContext:{urlPattern:"^https://.*\\.aliexpress\\.com/"},prehideSelectors:["#gdpr-new-container"],detectCmp:[{exists:"#gdpr-new-container,#voyager-gdpr > div"}],detectPopup:[{visible:"#gdpr-new-container,#voyager-gdpr > div"}],optIn:[{waitForThenClick:"#gdpr-new-container .btn-accept,#voyager-gdpr > div > div > button:nth-child(1)"}],optOut:[{if:{exists:"#voyager-gdpr > div"},then:[{waitForThenClick:"#voyager-gdpr > div > div > button:nth-child(2)"}],else:[{waitForThenClick:"#gdpr-new-container .btn-more"},{waitFor:"#gdpr-new-container .gdpr-dialog-switcher"},{click:"#gdpr-new-container .switcher-on",all:!0,optional:!0},{click:"#gdpr-new-container .btn-save"}]}]},{name:"almacmp",prehideSelectors:["#alma-cmpv2-container"],detectCmp:[{exists:"#alma-cmpv2-container"}],detectPopup:[{visible:"#alma-cmpv2-container #almacmp-modal-layer1"}],optIn:[{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer1 #almacmp-modalConfirmBtn"}],optOut:[{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer1 #almacmp-modalSettingBtn"},{waitFor:"#alma-cmpv2-container #almacmp-modal-layer2"},{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer2 #almacmp-reject-all-layer2"}],test:[{eval:"EVAL_ALMACMP_0"}]},{name:"altium.com",cosmetic:!0,prehideSelectors:[".altium-privacy-bar"],detectCmp:[{exists:".altium-privacy-bar"}],detectPopup:[{exists:".altium-privacy-bar"}],optIn:[{click:"a.altium-privacy-bar__btn"}],optOut:[{hide:".altium-privacy-bar"}]},{name:"amazon.com",prehideSelectors:['span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'],detectCmp:[{exists:'span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'}],detectPopup:[{visible:'span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'}],optIn:[{waitForVisible:"#sp-cc-accept"},{wait:500},{click:"#sp-cc-accept"}],optOut:[{waitForVisible:"#sp-cc-rejectall-link"},{wait:500},{click:"#sp-cc-rejectall-link"}]},{name:"amex",vendorUrl:"https://www.americanexpress.com/",cosmetic:!1,prehideSelectors:["#user-consent-management-granular-banner-overlay"],detectCmp:[{exists:"#user-consent-management-granular-banner-overlay"}],detectPopup:[{visible:"#user-consent-management-granular-banner-overlay"}],optIn:[{waitForThenClick:"[data-testid=granular-banner-button-accept-all]"}],optOut:[{waitForThenClick:"[data-testid=granular-banner-button-decline-all]"}]},{name:"aquasana.com",prehideSelectors:["#consent-tracking"],detectCmp:[{exists:"#consent-tracking"}],detectPopup:[{exists:"#consent-tracking"}],optIn:[{waitForThenClick:"#consent-tracking .affirm.btn"}],optOut:[{if:{exists:"#consent-tracking .decline.btn"},then:[{click:"#consent-tracking .decline.btn"}],else:[{hide:"#consent-tracking"}]}]},{name:"arbeitsagentur",vendorUrl:"https://www.arbeitsagentur.de/",prehideSelectors:[".modal-open bahf-cookie-disclaimer-dpl3"],detectCmp:[{exists:"bahf-cookie-disclaimer-dpl3"}],detectPopup:[{visible:"bahf-cookie-disclaimer-dpl3"}],optIn:[{waitForThenClick:["bahf-cookie-disclaimer-dpl3","bahf-cd-modal-dpl3 .ba-btn-primary"]}],optOut:[{waitForThenClick:["bahf-cookie-disclaimer-dpl3","bahf-cd-modal-dpl3 .ba-btn-contrast"]}],test:[{eval:"EVAL_ARBEITSAGENTUR_TEST"}]},{name:"asus",vendorUrl:"https://www.asus.com/",runContext:{urlPattern:"^https://www\\.asus\\.com/"},prehideSelectors:["#cookie-policy-info,#cookie-policy-info-bg"],detectCmp:[{exists:"#cookie-policy-info"}],detectPopup:[{visible:"#cookie-policy-info"}],optIn:[{waitForThenClick:'#cookie-policy-info [data-agree="Accept Cookies"]'}],optOut:[{if:{exists:"#cookie-policy-info .btn-reject"},then:[{waitForThenClick:"#cookie-policy-info .btn-reject"}],else:[{waitForThenClick:"#cookie-policy-info .btn-setting"},{waitForThenClick:'#cookie-policy-lightbox-wrapper [data-agree="Save Settings"]'}]}]},{name:"athlinks-com",runContext:{urlPattern:"^https://(www\\.)?athlinks\\.com/"},cosmetic:!0,prehideSelectors:["#footer-container ~ div"],detectCmp:[{exists:"#footer-container ~ div"}],detectPopup:[{visible:"#footer-container > div"}],optIn:[{click:"#footer-container ~ div button"}],optOut:[{hide:"#footer-container ~ div"}]},{name:"ausopen.com",cosmetic:!0,detectCmp:[{exists:".gdpr-popup__message"}],detectPopup:[{visible:".gdpr-popup__message"}],optOut:[{hide:".gdpr-popup__message"}],optIn:[{click:".gdpr-popup__message button"}]},{name:"automattic-cmp-optout",prehideSelectors:['form[class*="cookie-banner"][method="post"]'],detectCmp:[{exists:'form[class*="cookie-banner"][method="post"]'}],detectPopup:[{visible:'form[class*="cookie-banner"][method="post"]'}],optIn:[{click:'a[class*="accept-all-button"]'}],optOut:[{click:'form[class*="cookie-banner"] div[class*="simple-options"] a[class*="customize-button"]'},{waitForThenClick:"input[type=checkbox][checked]:not([disabled])",all:!0},{click:'a[class*="accept-selection-button"]'}]},{name:"aws.amazon.com",prehideSelectors:["#awsccc-cb-content","#awsccc-cs-container","#awsccc-cs-modalOverlay","#awsccc-cs-container-inner"],detectCmp:[{exists:"#awsccc-cb-content"}],detectPopup:[{visible:"#awsccc-cb-content"}],optIn:[{click:"button[data-id=awsccc-cb-btn-accept"}],optOut:[{click:"button[data-id=awsccc-cb-btn-customize]"},{waitFor:"input[aria-checked]"},{click:"input[aria-checked=true]",all:!0,optional:!0},{click:"button[data-id=awsccc-cs-btn-save]"}]},{name:"axeptio",prehideSelectors:[".axeptio_widget"],detectCmp:[{exists:".axeptio_widget"}],detectPopup:[{visible:".axeptio_widget"}],optIn:[{waitFor:".axeptio-widget--open"},{click:"button#axeptio_btn_acceptAll"}],optOut:[{waitFor:".axeptio-widget--open"},{click:"button#axeptio_btn_dismiss"}],test:[{eval:"EVAL_AXEPTIO_0"}]},{name:"baden-wuerttemberg.de",prehideSelectors:[".cookie-alert.t-dark"],cosmetic:!0,detectCmp:[{exists:".cookie-alert.t-dark"}],detectPopup:[{visible:".cookie-alert.t-dark"}],optIn:[{click:".cookie-alert__form input:not([disabled]):not([checked])"},{click:".cookie-alert__button button"}],optOut:[{hide:".cookie-alert.t-dark"}]},{name:"bahn-de",vendorUrl:"https://www.bahn.de/",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?bahn\\.de/"},intermediate:!1,prehideSelectors:[],detectCmp:[{exists:["body > div:first-child","#consent-layer"]}],detectPopup:[{visible:["body > div:first-child","#consent-layer"]}],optIn:[{waitForThenClick:["body > div:first-child","#consent-layer .js-accept-all-cookies"]}],optOut:[{waitForThenClick:["body > div:first-child","#consent-layer .js-accept-essential-cookies"]}],test:[{eval:"EVAL_BAHN_TEST"}]},{name:"bbb.org",runContext:{urlPattern:"^https://www\\.bbb\\.org/"},cosmetic:!0,prehideSelectors:['div[aria-label="use of cookies on bbb.org"]'],detectCmp:[{exists:'div[aria-label="use of cookies on bbb.org"]'}],detectPopup:[{visible:'div[aria-label="use of cookies on bbb.org"]'}],optIn:[{click:'div[aria-label="use of cookies on bbb.org"] button.bds-button-unstyled span.visually-hidden'}],optOut:[{hide:'div[aria-label="use of cookies on bbb.org"]'}]},{name:"bing.com",prehideSelectors:["#bnp_container"],detectCmp:[{exists:"#bnp_cookie_banner"}],detectPopup:[{visible:"#bnp_cookie_banner"}],optIn:[{click:"#bnp_btn_accept"}],optOut:[{click:"#bnp_btn_preference"},{click:"#mcp_savesettings"}],test:[{eval:"EVAL_BING_0"}]},{name:"blocksy",vendorUrl:"https://creativethemes.com/blocksy/docs/extensions/cookies-consent/",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,prehideSelectors:[".cookie-notification"],detectCmp:[{exists:"#blocksy-ext-cookies-consent-styles-css"}],detectPopup:[{visible:".cookie-notification"}],optIn:[{click:".cookie-notification .ct-cookies-decline-button"}],optOut:[{waitForThenClick:".cookie-notification .ct-cookies-decline-button"}],test:[{eval:"EVAL_BLOCKSY_0"}]},{name:"borlabs",detectCmp:[{exists:"._brlbs-block-content"}],detectPopup:[{visible:"._brlbs-bar-wrap,._brlbs-box-wrap"}],optIn:[{click:"a[data-cookie-accept-all]"}],optOut:[{click:"a[data-cookie-individual]"},{waitForVisible:".cookie-preference"},{click:"input[data-borlabs-cookie-checkbox]:checked",all:!0,optional:!0},{click:"#CookiePrefSave"},{wait:500}],prehideSelectors:["#BorlabsCookieBox"],test:[{eval:"EVAL_BORLABS_0"}]},{name:"bundesregierung.de",prehideSelectors:[".bpa-cookie-banner"],detectCmp:[{exists:".bpa-cookie-banner"}],detectPopup:[{visible:".bpa-cookie-banner .bpa-module-full-hero"}],optIn:[{click:".bpa-accept-all-button"}],optOut:[{wait:500,comment:"click is not immediately recognized"},{waitForThenClick:".bpa-close-button"}],test:[{eval:"EVAL_BUNDESREGIERUNG_DE_0"}]},{name:"burpee.com",cosmetic:!0,prehideSelectors:["#notice-cookie-block"],detectCmp:[{exists:"#notice-cookie-block"}],detectPopup:[{exists:"#html-body #notice-cookie-block"}],optIn:[{click:"#btn-cookie-allow"}],optOut:[{hide:"#html-body #notice-cookie-block, #notice-cookie"}]},{name:"canva.com",prehideSelectors:['div[role="dialog"] a[data-anchor-id="cookie-policy"]'],detectCmp:[{exists:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'}],detectPopup:[{exists:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'}],optIn:[{click:'div[role="dialog"] button:nth-child(1)'}],optOut:[{if:{exists:'div[role="dialog"] button:nth-child(3)'},then:[{click:'div[role="dialog"] button:nth-child(2)'}],else:[{click:'div[role="dialog"] button:nth-child(2)'},{waitFor:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'},{waitFor:'div[role="dialog"] button[role=switch]'},{click:'div[role="dialog"] button:nth-child(2):not([role])'},{click:'div[role="dialog"] div:last-child button:only-child'}]}],test:[{eval:"EVAL_CANVA_0"}]},{name:"canyon.com",runContext:{urlPattern:"^https://www\\.canyon\\.com/"},prehideSelectors:["div.modal.cookiesModal.is-open"],detectCmp:[{exists:"div.modal.cookiesModal.is-open"}],detectPopup:[{visible:"div.modal.cookiesModal.is-open"}],optIn:[{click:'div.cookiesModal__buttonWrapper > button[data-closecause="close-by-submit"]'}],optOut:[{click:'div.cookiesModal__buttonWrapper > button[data-closecause="close-by-manage-cookies"]'},{waitForThenClick:"button#js-manage-data-privacy-save-button"}]},{name:"cc-banner-springer",prehideSelectors:[".cc-banner[data-cc-banner]"],detectCmp:[{exists:".cc-banner[data-cc-banner]"}],detectPopup:[{visible:".cc-banner[data-cc-banner]"}],optIn:[{waitForThenClick:".cc-banner[data-cc-banner] button[data-cc-action=accept]"}],optOut:[{if:{exists:".cc-banner[data-cc-banner] button[data-cc-action=reject]"},then:[{click:".cc-banner[data-cc-banner] button[data-cc-action=reject]"}],else:[{waitForThenClick:".cc-banner[data-cc-banner] button[data-cc-action=preferences]"},{waitFor:".cc-preferences[data-cc-preferences]"},{click:".cc-preferences[data-cc-preferences] input[type=radio][data-cc-action=toggle-category][value=off]",all:!0,optional:!0},{if:{exists:".cc-preferences[data-cc-preferences] button[data-cc-action=reject]"},then:[{click:".cc-preferences[data-cc-preferences] button[data-cc-action=reject]"}],else:[{click:".cc-preferences[data-cc-preferences] button[data-cc-action=save]"}]}]}],test:[{eval:"EVAL_CC_BANNER2_0"}]},{name:"cc_banner",cosmetic:!0,prehideSelectors:[".cc_banner-wrapper"],detectCmp:[{exists:".cc_banner-wrapper"}],detectPopup:[{visible:".cc_banner"}],optIn:[{click:".cc_btn_accept_all"}],optOut:[{hide:".cc_banner-wrapper"}]},{name:"check24-partnerprogramm-de",prehideSelectors:["[data-modal-content]:has([data-toggle-target^='cookie'])"],detectCmp:[{exists:"[data-toggle-target^='cookie']"}],detectPopup:[{visible:"[data-toggle-target^='cookie']",check:"any"}],optIn:[{waitForThenClick:"[data-cookie-accept-all]"}],optOut:[{waitForThenClick:"[data-cookie-dismiss-all]"}]},{name:"ciaopeople.it",prehideSelectors:["#cp-gdpr-choices"],detectCmp:[{exists:"#cp-gdpr-choices"}],detectPopup:[{visible:"#cp-gdpr-choices"}],optIn:[{waitForThenClick:".gdpr-btm__right > button:nth-child(2)"}],optOut:[{waitForThenClick:".gdpr-top-content > button"},{waitFor:".gdpr-top-back"},{waitForThenClick:".gdpr-btm__right > button:nth-child(1)"}],test:[{visible:"#cp-gdpr-choices",check:"none"}]},{vendorUrl:"https://www.civicuk.com/cookie-control/",name:"civic-cookie-control",prehideSelectors:["#ccc-module,#ccc-overlay"],detectCmp:[{exists:"#ccc-module"}],detectPopup:[{visible:"#ccc"},{visible:"#ccc-module"}],optOut:[{click:"#ccc-reject-settings"}],optIn:[{click:"#ccc-recommended-settings"}]},{name:"click.io",prehideSelectors:["#cl-consent"],detectCmp:[{exists:"#cl-consent"}],detectPopup:[{visible:"#cl-consent"}],optIn:[{waitForThenClick:'#cl-consent [data-role="b_agree"]'}],optOut:[{waitFor:'#cl-consent [data-role="b_options"]'},{wait:500},{click:'#cl-consent [data-role="b_options"]'},{waitFor:'.cl-consent-popup.cl-consent-visible [data-role="alloff"]'},{click:'.cl-consent-popup.cl-consent-visible [data-role="alloff"]',all:!0},{click:'[data-role="b_save"]'}],test:[{eval:"EVAL_CLICKIO_0",comment:"TODO: this only checks if we interacted at all"}]},{name:"clinch",intermediate:!1,runContext:{frame:!1,main:!0},prehideSelectors:[".consent-modal[role=dialog]"],detectCmp:[{exists:".consent-modal[role=dialog]"}],detectPopup:[{visible:".consent-modal[role=dialog]"}],optIn:[{click:"#consent_agree"}],optOut:[{if:{exists:"#consent_reject"},then:[{click:"#consent_reject"}],else:[{click:"#manage_cookie_preferences"},{click:"#cookie_consent_preferences input:checked",all:!0,optional:!0},{click:"#consent_save"}]}],test:[{eval:"EVAL_CLINCH_0"}]},{name:"clustrmaps.com",runContext:{urlPattern:"^https://(www\\.)?clustrmaps\\.com/"},cosmetic:!0,prehideSelectors:["#gdpr-cookie-message"],detectCmp:[{exists:"#gdpr-cookie-message"}],detectPopup:[{visible:"#gdpr-cookie-message"}],optIn:[{click:"button#gdpr-cookie-accept"}],optOut:[{hide:"#gdpr-cookie-message"}]},{name:"coinbase",intermediate:!1,runContext:{frame:!0,main:!0,urlPattern:"^https://(www|help)\\.coinbase\\.com"},prehideSelectors:[],detectCmp:[{exists:"div[class^=CookieBannerContent__Container]"}],detectPopup:[{visible:"div[class^=CookieBannerContent__Container]"}],optIn:[{click:"div[class^=CookieBannerContent__CTA] :nth-last-child(1)"}],optOut:[{click:"button[class^=CookieBannerContent__Settings]"},{click:"div[class^=CookiePreferencesModal__CategoryContainer] input:checked",all:!0,optional:!0},{click:"div[class^=CookiePreferencesModal__ButtonContainer] > button"}],test:[{eval:"EVAL_COINBASE_0"}]},{name:"Complianz banner",prehideSelectors:["#cmplz-cookiebanner-container"],detectCmp:[{exists:"#cmplz-cookiebanner-container .cmplz-cookiebanner"}],detectPopup:[{visible:"#cmplz-cookiebanner-container .cmplz-cookiebanner",check:"any"}],optIn:[{waitForThenClick:".cmplz-cookiebanner .cmplz-accept"}],optOut:[{waitForThenClick:".cmplz-cookiebanner .cmplz-deny"}],test:[{eval:"EVAL_COMPLIANZ_BANNER_0"}]},{name:"Complianz categories",prehideSelectors:['.cc-type-categories[aria-describedby="cookieconsent:desc"]'],detectCmp:[{exists:'.cc-type-categories[aria-describedby="cookieconsent:desc"]'}],detectPopup:[{visible:'.cc-type-categories[aria-describedby="cookieconsent:desc"]'}],optIn:[{any:[{click:".cc-accept-all"},{click:".cc-allow-all"},{click:".cc-allow"},{click:".cc-dismiss"}]}],optOut:[{if:{exists:'.cc-type-categories[aria-describedby="cookieconsent:desc"] .cc-dismiss'},then:[{click:".cc-dismiss"}],else:[{click:".cc-type-categories input[type=checkbox]:not([disabled]):checked",all:!0,optional:!0},{click:".cc-save"}]}]},{name:"Complianz notice",prehideSelectors:['.cc-type-info[aria-describedby="cookieconsent:desc"]'],cosmetic:!0,detectCmp:[{exists:'.cc-type-info[aria-describedby="cookieconsent:desc"] .cc-compliance .cc-btn'}],detectPopup:[{visible:'.cc-type-info[aria-describedby="cookieconsent:desc"] .cc-compliance .cc-btn'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{if:{exists:".cc-deny"},then:[{click:".cc-deny"}],else:[{hide:'[aria-describedby="cookieconsent:desc"]'}]}]},{name:"Complianz opt-both",prehideSelectors:['[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'],detectCmp:[{exists:'[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'}],detectPopup:[{visible:'[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{waitForThenClick:".cc-deny"}]},{name:"Complianz opt-out",prehideSelectors:['[aria-describedby="cookieconsent:desc"].cc-type-opt-out'],detectCmp:[{exists:'[aria-describedby="cookieconsent:desc"].cc-type-opt-out'}],detectPopup:[{visible:'[aria-describedby="cookieconsent:desc"].cc-type-opt-out'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{if:{exists:".cc-deny"},then:[{click:".cc-deny"}],else:[{if:{exists:".cmp-pref-link"},then:[{click:".cmp-pref-link"},{waitForThenClick:".cmp-body [id*=rejectAll]"},{waitForThenClick:".cmp-body .cmp-save-btn"}]}]}]},{name:"Complianz optin",prehideSelectors:['.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'],detectCmp:[{exists:'.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'}],detectPopup:[{visible:'.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'}],optIn:[{any:[{click:".cc-accept-all"},{click:".cc-allow"},{click:".cc-dismiss"}]}],optOut:[{if:{visible:".cc-deny"},then:[{click:".cc-deny"}],else:[{if:{visible:".cc-settings"},then:[{waitForThenClick:".cc-settings"},{waitForVisible:".cc-settings-view"},{click:".cc-settings-view input[type=checkbox]:not([disabled]):checked",all:!0,optional:!0},{click:".cc-settings-view .cc-btn-accept-selected"}],else:[{click:".cc-dismiss"}]}]}]},{name:"cookie-law-info",prehideSelectors:["#cookie-law-info-bar"],detectCmp:[{exists:"#cookie-law-info-bar"},{eval:"EVAL_COOKIE_LAW_INFO_DETECT"}],detectPopup:[{visible:"#cookie-law-info-bar"}],optIn:[{click:'[data-cli_action="accept_all"]'}],optOut:[{hide:"#cookie-law-info-bar"},{eval:"EVAL_COOKIE_LAW_INFO_0"}],test:[{eval:"EVAL_COOKIE_LAW_INFO_1"}]},{name:"cookie-manager-popup",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,detectCmp:[{exists:"#notice-cookie-block #allow-functional-cookies, #notice-cookie-block #btn-cookie-settings"}],detectPopup:[{visible:"#notice-cookie-block"}],optIn:[{click:"#btn-cookie-allow"}],optOut:[{if:{exists:"#allow-functional-cookies"},then:[{click:"#allow-functional-cookies"}],else:[{waitForThenClick:"#btn-cookie-settings"},{waitForVisible:".modal-body"},{click:'.modal-body input:checked, .switch[data-switch="on"]',all:!0,optional:!0},{click:'[role="dialog"] .modal-footer button'}]}],prehideSelectors:["#btn-cookie-settings"],test:[{eval:"EVAL_COOKIE_MANAGER_POPUP_0"}]},{name:"cookie-notice",prehideSelectors:["#cookie-notice"],cosmetic:!0,detectCmp:[{visible:"#cookie-notice .cookie-notice-container"}],detectPopup:[{visible:"#cookie-notice"}],optIn:[{click:"#cn-accept-cookie"}],optOut:[{hide:"#cookie-notice"}]},{name:"cookie-script",vendorUrl:"https://cookie-script.com/",prehideSelectors:["#cookiescript_injected"],detectCmp:[{exists:"#cookiescript_injected"}],detectPopup:[{visible:"#cookiescript_injected"}],optOut:[{if:{exists:"#cookiescript_reject"},then:[{wait:100},{click:"#cookiescript_reject"}],else:[{click:"#cookiescript_manage"},{waitForVisible:".cookiescript_fsd_main"},{waitForThenClick:"#cookiescript_reject"}]}],optIn:[{click:"#cookiescript_accept"}]},{name:"cookieacceptbar",vendorUrl:"https://unknown",cosmetic:!0,prehideSelectors:["#cookieAcceptBar.cookieAcceptBar"],detectCmp:[{exists:"#cookieAcceptBar.cookieAcceptBar"}],detectPopup:[{visible:"#cookieAcceptBar.cookieAcceptBar"}],optIn:[{waitForThenClick:"#cookieAcceptBarConfirm"}],optOut:[{hide:"#cookieAcceptBar.cookieAcceptBar"}]},{name:"cookiealert",intermediate:!1,prehideSelectors:[],runContext:{frame:!0,main:!0},detectCmp:[{exists:".cookie-alert-extended"}],detectPopup:[{visible:".cookie-alert-extended-modal"}],optIn:[{click:"button[data-controller='cookie-alert/extended/button/accept']"},{eval:"EVAL_COOKIEALERT_0"}],optOut:[{click:"a[data-controller='cookie-alert/extended/detail-link']"},{click:".cookie-alert-configuration-input:checked",all:!0,optional:!0},{click:"button[data-controller='cookie-alert/extended/button/configuration']"},{eval:"EVAL_COOKIEALERT_0"}],test:[{eval:"EVAL_COOKIEALERT_2"}]},{name:"cookieconsent2",vendorUrl:"https://www.github.com/orestbida/cookieconsent",comment:"supports v2.x.x of the library",prehideSelectors:["#cc--main"],detectCmp:[{exists:"#cc--main"}],detectPopup:[{visible:"#cm"},{exists:"#s-all-bn"}],optIn:[{waitForThenClick:"#s-all-bn"}],optOut:[{waitForThenClick:"#s-rall-bn"}],test:[{eval:"EVAL_COOKIECONSENT2_TEST"}]},{name:"cookieconsent3",vendorUrl:"https://www.github.com/orestbida/cookieconsent",comment:"supports v3.x.x of the library",prehideSelectors:["#cc-main"],detectCmp:[{exists:"#cc-main"}],detectPopup:[{visible:"#cc-main .cm-wrapper"}],optIn:[{waitForThenClick:".cm__btn[data-role=all]"}],optOut:[{waitForThenClick:".cm__btn[data-role=necessary]"}],test:[{eval:"EVAL_COOKIECONSENT3_TEST"}]},{name:"cookiecuttr",vendorUrl:"https://github.com/cdwharton/cookieCuttr",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:""},prehideSelectors:[".cc-cookies"],detectCmp:[{exists:".cc-cookies .cc-cookie-accept"}],detectPopup:[{visible:".cc-cookies .cc-cookie-accept"}],optIn:[{waitForThenClick:".cc-cookies .cc-cookie-accept"}],optOut:[{if:{exists:".cc-cookies .cc-cookie-decline"},then:[{click:".cc-cookies .cc-cookie-decline"}],else:[{hide:".cc-cookies"}]}]},{name:"cookiefirst.com",prehideSelectors:["#cookiefirst-root,.cookiefirst-root,[aria-labelledby=cookie-preference-panel-title]"],detectCmp:[{exists:"#cookiefirst-root,.cookiefirst-root"}],detectPopup:[{visible:"#cookiefirst-root,.cookiefirst-root"}],optIn:[{click:"button[data-cookiefirst-action=accept]"}],optOut:[{if:{exists:"button[data-cookiefirst-action=adjust]"},then:[{click:"button[data-cookiefirst-action=adjust]"},{waitForVisible:"[data-cookiefirst-widget=modal]",timeout:1e3},{eval:"EVAL_COOKIEFIRST_1"},{wait:1e3},{click:"button[data-cookiefirst-action=save]"}],else:[{click:"button[data-cookiefirst-action=reject]"}]}],test:[{eval:"EVAL_COOKIEFIRST_0"}]},{name:"Cookie Information Banner",prehideSelectors:["#cookie-information-template-wrapper"],detectCmp:[{exists:"#cookie-information-template-wrapper"}],detectPopup:[{visible:"#cookie-information-template-wrapper"}],optIn:[{eval:"EVAL_COOKIEINFORMATION_1"}],optOut:[{hide:"#cookie-information-template-wrapper",comment:"some templates don't hide the banner automatically"},{eval:"EVAL_COOKIEINFORMATION_0"}],test:[{eval:"EVAL_COOKIEINFORMATION_2"}]},{name:"cookieyes",prehideSelectors:[".cky-overlay,.cky-consent-container"],detectCmp:[{exists:".cky-consent-container"}],detectPopup:[{visible:".cky-consent-container"}],optIn:[{waitForThenClick:".cky-consent-container [data-cky-tag=accept-button]"}],optOut:[{if:{exists:".cky-consent-container [data-cky-tag=reject-button]"},then:[{waitForThenClick:".cky-consent-container [data-cky-tag=reject-button]"}],else:[{if:{exists:".cky-consent-container [data-cky-tag=settings-button]"},then:[{click:".cky-consent-container [data-cky-tag=settings-button]"},{waitFor:".cky-modal-open input[type=checkbox]"},{click:".cky-modal-open input[type=checkbox]:checked",all:!0,optional:!0},{waitForThenClick:".cky-modal [data-cky-tag=detail-save-button]"}],else:[{hide:".cky-consent-container,.cky-overlay"}]}]}],test:[{eval:"EVAL_COOKIEYES_0"}]},{name:"corona-in-zahlen.de",prehideSelectors:[".cookiealert"],detectCmp:[{exists:".cookiealert"}],detectPopup:[{visible:".cookiealert"}],optOut:[{click:".configurecookies"},{click:".confirmcookies"}],optIn:[{click:".acceptcookies"}]},{name:"crossfit-com",cosmetic:!0,prehideSelectors:['body #modal > div > div[class^="_wrapper_"]'],detectCmp:[{exists:'body #modal > div > div[class^="_wrapper_"]'}],detectPopup:[{visible:'body #modal > div > div[class^="_wrapper_"]'}],optIn:[{click:'button[aria-label="accept cookie policy"]'}],optOut:[{hide:'body #modal > div > div[class^="_wrapper_"]'}]},{name:"csu-landtag-de",runContext:{urlPattern:"^https://(www\\.|)?csu-landtag\\.de"},prehideSelectors:["#cookie-disclaimer"],detectCmp:[{exists:"#cookie-disclaimer"}],detectPopup:[{visible:"#cookie-disclaimer"}],optIn:[{click:"#cookieall"}],optOut:[{click:"#cookiesel"}]},{name:"dailymotion-us",cosmetic:!0,prehideSelectors:['div[class*="CookiePopup__desktopContainer"]:has(div[class*="CookiePopup"])'],detectCmp:[{exists:'div[class*="CookiePopup__desktopContainer"]'}],detectPopup:[{visible:'div[class*="CookiePopup__desktopContainer"]'}],optIn:[{click:'div[class*="CookiePopup__desktopContainer"] > button > span'}],optOut:[{hide:'div[class*="CookiePopup__desktopContainer"]'}]},{name:"dailymotion.com",runContext:{urlPattern:"^https://(www\\.)?dailymotion\\.com/"},prehideSelectors:['div[class*="Overlay__container"]:has(div[class*="TCF2Popup"])'],detectCmp:[{exists:'div[class*="TCF2Popup"]'}],detectPopup:[{visible:'[class*="TCF2Popup"] a[href^="https://www.dailymotion.com/legal/cookiemanagement"]'}],optIn:[{waitForThenClick:'button[class*="TCF2Popup__button"]:not([class*="TCF2Popup__personalize"])'}],optOut:[{waitForThenClick:'button[class*="TCF2ContinueWithoutAcceptingButton"]'}],test:[{eval:"EVAL_DAILYMOTION_0"}]},{name:"dan-com",vendorUrl:"https://unknown",runContext:{main:!0,frame:!1},prehideSelectors:[],detectCmp:[{exists:".cookie-banner.show .cookie-banner__content-all-btn"}],detectPopup:[{visible:".cookie-banner.show .cookie-banner__content-all-btn"}],optIn:[{waitForThenClick:".cookie-banner__content-all-btn"}],optOut:[{waitForThenClick:".cookie-banner__content-essential-btn"}]},{name:"deepl.com",prehideSelectors:[".dl_cookieBanner_container"],detectCmp:[{exists:".dl_cookieBanner_container"}],detectPopup:[{visible:".dl_cookieBanner_container"}],optOut:[{click:".dl_cookieBanner--buttonSelected"}],optIn:[{click:".dl_cookieBanner--buttonAll"}]},{name:"delta.com",runContext:{urlPattern:"^https://www\\.delta\\.com/"},cosmetic:!0,prehideSelectors:["ngc-cookie-banner"],detectCmp:[{exists:"div.cookie-footer-container"}],detectPopup:[{visible:"div.cookie-footer-container"}],optIn:[{click:" button.cookie-close-icon"}],optOut:[{hide:"div.cookie-footer-container"}]},{name:"dmgmedia-us",prehideSelectors:["#mol-ads-cmp-iframe, div.mol-ads-cmp > form > div"],detectCmp:[{exists:"div.mol-ads-cmp > form > div"}],detectPopup:[{waitForVisible:"div.mol-ads-cmp > form > div"}],optIn:[{waitForThenClick:"button.mol-ads-cmp--btn-primary"}],optOut:[{waitForThenClick:"div.mol-ads-ccpa--message > u > a"},{waitForVisible:".mol-ads-cmp--modal-dialog"},{waitForThenClick:"a.mol-ads-cmp-footer-privacy"},{waitForThenClick:"button.mol-ads-cmp--btn-secondary"}]},{name:"dmgmedia",prehideSelectors:['[data-project="mol-fe-cmp"]'],detectCmp:[{exists:'[data-project="mol-fe-cmp"] [class*=footer]'}],detectPopup:[{visible:'[data-project="mol-fe-cmp"] [class*=footer]'}],optIn:[{waitForThenClick:'[data-project="mol-fe-cmp"] button[class*=primary]'}],optOut:[{waitForThenClick:'[data-project="mol-fe-cmp"] button[class*=basic]'},{waitForVisible:'[data-project="mol-fe-cmp"] div[class*="tabContent"]'},{waitForThenClick:'[data-project="mol-fe-cmp"] div[class*="toggle"][class*="enabled"]',all:!0},{waitForThenClick:['[data-project="mol-fe-cmp"] [class*=footer]',"xpath///button[contains(., 'Save & Exit')]"]}]},{name:"dndbeyond",vendorUrl:"https://www.dndbeyond.com/",runContext:{urlPattern:"^https://(www\\.)?dndbeyond\\.com/"},prehideSelectors:["[id^=cookie-consent-banner]"],detectCmp:[{exists:"[id^=cookie-consent-banner]"}],detectPopup:[{visible:"[id^=cookie-consent-banner]"}],optIn:[{waitForThenClick:"#cookie-consent-granted"}],optOut:[{waitForThenClick:"#cookie-consent-denied"}],test:[{eval:"EVAL_DNDBEYOND_TEST"}]},{name:"dpgmedia-nl",prehideSelectors:["#pg-shadow-host"],detectCmp:[{exists:"#pg-shadow-host"}],detectPopup:[{visible:["#pg-shadow-host","#pg-modal"]}],optIn:[{waitForThenClick:["#pg-shadow-host","#pg-accept-btn"]}],optOut:[{waitForThenClick:["#pg-shadow-host","#pg-configure-btn"]},{waitForThenClick:["#pg-shadow-host","#pg-reject-btn"]}]},{name:"Drupal",detectCmp:[{exists:"#drupalorg-crosssite-gdpr"}],detectPopup:[{visible:"#drupalorg-crosssite-gdpr"}],optOut:[{click:".no"}],optIn:[{click:".yes"}]},{name:"WP DSGVO Tools",link:"https://wordpress.org/plugins/shapepress-dsgvo/",prehideSelectors:[".sp-dsgvo"],cosmetic:!0,detectCmp:[{exists:".sp-dsgvo.sp-dsgvo-popup-overlay"}],detectPopup:[{visible:".sp-dsgvo.sp-dsgvo-popup-overlay",check:"any"}],optIn:[{click:".sp-dsgvo-privacy-btn-accept-all",all:!0}],optOut:[{hide:".sp-dsgvo.sp-dsgvo-popup-overlay"}],test:[{eval:"EVAL_DSGVO_0"}]},{name:"dunelm.com",prehideSelectors:["div[data-testid=cookie-consent-modal-backdrop]"],detectCmp:[{exists:"div[data-testid=cookie-consent-message-contents]"}],detectPopup:[{visible:"div[data-testid=cookie-consent-message-contents]"}],optIn:[{click:'[data-testid="cookie-consent-allow-all"]'}],optOut:[{click:"button[data-testid=cookie-consent-adjust-settings]"},{click:"button[data-testid=cookie-consent-preferences-save]"}],test:[{eval:"EVAL_DUNELM_0"}]},{name:"ebay",vendorUrl:"https://ebay.com",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?ebay\\.([.a-z]+)/"},prehideSelectors:["#gdpr-banner"],detectCmp:[{exists:"#gdpr-banner"}],detectPopup:[{visible:"#gdpr-banner"}],optIn:[{waitForThenClick:"#gdpr-banner-accept"}],optOut:[{waitForThenClick:"#gdpr-banner-decline"}]},{name:"ecosia",vendorUrl:"https://www.ecosia.org/",runContext:{urlPattern:"^https://www\\.ecosia\\.org/"},prehideSelectors:[".cookie-wrapper"],detectCmp:[{exists:".cookie-wrapper > .cookie-notice"}],detectPopup:[{visible:".cookie-wrapper > .cookie-notice"}],optIn:[{waitForThenClick:"[data-test-id=cookie-notice-accept]"}],optOut:[{waitForThenClick:"[data-test-id=cookie-notice-reject]"}]},{name:"Ensighten ensModal",prehideSelectors:[".ensModal"],detectCmp:[{exists:".ensModal"}],detectPopup:[{visible:"#ensModalWrapper[style*=block]"}],optIn:[{waitForThenClick:"#modalAcceptButton"}],optOut:[{wait:500},{visible:"#ensModalWrapper[style*=block]"},{waitForThenClick:".ensCheckbox:checked",all:!0},{waitForThenClick:"#ensSave"}]},{name:"Ensighten ensNotifyBanner",prehideSelectors:["#ensNotifyBanner"],detectCmp:[{exists:"#ensNotifyBanner"}],detectPopup:[{visible:"#ensNotifyBanner[style*=block]"}],optIn:[{waitForThenClick:"#ensCloseBanner"}],optOut:[{wait:500},{visible:"#ensNotifyBanner[style*=block]"},{waitForThenClick:"#ensRejectAll,#rejectAll,#ensRejectBanner,.rejectAll,#ensCloseBanner",timeout:2e3}]},{name:"espace-personnel.agirc-arrco.fr",runContext:{urlPattern:"^https://espace-personnel\\.agirc-arrco\\.fr/"},prehideSelectors:[".cdk-overlay-container"],detectCmp:[{exists:".cdk-overlay-container app-esaa-cookie-component"}],detectPopup:[{visible:".cdk-overlay-container app-esaa-cookie-component"}],optIn:[{waitForThenClick:".btn-cookie-accepter"}],optOut:[{waitForThenClick:".btn-cookie-refuser"}]},{name:"etsy",prehideSelectors:["#gdpr-single-choice-overlay","#gdpr-privacy-settings"],detectCmp:[{exists:"#gdpr-single-choice-overlay"}],detectPopup:[{visible:"#gdpr-single-choice-overlay"}],optOut:[{click:"button[data-gdpr-open-full-settings]"},{waitForVisible:".gdpr-overlay-body input",timeout:3e3},{wait:1e3},{eval:"EVAL_ETSY_0"},{eval:"EVAL_ETSY_1"}],optIn:[{click:"button[data-gdpr-single-choice-accept]"}]},{name:"eu-cookie-compliance-banner",detectCmp:[{exists:"body.eu-cookie-compliance-popup-open"}],detectPopup:[{exists:"body.eu-cookie-compliance-popup-open"}],optIn:[{click:".agree-button"}],optOut:[{if:{visible:".decline-button,.eu-cookie-compliance-save-preferences-button"},then:[{click:".decline-button,.eu-cookie-compliance-save-preferences-button"}]},{hide:".eu-cookie-compliance-banner-info, #sliding-popup"}],test:[{eval:"EVAL_EU_COOKIE_COMPLIANCE_0"}]},{name:"EU Cookie Law",prehideSelectors:[".pea_cook_wrapper,.pea_cook_more_info_popover"],cosmetic:!0,detectCmp:[{exists:".pea_cook_wrapper"}],detectPopup:[{wait:500},{visible:".pea_cook_wrapper"}],optIn:[{click:"#pea_cook_btn"}],optOut:[{hide:".pea_cook_wrapper"}],test:[{eval:"EVAL_EU_COOKIE_LAW_0"}]},{name:"europa-eu",vendorUrl:"https://ec.europa.eu/",runContext:{urlPattern:"^https://[^/]*europa\\.eu/"},prehideSelectors:["#cookie-consent-banner"],detectCmp:[{exists:".cck-container"}],detectPopup:[{visible:".cck-container"}],optIn:[{waitForThenClick:'.cck-actions-button[href="#accept"]'}],optOut:[{waitForThenClick:'.cck-actions-button[href="#refuse"]',hide:".cck-container"}]},{name:"EZoic",prehideSelectors:["#ez-cookie-dialog-wrapper"],detectCmp:[{exists:"#ez-cookie-dialog-wrapper"}],detectPopup:[{visible:"#ez-cookie-dialog-wrapper"}],optIn:[{click:"#ez-accept-all",optional:!0},{eval:"EVAL_EZOIC_0",optional:!0}],optOut:[{wait:500},{click:"#ez-manage-settings"},{waitFor:"#ez-cookie-dialog input[type=checkbox]"},{click:"#ez-cookie-dialog input[type=checkbox]:checked",all:!0},{click:"#ez-save-settings"}],test:[{eval:"EVAL_EZOIC_1"}]},{name:"facebook",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?facebook\\.com/"},prehideSelectors:['div[data-testid="cookie-policy-manage-dialog"]'],detectCmp:[{exists:'div[data-testid="cookie-policy-manage-dialog"]'}],detectPopup:[{visible:'div[data-testid="cookie-policy-manage-dialog"]'}],optIn:[{waitForThenClick:'button[data-cookiebanner="accept_button"]'},{waitForVisible:'div[data-testid="cookie-policy-manage-dialog"]',check:"none"}],optOut:[{waitForThenClick:'button[data-cookiebanner="accept_only_essential_button"]'},{waitForVisible:'div[data-testid="cookie-policy-manage-dialog"]',check:"none"}]},{name:"fides",vendorUrl:"https://github.com/ethyca/fides",prehideSelectors:["#fides-overlay"],detectCmp:[{exists:"#fides-overlay #fides-banner"}],detectPopup:[{visible:"#fides-overlay #fides-banner"},{eval:"EVAL_FIDES_DETECT_POPUP"}],optIn:[{waitForThenClick:"#fides-banner .fides-accept-all-button"}],optOut:[{waitForThenClick:"#fides-banner .fides-reject-all-button"}]},{name:"funding-choices",prehideSelectors:[".fc-consent-root,.fc-dialog-container,.fc-dialog-overlay,.fc-dialog-content"],detectCmp:[{exists:".fc-consent-root"}],detectPopup:[{exists:".fc-dialog-container"}],optOut:[{click:".fc-cta-do-not-consent,.fc-cta-manage-options"},{click:".fc-preference-consent:checked,.fc-preference-legitimate-interest:checked",all:!0,optional:!0},{click:".fc-confirm-choices",optional:!0}],optIn:[{click:".fc-cta-consent"}]},{name:"geeks-for-geeks",runContext:{urlPattern:"^https://www\\.geeksforgeeks\\.org/"},cosmetic:!0,prehideSelectors:[".cookie-consent"],detectCmp:[{exists:".cookie-consent"}],detectPopup:[{visible:".cookie-consent"}],optIn:[{click:".cookie-consent button.consent-btn"}],optOut:[{hide:".cookie-consent"}]},{name:"google-consent-standalone",prehideSelectors:[],detectCmp:[{exists:'a[href^="https://policies.google.com/technologies/cookies"'},{exists:'form[action^="https://consent.google."][action$="/save"]'}],detectPopup:[{visible:'a[href^="https://policies.google.com/technologies/cookies"'}],optIn:[{waitForThenClick:'form[action^="https://consent.google."][action$="/save"]:has(input[name=set_eom][value=false]) button'}],optOut:[{waitForThenClick:'form[action^="https://consent.google."][action$="/save"]:has(input[name=set_eom][value=true]) button'}]},{name:"google-cookiebar",vendorUrl:"https://www.android.com/better-together/quick-share-app/",cosmetic:!1,prehideSelectors:[".glue-cookie-notification-bar"],detectCmp:[{exists:".glue-cookie-notification-bar"}],detectPopup:[{visible:".glue-cookie-notification-bar"}],optIn:[{waitForThenClick:".glue-cookie-notification-bar__accept"}],optOut:[{if:{exists:".glue-cookie-notification-bar__reject"},then:[{click:".glue-cookie-notification-bar__reject"}],else:[{hide:".glue-cookie-notification-bar"}]}],test:[]},{name:"google.com",prehideSelectors:[".HTjtHe#xe7COe"],detectCmp:[{exists:".HTjtHe#xe7COe"},{exists:'.HTjtHe#xe7COe a[href^="https://policies.google.com/technologies/cookies"]'}],detectPopup:[{visible:".HTjtHe#xe7COe button#W0wltc"}],optIn:[{waitForThenClick:".HTjtHe#xe7COe button#L2AGLb"}],optOut:[{waitForThenClick:".HTjtHe#xe7COe button#W0wltc"}],test:[{eval:"EVAL_GOOGLE_0"}]},{name:"gov.uk",detectCmp:[{exists:"#global-cookie-message"}],detectPopup:[{exists:"#global-cookie-message"}],optIn:[{click:"button[data-accept-cookies=true]"}],optOut:[{click:"button[data-reject-cookies=true],#reject-cookies"},{click:"button[data-hide-cookie-banner=true],#hide-cookie-decision"}]},{name:"hashicorp",vendorUrl:"https://hashicorp.com/",runContext:{urlPattern:"^https://[^.]*\\.hashicorp\\.com/"},prehideSelectors:["[data-testid=consent-banner]"],detectCmp:[{exists:"[data-testid=consent-banner]"}],detectPopup:[{visible:"[data-testid=consent-banner]"}],optIn:[{waitForThenClick:"[data-testid=accept]"}],optOut:[{waitForThenClick:"[data-testid=manage-preferences]"},{waitForThenClick:"[data-testid=consent-mgr-dialog] [data-ga-button=save-preferences]"}]},{name:"healthline-media",prehideSelectors:["#modal-host > div.no-hash > div.window-wrapper"],detectCmp:[{exists:"#modal-host > div.no-hash > div.window-wrapper, div[data-testid=qualtrics-container]"}],detectPopup:[{exists:"#modal-host > div.no-hash > div.window-wrapper, div[data-testid=qualtrics-container]"}],optIn:[{click:"#modal-host > div.no-hash > div.window-wrapper > div:last-child button"}],optOut:[{if:{exists:'#modal-host > div.no-hash > div.window-wrapper > div:last-child a[href="/privacy-settings"]'},then:[{click:'#modal-host > div.no-hash > div.window-wrapper > div:last-child a[href="/privacy-settings"]'}],else:[{waitForVisible:"div#__next"},{click:"#__next div:nth-child(1) > button:first-child"}]}]},{name:"hema",prehideSelectors:[".cookie-modal"],detectCmp:[{visible:".cookie-modal .cookie-accept-btn"}],detectPopup:[{visible:".cookie-modal .cookie-accept-btn"}],optIn:[{waitForThenClick:".cookie-modal .cookie-accept-btn"}],optOut:[{waitForThenClick:".cookie-modal .js-cookie-reject-btn"}],test:[{eval:"EVAL_HEMA_TEST_0"}]},{name:"hetzner.com",runContext:{urlPattern:"^https://www\\.hetzner\\.com/"},prehideSelectors:["#CookieConsent"],detectCmp:[{exists:"#CookieConsent"}],detectPopup:[{visible:"#CookieConsent"}],optIn:[{click:"#CookieConsentGiven"}],optOut:[{click:"#CookieConsentDeclined"}]},{name:"hl.co.uk",prehideSelectors:[".cookieModalContent","#cookie-banner-overlay"],detectCmp:[{exists:"#cookie-banner-overlay"}],detectPopup:[{exists:"#cookie-banner-overlay"}],optIn:[{click:"#acceptCookieButton"}],optOut:[{click:"#manageCookie"},{hide:".cookieSettingsModal"},{waitFor:"#AOCookieToggle"},{click:"#AOCookieToggle[aria-pressed=true]",optional:!0},{waitFor:"#TPCookieToggle"},{click:"#TPCookieToggle[aria-pressed=true]",optional:!0},{click:"#updateCookieButton"}]},{name:"holidaymedia",vendorUrl:"https://holidaymedia.nl/",prehideSelectors:["dialog[data-cookie-consent]"],detectCmp:[{exists:"dialog[data-cookie-consent]"}],detectPopup:[{visible:"dialog[data-cookie-consent]"}],optIn:[{waitForThenClick:"button.cookie-consent__button--accept-all"}],optOut:[{waitForThenClick:'a[data-cookie-accept="functional"]',timeout:2e3}]},{name:"hu-manity",vendorUrl:"https://hu-manity.co/",prehideSelectors:["#hu.hu-wrapper"],detectCmp:[{exists:"#hu.hu-visible"}],detectPopup:[{visible:"#hu.hu-visible"}],optIn:[{waitForThenClick:"[data-hu-action=cookies-notice-consent-choices-3]"},{waitForThenClick:"#hu-cookies-save"}],optOut:[{waitForThenClick:"#hu-cookies-save"}]},{name:"hubspot",detectCmp:[{exists:"#hs-eu-cookie-confirmation"}],detectPopup:[{visible:"#hs-eu-cookie-confirmation"}],optIn:[{click:"#hs-eu-confirmation-button"}],optOut:[{click:"#hs-eu-decline-button"}]},{name:"indeed.com",cosmetic:!0,prehideSelectors:["#CookiePrivacyNotice"],detectCmp:[{exists:"#CookiePrivacyNotice"}],detectPopup:[{visible:"#CookiePrivacyNotice"}],optIn:[{click:"#CookiePrivacyNotice button[data-gnav-element-name=CookiePrivacyNoticeOk]"}],optOut:[{hide:"#CookiePrivacyNotice"}]},{name:"ing.de",runContext:{urlPattern:"^https://www\\.ing\\.de/"},cosmetic:!0,prehideSelectors:['div[slot="backdrop"]'],detectCmp:[{exists:'[data-tag-name="ing-cc-dialog-frame"]'}],detectPopup:[{visible:'[data-tag-name="ing-cc-dialog-frame"]'}],optIn:[{click:['[data-tag-name="ing-cc-dialog-level0"]','[data-tag-name="ing-cc-button"][class*="accept"]']}],optOut:[{click:['[data-tag-name="ing-cc-dialog-level0"]','[data-tag-name="ing-cc-button"][class*="more"]']}]},{name:"instagram",vendorUrl:"https://instagram.com",runContext:{urlPattern:"^https://www\\.instagram\\.com/"},prehideSelectors:[],detectCmp:[{exists:'xpath///span[contains(., "Vill du tillåta användningen av cookies från Instagram i den här webbläsaren?") or contains(., "Allow the use of cookies from Instagram on this browser?") or contains(., "Povolit v prohlížeči použití souborů cookie z Instagramu?") or contains(., "Dopustiti upotrebu kolačića s Instagrama na ovom pregledniku?") or contains(., "Разрешить использование файлов cookie от Instagram в этом браузере?") or contains(., "Vuoi consentire l\'uso dei cookie di Instagram su questo browser?") or contains(., "Povoliť používanie cookies zo služby Instagram v tomto prehliadači?") or contains(., "Die Verwendung von Cookies durch Instagram in diesem Browser erlauben?") or contains(., "Sallitaanko Instagramin evästeiden käyttö tällä selaimella?") or contains(., "Engedélyezed az Instagram cookie-jainak használatát ebben a böngészőben?") or contains(., "Het gebruik van cookies van Instagram toestaan in deze browser?") or contains(., "Bu tarayıcıda Instagram\'dan çerez kullanımına izin verilsin mi?") or contains(., "Permitir o uso de cookies do Instagram neste navegador?") or contains(., "Permiţi folosirea modulelor cookie de la Instagram în acest browser?") or contains(., "Autoriser l’utilisation des cookies d’Instagram sur ce navigateur ?") or contains(., "¿Permitir el uso de cookies de Instagram en este navegador?") or contains(., "Zezwolić na użycie plików cookie z Instagramu w tej przeglądarce?") or contains(., "Να επιτρέπεται η χρήση cookies από τo Instagram σε αυτό το πρόγραμμα περιήγησης;") or contains(., "Разрешавате ли използването на бисквитки от Instagram на този браузър?") or contains(., "Vil du tillade brugen af cookies fra Instagram i denne browser?") or contains(., "Vil du tillate bruk av informasjonskapsler fra Instagram i denne nettleseren?")]'}],detectPopup:[{visible:'xpath///span[contains(., "Vill du tillåta användningen av cookies från Instagram i den här webbläsaren?") or contains(., "Allow the use of cookies from Instagram on this browser?") or contains(., "Povolit v prohlížeči použití souborů cookie z Instagramu?") or contains(., "Dopustiti upotrebu kolačića s Instagrama na ovom pregledniku?") or contains(., "Разрешить использование файлов cookie от Instagram в этом браузере?") or contains(., "Vuoi consentire l\'uso dei cookie di Instagram su questo browser?") or contains(., "Povoliť používanie cookies zo služby Instagram v tomto prehliadači?") or contains(., "Die Verwendung von Cookies durch Instagram in diesem Browser erlauben?") or contains(., "Sallitaanko Instagramin evästeiden käyttö tällä selaimella?") or contains(., "Engedélyezed az Instagram cookie-jainak használatát ebben a böngészőben?") or contains(., "Het gebruik van cookies van Instagram toestaan in deze browser?") or contains(., "Bu tarayıcıda Instagram\'dan çerez kullanımına izin verilsin mi?") or contains(., "Permitir o uso de cookies do Instagram neste navegador?") or contains(., "Permiţi folosirea modulelor cookie de la Instagram în acest browser?") or contains(., "Autoriser l’utilisation des cookies d’Instagram sur ce navigateur ?") or contains(., "¿Permitir el uso de cookies de Instagram en este navegador?") or contains(., "Zezwolić na użycie plików cookie z Instagramu w tej przeglądarce?") or contains(., "Να επιτρέπεται η χρήση cookies από τo Instagram σε αυτό το πρόγραμμα περιήγησης;") or contains(., "Разрешавате ли използването на бисквитки от Instagram на този браузър?") or contains(., "Vil du tillade brugen af cookies fra Instagram i denne browser?") or contains(., "Vil du tillate bruk av informasjonskapsler fra Instagram i denne nettleseren?")]'}],optIn:[{waitForThenClick:"xpath///button[contains(., 'Tillad alle cookies') or contains(., 'Alle Cookies erlauben') or contains(., 'Allow all cookies') or contains(., 'Разрешаване на всички бисквитки') or contains(., 'Tillåt alla cookies') or contains(., 'Povolit všechny soubory cookie') or contains(., 'Tüm çerezlere izin ver') or contains(., 'Permite toate modulele cookie') or contains(., 'Να επιτρέπονται όλα τα cookies') or contains(., 'Tillat alle informasjonskapsler') or contains(., 'Povoliť všetky cookies') or contains(., 'Permitir todas las cookies') or contains(., 'Permitir todos os cookies') or contains(., 'Alle cookies toestaan') or contains(., 'Salli kaikki evästeet') or contains(., 'Consenti tutti i cookie') or contains(., 'Az összes cookie engedélyezése') or contains(., 'Autoriser tous les cookies') or contains(., 'Zezwól na wszystkie pliki cookie') or contains(., 'Разрешить все cookie') or contains(., 'Dopusti sve kolačiće')]"}],optOut:[{waitForThenClick:"xpath///button[contains(., 'Отклонить необязательные файлы cookie') or contains(., 'Decline optional cookies') or contains(., 'Refuser les cookies optionnels') or contains(., 'Hylkää valinnaiset evästeet') or contains(., 'Afvis valgfrie cookies') or contains(., 'Odmietnuť nepovinné cookies') or contains(., 'Απόρριψη προαιρετικών cookies') or contains(., 'Neka valfria cookies') or contains(., 'Optionale Cookies ablehnen') or contains(., 'Rifiuta cookie facoltativi') or contains(., 'Odbij neobavezne kolačiće') or contains(., 'Avvis valgfrie informasjonskapsler') or contains(., 'İsteğe bağlı çerezleri reddet') or contains(., 'Recusar cookies opcionais') or contains(., 'Optionele cookies afwijzen') or contains(., 'Rechazar cookies opcionales') or contains(., 'Odrzuć opcjonalne pliki cookie') or contains(., 'Отхвърляне на бисквитките по избор') or contains(., 'Odmítnout volitelné soubory cookie') or contains(., 'Refuză modulele cookie opţionale') or contains(., 'A nem kötelező cookie-k elutasítása')]"},{wait:2e3}]},{name:"ionos.de",prehideSelectors:[".privacy-consent--backdrop",".privacy-consent--modal"],detectCmp:[{exists:".privacy-consent--modal"}],detectPopup:[{visible:".privacy-consent--modal"}],optIn:[{click:"#selectAll"}],optOut:[{click:".footer-config-link"},{click:"#confirmSelection"}]},{name:"itopvpn.com",cosmetic:!0,prehideSelectors:[".pop-cookie"],detectCmp:[{exists:".pop-cookie"}],detectPopup:[{exists:".pop-cookie"}],optIn:[{click:"#_pcookie"}],optOut:[{hide:".pop-cookie"}]},{name:"iubenda",prehideSelectors:["#iubenda-cs-banner"],detectCmp:[{exists:"#iubenda-cs-banner"}],detectPopup:[{visible:".iubenda-cs-accept-btn"}],optIn:[{waitForThenClick:".iubenda-cs-accept-btn"}],optOut:[{waitForThenClick:".iubenda-cs-customize-btn"},{eval:"EVAL_IUBENDA_0"},{waitForThenClick:"#iubFooterBtn"}],test:[{eval:"EVAL_IUBENDA_1"}]},{name:"iWink",prehideSelectors:["body.cookies-request #cookie-bar"],detectCmp:[{exists:"body.cookies-request #cookie-bar"}],detectPopup:[{visible:"body.cookies-request #cookie-bar"}],optIn:[{waitForThenClick:"body.cookies-request #cookie-bar .allow-cookies"}],optOut:[{waitForThenClick:"body.cookies-request #cookie-bar .disallow-cookies"}],test:[{eval:"EVAL_IWINK_TEST"}]},{name:"jdsports",vendorUrl:"https://www.jdsports.co.uk/",runContext:{urlPattern:"^https://(www|m)\\.jdsports\\."},prehideSelectors:[".miniConsent,#PrivacyPolicyBanner"],detectCmp:[{exists:".miniConsent,#PrivacyPolicyBanner"}],detectPopup:[{visible:".miniConsent,#PrivacyPolicyBanner"}],optIn:[{waitForThenClick:".miniConsent .accept-all-cookies"}],optOut:[{if:{exists:"#PrivacyPolicyBanner"},then:[{hide:"#PrivacyPolicyBanner"}],else:[{waitForThenClick:"#cookie-settings"},{waitForThenClick:"#reject-all-cookies"}]}]},{name:"johnlewis.com",prehideSelectors:["div[class^=pecr-cookie-banner-]"],detectCmp:[{exists:"div[class^=pecr-cookie-banner-]"}],detectPopup:[{exists:"div[class^=pecr-cookie-banner-]"}],optOut:[{click:"button[data-test^=manage-cookies]"},{wait:"500"},{click:"label[data-test^=toggle][class*=checked]:not([class*=disabled])",all:!0,optional:!0},{click:"button[data-test=save-preferences]"}],optIn:[{click:"button[data-test=allow-all]"}]},{name:"jquery.cookieBar",vendorUrl:"https://github.com/kovarp/jquery.cookieBar",prehideSelectors:[".cookie-bar"],cosmetic:!0,detectCmp:[{exists:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons"}],detectPopup:[{visible:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons",check:"any"}],optIn:[{click:".cookie-bar .cookie-bar__btn"}],optOut:[{hide:".cookie-bar"}],test:[{visible:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons",check:"none"},{eval:"EVAL_JQUERY_COOKIEBAR_0"}]},{name:"justwatch.com",prehideSelectors:[".consent-banner"],detectCmp:[{exists:".consent-banner .consent-banner__actions"}],detectPopup:[{visible:".consent-banner .consent-banner__actions"}],optIn:[{click:".consent-banner__actions button.basic-button.primary"}],optOut:[{click:".consent-banner__actions button.basic-button.secondary"},{waitForThenClick:".consent-modal__footer button.basic-button.secondary"},{waitForThenClick:".consent-modal ion-content > div > a:nth-child(9)"},{click:"label.consent-switch input[type=checkbox]:checked",all:!0,optional:!0},{waitForVisible:".consent-modal__footer button.basic-button.primary"},{click:".consent-modal__footer button.basic-button.primary"}]},{name:"ketch",vendorUrl:"https://www.ketch.com",runContext:{frame:!1,main:!0},intermediate:!1,prehideSelectors:["#lanyard_root div[role='dialog']"],detectCmp:[{exists:"#lanyard_root div[role='dialog']"}],detectPopup:[{visible:"#lanyard_root div[role='dialog']"}],optIn:[{if:{exists:"#lanyard_root button[class='confirmButton']"},then:[{waitForThenClick:"#lanyard_root div[class*=buttons] > :nth-child(2)"},{click:"#lanyard_root button[class='confirmButton']"}],else:[{waitForThenClick:"#lanyard_root div[class*=buttons] > :nth-child(2)"}]}],optOut:[{if:{exists:"#lanyard_root [aria-describedby=banner-description]"},then:[{waitForThenClick:"#lanyard_root div[class*=buttons] > button[class*=secondaryButton], #lanyard_root button[class*=buttons-secondary]",comment:"can be either settings or reject button"}]},{waitFor:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description], #ketch-preferences",timeout:1e3,optional:!0},{if:{exists:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description], #ketch-preferences"},then:[{waitForThenClick:"#lanyard_root button[class*=rejectButton], #lanyard_root button[class*=rejectAllButton]"},{click:"#lanyard_root button[class*=confirmButton],#lanyard_root div[class*=actions_] > button:nth-child(1), #lanyard_root button[class*=actionButton]"}]}],test:[{eval:"EVAL_KETCH_TEST"}]},{name:"kleinanzeigen-de",runContext:{urlPattern:"^https?://(www\\.)?kleinanzeigen\\.de"},prehideSelectors:["#gdpr-banner-container"],detectCmp:[{any:[{exists:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"},{exists:"#ConsentManagementPage"}]}],detectPopup:[{any:[{visible:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"},{visible:"#ConsentManagementPage"}]}],optIn:[{if:{exists:"#gdpr-banner-container #gdpr-banner"},then:[{click:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-accept]"}],else:[{click:"#ConsentManagementPage .Button-primary"}]}],optOut:[{if:{exists:"#gdpr-banner-container #gdpr-banner"},then:[{click:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"}],else:[{click:"#ConsentManagementPage .Button-secondary"}]}]},{name:"lightbox",prehideSelectors:[".darken-layer.open,.lightbox.lightbox--cookie-consent"],detectCmp:[{exists:"body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"}],detectPopup:[{visible:"body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"}],optOut:[{click:".cookie-consent__footer > button[type='submit']:not([data-button='selectAll'])"}],optIn:[{click:".cookie-consent__footer > button[type='submit'][data-button='selectAll']"}]},{name:"lineagrafica",vendorUrl:"https://addons.prestashop.com/en/legal/8734-eu-cookie-law-gdpr-banner-blocker.html",cosmetic:!0,prehideSelectors:["#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"],detectCmp:[{exists:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}],detectPopup:[{exists:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}],optIn:[{waitForThenClick:"#lgcookieslaw_accept"}],optOut:[{hide:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}]},{name:"linkedin.com",prehideSelectors:[".artdeco-global-alert[type=COOKIE_CONSENT]"],detectCmp:[{exists:".artdeco-global-alert[type=COOKIE_CONSENT]"}],detectPopup:[{visible:".artdeco-global-alert[type=COOKIE_CONSENT]"}],optIn:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=ACCEPT]"},{wait:500},{waitForThenClick:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=ACCEPT]"}],optOut:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=DENY]"},{wait:500},{waitForThenClick:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=DENY]"}],test:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT]",check:"none"}]},{name:"livejasmin",vendorUrl:"https://www.livejasmin.com/",runContext:{urlPattern:"^https://(m|www)\\.livejasmin\\.com/"},prehideSelectors:["#consent_modal"],detectCmp:[{exists:"#consent_modal"}],detectPopup:[{visible:"#consent_modal"}],optIn:[{waitForThenClick:"#consent_modal button[data-testid=ButtonStyledButton]:first-of-type"}],optOut:[{waitForThenClick:"#consent_modal button[data-testid=ButtonStyledButton]:nth-of-type(2)"},{waitForVisible:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent]"},{click:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent] input[data-testid=PrivacyPreferenceCenterWithConsentCookieSwitch]:checked",optional:!0,all:!0},{waitForThenClick:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent] button[data-testid=ButtonStyledButton]:last-child"}]},{name:"macpaw.com",cosmetic:!0,prehideSelectors:['div[data-banner="cookies"]'],detectCmp:[{exists:'div[data-banner="cookies"]'}],detectPopup:[{exists:'div[data-banner="cookies"]'}],optIn:[{click:'button[data-banner-close="cookies"]'}],optOut:[{hide:'div[data-banner="cookies"]'}]},{name:"marksandspencer.com",cosmetic:!0,detectCmp:[{exists:".navigation-cookiebbanner"}],detectPopup:[{visible:".navigation-cookiebbanner"}],optOut:[{hide:".navigation-cookiebbanner"}],optIn:[{click:".navigation-cookiebbanner__submit"}]},{name:"mediamarkt.de",prehideSelectors:["div[aria-labelledby=pwa-consent-layer-title]","div[class^=StyledConsentLayerWrapper-]"],detectCmp:[{exists:"div[aria-labelledby^=pwa-consent-layer-title]"}],detectPopup:[{exists:"div[aria-labelledby^=pwa-consent-layer-title]"}],optOut:[{click:"button[data-test^=pwa-consent-layer-deny-all]"}],optIn:[{click:"button[data-test^=pwa-consent-layer-accept-all"}]},{name:"Mediavine",prehideSelectors:['[data-name="mediavine-gdpr-cmp"]'],detectCmp:[{exists:'[data-name="mediavine-gdpr-cmp"]'}],detectPopup:[{wait:500},{visible:'[data-name="mediavine-gdpr-cmp"]'}],optIn:[{waitForThenClick:'[data-name="mediavine-gdpr-cmp"] [format="primary"]'}],optOut:[{waitForThenClick:'[data-name="mediavine-gdpr-cmp"] [data-view="manageSettings"]'},{waitFor:'[data-name="mediavine-gdpr-cmp"] input[type=checkbox]'},{eval:"EVAL_MEDIAVINE_0",optional:!0},{click:'[data-name="mediavine-gdpr-cmp"] [format="secondary"]'}]},{name:"medium",vendorUrl:"https://medium.com",cosmetic:!0,runContext:{main:!0,frame:!1,urlPattern:"^https://([a-z0-9-]+\\.)?medium\\.com/"},prehideSelectors:[],detectCmp:[{exists:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}],detectPopup:[{visible:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}],optIn:[{waitForThenClick:"[data-testid=close-button]"}],optOut:[{hide:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}]},{name:"microsoft.com",prehideSelectors:["#wcpConsentBannerCtrl"],detectCmp:[{exists:"#wcpConsentBannerCtrl"}],detectPopup:[{exists:"#wcpConsentBannerCtrl"}],optOut:[{eval:"EVAL_MICROSOFT_0"}],optIn:[{eval:"EVAL_MICROSOFT_1"}],test:[{eval:"EVAL_MICROSOFT_2"}]},{name:"midway-usa",runContext:{urlPattern:"^https://www\\.midwayusa\\.com/"},cosmetic:!0,prehideSelectors:["#cookie-container"],detectCmp:[{exists:['div[aria-label="Cookie Policy Banner"]']}],detectPopup:[{visible:"#cookie-container"}],optIn:[{click:"button#cookie-btn"}],optOut:[{hide:'div[aria-label="Cookie Policy Banner"]'}]},{name:"moneysavingexpert.com",detectCmp:[{exists:"dialog[data-testid=accept-our-cookies-dialog]"}],detectPopup:[{visible:"dialog[data-testid=accept-our-cookies-dialog]"}],optIn:[{click:"#banner-accept"}],optOut:[{click:"#banner-manage"},{click:"#pc-confirm"}]},{name:"monzo.com",prehideSelectors:[".cookie-alert, cookie-alert__content"],detectCmp:[{exists:'div.cookie-alert[role="dialog"]'},{exists:'a[href*="monzo"]'}],detectPopup:[{visible:".cookie-alert__content"}],optIn:[{click:".js-accept-cookie-policy"}],optOut:[{click:".js-decline-cookie-policy"}]},{name:"Moove",prehideSelectors:["#moove_gdpr_cookie_info_bar"],detectCmp:[{exists:"#moove_gdpr_cookie_info_bar"}],detectPopup:[{visible:"#moove_gdpr_cookie_info_bar:not(.moove-gdpr-info-bar-hidden)"}],optIn:[{waitForThenClick:".moove-gdpr-infobar-allow-all"}],optOut:[{if:{exists:"#moove_gdpr_cookie_info_bar .change-settings-button"},then:[{click:"#moove_gdpr_cookie_info_bar .change-settings-button"},{waitForVisible:"#moove_gdpr_cookie_modal"},{eval:"EVAL_MOOVE_0"},{click:".moove-gdpr-modal-save-settings"}],else:[{hide:"#moove_gdpr_cookie_info_bar"}]}],test:[{visible:"#moove_gdpr_cookie_info_bar",check:"none"}]},{name:"national-lottery.co.uk",detectCmp:[{exists:".cuk_cookie_consent"}],detectPopup:[{visible:".cuk_cookie_consent",check:"any"}],optOut:[{click:".cuk_cookie_consent_manage_pref"},{click:".cuk_cookie_consent_save_pref"},{click:".cuk_cookie_consent_close"}],optIn:[{click:".cuk_cookie_consent_accept_all"}]},{name:"nba.com",runContext:{urlPattern:"^https://(www\\.)?nba.com/"},cosmetic:!0,prehideSelectors:["#onetrust-banner-sdk"],detectCmp:[{exists:"#onetrust-banner-sdk"}],detectPopup:[{visible:"#onetrust-banner-sdk"}],optIn:[{click:"#onetrust-accept-btn-handler"}],optOut:[{hide:"#onetrust-banner-sdk"}]},{name:"netbeat.de",runContext:{urlPattern:"^https://(www\\.)?netbeat\\.de/"},prehideSelectors:["div#cookieWarning"],detectCmp:[{exists:"div#cookieWarning"}],detectPopup:[{visible:"div#cookieWarning"}],optIn:[{waitForThenClick:"a#btnCookiesAcceptAll"}],optOut:[{waitForThenClick:"a#btnCookiesDenyAll"}]},{name:"netflix.de",detectCmp:[{exists:"#cookie-disclosure"}],detectPopup:[{visible:".cookie-disclosure-message",check:"any"}],optIn:[{click:".btn-accept"}],optOut:[{hide:"#cookie-disclosure"},{click:".btn-reject"}]},{name:"nhs.uk",prehideSelectors:["#nhsuk-cookie-banner"],detectCmp:[{exists:"#nhsuk-cookie-banner"}],detectPopup:[{exists:"#nhsuk-cookie-banner"}],optOut:[{click:"#nhsuk-cookie-banner__link_accept"}],optIn:[{click:"#nhsuk-cookie-banner__link_accept_analytics"}]},{name:"nike",vendorUrl:"https://nike.com",runContext:{urlPattern:"^https://(www\\.)?nike\\.com/"},prehideSelectors:[],detectCmp:[{exists:"[data-testid=cookie-dialog-root]"}],detectPopup:[{visible:"[data-testid=cookie-dialog-root]"}],optIn:[{waitForThenClick:"[data-testid=dialog-accept-button]"}],optOut:[{waitForThenClick:"input[type=radio][id$=-declineLabel]",all:!0},{waitForThenClick:"[data-testid=confirm-choice-button]"}]},{name:"notice-cookie",prehideSelectors:[".button--notice"],cosmetic:!0,detectCmp:[{exists:".notice--cookie"}],detectPopup:[{visible:".notice--cookie"}],optIn:[{click:".button--notice"}],optOut:[{hide:".notice--cookie"}]},{name:"nrk.no",cosmetic:!0,prehideSelectors:[".nrk-masthead__info-banner--cookie"],detectCmp:[{exists:".nrk-masthead__info-banner--cookie"}],detectPopup:[{exists:".nrk-masthead__info-banner--cookie"}],optIn:[{click:"div.nrk-masthead__info-banner--cookie button > span:has(+ svg.nrk-close)"}],optOut:[{hide:".nrk-masthead__info-banner--cookie"}]},{name:"obi.de",prehideSelectors:[".disc-cp--active"],detectCmp:[{exists:".disc-cp-modal__modal"}],detectPopup:[{visible:".disc-cp-modal__modal"}],optIn:[{click:".js-disc-cp-accept-all"}],optOut:[{click:".js-disc-cp-deny-all"}]},{name:"om",vendorUrl:"https://olli-machts.de/en/extension/cookie-manager",prehideSelectors:[".tx-om-cookie-consent"],detectCmp:[{exists:".tx-om-cookie-consent .active[data-omcookie-panel]"}],detectPopup:[{exists:".tx-om-cookie-consent .active[data-omcookie-panel]"}],optIn:[{waitForThenClick:"[data-omcookie-panel-save=all]"}],optOut:[{if:{exists:"[data-omcookie-panel-save=min]"},then:[{waitForThenClick:"[data-omcookie-panel-save=min]"}],else:[{click:"input[data-omcookie-panel-grp]:checked:not(:disabled)",all:!0,optional:!0},{waitForThenClick:"[data-omcookie-panel-save=save]"}]}]},{name:"onlyFans.com",runContext:{urlPattern:"^https://onlyfans\\.com/"},prehideSelectors:["div.b-cookies-informer"],detectCmp:[{exists:"div.b-cookies-informer"}],detectPopup:[{exists:"div.b-cookies-informer"}],optIn:[{click:"div.b-cookies-informer__nav > button:nth-child(2)"}],optOut:[{click:"div.b-cookies-informer__nav > button:nth-child(1)"},{if:{exists:"div.b-cookies-informer__switchers"},then:[{click:"div.b-cookies-informer__switchers input:not([disabled])",all:!0},{click:"div.b-cookies-informer__nav > button"}]}]},{name:"openai",vendorUrl:"https://platform.openai.com/",cosmetic:!1,runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?openai\\.com/"},prehideSelectors:["[data-testid=cookie-consent-banner]"],detectCmp:[{exists:"[data-testid=cookie-consent-banner]"}],detectPopup:[{visible:"[data-testid=cookie-consent-banner]"}],optIn:[{waitForThenClick:"xpath///button[contains(., 'Accept all')]"}],optOut:[{waitForThenClick:"xpath///button[contains(., 'Reject all')]"}],test:[{wait:500},{eval:"EVAL_OPENAI_TEST"}]},{name:"openli",vendorUrl:"https://openli.com",prehideSelectors:[".legalmonster-cleanslate"],detectCmp:[{exists:".legalmonster-cleanslate"}],detectPopup:[{visible:".legalmonster-cleanslate #lm-cookie-wall-container",check:"any"}],optIn:[{waitForThenClick:"#lm-accept-all"}],optOut:[{waitForThenClick:"#lm-accept-necessary"}]},{name:"opera.com",vendorUrl:"https://unknown",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,prehideSelectors:[],detectCmp:[{exists:"#cookie-consent .manage-cookies__btn"}],detectPopup:[{visible:"#cookie-consent .cookie-basic-consent__btn"}],optIn:[{waitForThenClick:"#cookie-consent .cookie-basic-consent__btn"}],optOut:[{waitForThenClick:"#cookie-consent .manage-cookies__btn"},{waitForThenClick:"#cookie-consent .active.marketing_option_switch.cookie-consent__switch",all:!0},{waitForThenClick:"#cookie-consent .cookie-selection__btn"}],test:[{eval:"EVAL_OPERA_0"}]},{name:"osano",prehideSelectors:[".osano-cm-window,.osano-cm-dialog"],detectCmp:[{exists:".osano-cm-window"}],detectPopup:[{visible:".osano-cm-dialog"}],optIn:[{click:".osano-cm-accept-all",optional:!0}],optOut:[{waitForThenClick:".osano-cm-denyAll"}]},{name:"otto.de",prehideSelectors:[".cookieBanner--visibility"],detectCmp:[{exists:".cookieBanner--visibility"}],detectPopup:[{visible:".cookieBanner__wrapper"}],optIn:[{click:".js_cookieBannerPermissionButton"}],optOut:[{click:".js_cookieBannerProhibitionButton"}]},{name:"ourworldindata",vendorUrl:"https://ourworldindata.org/",runContext:{urlPattern:"^https://ourworldindata\\.org/"},prehideSelectors:[".cookie-manager"],detectCmp:[{exists:".cookie-manager"}],detectPopup:[{visible:".cookie-manager .cookie-notice.open"}],optIn:[{waitForThenClick:".cookie-notice [data-test=accept]"}],optOut:[{waitForThenClick:".cookie-notice [data-test=reject]"}]},{name:"pabcogypsum",vendorUrl:"https://unknown",prehideSelectors:[".js-cookie-notice:has(#cookie_settings-form)"],detectCmp:[{exists:".js-cookie-notice #cookie_settings-form"}],detectPopup:[{visible:".js-cookie-notice #cookie_settings-form"}],optIn:[{waitForThenClick:".js-cookie-notice button[value=allow]"}],optOut:[{waitForThenClick:".js-cookie-notice button[value=disable]"}]},{name:"paypal-us",prehideSelectors:["#ccpaCookieContent_wrapper, article.ppvx_modal--overpanel"],detectCmp:[{exists:"#ccpaCookieBanner, .privacy-sheet-content"}],detectPopup:[{visible:"#ccpaCookieBanner, .privacy-sheet-content"}],optIn:[{click:"#acceptAllButton"}],optOut:[{if:{exists:"#bannerDeclineButton"},then:[{click:"#bannerDeclineButton"}],else:[{if:{exists:"a#manageCookiesLink"},then:[{click:"a#manageCookiesLink"}],else:[{waitForVisible:".privacy-sheet-content #formContent"},{click:"#formContent .cookiepref-11m2iee-checkbox_base input:checked",all:!0,optional:!0},{click:".cookieAction.saveCookie,.confirmCookie #submitCookiesBtn"}]}]}]},{name:"paypal.com",prehideSelectors:["#gdprCookieBanner"],detectCmp:[{exists:"#gdprCookieBanner"}],detectPopup:[{visible:"#gdprCookieContent_wrapper"}],optIn:[{click:"#acceptAllButton"}],optOut:[{wait:200},{click:".gdprCookieBanner_decline-button"}],test:[{wait:500},{eval:"EVAL_PAYPAL_0"}]},{name:"pinetools.com",cosmetic:!0,prehideSelectors:["#aviso_cookies"],detectCmp:[{exists:"#aviso_cookies"}],detectPopup:[{exists:".lang_en #aviso_cookies"}],optIn:[{click:"#aviso_cookies .a_boton_cerrar"}],optOut:[{hide:"#aviso_cookies"}]},{name:"pinterest-business",vendorUrl:"https://business.pinterest.com/",runContext:{urlPattern:"^https://.*\\.pinterest\\.com/"},prehideSelectors:[".BusinessCookieConsent"],detectCmp:[{exists:".BusinessCookieConsent"}],detectPopup:[{visible:".BusinessCookieConsent [data-id=cookie-consent-banner-buttons]"}],optIn:[{waitForThenClick:"[data-id=cookie-consent-banner-buttons] > div:nth-child(1) button"}],optOut:[{waitForThenClick:"[data-id=cookie-consent-banner-buttons] > div:nth-child(2) button"}]},{name:"pmc",cosmetic:!0,prehideSelectors:["#pmc-pp-tou--notice"],detectCmp:[{exists:"#pmc-pp-tou--notice"}],detectPopup:[{visible:"#pmc-pp-tou--notice"}],optIn:[{click:"span.pmc-pp-tou--notice-close-btn"}],optOut:[{hide:"#pmc-pp-tou--notice"}]},{name:"pornhub.com",runContext:{urlPattern:"^https://(www\\.)?pornhub\\.com/"},cosmetic:!0,prehideSelectors:[".cookiesBanner"],detectCmp:[{exists:".cookiesBanner"}],detectPopup:[{visible:".cookiesBanner"}],optIn:[{click:".cookiesBanner .okButton"}],optOut:[{hide:".cookiesBanner"}]},{name:"pornpics.com",cosmetic:!0,prehideSelectors:["#cookie-contract"],detectCmp:[{exists:"#cookie-contract"}],detectPopup:[{visible:"#cookie-contract"}],optIn:[{click:"#cookie-contract .icon-cross"}],optOut:[{hide:"#cookie-contract"}]},{name:"PrimeBox CookieBar",prehideSelectors:["#cookie-bar"],detectCmp:[{exists:"#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy"}],detectPopup:[{visible:"#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy",check:"any"}],optIn:[{waitForThenClick:"#cookie-bar .cb-enable"}],optOut:[{click:"#cookie-bar .cb-disable",optional:!0},{hide:"#cookie-bar"}],test:[{eval:"EVAL_PRIMEBOX_0"}]},{name:"privacymanager.io",prehideSelectors:["#gdpr-consent-tool-wrapper",'iframe[src^="https://cmp-consent-tool.privacymanager.io"]'],runContext:{urlPattern:"^https://cmp-consent-tool\\.privacymanager\\.io/",main:!1,frame:!0},detectCmp:[{exists:"button#save"}],detectPopup:[{visible:"button#save"}],optIn:[{click:"button#save"}],optOut:[{if:{exists:"#denyAll"},then:[{click:"#denyAll"},{waitForThenClick:".okButton"}],else:[{waitForThenClick:"#manageSettings"},{waitFor:".purposes-overview-list"},{waitFor:"button#saveAndExit"},{click:"span[role=checkbox][aria-checked=true]",all:!0,optional:!0},{click:"button#saveAndExit"}]}]},{name:"productz.com",vendorUrl:"https://productz.com/",runContext:{urlPattern:"^https://productz\\.com/"},prehideSelectors:[],detectCmp:[{exists:".c-modal.is-active"}],detectPopup:[{visible:".c-modal.is-active"}],optIn:[{waitForThenClick:".c-modal.is-active .is-accept"}],optOut:[{waitForThenClick:".c-modal.is-active .is-dismiss"}]},{name:"pubtech",prehideSelectors:["#pubtech-cmp"],detectCmp:[{exists:"#pubtech-cmp"}],detectPopup:[{visible:"#pubtech-cmp #pt-actions"}],optIn:[{if:{exists:"#pt-accept-all"},then:[{click:"#pubtech-cmp #pt-actions #pt-accept-all"}],else:[{click:"#pubtech-cmp #pt-actions button:nth-of-type(2)"}]}],optOut:[{click:"#pubtech-cmp #pt-close"}],test:[{eval:"EVAL_PUBTECH_0"}]},{name:"quantcast",prehideSelectors:["#qc-cmp2-main,#qc-cmp2-container"],detectCmp:[{exists:"#qc-cmp2-container"}],detectPopup:[{visible:"#qc-cmp2-ui"}],optOut:[{waitFor:'.qc-cmp2-summary-buttons > button[mode="secondary"]',timeout:2e3},{if:{exists:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(2)'},then:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(2)'}],else:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(1)'},{waitFor:"#qc-cmp2-ui"},{click:'.qc-cmp2-toggle-switch > button[aria-checked="true"]',all:!0,optional:!0},{click:'.qc-cmp2-main button[aria-label="REJECT ALL"]',optional:!0},{waitForThenClick:'.qc-cmp2-main button[aria-label="SAVE & EXIT"],.qc-cmp2-buttons-desktop > button[mode="primary"]',timeout:5e3}]}],optIn:[{click:'.qc-cmp2-summary-buttons > button[mode="primary"]'}]},{name:"reddit.com",runContext:{urlPattern:"^https://www\\.reddit\\.com/"},prehideSelectors:["[bundlename=reddit_cookie_banner]"],detectCmp:[{exists:"reddit-cookie-banner"}],detectPopup:[{visible:"reddit-cookie-banner"}],optIn:[{waitForThenClick:["reddit-cookie-banner","#accept-all-cookies-button > button"]}],optOut:[{waitForThenClick:["reddit-cookie-banner","#reject-nonessential-cookies-button > button"]}],test:[{eval:"EVAL_REDDIT_0"}]},{name:"roblox",vendorUrl:"https://roblox.com",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?roblox\\.com/"},prehideSelectors:[],detectCmp:[{exists:".cookie-banner-wrapper"}],detectPopup:[{visible:".cookie-banner-wrapper .cookie-banner"}],optIn:[{waitForThenClick:".cookie-banner-wrapper button.btn-cta-lg"}],optOut:[{waitForThenClick:".cookie-banner-wrapper button.btn-secondary-lg"}],test:[{eval:"EVAL_ROBLOX_TEST"}]},{name:"rog-forum.asus.com",runContext:{urlPattern:"^https://rog-forum\\.asus\\.com/"},prehideSelectors:["#cookie-policy-info"],detectCmp:[{exists:"#cookie-policy-info"}],detectPopup:[{visible:"#cookie-policy-info"}],optIn:[{click:'div.cookie-btn-box > div[aria-label="Accept"]'}],optOut:[{click:'div.cookie-btn-box > div[aria-label="Reject"]'},{waitForThenClick:'.cookie-policy-lightbox-bottom > div[aria-label="Save Settings"]'}]},{name:"roofingmegastore.co.uk",runContext:{urlPattern:"^https://(www\\.)?roofingmegastore\\.co\\.uk"},prehideSelectors:["#m-cookienotice"],detectCmp:[{exists:"#m-cookienotice"}],detectPopup:[{visible:"#m-cookienotice"}],optIn:[{click:"#accept-cookies"}],optOut:[{click:"#manage-cookies"},{waitForThenClick:"#accept-selected"}]},{name:"samsung.com",runContext:{urlPattern:"^https://www\\.samsung\\.com/"},cosmetic:!0,prehideSelectors:["div.cookie-bar"],detectCmp:[{exists:"div.cookie-bar"}],detectPopup:[{visible:"div.cookie-bar"}],optIn:[{click:"div.cookie-bar__manage > a"}],optOut:[{hide:"div.cookie-bar"}]},{name:"setapp.com",vendorUrl:"https://setapp.com/",cosmetic:!0,runContext:{urlPattern:"^https://setapp\\.com/"},prehideSelectors:[],detectCmp:[{exists:".cookie-banner.js-cookie-banner"}],detectPopup:[{visible:".cookie-banner.js-cookie-banner"}],optIn:[{waitForThenClick:".cookie-banner.js-cookie-banner button"}],optOut:[{hide:".cookie-banner.js-cookie-banner"}]},{name:"sibbo",prehideSelectors:["sibbo-cmp-layout"],detectCmp:[{exists:"sibbo-cmp-layout"}],detectPopup:[{visible:"#rejectAllMain"}],optIn:[{click:"#acceptAllMain"}],optOut:[{click:"#rejectAllMain"}]},{name:"similarweb.com",cosmetic:!0,prehideSelectors:[".app-cookies-notification"],detectCmp:[{exists:".app-cookies-notification"}],detectPopup:[{exists:".app-layout .app-cookies-notification"}],optIn:[{click:"button.app-cookies-notification__dismiss"}],optOut:[{hide:".app-layout .app-cookies-notification"}]},{name:"Sirdata",cosmetic:!1,prehideSelectors:["#sd-cmp"],detectCmp:[{exists:"#sd-cmp"}],detectPopup:[{visible:"#sd-cmp"}],optIn:[{waitForThenClick:"#sd-cmp .sd-cmp-3cRQ2"}],optOut:[{waitForThenClick:["#sd-cmp","xpath///span[contains(., 'Do not accept') or contains(., 'Acceptera inte') or contains(., 'No aceptar') or contains(., 'Ikke acceptere') or contains(., 'Nicht akzeptieren') or contains(., 'Не приемам') or contains(., 'Να μην γίνει αποδοχή') or contains(., 'Niet accepteren') or contains(., 'Nepřijímat') or contains(., 'Nie akceptuj') or contains(., 'Nu acceptați') or contains(., 'Não aceitar') or contains(., 'Continuer sans accepter') or contains(., 'Non accettare') or contains(., 'Nem fogad el')]"]}]},{name:"snigel",detectCmp:[{exists:".snigel-cmp-framework"}],detectPopup:[{visible:".snigel-cmp-framework"}],optOut:[{click:"#sn-b-custom"},{click:"#sn-b-save"}],test:[{eval:"EVAL_SNIGEL_0"}],optIn:[{click:".snigel-cmp-framework #accept-choices"}]},{name:"steampowered.com",detectCmp:[{exists:".cookiepreferences_popup"},{visible:".cookiepreferences_popup"}],detectPopup:[{visible:".cookiepreferences_popup"}],optOut:[{click:"#rejectAllButton"}],optIn:[{click:"#acceptAllButton"}],test:[{wait:1e3},{eval:"EVAL_STEAMPOWERED_0"}]},{name:"strato.de",prehideSelectors:[".consent__wrapper"],runContext:{urlPattern:"^https://www\\.strato\\.de/"},detectCmp:[{exists:".consent"}],detectPopup:[{visible:".consent"}],optIn:[{click:"button.consentAgree"}],optOut:[{click:"button.consentSettings"},{waitForThenClick:"button#consentSubmit"}]},{name:"svt.se",vendorUrl:"https://www.svt.se/",runContext:{urlPattern:"^https://www\\.svt\\.se/"},prehideSelectors:["[class*=CookieConsent__root___]"],detectCmp:[{exists:"[class*=CookieConsent__root___]"}],detectPopup:[{visible:"[class*=CookieConsent__modal___]"}],optIn:[{waitForThenClick:"[class*=CookieConsent__modal___] > div > button[class*=primary]"}],optOut:[{waitForThenClick:"[class*=CookieConsent__modal___] > div > button[class*=secondary]:nth-child(2)"}],test:[{eval:"EVAL_SVT_TEST"}]},{name:"takealot.com",cosmetic:!0,prehideSelectors:['div[class^="cookies-banner-module_"]'],detectCmp:[{exists:'div[class^="cookies-banner-module_cookie-banner_"]'}],detectPopup:[{exists:'div[class^="cookies-banner-module_cookie-banner_"]'}],optIn:[{click:'button[class*="cookies-banner-module_dismiss-button_"]'}],optOut:[{hide:'div[class^="cookies-banner-module_"]'},{if:{exists:'div[class^="cookies-banner-module_small-cookie-banner_"]'},then:[{eval:"EVAL_TAKEALOT_0"}],else:[]}]},{name:"tarteaucitron.js",prehideSelectors:["#tarteaucitronRoot"],detectCmp:[{exists:"#tarteaucitronRoot"}],detectPopup:[{visible:"#tarteaucitronRoot #tarteaucitronAlertBig",check:"any"}],optIn:[{eval:"EVAL_TARTEAUCITRON_1"}],optOut:[{eval:"EVAL_TARTEAUCITRON_0"}],test:[{eval:"EVAL_TARTEAUCITRON_2",comment:"sometimes there are required categories, so we check that at least something is false"}]},{name:"taunton",vendorUrl:"https://www.taunton.com/",prehideSelectors:["#taunton-user-consent__overlay"],detectCmp:[{exists:"#taunton-user-consent__overlay"}],detectPopup:[{exists:"#taunton-user-consent__overlay:not([aria-hidden=true])"}],optIn:[{click:"#taunton-user-consent__toolbar input[type=checkbox]:not(:checked)"},{click:"#taunton-user-consent__toolbar button[type=submit]"}],optOut:[{click:"#taunton-user-consent__toolbar input[type=checkbox]:checked",optional:!0,all:!0},{click:"#taunton-user-consent__toolbar button[type=submit]"}],test:[{eval:"EVAL_TAUNTON_TEST"}]},{name:"Tealium",prehideSelectors:["#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs,#__tealiumImplicitmodal,#consent-layer"],detectCmp:[{exists:"#__tealiumGDPRecModal *,#__tealiumGDPRcpPrefs *,#__tealiumImplicitmodal *"},{eval:"EVAL_TEALIUM_0"}],detectPopup:[{visible:"#__tealiumGDPRecModal *,#__tealiumGDPRcpPrefs *,#__tealiumImplicitmodal *",check:"any"}],optOut:[{eval:"EVAL_TEALIUM_1"},{eval:"EVAL_TEALIUM_DONOTSELL"},{hide:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs,#__tealiumImplicitmodal"},{waitForThenClick:"#cm-acceptNone,.js-accept-essential-cookies",timeout:1e3,optional:!0}],optIn:[{hide:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs"},{eval:"EVAL_TEALIUM_2"}],test:[{eval:"EVAL_TEALIUM_3"},{eval:"EVAL_TEALIUM_DONOTSELL_CHECK"},{visible:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs",check:"none"}]},{name:"temu",vendorUrl:"https://temu.com",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?temu\\.com/"},prehideSelectors:[],detectCmp:[{exists:'div > div > div > div > span[href*="/cookie-and-similar-technologies-policy.html"]'}],detectPopup:[{visible:'div > div > div > div > span[href*="/cookie-and-similar-technologies-policy.html"]'}],optIn:[{waitForThenClick:'div > div > div:has(> div > span[href*="/cookie-and-similar-technologies-policy.html"]) > [role=button]:nth-child(3)'}],optOut:[{if:{exists:"xpath///span[contains(., 'Alle afwijzen') or contains(., 'Reject all') or contains(., 'Tümünü reddet') or contains(., 'Odrzuć wszystko')]"},then:[{waitForThenClick:"xpath///span[contains(., 'Alle afwijzen') or contains(., 'Reject all') or contains(., 'Tümünü reddet') or contains(., 'Odrzuć wszystko')]"}],else:[{waitForThenClick:'div > div > div:has(> div > span[href*="/cookie-and-similar-technologies-policy.html"]) > [role=button]:nth-child(2)'}]}]},{name:"Termly",prehideSelectors:["#termly-code-snippet-support"],detectCmp:[{exists:"#termly-code-snippet-support"}],detectPopup:[{visible:"#termly-code-snippet-support div"}],optIn:[{waitForThenClick:'[data-tid="banner-accept"]'}],optOut:[{if:{exists:'[data-tid="banner-decline"]'},then:[{click:'[data-tid="banner-decline"]'}],else:[{click:".t-preference-button"},{wait:500},{if:{exists:".t-declineAllButton"},then:[{click:".t-declineAllButton"}],else:[{waitForThenClick:".t-preference-modal input[type=checkbox][checked]:not([disabled])",all:!0},{waitForThenClick:".t-saveButton"}]}]}]},{name:"termsfeed",vendorUrl:"https://termsfeed.com",comment:"v4.x.x",prehideSelectors:[".termsfeed-com---nb"],detectCmp:[{exists:".termsfeed-com---nb"}],detectPopup:[{visible:".termsfeed-com---nb"}],optIn:[{waitForThenClick:".cc-nb-okagree"}],optOut:[{waitForThenClick:".cc-nb-reject"}]},{name:"termsfeed3",vendorUrl:"https://termsfeed.com",comment:"v3.x.x",prehideSelectors:[".cc_dialog.cc_css_reboot,.cc_overlay_lock"],detectCmp:[{exists:".cc_dialog.cc_css_reboot"}],detectPopup:[{visible:".cc_dialog.cc_css_reboot"}],optIn:[{waitForThenClick:".cc_dialog.cc_css_reboot .cc_b_ok"}],optOut:[{if:{exists:".cc_dialog.cc_css_reboot .cc_b_cp"},then:[{click:".cc_dialog.cc_css_reboot .cc_b_cp"},{waitForVisible:".cookie-consent-preferences-dialog .cc_cp_f_save button"},{waitForThenClick:".cookie-consent-preferences-dialog .cc_cp_f_save button"}],else:[{hide:".cc_dialog.cc_css_reboot,.cc_overlay_lock"}]}]},{name:"tesla",vendorUrl:"https://tesla.com/",runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?tesla\\.com/"},prehideSelectors:[],detectCmp:[{exists:"#cookie_banner"}],detectPopup:[{visible:"#cookie_banner"}],optIn:[{waitForThenClick:"#tsla-accept-cookie"}],optOut:[{waitForThenClick:"#tsla-reject-cookie"}],test:[{eval:"EVAL_TESLA_TEST"}]},{name:"Test page cosmetic CMP",cosmetic:!0,prehideSelectors:["#privacy-test-page-cmp-test-prehide"],detectCmp:[{exists:"#privacy-test-page-cmp-test-banner"}],detectPopup:[{visible:"#privacy-test-page-cmp-test-banner"}],optIn:[{waitFor:"#accept-all"},{click:"#accept-all"}],optOut:[{hide:"#privacy-test-page-cmp-test-banner"}],test:[{wait:500},{eval:"EVAL_TESTCMP_COSMETIC_0"}]},{name:"Test page CMP",prehideSelectors:["#reject-all"],detectCmp:[{exists:"#privacy-test-page-cmp-test"}],detectPopup:[{visible:"#privacy-test-page-cmp-test"}],optIn:[{waitFor:"#accept-all"},{click:"#accept-all"}],optOut:[{waitFor:"#reject-all"},{click:"#reject-all"}],test:[{eval:"EVAL_TESTCMP_0"}]},{name:"thalia.de",prehideSelectors:[".consent-banner-box"],detectCmp:[{exists:"consent-banner[component=consent-banner]"}],detectPopup:[{visible:".consent-banner-box"}],optIn:[{click:".button-zustimmen"}],optOut:[{click:"button[data-consent=disagree]"}]},{name:"thefreedictionary.com",prehideSelectors:["#cmpBanner"],detectCmp:[{exists:"#cmpBanner"}],detectPopup:[{visible:"#cmpBanner"}],optIn:[{eval:"EVAL_THEFREEDICTIONARY_1"}],optOut:[{eval:"EVAL_THEFREEDICTIONARY_0"}]},{name:"theverge",runContext:{frame:!1,main:!0,urlPattern:"^https://(www)?\\.theverge\\.com"},intermediate:!1,prehideSelectors:[".duet--cta--cookie-banner"],detectCmp:[{exists:".duet--cta--cookie-banner"}],detectPopup:[{visible:".duet--cta--cookie-banner"}],optIn:[{click:".duet--cta--cookie-banner button.tracking-12",all:!1}],optOut:[{click:".duet--cta--cookie-banner button.tracking-12 > span"}],test:[{eval:"EVAL_THEVERGE_0"}]},{name:"tidbits-com",cosmetic:!0,prehideSelectors:["#eu_cookie_law_widget-2"],detectCmp:[{exists:"#eu_cookie_law_widget-2"}],detectPopup:[{visible:"#eu_cookie_law_widget-2"}],optIn:[{click:"#eu-cookie-law form > input.accept"}],optOut:[{hide:"#eu_cookie_law_widget-2"}]},{name:"tractor-supply",runContext:{urlPattern:"^https://www\\.tractorsupply\\.com/"},cosmetic:!0,prehideSelectors:[".tsc-cookie-banner"],detectCmp:[{exists:".tsc-cookie-banner"}],detectPopup:[{visible:".tsc-cookie-banner"}],optIn:[{click:"#cookie-banner-cancel"}],optOut:[{hide:".tsc-cookie-banner"}]},{name:"trader-joes-com",cosmetic:!0,prehideSelectors:['div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'],detectCmp:[{exists:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}],detectPopup:[{visible:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}],optIn:[{click:'div[class^="CookiesAlert_cookiesAlert__container__"] button'}],optOut:[{hide:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}]},{name:"transcend",vendorUrl:"https://unknown",cosmetic:!0,prehideSelectors:["#transcend-consent-manager"],detectCmp:[{exists:"#transcend-consent-manager"}],detectPopup:[{visible:"#transcend-consent-manager"}],optIn:[{waitForThenClick:["#transcend-consent-manager","#consentManagerMainDialog .inner-container button"]}],optOut:[{hide:"#transcend-consent-manager"}]},{name:"transip-nl",runContext:{urlPattern:"^https://www\\.transip\\.nl/"},prehideSelectors:["#consent-modal"],detectCmp:[{any:[{exists:"#consent-modal"},{exists:"#privacy-settings-content"}]}],detectPopup:[{any:[{visible:"#consent-modal"},{visible:"#privacy-settings-content"}]}],optIn:[{click:'button[type="submit"]'}],optOut:[{if:{exists:"#privacy-settings-content"},then:[{click:'button[type="submit"]'}],else:[{click:"div.one-modal__action-footer-column--secondary > a"}]}]},{name:"tropicfeel-com",prehideSelectors:["#shopify-section-cookies-controller"],detectCmp:[{exists:"#shopify-section-cookies-controller"}],detectPopup:[{visible:"#shopify-section-cookies-controller #cookies-controller-main-pane",check:"any"}],optIn:[{waitForThenClick:"#cookies-controller-main-pane form[data-form-allow-all] button"}],optOut:[{click:"#cookies-controller-main-pane a[data-tab-target=manage-cookies]"},{waitFor:"#manage-cookies-pane.active"},{click:"#manage-cookies-pane.active input[type=checkbox][checked]:not([disabled])",all:!0},{click:"#manage-cookies-pane.active button[type=submit]"}],test:[]},{name:"true-car",runContext:{urlPattern:"^https://www\\.truecar\\.com/"},cosmetic:!0,prehideSelectors:[['div[aria-labelledby="cookie-banner-heading"]']],detectCmp:[{exists:'div[aria-labelledby="cookie-banner-heading"]'}],detectPopup:[{visible:'div[aria-labelledby="cookie-banner-heading"]'}],optIn:[{click:'div[aria-labelledby="cookie-banner-heading"] > button[aria-label="Close"]'}],optOut:[{hide:'div[aria-labelledby="cookie-banner-heading"]'}]},{name:"truyo",prehideSelectors:["#truyo-consent-module"],detectCmp:[{exists:"#truyo-cookieBarContent"}],detectPopup:[{visible:"#truyo-consent-module"}],optIn:[{click:"button#acceptAllCookieButton"}],optOut:[{click:"button#declineAllCookieButton"}]},{name:"twcc",vendorUrl:"https://unknown",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:""},prehideSelectors:["#twcc__mechanism"],detectCmp:[{exists:"#twcc__mechanism .twcc__notice"}],detectPopup:[{visible:"#twcc__mechanism .twcc__notice"}],optIn:[{waitForThenClick:"#twcc__accept-button"}],optOut:[{waitForThenClick:"#twcc__decline-button"}],test:[{eval:"EVAL_TWCC_TEST"}]},{name:"twitch-mobile",vendorUrl:"https://m.twitch.tv/",cosmetic:!0,runContext:{urlPattern:"^https?://m\\.twitch\\.tv"},prehideSelectors:[],detectCmp:[{exists:'.ReactModal__Overlay [href="https://www.twitch.tv/p/cookie-policy"]'}],detectPopup:[{visible:'.ReactModal__Overlay [href="https://www.twitch.tv/p/cookie-policy"]'}],optIn:[{waitForThenClick:'.ReactModal__Overlay:has([href="https://www.twitch.tv/p/cookie-policy"]) button'}],optOut:[{hide:'.ReactModal__Overlay:has([href="https://www.twitch.tv/p/cookie-policy"])'}]},{name:"twitch.tv",runContext:{urlPattern:"^https?://(www\\.)?twitch\\.tv"},prehideSelectors:["div:has(> .consent-banner .consent-banner__content--gdpr-v2),.ReactModalPortal:has([data-a-target=consent-modal-save])"],detectCmp:[{exists:".consent-banner .consent-banner__content--gdpr-v2"}],detectPopup:[{visible:".consent-banner .consent-banner__content--gdpr-v2"}],optIn:[{click:'button[data-a-target="consent-banner-accept"]'}],optOut:[{hide:"div:has(> .consent-banner .consent-banner__content--gdpr-v2)"},{click:'button[data-a-target="consent-banner-manage-preferences"]'},{waitFor:"input[type=checkbox][data-a-target=tw-checkbox]"},{click:"input[type=checkbox][data-a-target=tw-checkbox][checked]:not([disabled])",all:!0,optional:!0},{waitForThenClick:"[data-a-target=consent-modal-save]"},{waitForVisible:".ReactModalPortal:has([data-a-target=consent-modal-save])",check:"none"}]},{name:"twitter",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?(twitter|x)\\.com/"},prehideSelectors:['[data-testid="BottomBar"]'],detectCmp:[{exists:'[data-testid="BottomBar"] div'}],detectPopup:[{visible:'[data-testid="BottomBar"] div'}],optIn:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>button[role=button]>span) > div:last-child > button[role=button]:first-child'}],optOut:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>button[role=button]>span) > div:last-child > button[role=button]:last-child'}],TODOtest:[{eval:"EVAL_document.cookie.includes('d_prefs=MjoxLGNvbnNlbnRfdmVyc2lvbjoy')"}]},{name:"ubuntu.com",prehideSelectors:["dialog.cookie-policy"],detectCmp:[{any:[{exists:"dialog.cookie-policy header"},{exists:'xpath///*[@id="modal"]/div/header'}]}],detectPopup:[{any:[{visible:"dialog header"},{visible:'xpath///*[@id="modal"]/div/header'}]}],optIn:[{any:[{waitForThenClick:"#cookie-policy-button-accept"},{waitForThenClick:'xpath///*[@id="cookie-policy-button-accept"]'}]}],optOut:[{any:[{waitForThenClick:"button.js-manage"},{waitForThenClick:'xpath///*[@id="cookie-policy-content"]/p[4]/button[2]'}]},{waitForThenClick:"dialog.cookie-policy .p-switch__input:checked",optional:!0,all:!0,timeout:500},{any:[{waitForThenClick:"dialog.cookie-policy .js-save-preferences"},{waitForThenClick:'xpath///*[@id="modal"]/div/button'}]}],test:[{eval:"EVAL_UBUNTU_COM_0"}]},{name:"UK Cookie Consent",prehideSelectors:["#catapult-cookie-bar"],cosmetic:!0,detectCmp:[{exists:"#catapult-cookie-bar"}],detectPopup:[{exists:".has-cookie-bar #catapult-cookie-bar"}],optIn:[{click:"#catapultCookie"}],optOut:[{hide:"#catapult-cookie-bar"}],test:[{eval:"EVAL_UK_COOKIE_CONSENT_0"}]},{name:"urbanarmorgear-com",cosmetic:!0,prehideSelectors:['div[class^="Layout__CookieBannerContainer-"]'],detectCmp:[{exists:'div[class^="Layout__CookieBannerContainer-"]'}],detectPopup:[{visible:'div[class^="Layout__CookieBannerContainer-"]'}],optIn:[{click:'button[class^="CookieBanner__AcceptButton"]'}],optOut:[{hide:'div[class^="Layout__CookieBannerContainer-"]'}]},{name:"usercentrics-api",detectCmp:[{exists:"#usercentrics-root,#usercentrics-cmp-ui"}],detectPopup:[{eval:"EVAL_USERCENTRICS_API_0"},{if:{exists:"#usercentrics-cmp-ui"},then:[{waitForVisible:"#usercentrics-cmp-ui",timeout:2e3}],else:[{exists:["#usercentrics-root","[data-testid=uc-container]"]},{waitForVisible:"#usercentrics-root",timeout:2e3}]}],optIn:[{eval:"EVAL_USERCENTRICS_API_3"},{eval:"EVAL_USERCENTRICS_API_1"},{eval:"EVAL_USERCENTRICS_API_5"}],optOut:[{eval:"EVAL_USERCENTRICS_API_1"},{eval:"EVAL_USERCENTRICS_API_2"}],test:[{eval:"EVAL_USERCENTRICS_API_6"}]},{name:"usercentrics-button",detectCmp:[{exists:"#usercentrics-button"}],detectPopup:[{visible:"#usercentrics-button #uc-btn-accept-banner"}],optIn:[{click:"#usercentrics-button #uc-btn-accept-banner"}],optOut:[{click:"#usercentrics-button #uc-btn-deny-banner"}],test:[{eval:"EVAL_USERCENTRICS_BUTTON_0"}]},{name:"uswitch.com",runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?uswitch\\.com/"},prehideSelectors:[".ucb"],detectCmp:[{exists:".ucb-banner"}],detectPopup:[{visible:".ucb-banner"}],optIn:[{waitForThenClick:".ucb-banner .ucb-btn-accept"}],optOut:[{waitForThenClick:".ucb-banner .ucb-btn-save"}]},{name:"vodafone.de",runContext:{urlPattern:"^https://www\\.vodafone\\.de/"},prehideSelectors:[".dip-consent,.dip-consent-container"],detectCmp:[{exists:".dip-consent-container"}],detectPopup:[{visible:".dip-consent-content"}],optOut:[{click:'.dip-consent-btn[tabindex="2"]'}],optIn:[{click:'.dip-consent-btn[tabindex="1"]'}]},{name:"waitrose.com",prehideSelectors:["div[aria-labelledby=CookieAlertModalHeading]","section[data-test=initial-waitrose-cookie-consent-banner]","section[data-test=cookie-consent-modal]"],detectCmp:[{exists:"section[data-test=initial-waitrose-cookie-consent-banner]"}],detectPopup:[{visible:"section[data-test=initial-waitrose-cookie-consent-banner]"}],optIn:[{click:"button[data-test=accept-all]"}],optOut:[{click:"button[data-test=manage-cookies]"},{wait:200},{eval:"EVAL_WAITROSE_0"},{click:"button[data-test=submit]"}],test:[{eval:"EVAL_WAITROSE_1"}]},{name:"webflow",vendorUrl:"https://webflow.com/",prehideSelectors:[".fs-cc-components"],detectCmp:[{exists:".fs-cc-components"}],detectPopup:[{visible:".fs-cc-components"},{visible:"[fs-cc=banner]"}],optIn:[{wait:500},{waitForThenClick:"[fs-cc=banner] [fs-cc=allow]"}],optOut:[{wait:500},{waitForThenClick:"[fs-cc=banner] [fs-cc=deny]"}]},{name:"wetransfer.com",detectCmp:[{exists:".welcome__cookie-notice"}],detectPopup:[{visible:".welcome__cookie-notice"}],optIn:[{click:".welcome__button--accept"}],optOut:[{click:".welcome__button--decline"}]},{name:"whitepages.com",runContext:{urlPattern:"^https://www\\.whitepages\\.com/"},cosmetic:!0,prehideSelectors:[".cookie-wrapper, .cookie-overlay"],detectCmp:[{exists:".cookie-wrapper"}],detectPopup:[{visible:".cookie-overlay"}],optIn:[{click:'button[aria-label="Got it"]'}],optOut:[{hide:".cookie-wrapper"}]},{name:"wolframalpha",vendorUrl:"https://www.wolframalpha.com",prehideSelectors:[],cosmetic:!0,runContext:{urlPattern:"^https://www\\.wolframalpha\\.com/"},detectCmp:[{exists:"section._a_yb"}],detectPopup:[{visible:"section._a_yb"}],optIn:[{waitForThenClick:"section._a_yb button"}],optOut:[{hide:"section._a_yb"}]},{name:"woo-commerce-com",prehideSelectors:[".wccom-comp-privacy-banner .wccom-privacy-banner"],detectCmp:[{exists:".wccom-comp-privacy-banner .wccom-privacy-banner"}],detectPopup:[{exists:".wccom-comp-privacy-banner .wccom-privacy-banner"}],optIn:[{click:".wccom-privacy-banner__content-buttons button.is-primary"}],optOut:[{click:".wccom-privacy-banner__content-buttons button.is-secondary"},{waitForThenClick:"input[type=checkbox][checked]:not([disabled])",all:!0},{click:"div.wccom-modal__footer > button"}]},{name:"WP Cookie Notice for GDPR",vendorUrl:"https://wordpress.org/plugins/gdpr-cookie-consent/",prehideSelectors:["#gdpr-cookie-consent-bar"],detectCmp:[{exists:"#gdpr-cookie-consent-bar"}],detectPopup:[{visible:"#gdpr-cookie-consent-bar"}],optIn:[{waitForThenClick:"#gdpr-cookie-consent-bar #cookie_action_accept"}],optOut:[{waitForThenClick:"#gdpr-cookie-consent-bar #cookie_action_reject"}],test:[{eval:"EVAL_WP_COOKIE_NOTICE_0"}]},{name:"wpcc",cosmetic:!0,prehideSelectors:[".wpcc-container"],detectCmp:[{exists:".wpcc-container"}],detectPopup:[{exists:".wpcc-container .wpcc-message"}],optIn:[{click:".wpcc-compliance .wpcc-btn"}],optOut:[{hide:".wpcc-container"}]},{name:"xe.com",vendorUrl:"https://www.xe.com/",runContext:{urlPattern:"^https://www\\.xe\\.com/"},prehideSelectors:["[class*=ConsentBanner]"],detectCmp:[{exists:"[class*=ConsentBanner]"}],detectPopup:[{visible:"[class*=ConsentBanner]"}],optIn:[{waitForThenClick:"[class*=ConsentBanner] .egnScw"}],optOut:[{wait:1e3},{waitForThenClick:"[class*=ConsentBanner] .frDWEu"},{waitForThenClick:"[class*=ConsentBanner] .hXIpFU"}],test:[{eval:"EVAL_XE_TEST"}]},{name:"xhamster-eu",prehideSelectors:[".cookies-modal"],detectCmp:[{exists:".cookies-modal"}],detectPopup:[{exists:".cookies-modal"}],optIn:[{click:"button.cmd-button-accept-all"}],optOut:[{click:"button.cmd-button-reject-all"}]},{name:"xhamster-us",runContext:{urlPattern:"^https://(www\\.)?xhamster\\d?\\.com"},cosmetic:!0,prehideSelectors:[".cookie-announce"],detectCmp:[{exists:".cookie-announce"}],detectPopup:[{visible:".cookie-announce .announce-text"}],optIn:[{click:".cookie-announce button.xh-button"}],optOut:[{hide:".cookie-announce"}]},{name:"xing.com",detectCmp:[{exists:"div[class^=cookie-consent-CookieConsent]"}],detectPopup:[{exists:"div[class^=cookie-consent-CookieConsent]"}],optIn:[{click:"#consent-accept-button"}],optOut:[{click:"#consent-settings-button"},{click:".consent-banner-button-accept-overlay"}],test:[{eval:"EVAL_XING_0"}]},{name:"xnxx-com",cosmetic:!0,prehideSelectors:["#cookies-use-alert"],detectCmp:[{exists:"#cookies-use-alert"}],detectPopup:[{visible:"#cookies-use-alert"}],optIn:[{click:"#cookies-use-alert .close"}],optOut:[{hide:"#cookies-use-alert"}]},{name:"xvideos",vendorUrl:"https://xvideos.com",runContext:{urlPattern:"^https://[^/]*xvideos\\.com/"},prehideSelectors:[],detectCmp:[{exists:".disclaimer-opened #disclaimer-cookies"}],detectPopup:[{visible:".disclaimer-opened #disclaimer-cookies"}],optIn:[{waitForThenClick:"#disclaimer-accept_cookies"}],optOut:[{waitForThenClick:"#disclaimer-reject_cookies"}]},{name:"Yahoo",runContext:{urlPattern:"^https://consent\\.yahoo\\.com/v2/"},prehideSelectors:["#reject-all"],detectCmp:[{exists:"#consent-page"}],detectPopup:[{visible:"#consent-page"}],optIn:[{waitForThenClick:"#consent-page button[value=agree]"}],optOut:[{waitForThenClick:"#consent-page button[value=reject]"}]},{name:"youporn.com",cosmetic:!0,prehideSelectors:[".euCookieModal, #js_euCookieModal"],detectCmp:[{exists:".euCookieModal"}],detectPopup:[{exists:".euCookieModal, #js_euCookieModal"}],optIn:[{click:'button[name="user_acceptCookie"]'}],optOut:[{hide:".euCookieModal"}]},{name:"youtube-desktop",prehideSelectors:["tp-yt-iron-overlay-backdrop.opened","ytd-consent-bump-v2-lightbox"],detectCmp:[{exists:"ytd-consent-bump-v2-lightbox tp-yt-paper-dialog"},{exists:'ytd-consent-bump-v2-lightbox tp-yt-paper-dialog a[href^="https://consent.youtube.com/"]'}],detectPopup:[{visible:"ytd-consent-bump-v2-lightbox tp-yt-paper-dialog"}],optIn:[{waitForThenClick:"ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:last-child #button,ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:last-child button"},{wait:500}],optOut:[{waitForThenClick:"ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:first-child #button,ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:first-child button"},{wait:500}],test:[{wait:500},{eval:"EVAL_YOUTUBE_DESKTOP_0"}]},{name:"youtube-mobile",prehideSelectors:[".consent-bump-v2-lightbox"],detectCmp:[{exists:"ytm-consent-bump-v2-renderer"}],detectPopup:[{visible:"ytm-consent-bump-v2-renderer"}],optIn:[{waitForThenClick:"ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons c3-material-button:first-child button, ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons ytm-button-renderer:first-child button"},{wait:500}],optOut:[{waitForThenClick:"ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons c3-material-button:nth-child(2) button, ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons ytm-button-renderer:nth-child(2) button"},{wait:500}],test:[{wait:500},{eval:"EVAL_YOUTUBE_MOBILE_0"}]},{name:"zdf",prehideSelectors:["#zdf-cmp-banner-sdk"],detectCmp:[{exists:"#zdf-cmp-banner-sdk"}],detectPopup:[{visible:"#zdf-cmp-main.zdf-cmp-show"}],optIn:[{waitForThenClick:"#zdf-cmp-main #zdf-cmp-accept-btn"}],optOut:[{waitForThenClick:"#zdf-cmp-main #zdf-cmp-deny-btn"}],test:[]},{name:"zentralruf-de",runContext:{urlPattern:"^https://(www\\.)?zentralruf\\.de"},prehideSelectors:["#cookie_modal_wrapper"],detectCmp:[{exists:"#cookie_modal_wrapper"}],detectPopup:[{visible:"#cookie_modal_wrapper"}],optIn:[{waitForThenClick:"#cookie_modal_wrapper #cookie_modal_button_consent_all"}],optOut:[{waitForThenClick:"#cookie_modal_wrapper #cookie_modal_button_choose"}]}],A={"didomi.io":{detectors:[{presentMatcher:{target:{selector:"#didomi-host, #didomi-notice"},type:"css"},showingMatcher:{target:{selector:"body.didomi-popup-open, .didomi-notice-banner"},type:"css"}}],methods:[{action:{target:{selector:".didomi-popup-notice-buttons .didomi-button:not(.didomi-button-highlight), .didomi-notice-banner .didomi-learn-more-button"},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{retries:50,target:{selector:"#didomi-purpose-cookies"},type:"waitcss",waitTime:50},{consents:[{description:"Share (everything) with others",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-share_whith_others]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-share_whith_others]:last-child"},type:"click"},type:"X"},{description:"Information storage and access",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-cookies]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-cookies]:last-child"},type:"click"},type:"D"},{description:"Content selection, offers and marketing",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-CL-T1Rgm7]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-CL-T1Rgm7]:last-child"},type:"click"},type:"E"},{description:"Analytics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-analytics]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-analytics]:last-child"},type:"click"},type:"B"},{description:"Analytics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-M9NRHJe3G]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-M9NRHJe3G]:last-child"},type:"click"},type:"B"},{description:"Ad and content selection",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-advertising_personalization]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-advertising_personalization]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection",falseAction:{parent:{childFilter:{target:{selector:"#didomi-purpose-pub-ciblee"}},selector:".didomi-consent-popup-data-processing, .didomi-components-accordion-label-container"},target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-pub-ciblee]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-pub-ciblee]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - basics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-q4zlJqdcD]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-q4zlJqdcD]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - partners and subsidiaries",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-partenaire-cAsDe8jC]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-partenaire-cAsDe8jC]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-p4em9a8m]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-p4em9a8m]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - others",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-autres-pub]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-autres-pub]:last-child"},type:"click"},type:"F"},{description:"Social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-reseauxsociaux]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-reseauxsociaux]:last-child"},type:"click"},type:"A"},{description:"Social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-social_media]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-social_media]:last-child"},type:"click"},type:"A"},{description:"Content selection",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-content_personalization]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-content_personalization]:last-child"},type:"click"},type:"E"},{description:"Ad delivery",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-ad_delivery]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-ad_delivery]:last-child"},type:"click"},type:"F"}],type:"consent"},{action:{consents:[{matcher:{childFilter:{target:{selector:":not(.didomi-components-radio__option--selected)"}},type:"css"},trueAction:{target:{selector:":nth-child(2)"},type:"click"},falseAction:{target:{selector:":first-child"},type:"click"},type:"X"}],type:"consent"},target:{selector:".didomi-components-radio"},type:"foreach"}],type:"list"},name:"DO_CONSENT"},{action:{parent:{selector:".didomi-consent-popup-footer .didomi-consent-popup-actions"},target:{selector:".didomi-components-button:first-child"},type:"click"},name:"SAVE_CONSENT"}]},oil:{detectors:[{presentMatcher:{target:{selector:".as-oil-content-overlay"},type:"css"},showingMatcher:{target:{selector:".as-oil-content-overlay"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".as-js-advanced-settings"},type:"click"},{retries:"10",target:{selector:".as-oil-cpc__purpose-container"},type:"waitcss",waitTime:"250"}],type:"list"},name:"OPEN_OPTIONS"},{action:{actions:[{consents:[{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Information storage and access","Opbevaring af og adgang til oplysninger på din enhed"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Information storage and access","Opbevaring af og adgang til oplysninger på din enhed"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"D"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personlige annoncer","Personalisation"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personlige annoncer","Personalisation"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"E"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Annoncevalg, levering og rapportering","Ad selection, delivery, reporting"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Annoncevalg, levering og rapportering","Ad selection, delivery, reporting"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"F"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personalisering af indhold","Content selection, delivery, reporting"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personalisering af indhold","Content selection, delivery, reporting"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"E"},{matcher:{parent:{childFilter:{target:{selector:".as-oil-cpc__purpose-header",textFilter:["Måling","Measurement"]}},selector:".as-oil-cpc__purpose-container"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{childFilter:{target:{selector:".as-oil-cpc__purpose-header",textFilter:["Måling","Measurement"]}},selector:".as-oil-cpc__purpose-container"},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"B"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:"Google"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:"Google"},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"F"}],type:"consent"}],type:"list"},name:"DO_CONSENT"},{action:{target:{selector:".as-oil__btn-optin"},type:"click"},name:"SAVE_CONSENT"},{action:{target:{selector:"div.as-oil"},type:"hide"},name:"HIDE_CMP"}]},optanon:{detectors:[{presentMatcher:{target:{selector:"#optanon-menu, .optanon-alert-box-wrapper"},type:"css"},showingMatcher:{target:{displayFilter:!0,selector:".optanon-alert-box-wrapper"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".optanon-alert-box-wrapper .optanon-toggle-display, a[onclick*='OneTrust.ToggleInfoDisplay()'], a[onclick*='Optanon.ToggleInfoDisplay()']"},type:"click"}],type:"list"},name:"OPEN_OPTIONS"},{action:{actions:[{target:{selector:".preference-menu-item #Your-privacy"},type:"click"},{target:{selector:"#optanon-vendor-consent-text"},type:"click"},{action:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},target:{selector:"#optanon-vendor-consent-list .vendor-item"},type:"foreach"},{target:{selector:".vendor-consent-back-link"},type:"click"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-performance"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-performance"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-functional"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-functional"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-advertising"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-advertising"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-social"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-social"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Social Media Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Social Media Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalisation"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalisation"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Site monitoring cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Site monitoring cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Third party privacy-enhanced content"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Third party privacy-enhanced content"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Performance & Advertising Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Performance & Advertising Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Information storage and access"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Information storage and access"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"D"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad selection, delivery, reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad selection, delivery, reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content selection, delivery, reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content selection, delivery, reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Measurement"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Measurement"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Recommended Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Recommended Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Unclassified Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Unclassified Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Analytical Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Analytical Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Marketing Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Marketing Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalization"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalization"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad Selection, Delivery & Reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad Selection, Delivery & Reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content Selection, Delivery & Reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content Selection, Delivery & Reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"}],type:"list"},name:"DO_CONSENT"},{action:{parent:{selector:".optanon-save-settings-button"},target:{selector:".optanon-white-button-middle"},type:"click"},name:"SAVE_CONSENT"},{action:{actions:[{target:{selector:"#optanon-popup-wrapper"},type:"hide"},{target:{selector:"#optanon-popup-bg"},type:"hide"},{target:{selector:".optanon-alert-box-wrapper"},type:"hide"}],type:"list"},name:"HIDE_CMP"}]},quantcast2:{detectors:[{presentMatcher:{target:{selector:"[data-tracking-opt-in-overlay]"},type:"css"},showingMatcher:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-learn-more]"},type:"css"}}],methods:[{action:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-learn-more]"},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{type:"wait",waitTime:500},{action:{actions:[{target:{selector:"div",textFilter:["Information storage and access"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"D"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Personalization"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"F"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Ad selection, delivery, reporting"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"F"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Content selection, delivery, reporting"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"E"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Measurement"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"B"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Other Partners"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},type:"ifcss"}],type:"list"},parent:{childFilter:{target:{selector:"input"}},selector:"[data-tracking-opt-in-overlay] > div > div"},target:{childFilter:{target:{selector:"input"}},selector:":scope > div"},type:"foreach"}],type:"list"},name:"DO_CONSENT"},{action:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-save]"},type:"click"},name:"SAVE_CONSENT"}]},springer:{detectors:[{presentMatcher:{parent:null,target:{selector:".cmp-app_gdpr"},type:"css"},showingMatcher:{parent:null,target:{displayFilter:!0,selector:".cmp-popup_popup"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".cmp-intro_rejectAll"},type:"click"},{type:"wait",waitTime:250},{target:{selector:".cmp-purposes_purposeItem:not(.cmp-purposes_selectedPurpose)"},type:"click"}],type:"list"},name:"OPEN_OPTIONS"},{action:{consents:[{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Przechowywanie informacji na urządzeniu lub dostęp do nich",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Przechowywanie informacji na urządzeniu lub dostęp do nich",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"D"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór podstawowych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór podstawowych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"F"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"F"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"E"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"E"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Stosowanie badań rynkowych w celu generowania opinii odbiorców",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Stosowanie badań rynkowych w celu generowania opinii odbiorców",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"X"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Opracowywanie i ulepszanie produktów",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Opracowywanie i ulepszanie produktów",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"X"}],type:"consent"},name:"DO_CONSENT"},{action:{target:{selector:".cmp-details_save"},type:"click"},name:"SAVE_CONSENT"}]},wordpressgdpr:{detectors:[{presentMatcher:{parent:null,target:{selector:".wpgdprc-consent-bar"},type:"css"},showingMatcher:{parent:null,target:{displayFilter:!0,selector:".wpgdprc-consent-bar"},type:"css"}}],methods:[{action:{parent:null,target:{selector:".wpgdprc-consent-bar .wpgdprc-consent-bar__settings",textFilter:null},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{target:{selector:".wpgdprc-consent-modal .wpgdprc-button",textFilter:"Eyeota"},type:"click"},{consents:[{description:"Eyeota Cookies",matcher:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Eyeota"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Eyeota"},target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},{target:{selector:".wpgdprc-consent-modal .wpgdprc-button",textFilter:"Advertising"},type:"click"},{consents:[{description:"Advertising Cookies",matcher:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Advertising"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Advertising"},target:{selector:"label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},name:"DO_CONSENT"},{action:{parent:null,target:{selector:".wpgdprc-button",textFilter:"Save my settings"},type:"click"},name:"SAVE_CONSENT"}]}},E={autoconsent:f,consentomatic:A},x=Object.freeze({__proto__:null,autoconsent:f,consentomatic:A,default:E});const O=new class{constructor(e,t=null,o=null){if(this.id=a(),this.rules=[],this.foundCmp=null,this.state={lifecycle:"loading",prehideOn:!1,findCmpAttempts:0,detectedCmps:[],detectedPopups:[],selfTest:null},r.sendContentMessage=e,this.sendContentMessage=e,this.rules=[],this.updateState({lifecycle:"loading"}),this.addDynamicRules(),t)this.initialize(t,o);else{o&&this.parseDeclarativeRules(o);e({type:"init",url:window.location.href}),this.updateState({lifecycle:"waitingForInitResponse"})}this.domActions=new v(this)}initialize(e,t){const o=g(e);if(o.logs.lifecycle&&console.log("autoconsent init",window.location.href),this.config=o,o.enabled){if(t&&this.parseDeclarativeRules(t),this.rules=function(e,t){return e.filter((e=>(!t.disabledCmps||!t.disabledCmps.includes(e.name))&&(t.enableCosmeticRules||!e.isCosmetic)))}(this.rules,o),e.enablePrehide)if(document.documentElement)this.prehideElements();else{const e=()=>{window.removeEventListener("DOMContentLoaded",e),this.prehideElements()};window.addEventListener("DOMContentLoaded",e)}if("loading"===document.readyState){const e=()=>{window.removeEventListener("DOMContentLoaded",e),this.start()};window.addEventListener("DOMContentLoaded",e)}else this.start();this.updateState({lifecycle:"initialized"})}else o.logs.lifecycle&&console.log("autoconsent is disabled")}addDynamicRules(){C.forEach((e=>{this.rules.push(new e(this))}))}parseDeclarativeRules(e){Object.keys(e.consentomatic).forEach((t=>{this.addConsentomaticCMP(t,e.consentomatic[t])})),e.autoconsent.forEach((e=>{this.addDeclarativeCMP(e)}))}addDeclarativeCMP(e){this.rules.push(new u(e,this))}addConsentomaticCMP(e,t){this.rules.push(new m(`com_${e}`,t))}start(){window.requestIdleCallback?window.requestIdleCallback((()=>this._start()),{timeout:500}):this._start()}async _start(){const e=this.config.logs;e.lifecycle&&console.log(`Detecting CMPs on ${window.location.href}`),this.updateState({lifecycle:"started"});const t=await this.findCmp(this.config.detectRetries);if(this.updateState({detectedCmps:t.map((e=>e.name))}),0===t.length)return e.lifecycle&&console.log("no CMP found",location.href),this.config.enablePrehide&&this.undoPrehide(),this.updateState({lifecycle:"nothingDetected"}),!1;this.updateState({lifecycle:"cmpDetected"});const o=[],i=[];for(const e of t)e.isCosmetic?i.push(e):o.push(e);let c=!1,n=await this.detectPopups(o,(async e=>{c=await this.handlePopup(e)}));if(0===n.length&&(n=await this.detectPopups(i,(async e=>{c=await this.handlePopup(e)}))),0===n.length)return e.lifecycle&&console.log("no popup found"),this.config.enablePrehide&&this.undoPrehide(),!1;if(n.length>1){const t={msg:"Found multiple CMPs, check the detection rules.",cmps:n.map((e=>e.name))};e.errors&&console.warn(t.msg,t.cmps),this.sendContentMessage({type:"autoconsentError",details:t})}return c}async findCmp(e){const t=this.config.logs;this.updateState({findCmpAttempts:this.state.findCmpAttempts+1});const o=[];for(const e of this.rules)try{if(!e.checkRunContext())continue;await e.detectCmp()&&(t.lifecycle&&console.log(`Found CMP: ${e.name} ${window.location.href}`),this.sendContentMessage({type:"cmpDetected",url:location.href,cmp:e.name}),o.push(e))}catch(o){t.errors&&console.warn(`error detecting ${e.name}`,o)}return 0===o.length&&e>0?(await this.domActions.wait(500),this.findCmp(e-1)):o}async detectPopup(e){if(await this.waitForPopup(e).catch((t=>(this.config.logs.errors&&console.warn(`error waiting for a popup for ${e.name}`,t),!1))))return this.updateState({detectedPopups:this.state.detectedPopups.concat([e.name])}),this.sendContentMessage({type:"popupFound",cmp:e.name,url:location.href}),e;throw new Error("Popup is not shown")}async detectPopups(e,t){const o=e.map((e=>this.detectPopup(e)));await Promise.any(o).then((e=>{t(e)})).catch((()=>null));const i=await Promise.allSettled(o),c=[];for(const e of i)"fulfilled"===e.status&&c.push(e.value);return c}async handlePopup(e){return this.updateState({lifecycle:"openPopupDetected"}),this.config.enablePrehide&&!this.state.prehideOn&&this.prehideElements(),this.foundCmp=e,"optOut"===this.config.autoAction?await this.doOptOut():"optIn"===this.config.autoAction?await this.doOptIn():(this.config.logs.lifecycle&&console.log("waiting for opt-out signal...",location.href),!0)}async doOptOut(){const e=this.config.logs;let t;return this.updateState({lifecycle:"runningOptOut"}),this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: opt out on ${window.location.href}`),t=await this.foundCmp.optOut(),e.lifecycle&&console.log(`${this.foundCmp.name}: opt out result ${t}`)):(e.errors&&console.log("no CMP to opt out"),t=!1),this.config.enablePrehide&&this.undoPrehide(),this.sendContentMessage({type:"optOutResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,scheduleSelfTest:this.foundCmp&&this.foundCmp.hasSelfTest,url:location.href}),t&&!this.foundCmp.isIntermediate?(this.sendContentMessage({type:"autoconsentDone",cmp:this.foundCmp.name,isCosmetic:this.foundCmp.isCosmetic,url:location.href}),this.updateState({lifecycle:"done"})):this.updateState({lifecycle:t?"optOutSucceeded":"optOutFailed"}),t}async doOptIn(){const e=this.config.logs;let t;return this.updateState({lifecycle:"runningOptIn"}),this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: opt in on ${window.location.href}`),t=await this.foundCmp.optIn(),e.lifecycle&&console.log(`${this.foundCmp.name}: opt in result ${t}`)):(e.errors&&console.log("no CMP to opt in"),t=!1),this.config.enablePrehide&&this.undoPrehide(),this.sendContentMessage({type:"optInResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,scheduleSelfTest:!1,url:location.href}),t&&!this.foundCmp.isIntermediate?(this.sendContentMessage({type:"autoconsentDone",cmp:this.foundCmp.name,isCosmetic:this.foundCmp.isCosmetic,url:location.href}),this.updateState({lifecycle:"done"})):this.updateState({lifecycle:t?"optInSucceeded":"optInFailed"}),t}async doSelfTest(){const e=this.config.logs;let t;return this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: self-test on ${window.location.href}`),t=await this.foundCmp.test()):(e.errors&&console.log("no CMP to self test"),t=!1),this.sendContentMessage({type:"selfTestResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,url:location.href}),this.updateState({selfTest:t}),t}async waitForPopup(e,t=5,o=500){const i=this.config.logs;i.lifecycle&&console.log("checking if popup is open...",e.name);const c=await e.detectPopup().catch((t=>(i.errors&&console.warn(`error detecting popup for ${e.name}`,t),!1)));return!c&&t>0?(await this.domActions.wait(o),this.waitForPopup(e,t-1,o)):(i.lifecycle&&console.log(e.name,"popup is "+(c?"open":"not open")),c)}prehideElements(){const e=this.config.logs,t=this.rules.filter((e=>e.prehideSelectors&&e.checkRunContext())).reduce(((e,t)=>[...e,...t.prehideSelectors]),["#didomi-popup,.didomi-popup-container,.didomi-popup-notice,.didomi-consent-popup-preferences,#didomi-notice,.didomi-popup-backdrop,.didomi-screen-medium"]);return this.updateState({prehideOn:!0}),setTimeout((()=>{this.config.enablePrehide&&this.state.prehideOn&&!["runningOptOut","runningOptIn"].includes(this.state.lifecycle)&&(e.lifecycle&&console.log("Process is taking too long, unhiding elements"),this.undoPrehide())}),this.config.prehideTimeout||2e3),this.domActions.prehide(t.join(","))}undoPrehide(){return this.updateState({prehideOn:!1}),this.domActions.undoPrehide()}updateState(e){Object.assign(this.state,e),this.sendContentMessage({type:"report",instanceId:this.id,url:window.location.href,mainFrame:window.top===window.self,state:this.state})}async receiveMessageCallback(e){const t=this.config?.logs;switch(t?.messages&&console.log("received from background",e,window.location.href),e.type){case"initResp":this.initialize(e.config,e.rules);break;case"optIn":await this.doOptIn();break;case"optOut":await this.doOptOut();break;case"selfTest":await this.doSelfTest();break;case"evalResp":!function(e,t){const o=r.pending.get(e);o?(r.pending.delete(e),o.timer&&window.clearTimeout(o.timer),o.resolve(t)):console.warn("no eval #",e)}(e.id,e.result)}}}((e=>{window.webkit.messageHandlers[e.type]&&window.webkit.messageHandlers[e.type].postMessage(e).then((e=>{O.receiveMessageCallback(e)}))}),null,x);window.autoconsentMessageCallback=e=>{O.receiveMessageCallback(e)}}(); +!function(){"use strict";var e=class e{static setBase(t){e.base=t}static findElement(t,o=null,i=!1){let n=null;return n=null!=o?Array.from(o.querySelectorAll(t.selector)):null!=e.base?Array.from(e.base.querySelectorAll(t.selector)):Array.from(document.querySelectorAll(t.selector)),null!=t.textFilter&&(n=n.filter((e=>{const o=e.textContent.toLowerCase();if(Array.isArray(t.textFilter)){let e=!1;for(const i of t.textFilter)if(-1!==o.indexOf(i.toLowerCase())){e=!0;break}return e}return null!=t.textFilter&&-1!==o.indexOf(t.textFilter.toLowerCase())}))),null!=t.styleFilters&&(n=n.filter((e=>{const o=window.getComputedStyle(e);let i=!0;for(const e of t.styleFilters){const t=o[e.option];i=e.negated?i&&t!==e.value:i&&t===e.value}return i}))),null!=t.displayFilter&&(n=n.filter((e=>t.displayFilter?0!==e.offsetHeight:0===e.offsetHeight))),null!=t.iframeFilter&&(n=n.filter((()=>t.iframeFilter?window.location!==window.parent.location:window.location===window.parent.location))),null!=t.childFilter&&(n=n.filter((o=>{const i=e.base;e.setBase(o);const n=e.find(t.childFilter);return e.setBase(i),null!=n.target}))),i?n:(n.length>1&&console.warn("Multiple possible targets: ",n,t,o),n[0])}static find(t,o=!1){const i=[];if(null!=t.parent){const n=e.findElement(t.parent,null,o);if(null!=n){if(n instanceof Array)return n.forEach((n=>{const s=e.findElement(t.target,n,o);s instanceof Array?s.forEach((e=>{i.push({parent:n,target:e})})):i.push({parent:n,target:s})})),i;{const s=e.findElement(t.target,n,o);s instanceof Array?s.forEach((e=>{i.push({parent:n,target:e})})):i.push({parent:n,target:s})}}}else{const n=e.findElement(t.target,null,o);n instanceof Array?n.forEach((e=>{i.push({parent:null,target:e})})):i.push({parent:null,target:n})}return 0===i.length&&i.push({parent:null,target:null}),o?i:(1!==i.length&&console.warn("Multiple results found, even though multiple false",i),i[0])}};e.base=null;var t=e;function o(e){const o=t.find(e);return"css"===e.type?!!o.target:"checkbox"===e.type?!!o.target&&o.target.checked:void 0}async function i(e,c){switch(e.type){case"click":return async function(e){const o=t.find(e);null!=o.target&&o.target.click();return s(n)}(e);case"list":return async function(e,t){for(const o of e.actions)await i(o,t)}(e,c);case"consent":return async function(e,t){for(const n of e.consents){const e=-1!==t.indexOf(n.type);if(n.matcher&&n.toggleAction){o(n.matcher)!==e&&await i(n.toggleAction)}else e?await i(n.trueAction):await i(n.falseAction)}}(e,c);case"ifcss":return async function(e,o){const n=t.find(e);n.target?e.falseAction&&await i(e.falseAction,o):e.trueAction&&await i(e.trueAction,o)}(e,c);case"waitcss":return async function(e){await new Promise((o=>{let i=e.retries||10;const n=e.waitTime||250,s=()=>{const c=t.find(e);(e.negated&&c.target||!e.negated&&!c.target)&&i>0?(i-=1,setTimeout(s,n)):o()};s()}))}(e);case"foreach":return async function(e,o){const n=t.find(e,!0),s=t.base;for(const s of n)s.target&&(t.setBase(s.target),await i(e.action,o));t.setBase(s)}(e,c);case"hide":return async function(e){const o=t.find(e);o.target&&o.target.classList.add("Autoconsent-Hidden")}(e);case"slide":return async function(e){const o=t.find(e),i=t.find(e.dragTarget);if(o.target){const e=o.target.getBoundingClientRect(),t=i.target.getBoundingClientRect();let n=t.top-e.top,s=t.left-e.left;"y"===this.config.axis.toLowerCase()&&(s=0),"x"===this.config.axis.toLowerCase()&&(n=0);const c=window.screenX+e.left+e.width/2,r=window.screenY+e.top+e.height/2,a=e.left+e.width/2,l=e.top+e.height/2,p=document.createEvent("MouseEvents");p.initMouseEvent("mousedown",!0,!0,window,0,c,r,a,l,!1,!1,!1,!1,0,o.target);const d=document.createEvent("MouseEvents");d.initMouseEvent("mousemove",!0,!0,window,0,c+s,r+n,a+s,l+n,!1,!1,!1,!1,0,o.target);const u=document.createEvent("MouseEvents");u.initMouseEvent("mouseup",!0,!0,window,0,c+s,r+n,a+s,l+n,!1,!1,!1,!1,0,o.target),o.target.dispatchEvent(p),await this.waitTimeout(10),o.target.dispatchEvent(d),await this.waitTimeout(10),o.target.dispatchEvent(u)}}(e);case"close":return async function(){window.close()}();case"wait":return async function(e){await s(e.waitTime)}(e);case"eval":return async function(e){return console.log("eval!",e.code),new Promise((t=>{try{e.async?(window.eval(e.code),setTimeout((()=>{t(window.eval("window.__consentCheckResult"))}),e.timeout||250)):t(window.eval(e.code))}catch(o){console.warn("eval error",o,e.code),t(!1)}}))}(e);default:throw new Error("Unknown action type: "+e.type)}}var n=0;function s(e){return new Promise((t=>{setTimeout((()=>{t()}),e)}))}function c(){return crypto&&void 0!==crypto.randomUUID?crypto.randomUUID():Math.random().toString()}var r=class{constructor(e,t=1e3){this.id=e,this.promise=new Promise(((e,t)=>{this.resolve=e,this.reject=t})),this.timer=window.setTimeout((()=>{this.reject(new Error("timeout"))}),t)}},a={pending:new Map,sendContentMessage:null};var l={EVAL_0:()=>console.log(1),EVAL_CONSENTMANAGER_1:()=>window.__cmp&&"object"==typeof __cmp("getCMPData"),EVAL_CONSENTMANAGER_2:()=>!__cmp("consentStatus").userChoiceExists,EVAL_CONSENTMANAGER_3:()=>__cmp("setConsent",0),EVAL_CONSENTMANAGER_4:()=>__cmp("setConsent",1),EVAL_CONSENTMANAGER_5:()=>__cmp("consentStatus").userChoiceExists,EVAL_COOKIEBOT_1:()=>!!window.Cookiebot,EVAL_COOKIEBOT_2:()=>!window.Cookiebot.hasResponse&&!0===window.Cookiebot.dialog?.visible,EVAL_COOKIEBOT_3:()=>window.Cookiebot.withdraw()||!0,EVAL_COOKIEBOT_4:()=>window.Cookiebot.hide()||!0,EVAL_COOKIEBOT_5:()=>!0===window.Cookiebot.declined,EVAL_KLARO_1:()=>{const e=globalThis.klaroConfig||globalThis.klaro?.getManager&&globalThis.klaro.getManager().config;if(!e)return!0;const t=(e.services||e.apps).filter((e=>!e.required)).map((e=>e.name));if(klaro&&klaro.getManager){const e=klaro.getManager();return t.every((t=>!e.consents[t]))}if(klaroConfig&&"cookie"===klaroConfig.storageMethod){const e=klaroConfig.cookieName||klaroConfig.storageName,o=JSON.parse(decodeURIComponent(document.cookie.split(";").find((t=>t.trim().startsWith(e))).split("=")[1]));return Object.keys(o).filter((e=>t.includes(e))).every((e=>!1===o[e]))}},EVAL_KLARO_OPEN_POPUP:()=>{klaro.show(void 0,!0)},EVAL_KLARO_TRY_API_OPT_OUT:()=>{if(window.klaro&&"function"==typeof klaro.show&&"function"==typeof klaro.getManager)try{return klaro.getManager().changeAll(!1),klaro.getManager().saveAndApplyConsents(),!0}catch(e){return console.warn(e),!1}return!1},EVAL_ONETRUST_1:()=>window.OnetrustActiveGroups.split(",").filter((e=>e.length>0)).length<=1,EVAL_TRUSTARC_TOP:()=>window&&window.truste&&"0"===window.truste.eu.bindMap.prefCookie,EVAL_TRUSTARC_FRAME_TEST:()=>window&&window.QueryString&&"0"===window.QueryString.preferences,EVAL_TRUSTARC_FRAME_GTM:()=>window&&window.QueryString&&"1"===window.QueryString.gtm,EVAL_ABC_TEST:()=>document.cookie.includes("trackingconsent"),EVAL_ADROLL_0:()=>!document.cookie.includes("__adroll_fpc"),EVAL_ALMACMP_0:()=>document.cookie.includes('"name":"Google","consent":false'),EVAL_AFFINITY_SERIF_COM_0:()=>document.cookie.includes("serif_manage_cookies_viewed")&&!document.cookie.includes("serif_allow_analytics"),EVAL_ARBEITSAGENTUR_TEST:()=>document.cookie.includes("cookie_consent=denied"),EVAL_AXEPTIO_0:()=>document.cookie.includes("axeptio_authorized_vendors=%2C%2C"),EVAL_BAHN_TEST:()=>1===utag.gdpr.getSelectedCategories().length,EVAL_BING_0:()=>document.cookie.includes("AD=0"),EVAL_BLOCKSY_0:()=>document.cookie.includes("blocksy_cookies_consent_accepted=no"),EVAL_BORLABS_0:()=>!JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>-1!==e.indexOf("borlabs-cookie"))).split("=",2)[1])).consents.statistics,EVAL_BUNDESREGIERUNG_DE_0:()=>document.cookie.match("cookie-allow-tracking=0"),EVAL_CANVA_0:()=>!document.cookie.includes("gtm_fpc_engagement_event"),EVAL_CC_BANNER2_0:()=>!!document.cookie.match(/sncc=[^;]+D%3Dtrue/),EVAL_CLICKIO_0:()=>document.cookie.includes("__lxG__consent__v2_daisybit="),EVAL_CLINCH_0:()=>document.cookie.includes("ctc_rejected=1"),EVAL_COOKIECONSENT2_TEST:()=>document.cookie.includes("cc_cookie="),EVAL_COOKIECONSENT3_TEST:()=>document.cookie.includes("cc_cookie="),EVAL_COINBASE_0:()=>JSON.parse(decodeURIComponent(document.cookie.match(/cm_(eu|default)_preferences=([0-9a-zA-Z\\{\\}\\[\\]%:]*);?/)[2])).consent.length<=1,EVAL_COMPLIANZ_BANNER_0:()=>document.cookie.includes("cmplz_banner-status=dismissed"),EVAL_COOKIE_LAW_INFO_0:()=>CLI.disableAllCookies()||CLI.reject_close()||!0,EVAL_COOKIE_LAW_INFO_1:()=>-1===document.cookie.indexOf("cookielawinfo-checkbox-non-necessary=yes"),EVAL_COOKIE_LAW_INFO_DETECT:()=>!!window.CLI,EVAL_COOKIE_MANAGER_POPUP_0:()=>!1===JSON.parse(document.cookie.split(";").find((e=>e.trim().startsWith("CookieLevel"))).split("=")[1]).social,EVAL_COOKIEALERT_0:()=>document.querySelector("body").removeAttribute("style")||!0,EVAL_COOKIEALERT_1:()=>document.querySelector("body").removeAttribute("style")||!0,EVAL_COOKIEALERT_2:()=>!0===window.CookieConsent.declined,EVAL_COOKIEFIRST_0:()=>{return!1===(e=JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>-1!==e.indexOf("cookiefirst"))).trim()).split("=")[1])).performance&&!1===e.functional&&!1===e.advertising;var e},EVAL_COOKIEFIRST_1:()=>document.querySelectorAll("button[data-cookiefirst-accent-color=true][role=checkbox]:not([disabled])").forEach((e=>"true"===e.getAttribute("aria-checked")&&e.click()))||!0,EVAL_COOKIEINFORMATION_0:()=>CookieInformation.declineAllCategories()||!0,EVAL_COOKIEINFORMATION_1:()=>CookieInformation.submitAllCategories()||!0,EVAL_COOKIEINFORMATION_2:()=>document.cookie.includes("CookieInformationConsent="),EVAL_COOKIEYES_0:()=>document.cookie.includes("advertisement:no"),EVAL_DAILYMOTION_0:()=>!!document.cookie.match("dm-euconsent-v2"),EVAL_DNDBEYOND_TEST:()=>document.cookie.includes("cookie-consent=denied"),EVAL_DSGVO_0:()=>!document.cookie.includes("sp_dsgvo_cookie_settings"),EVAL_DUNELM_0:()=>document.cookie.includes("cc_functional=0")&&document.cookie.includes("cc_targeting=0"),EVAL_ETSY_0:()=>document.querySelectorAll(".gdpr-overlay-body input").forEach((e=>{e.checked=!1}))||!0,EVAL_ETSY_1:()=>document.querySelector(".gdpr-overlay-view button[data-wt-overlay-close]").click()||!0,EVAL_EU_COOKIE_COMPLIANCE_0:()=>-1===document.cookie.indexOf("cookie-agreed=2"),EVAL_EU_COOKIE_LAW_0:()=>!document.cookie.includes("euCookie"),EVAL_EZOIC_0:()=>ezCMP.handleAcceptAllClick(),EVAL_EZOIC_1:()=>!!document.cookie.match(/ez-consent-tcf/),EVAL_FIDES_DETECT_POPUP:()=>window.Fides?.initialized,EVAL_GOOGLE_0:()=>!!document.cookie.match(/SOCS=CAE/),EVAL_HEMA_TEST_0:()=>document.cookie.includes("cookies_rejected=1"),EVAL_IUBENDA_0:()=>document.querySelectorAll(".purposes-item input[type=checkbox]:not([disabled])").forEach((e=>{e.checked&&e.click()}))||!0,EVAL_IUBENDA_1:()=>!!document.cookie.match(/_iub_cs-\d+=/),EVAL_IWINK_TEST:()=>document.cookie.includes("cookie_permission_granted=no"),EVAL_JQUERY_COOKIEBAR_0:()=>!document.cookie.includes("cookies-state=accepted"),EVAL_KETCH_TEST:()=>document.cookie.includes("_ketch_consent_v1_"),EVAL_MEDIAVINE_0:()=>document.querySelectorAll('[data-name="mediavine-gdpr-cmp"] input[type=checkbox]').forEach((e=>e.checked&&e.click()))||!0,EVAL_MICROSOFT_0:()=>Array.from(document.querySelectorAll("div > button")).filter((e=>e.innerText.match("Reject|Ablehnen")))[0].click()||!0,EVAL_MICROSOFT_1:()=>Array.from(document.querySelectorAll("div > button")).filter((e=>e.innerText.match("Accept|Annehmen")))[0].click()||!0,EVAL_MICROSOFT_2:()=>!!document.cookie.match("MSCC|GHCC"),EVAL_MOOVE_0:()=>document.querySelectorAll("#moove_gdpr_cookie_modal input").forEach((e=>{e.disabled||(e.checked="moove_gdpr_strict_cookies"===e.name||"moove_gdpr_strict_cookies"===e.id)}))||!0,EVAL_ONENINETWO_0:()=>document.cookie.includes("CC_ADVERTISING=NO")&&document.cookie.includes("CC_ANALYTICS=NO"),EVAL_OPENAI_TEST:()=>document.cookie.includes("oai-allow-ne=false"),EVAL_OPERA_0:()=>document.cookie.includes("cookie_consent_essential=true")&&!document.cookie.includes("cookie_consent_marketing=true"),EVAL_PAYPAL_0:()=>!0===document.cookie.includes("cookie_prefs"),EVAL_PRIMEBOX_0:()=>!document.cookie.includes("cb-enabled=accepted"),EVAL_PUBTECH_0:()=>document.cookie.includes("euconsent-v2")&&(document.cookie.match(/.YAAAAAAAAAAA/)||document.cookie.match(/.aAAAAAAAAAAA/)||document.cookie.match(/.YAAACFgAAAAA/)),EVAL_REDDIT_0:()=>document.cookie.includes("eu_cookie={%22opted%22:true%2C%22nonessential%22:false}"),EVAL_ROBLOX_TEST:()=>document.cookie.includes("RBXcb"),EVAL_SIRDATA_UNBLOCK_SCROLL:()=>(document.documentElement.classList.forEach((e=>{e.startsWith("sd-cmp-")&&document.documentElement.classList.remove(e)})),!0),EVAL_SNIGEL_0:()=>!!document.cookie.match("snconsent"),EVAL_STEAMPOWERED_0:()=>2===JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>e.trim().startsWith("cookieSettings"))).split("=")[1])).preference_state,EVAL_SVT_TEST:()=>document.cookie.includes('cookie-consent-1={"optedIn":true,"functionality":false,"statistics":false}'),EVAL_TAKEALOT_0:()=>document.body.classList.remove("freeze")||(document.body.style="")||!0,EVAL_TARTEAUCITRON_0:()=>tarteaucitron.userInterface.respondAll(!1)||!0,EVAL_TARTEAUCITRON_1:()=>tarteaucitron.userInterface.respondAll(!0)||!0,EVAL_TARTEAUCITRON_2:()=>document.cookie.match(/tarteaucitron=[^;]*/)?.[0].includes("false"),EVAL_TAUNTON_TEST:()=>document.cookie.includes("taunton_user_consent_submitted=true"),EVAL_TEALIUM_0:()=>void 0!==window.utag&&"object"==typeof utag.gdpr,EVAL_TEALIUM_1:()=>utag.gdpr.setConsentValue(!1)||!0,EVAL_TEALIUM_DONOTSELL:()=>utag.gdpr.dns?.setDnsState(!1)||!0,EVAL_TEALIUM_2:()=>utag.gdpr.setConsentValue(!0)||!0,EVAL_TEALIUM_3:()=>1!==utag.gdpr.getConsentState(),EVAL_TEALIUM_DONOTSELL_CHECK:()=>1!==utag.gdpr.dns?.getDnsState(),EVAL_TESLA_TEST:()=>document.cookie.includes("tsla-cookie-consent=rejected"),EVAL_TESTCMP_0:()=>"button_clicked"===window.results.results[0],EVAL_TESTCMP_COSMETIC_0:()=>"banner_hidden"===window.results.results[0],EVAL_THEFREEDICTIONARY_0:()=>cmpUi.showPurposes()||cmpUi.rejectAll()||!0,EVAL_THEFREEDICTIONARY_1:()=>cmpUi.allowAll()||!0,EVAL_THEVERGE_0:()=>document.cookie.includes("_duet_gdpr_acknowledged=1"),EVAL_TWCC_TEST:()=>document.cookie.includes("twCookieConsent="),EVAL_UBUNTU_COM_0:()=>document.cookie.includes("_cookies_accepted=essential"),EVAL_UK_COOKIE_CONSENT_0:()=>!document.cookie.includes("catAccCookies"),EVAL_USERCENTRICS_API_0:()=>"object"==typeof UC_UI,EVAL_USERCENTRICS_API_1:()=>!!UC_UI.closeCMP(),EVAL_USERCENTRICS_API_2:()=>!!UC_UI.denyAllConsents(),EVAL_USERCENTRICS_API_3:()=>!!UC_UI.acceptAllConsents(),EVAL_USERCENTRICS_API_4:()=>!!UC_UI.closeCMP(),EVAL_USERCENTRICS_API_5:()=>!0===UC_UI.areAllConsentsAccepted(),EVAL_USERCENTRICS_API_6:()=>!1===UC_UI.areAllConsentsAccepted(),EVAL_USERCENTRICS_BUTTON_0:()=>JSON.parse(localStorage.getItem("usercentrics")).consents.every((e=>e.isEssential||!e.consentStatus)),EVAL_WAITROSE_0:()=>Array.from(document.querySelectorAll("label[id$=cookies-deny-label]")).forEach((e=>e.click()))||!0,EVAL_WAITROSE_1:()=>document.cookie.includes("wtr_cookies_advertising=0")&&document.cookie.includes("wtr_cookies_analytics=0"),EVAL_WP_COOKIE_NOTICE_0:()=>document.cookie.includes("wpl_viewed_cookie=no"),EVAL_XE_TEST:()=>document.cookie.includes("xeConsentState={%22performance%22:false%2C%22marketing%22:false%2C%22compliance%22:false}"),EVAL_XING_0:()=>document.cookie.includes("userConsent=%7B%22marketing%22%3Afalse"),EVAL_YOUTUBE_DESKTOP_0:()=>!!document.cookie.match(/SOCS=CAE/),EVAL_YOUTUBE_MOBILE_0:()=>!!document.cookie.match(/SOCS=CAE/)};var p={main:!0,frame:!1,urlPattern:""},d=class{constructor(e){this.runContext=p,this.autoconsent=e}get hasSelfTest(){throw new Error("Not Implemented")}get isIntermediate(){throw new Error("Not Implemented")}get isCosmetic(){throw new Error("Not Implemented")}mainWorldEval(e){const t=l[e];if(!t)return console.warn("Snippet not found",e),Promise.resolve(!1);const o=this.autoconsent.config.logs;if(this.autoconsent.config.isMainWorld){o.evals&&console.log("inline eval:",e,t);let i=!1;try{i=!!t.call(globalThis)}catch(t){o.evals&&console.error("error evaluating rule",e,t)}return Promise.resolve(i)}const i=`(${t.toString()})()`;return o.evals&&console.log("async eval:",e,i),function(e,t){const o=c();a.sendContentMessage({type:"eval",id:o,code:e,snippetId:t});const i=new r(o);return a.pending.set(i.id,i),i.promise}(i,e).catch((t=>(o.evals&&console.error("error evaluating rule",e,t),!1)))}checkRunContext(){const e={...p,...this.runContext},t=window.top===window;return!(t&&!e.main)&&(!(!t&&!e.frame)&&!(e.urlPattern&&!window.location.href.match(e.urlPattern)))}detectCmp(){throw new Error("Not Implemented")}async detectPopup(){return!1}optOut(){throw new Error("Not Implemented")}optIn(){throw new Error("Not Implemented")}openCmp(){throw new Error("Not Implemented")}async test(){return Promise.resolve(!0)}click(e,t=!1){return this.autoconsent.domActions.click(e,t)}elementExists(e){return this.autoconsent.domActions.elementExists(e)}elementVisible(e,t){return this.autoconsent.domActions.elementVisible(e,t)}waitForElement(e,t){return this.autoconsent.domActions.waitForElement(e,t)}waitForVisible(e,t,o){return this.autoconsent.domActions.waitForVisible(e,t,o)}waitForThenClick(e,t,o){return this.autoconsent.domActions.waitForThenClick(e,t,o)}wait(e){return this.autoconsent.domActions.wait(e)}hide(e,t){return this.autoconsent.domActions.hide(e,t)}prehide(e){return this.autoconsent.domActions.prehide(e)}undoPrehide(){return this.autoconsent.domActions.undoPrehide()}querySingleReplySelector(e,t){return this.autoconsent.domActions.querySingleReplySelector(e,t)}querySelectorChain(e){return this.autoconsent.domActions.querySelectorChain(e)}elementSelector(e){return this.autoconsent.domActions.elementSelector(e)}},u=class extends d{constructor(e,t){super(t),this.rule=e,this.name=e.name,this.runContext=e.runContext||p}get hasSelfTest(){return!!this.rule.test}get isIntermediate(){return!!this.rule.intermediate}get isCosmetic(){return!!this.rule.cosmetic}get prehideSelectors(){return this.rule.prehideSelectors}async detectCmp(){return!!this.rule.detectCmp&&this._runRulesParallel(this.rule.detectCmp)}async detectPopup(){return!!this.rule.detectPopup&&this._runRulesSequentially(this.rule.detectPopup)}async optOut(){const e=this.autoconsent.config.logs;return!!this.rule.optOut&&(e.lifecycle&&console.log("Initiated optOut()",this.rule.optOut),this._runRulesSequentially(this.rule.optOut))}async optIn(){const e=this.autoconsent.config.logs;return!!this.rule.optIn&&(e.lifecycle&&console.log("Initiated optIn()",this.rule.optIn),this._runRulesSequentially(this.rule.optIn))}async openCmp(){return!!this.rule.openCmp&&this._runRulesSequentially(this.rule.openCmp)}async test(){return this.hasSelfTest?this._runRulesSequentially(this.rule.test):super.test()}async evaluateRuleStep(e){const t=[],o=this.autoconsent.config.logs;if(e.exists&&t.push(this.elementExists(e.exists)),e.visible&&t.push(this.elementVisible(e.visible,e.check)),e.eval){const o=this.mainWorldEval(e.eval);t.push(o)}if(e.waitFor&&t.push(this.waitForElement(e.waitFor,e.timeout)),e.waitForVisible&&t.push(this.waitForVisible(e.waitForVisible,e.timeout,e.check)),e.click&&t.push(this.click(e.click,e.all)),e.waitForThenClick&&t.push(this.waitForThenClick(e.waitForThenClick,e.timeout,e.all)),e.wait&&t.push(this.wait(e.wait)),e.hide&&t.push(this.hide(e.hide,e.method)),e.if){if(!e.if.exists&&!e.if.visible)return console.error("invalid conditional rule",e.if),!1;const i=await this.evaluateRuleStep(e.if);o.rulesteps&&console.log("Condition is",i),i?t.push(this._runRulesSequentially(e.then)):e.else?t.push(this._runRulesSequentially(e.else)):t.push(!0)}if(e.any){for(const t of e.any)if(await this.evaluateRuleStep(t))return!0;return!1}if(0===t.length)return o.errors&&console.warn("Unrecognized rule",e),!1;return(await Promise.all(t)).reduce(((e,t)=>e&&t),!0)}async _runRulesParallel(e){const t=e.map((e=>this.evaluateRuleStep(e)));return(await Promise.all(t)).every((e=>!!e))}async _runRulesSequentially(e){const t=this.autoconsent.config.logs;for(const o of e){t.rulesteps&&console.log("Running rule...",o);const e=await this.evaluateRuleStep(o);if(t.rulesteps&&console.log("...rule result",e),!e&&!o.optional)return!1}return!0}},h=class{constructor(e,t){this.name=e,this.config=t,this.methods=new Map,this.runContext=p,this.isCosmetic=!1,t.methods.forEach((e=>{e.action&&this.methods.set(e.name,e.action)})),this.hasSelfTest=!1}get isIntermediate(){return!1}checkRunContext(){return!0}async detectCmp(){return this.config.detectors.map((e=>o(e.presentMatcher))).some((e=>!!e))}async detectPopup(){return this.config.detectors.map((e=>o(e.showingMatcher))).some((e=>!!e))}async executeAction(e,t){return!this.methods.has(e)||i(this.methods.get(e),t)}async optOut(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),await this.executeAction("HIDE_CMP"),await this.executeAction("DO_CONSENT",[]),await this.executeAction("SAVE_CONSENT"),!0}async optIn(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),await this.executeAction("HIDE_CMP"),await this.executeAction("DO_CONSENT",["D","A","B","E","F","X"]),await this.executeAction("SAVE_CONSENT"),!0}async openCmp(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),!0}async test(){return!0}};function m(e="autoconsent-css-rules"){const t=`style#${e}`,o=document.querySelector(t);if(o&&o instanceof HTMLStyleElement)return o;{const t=document.head||document.getElementsByTagName("head")[0]||document.documentElement,o=document.createElement("style");return o.id=e,t.appendChild(o),o}}function A(e){return`${"opacity"===e?"opacity: 0":"display: none"} !important; z-index: -1 !important; pointer-events: none !important;`}function g(e,t,o="display"){const i=`${t} { ${A(o)} } `;return e instanceof HTMLStyleElement&&(e.innerText+=i,t.length>0)}async function f(e,t,o){const i=await e();return!i&&t>0?new Promise((i=>{setTimeout((async()=>{i(f(e,t-1,o))}),o)})):Promise.resolve(i)}function k(e){if(!e)return!1;if(null!==e.offsetParent)return!0;{const t=window.getComputedStyle(e);if("fixed"===t.position&&"none"!==t.display)return!0}return!1}function b(e){const t={enabled:!0,autoAction:"optOut",disabledCmps:[],enablePrehide:!0,enableCosmeticRules:!0,detectRetries:20,isMainWorld:!1,prehideTimeout:2e3,enableFilterList:!1,logs:{lifecycle:!1,rulesteps:!1,evals:!1,errors:!0,messages:!1}},o=(i=t,globalThis.structuredClone?structuredClone(i):JSON.parse(JSON.stringify(i)));var i;for(const i of Object.keys(t))void 0!==e[i]&&(o[i]=e[i]);return o}var y="#truste-show-consent",w="#truste-consent-track",v=[class extends d{constructor(e){super(e),this.name="TrustArc-top",this.prehideSelectors=[".trustarc-banner-container",`.truste_popframe,.truste_overlay,.truste_box_overlay,${w}`],this.runContext={main:!0,frame:!1},this._shortcutButton=null,this._optInDone=!1}get hasSelfTest(){return!0}get isIntermediate(){return!this._optInDone&&!this._shortcutButton}get isCosmetic(){return!1}async detectCmp(){const e=this.elementExists(`${y},${w}`);return e&&(this._shortcutButton=document.querySelector("#truste-consent-required")),e}async detectPopup(){return this.elementVisible(`#truste-consent-content,#trustarc-banner-overlay,${w}`,"any")}openFrame(){this.click(y)}async optOut(){return this._shortcutButton?(this._shortcutButton.click(),!0):(g(m(),`.truste_popframe, .truste_overlay, .truste_box_overlay, ${w}`),this.click(y),setTimeout((()=>{m().remove()}),1e4),!0)}async optIn(){return this._optInDone=!0,this.click("#truste-consent-button")}async openCmp(){return!0}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_TRUSTARC_TOP")}},class extends d{constructor(){super(...arguments),this.name="TrustArc-frame",this.runContext={main:!1,frame:!0,urlPattern:"^https://consent-pref\\.trustarc\\.com/\\?"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return!0}async detectPopup(){return this.elementVisible("#defaultpreferencemanager","any")&&this.elementVisible(".mainContent","any")}async navigateToSettings(){return await f((async()=>this.elementExists(".shp")||this.elementVisible(".advance","any")||this.elementExists(".switch span:first-child")),10,500),this.elementExists(".shp")&&this.click(".shp"),await this.waitForElement(".prefPanel",5e3),this.elementVisible(".advance","any")&&this.click(".advance"),await f((()=>this.elementVisible(".switch span:first-child","any")),5,1e3)}async optOut(){if(await this.mainWorldEval("EVAL_TRUSTARC_FRAME_TEST"))return!0;let e=3e3;return await this.mainWorldEval("EVAL_TRUSTARC_FRAME_GTM")&&(e=1500),await f((()=>"complete"===document.readyState),20,100),await this.waitForElement(".mainContent[aria-hidden=false]",e),!!this.click(".rejectAll")||(this.elementExists(".prefPanel")&&await this.waitForElement('.prefPanel[style="visibility: visible;"]',e),this.click("#catDetails0")?(this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",e),!0):this.click(".required")?(this.waitForThenClick("#gwt-debug-close_id",e),!0):(await this.navigateToSettings(),this.click(".switch span:nth-child(1):not(.active)",!0),this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",10*e),!0))}async optIn(){return this.click(".call")||(await this.navigateToSettings(),this.click(".switch span:nth-child(2)",!0),this.click(".submit"),this.waitForElement("#gwt-debug-close_id",3e5).then((()=>{this.click("#gwt-debug-close_id")}))),!0}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_TRUSTARC_FRAME_TEST")}},class extends d{constructor(){super(...arguments),this.name="Cybotcookiebot",this.prehideSelectors=["#CybotCookiebotDialog,#CybotCookiebotDialogBodyUnderlay,#dtcookie-container,#cookiebanner,#cb-cookieoverlay,.modal--cookie-banner,#cookiebanner_outer,#CookieBanner"]}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return await this.mainWorldEval("EVAL_COOKIEBOT_1")}async detectPopup(){return this.mainWorldEval("EVAL_COOKIEBOT_2")}async optOut(){await this.wait(500);let e=await this.mainWorldEval("EVAL_COOKIEBOT_3");return await this.wait(500),e=e&&await this.mainWorldEval("EVAL_COOKIEBOT_4"),e}async optIn(){return this.elementExists("#dtcookie-container")?this.click(".h-dtcookie-accept"):(this.click(".CybotCookiebotDialogBodyLevelButton:not(:checked):enabled",!0),this.click("#CybotCookiebotDialogBodyLevelButtonAccept"),this.click("#CybotCookiebotDialogBodyButtonAccept"),!0)}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_COOKIEBOT_5")}},class extends d{constructor(){super(...arguments),this.name="Sourcepoint-frame",this.prehideSelectors=["div[id^='sp_message_container_'],.message-overlay","#sp_privacy_manager_container"],this.ccpaNotice=!1,this.ccpaPopup=!1,this.runContext={main:!0,frame:!0}}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){const e=new URL(location.href);return e.searchParams.has("message_id")&&"ccpa-notice.sp-prod.net"===e.hostname?(this.ccpaNotice=!0,!0):"ccpa-pm.sp-prod.net"===e.hostname?(this.ccpaPopup=!0,!0):("/index.html"===e.pathname||"/privacy-manager/index.html"===e.pathname||"/ccpa_pm/index.html"===e.pathname)&&(e.searchParams.has("message_id")||e.searchParams.has("requestUUID")||e.searchParams.has("consentUUID"))}async detectPopup(){return!!this.ccpaNotice||(this.ccpaPopup?await this.waitForElement(".priv-save-btn",2e3):(await this.waitForElement(".sp_choice_type_11,.sp_choice_type_12,.sp_choice_type_13,.sp_choice_type_ACCEPT_ALL,.sp_choice_type_SAVE_AND_EXIT",2e3),!this.elementExists(".sp_choice_type_9")))}async optIn(){return await this.waitForElement(".sp_choice_type_11,.sp_choice_type_ACCEPT_ALL",2e3),!!this.click(".sp_choice_type_11")||!!this.click(".sp_choice_type_ACCEPT_ALL")}isManagerOpen(){return"/privacy-manager/index.html"===location.pathname||"/ccpa_pm/index.html"===location.pathname}async optOut(){const e=this.autoconsent.config.logs;if(this.ccpaPopup){const e=document.querySelectorAll(".priv-purpose-container .sp-switch-arrow-block a.neutral.on .right");for(const t of e)t.click();const t=document.querySelectorAll(".priv-purpose-container .sp-switch-arrow-block a.switch-bg.on");for(const e of t)e.click();return this.click(".priv-save-btn")}if(!this.isManagerOpen()){if(!await this.waitForElement(".sp_choice_type_12,.sp_choice_type_13"))return!1;if(!this.elementExists(".sp_choice_type_12"))return this.click(".sp_choice_type_13");this.click(".sp_choice_type_12"),await f((()=>this.isManagerOpen()),200,100)}await this.waitForElement(".type-modal",2e4),this.waitForThenClick(".ccpa-stack .pm-switch[aria-checked=true] .slider",500,!0);try{const e=".sp_choice_type_REJECT_ALL",t=".reject-toggle",o=await Promise.race([this.waitForElement(e,2e3).then((e=>e?0:-1)),this.waitForElement(t,2e3).then((e=>e?1:-1)),this.waitForElement(".pm-features",2e3).then((e=>e?2:-1))]);if(0===o)return await this.waitForVisible(e),this.click(e);1===o?this.click(t):2===o&&(await this.waitForElement(".pm-features",1e4),this.click(".checked > span",!0),this.click(".chevron"))}catch(t){e.errors&&console.warn(t)}return this.click(".sp_choice_type_SAVE_AND_EXIT")}},class extends d{constructor(){super(...arguments),this.name="consentmanager.net",this.prehideSelectors=["#cmpbox,#cmpbox2"],this.apiAvailable=!1}get hasSelfTest(){return this.apiAvailable}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.apiAvailable=await this.mainWorldEval("EVAL_CONSENTMANAGER_1"),!!this.apiAvailable||this.elementExists("#cmpbox")}async detectPopup(){return this.apiAvailable?(await this.wait(500),await this.mainWorldEval("EVAL_CONSENTMANAGER_2")):this.elementVisible("#cmpbox .cmpmore","any")}async optOut(){return await this.wait(500),this.apiAvailable?await this.mainWorldEval("EVAL_CONSENTMANAGER_3"):!!this.click(".cmpboxbtnno")||(this.elementExists(".cmpwelcomeprpsbtn")?(this.click(".cmpwelcomeprpsbtn > a[aria-checked=true]",!0),this.click(".cmpboxbtnsave"),!0):(this.click(".cmpboxbtncustom"),await this.waitForElement(".cmptblbox",2e3),this.click(".cmptdchoice > a[aria-checked=true]",!0),this.click(".cmpboxbtnyescustomchoices"),this.hide("#cmpwrapper,#cmpbox","display"),!0))}async optIn(){return this.apiAvailable?await this.mainWorldEval("EVAL_CONSENTMANAGER_4"):this.click(".cmpboxbtnyes")}async test(){if(this.apiAvailable)return await this.mainWorldEval("EVAL_CONSENTMANAGER_5")}},class extends d{constructor(){super(...arguments),this.name="Evidon"}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("#_evidon_banner")}async detectPopup(){return this.elementVisible("#_evidon_banner","any")}async optOut(){return this.click("#_evidon-decline-button")||(g(m(),"#evidon-prefdiag-overlay,#evidon-prefdiag-background,#_evidon-background"),await this.waitForThenClick("#_evidon-option-button"),await this.waitForElement("#evidon-prefdiag-overlay",5e3),await this.wait(500),await this.waitForThenClick("#evidon-prefdiag-decline")),!0}async optIn(){return this.click("#_evidon-accept-button")}},class extends d{constructor(){super(...arguments),this.name="Onetrust",this.prehideSelectors=["#onetrust-banner-sdk,#onetrust-consent-sdk,.onetrust-pc-dark-filter,.js-consent-banner"],this.runContext={urlPattern:"^(?!.*https://www\\.nba\\.com/)"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("#onetrust-banner-sdk,#onetrust-pc-sdk")}async detectPopup(){return this.elementVisible("#onetrust-banner-sdk,#onetrust-pc-sdk","any")}async optOut(){return this.elementVisible("#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies","any")?this.click("#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies"):(this.elementExists("#onetrust-pc-btn-handler")?this.click("#onetrust-pc-btn-handler"):this.click(".ot-sdk-show-settings,button.js-cookie-settings"),await this.waitForElement("#onetrust-consent-sdk",2e3),await this.wait(1e3),this.click("#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked",!0),await this.wait(1e3),await this.waitForElement(".save-preference-btn-handler,.js-consent-save",2e3),this.click(".save-preference-btn-handler,.js-consent-save"),await this.waitForVisible("#onetrust-banner-sdk",5e3,"none"),!0)}async optIn(){return this.click("#onetrust-accept-btn-handler,#accept-recommended-btn-handler,.js-accept-cookies")}async test(){return await f((()=>this.mainWorldEval("EVAL_ONETRUST_1")),10,500)}},class extends d{constructor(){super(...arguments),this.name="Klaro",this.prehideSelectors=[".klaro"],this.settingsOpen=!1}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".klaro > .cookie-modal")?(this.settingsOpen=!0,!0):this.elementExists(".klaro > .cookie-notice")}async detectPopup(){return this.elementVisible(".klaro > .cookie-notice,.klaro > .cookie-modal","any")}async optOut(){return!!await this.mainWorldEval("EVAL_KLARO_TRY_API_OPT_OUT")||(!!this.click(".klaro .cn-decline")||(await this.mainWorldEval("EVAL_KLARO_OPEN_POPUP"),!!this.click(".klaro .cn-decline")||(this.click(".cm-purpose:not(.cm-toggle-all) > input:not(.half-checked,.required,.only-required),.cm-purpose:not(.cm-toggle-all) > div > input:not(.half-checked,.required,.only-required)",!0),this.click(".cm-btn-accept,.cm-button"))))}async optIn(){return!!this.click(".klaro .cm-btn-accept-all")||(this.settingsOpen?(this.click(".cm-purpose:not(.cm-toggle-all) > input.half-checked",!0),this.click(".cm-btn-accept")):this.click(".klaro .cookie-notice .cm-btn-success"))}async test(){return await this.mainWorldEval("EVAL_KLARO_1")}},class extends d{constructor(){super(...arguments),this.name="Uniconsent"}get prehideSelectors(){return[".unic",".modal:has(.unic)"]}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".unic .unic-box,.unic .unic-bar,.unic .unic-modal")}async detectPopup(){return this.elementVisible(".unic .unic-box,.unic .unic-bar,.unic .unic-modal","any")}async optOut(){if(await this.waitForElement(".unic button",1e3),document.querySelectorAll(".unic button").forEach((e=>{const t=e.textContent;(t.includes("Manage Options")||t.includes("Optionen verwalten"))&&e.click()})),await this.waitForElement(".unic input[type=checkbox]",1e3)){await this.waitForElement(".unic button",1e3),document.querySelectorAll(".unic input[type=checkbox]").forEach((e=>{e.checked&&e.click()}));for(const e of document.querySelectorAll(".unic button")){const t=e.textContent;for(const o of["Confirm Choices","Save Choices","Auswahl speichern"])if(t.includes(o))return e.click(),await this.wait(500),!0}}return!1}async optIn(){return this.waitForThenClick(".unic #unic-agree")}async test(){await this.wait(1e3);return!this.elementExists(".unic .unic-box,.unic .unic-bar")}},class extends d{constructor(){super(...arguments),this.prehideSelectors=[".cmp-root"],this.name="Conversant"}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".cmp-root .cmp-receptacle")}async detectPopup(){return this.elementVisible(".cmp-root .cmp-receptacle","any")}async optOut(){if(!await this.waitForThenClick(".cmp-main-button:not(.cmp-main-button--primary)"))return!1;if(!await this.waitForElement(".cmp-view-tab-tabs"))return!1;await this.waitForThenClick(".cmp-view-tab-tabs > :first-child"),await this.waitForThenClick(".cmp-view-tab-tabs > .cmp-view-tab--active:first-child");for(const e of Array.from(document.querySelectorAll(".cmp-accordion-item"))){e.querySelector(".cmp-accordion-item-title").click(),await f((()=>!!e.querySelector(".cmp-accordion-item-content.cmp-active")),10,50);const t=e.querySelector(".cmp-accordion-item-content.cmp-active");t.querySelectorAll(".cmp-toggle-actions .cmp-toggle-deny:not(.cmp-toggle-deny--active)").forEach((e=>e.click())),t.querySelectorAll(".cmp-toggle-actions .cmp-toggle-checkbox:not(.cmp-toggle-checkbox--active)").forEach((e=>e.click()))}return await this.click(".cmp-main-button:not(.cmp-main-button--primary)"),!0}async optIn(){return this.waitForThenClick(".cmp-main-button.cmp-main-button--primary")}async test(){return document.cookie.includes("cmp-data=0")}},class extends d{constructor(){super(...arguments),this.name="tiktok.com",this.runContext={urlPattern:"tiktok"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}getShadowRoot(){const e=document.querySelector("tiktok-cookie-banner");return e?e.shadowRoot:null}async detectCmp(){return this.elementExists("tiktok-cookie-banner")}async detectPopup(){return k(this.getShadowRoot().querySelector(".tiktok-cookie-banner"))}async optOut(){const e=this.autoconsent.config.logs,t=this.getShadowRoot().querySelector(".button-wrapper button:first-child");return t?(e.rulesteps&&console.log("[clicking]",t),t.click(),!0):(e.errors&&console.log("no decline button found"),!1)}async optIn(){const e=this.autoconsent.config.logs,t=this.getShadowRoot().querySelector(".button-wrapper button:last-child");return t?(e.rulesteps&&console.log("[clicking]",t),t.click(),!0):(e.errors&&console.log("no accept button found"),!1)}async test(){const e=document.cookie.match(/cookie-consent=([^;]+)/);if(!e)return!1;const t=JSON.parse(decodeURIComponent(e[1]));return Object.values(t).every((e=>"boolean"!=typeof e||!1===e))}},class extends d{constructor(){super(...arguments),this.name="airbnb",this.runContext={urlPattern:"^https://(www\\.)?airbnb\\.[^/]+/"},this.prehideSelectors=["div[data-testid=main-cookies-banner-container]",'div:has(> div:first-child):has(> div:last-child):has(> section [data-testid="strictly-necessary-cookies"])']}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("div[data-testid=main-cookies-banner-container]")}async detectPopup(){return this.elementVisible("div[data-testid=main-cookies-banner-container","any")}async optOut(){let e;for(await this.waitForThenClick("div[data-testid=main-cookies-banner-container] button._snbhip0");e=document.querySelector("[data-testid=modal-container] button[aria-checked=true]:not([disabled])");)e.click();return this.waitForThenClick("button[data-testid=save-btn]")}async optIn(){return this.waitForThenClick("div[data-testid=main-cookies-banner-container] button._148dgdpk")}async test(){return await f((()=>!!document.cookie.match("OptanonAlertBoxClosed")),20,200)}},class extends d{constructor(){super(...arguments),this.name="tumblr-com",this.runContext={urlPattern:"^https://(www\\.)?tumblr\\.com/"}}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}get prehideSelectors(){return["#cmp-app-container"]}async detectCmp(){return this.elementExists("#cmp-app-container")}async detectPopup(){return this.elementVisible("#cmp-app-container","any")}async optOut(){let e=document.querySelector("#cmp-app-container iframe"),t=e.contentDocument?.querySelector(".cmp-components-button.is-secondary");return!!t&&(t.click(),await f((()=>{const e=document.querySelector("#cmp-app-container iframe");return!!e.contentDocument?.querySelector(".cmp__dialog input")}),5,500),e=document.querySelector("#cmp-app-container iframe"),t=e.contentDocument?.querySelector(".cmp-components-button.is-secondary"),!!t&&(t.click(),!0))}async optIn(){const e=document.querySelector("#cmp-app-container iframe").contentDocument.querySelector(".cmp-components-button.is-primary");return!!e&&(e.click(),!0)}},class extends d{constructor(){super(...arguments),this.name="Admiral"}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("div > div[class*=Card] > div[class*=Frame] > div[class*=Pills] > button[class*=Pills__StyledPill]")}async detectPopup(){return this.elementVisible("div > div[class*=Card] > div[class*=Frame] > div[class*=Pills] > button[class*=Pills__StyledPill]","any")}async optOut(){const e="xpath///button[contains(., 'Afvis alle') or contains(., 'Reject all') or contains(., 'Odbaci sve') or contains(., 'Rechazar todo') or contains(., 'Atmesti visus') or contains(., 'Odmítnout vše') or contains(., 'Απόρριψη όλων') or contains(., 'Rejeitar tudo') or contains(., 'Tümünü reddet') or contains(., 'Отклонить все') or contains(., 'Noraidīt visu') or contains(., 'Avvisa alla') or contains(., 'Odrzuć wszystkie') or contains(., 'Alles afwijzen') or contains(., 'Отхвърляне на всички') or contains(., 'Rifiuta tutto') or contains(., 'Zavrni vse') or contains(., 'Az összes elutasítása') or contains(., 'Respingeți tot') or contains(., 'Alles ablehnen') or contains(., 'Tout rejeter') or contains(., 'Odmietnuť všetko') or contains(., 'Lükka kõik tagasi') or contains(., 'Hylkää kaikki')]";if(await this.waitForElement(e,500))return this.click(e);const t="xpath///button[contains(., 'Spara & avsluta') or contains(., 'Save & exit') or contains(., 'Uložit a ukončit') or contains(., 'Enregistrer et quitter') or contains(., 'Speichern & Verlassen') or contains(., 'Tallenna ja poistu') or contains(., 'Išsaugoti ir išeiti') or contains(., 'Opslaan & afsluiten') or contains(., 'Guardar y salir') or contains(., 'Shrani in zapri') or contains(., 'Uložiť a ukončiť') or contains(., 'Kaydet ve çıkış yap') or contains(., 'Сохранить и выйти') or contains(., 'Salvesta ja välju') or contains(., 'Salva ed esci') or contains(., 'Gem & afslut') or contains(., 'Αποθήκευση και έξοδος') or contains(., 'Saglabāt un iziet') or contains(., 'Mentés és kilépés') or contains(., 'Guardar e sair') or contains(., 'Zapisz & zakończ') or contains(., 'Salvare și ieșire') or contains(., 'Spremi i izađi') or contains(., 'Запазване и изход')]";if(await this.waitForThenClick("xpath///button[contains(., 'Zwecke') or contains(., 'Σκοποί') or contains(., 'Purposes') or contains(., 'Цели') or contains(., 'Eesmärgid') or contains(., 'Tikslai') or contains(., 'Svrhe') or contains(., 'Cele') or contains(., 'Účely') or contains(., 'Finalidades') or contains(., 'Mērķi') or contains(., 'Scopuri') or contains(., 'Fines') or contains(., 'Ändamål') or contains(., 'Finalités') or contains(., 'Doeleinden') or contains(., 'Tarkoitukset') or contains(., 'Scopi') or contains(., 'Amaçlar') or contains(., 'Nameni') or contains(., 'Célok') or contains(., 'Formål')]")&&await this.waitForVisible(t)){return this.elementSelector(t)[0].parentElement.parentElement.querySelectorAll("input[type=checkbox]:checked").forEach((e=>e.click())),this.click(t)}return!1}async optIn(){return this.click("xpath///button[contains(., 'Sprejmi vse') or contains(., 'Prihvati sve') or contains(., 'Godkänn alla') or contains(., 'Prijať všetko') or contains(., 'Принять все') or contains(., 'Aceptar todo') or contains(., 'Αποδοχή όλων') or contains(., 'Zaakceptuj wszystkie') or contains(., 'Accetta tutto') or contains(., 'Priimti visus') or contains(., 'Pieņemt visu') or contains(., 'Tümünü kabul et') or contains(., 'Az összes elfogadása') or contains(., 'Accept all') or contains(., 'Приемане на всички') or contains(., 'Accepter alle') or contains(., 'Hyväksy kaikki') or contains(., 'Tout accepter') or contains(., 'Alles accepteren') or contains(., 'Aktsepteeri kõik') or contains(., 'Přijmout vše') or contains(., 'Alles akzeptieren') or contains(., 'Aceitar tudo') or contains(., 'Acceptați tot')]")}}],_=class{constructor(e){this.autoconsentInstance=e}click(e,t=!1){const o=this.elementSelector(e);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[click]",e,t,o),o.length>0&&(t?o.forEach((e=>e.click())):o[0].click()),o.length>0}elementExists(e){return this.elementSelector(e).length>0}elementVisible(e,t){const o=this.elementSelector(e),i=new Array(o.length);return o.forEach(((e,t)=>{i[t]=k(e)})),"none"===t?i.every((e=>!e)):0!==i.length&&("any"===t?i.some((e=>e)):i.every((e=>e)))}waitForElement(e,t=1e4){const o=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForElement]",e),f((()=>this.elementSelector(e).length>0),o,200)}waitForVisible(e,t=1e4,o="any"){const i=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForVisible]",e),f((()=>this.elementVisible(e,o)),i,200)}async waitForThenClick(e,t=1e4,o=!1){return await this.waitForElement(e,t),this.click(e,o)}wait(e){return this.autoconsentInstance.config.logs.rulesteps&&console.log("[wait]",e),new Promise((t=>{setTimeout((()=>{t(!0)}),e)}))}hide(e,t){this.autoconsentInstance.config.logs.rulesteps&&console.log("[hide]",e);return g(m(),e,t)}prehide(e){const t=m("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[prehide]",t,location.href),g(t,e,"opacity")}undoPrehide(){const e=m("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[undoprehide]",e,location.href),e&&e.remove(),!!e}async createOrUpdateStyleSheet(e,t){return t||(t=new CSSStyleSheet),t=await t.replace(e)}removeStyleSheet(e){return!!e&&(e.replace(""),!0)}querySingleReplySelector(e,t=document){if(e.startsWith("aria/"))return[];if(e.startsWith("xpath/")){const o=e.slice(6),i=document.evaluate(o,t,null,XPathResult.ANY_TYPE,null);let n=null;const s=[];for(;n=i.iterateNext();)s.push(n);return s}return e.startsWith("text/")||e.startsWith("pierce/")?[]:t.shadowRoot?Array.from(t.shadowRoot.querySelectorAll(e)):Array.from(t.querySelectorAll(e))}querySelectorChain(e){let t,o=document;for(const i of e){if(t=this.querySingleReplySelector(i,o),0===t.length)return[];o=t[0]}return t}elementSelector(e){return"string"==typeof e?this.querySingleReplySelector(e):this.querySelectorChain(e)}};function C(){return{chars:new Map,code:void 0}}var x=new Uint8Array(0),S=class{constructor(e,t=3e4){this.trie=function(e){const t=C();for(let o=0;o figure.wp-block-image:has(> img[class^="wp-image-"][src^="https://www.sinhasannews.com/"][width="','"]:not([style^="width: 1px; height: 1px; position: absolute; left: -10000px; top: -"])',"acs, document.createElement, %2Fl%5C.parentNode%5C.insertBefore%5C(s%2F","%2Fvisit%2F%22%5D%5Btitle%5E%3D%22https%3A%2F%2F%22%5D, %5Btitle%5D",", OptanonConsent, groups%3DC0001%253A1%252CC0002%253A0%252CC000","rmnt, script, %2Fh%3DdecodeURIComponent%7CpopundersPerIP%2F",'.project-description [href^="/linkout?remoteUrl="][href*="',':not([style^="position: absolute; left: -5000px"])',"href-sanitizer, a%5Bhref%5E%3D%22https%3A%2F%2F","ra, oncontextmenu%7Condragstart%7Conselectstart",", OptanonAlertBoxClosed, %24currentDate%24","acs, document.querySelectorAll, popMagic","acs, addEventListener, google_ad_client","aost, String.prototype.charCodeAt, ai_","aopr, app_vars.force_disable_adblock","acs, document.addEventListener, ","taboola-below-article-thumbnails","acs, document.getElementById, ","no-fetch-if, googlesyndication","aopr, document.dispatchEvent","no-xhr-if, googlesyndication",", document.createElement, ","acs, String.fromCharCode, ","%2522%253Afalse%252C%2522",", document.oncontextmenu","%2522%253Atrue%252C%2522","aeld, DOMContentLoaded, ","nosiif, visibility, 1000","set-local-storage-item, ","%2522%3Afalse%252C%2522","trusted-click-element, ","set, blurred, false","acs, eval, replace","decodeURIComponent",'[target="_blank"]',"%22%3Afalse%2C%22","^script:has-text(",'[href^="https://','[href^="http://','[href="https://','[src^="https://','[data-testid="',"modal-backdrop","rmnt, script, ","BlockDetected","trusted-set-",".prototype.","contextmenu","no-fetch-if","otification",":has-text(","background",'[class*="','[class^="',"body,html","container","Container","decodeURI","div[class",'div[id^="',"div[style","document.","no-xhr-if","placehold",'[href*="',"#wpsafe-","AAAAAAAA","Detector","disclaim","nano-sib","nextFunc","noopFunc","nostif, ","nowebrtc",'.com/"]',"300x250","article","consent","Consent","content","display","keydown","message","Message","overlay","privacy","sidebar","sponsor","wrapper","-child","[data-","accept","Accept","aopr, ","banner","bottom","cookie","Cookie","google","nosiif","notice","nowoif","policy","Policy","script","widget",":has(",":not(","block","Block","click","deskt","disab","fixed","frame","modal","popup","video",".com","2%3A","aeld","body","butt","foot","gdpr","html","icky","ight","show","tion","true"," > ","%3D","%7C","age","box","div","ent","out","rap","set","__",", ",'"]',"%2","%5",'="',"00","ac","ad","Ad","al","an","ar","at","e-","ed","en","er","he","id","in","la","le","lo","od","ol","om","on","op","or","re","s_","s-","se","st","t-","te","ti","un","_","-",";",":",".","(",")","[","]","*","/","#","^","0","1","2","3","4","5","6","7","8","9","b","B","c","C","d","D","e","E","f","F","g","G","h","H","I","j","J","k","l","L","m","M","n","N","O","p","P","q","Q","R","s","S","t","T","u","U","v","V","w","W","x","y","Y","z"],O=["sandbox allow-forms allow-same-origin allow-scripts allow-modals allow-orientation-lock allow-pointer-lock allow-presentation allow-top-navigation","script-src 'self' 'unsafe-inline' 'unsafe-eval' "," *.google.com *.gstatic.com *.googleapis.com",".com *.google.com *.googletagmanager.com *.","script-src 'self' '*' 'unsafe-inline'","default-src 'unsafe-inline' 'self'","script-src 'self' 'unsafe-eval' "," *.google.com *.gstatic.com *.","t-src 'self' 'unsafe-inline' ","script-src * 'unsafe-inline'",".com *.googleapis.com *."," *.googletagmanager.com",".com *.bootstrapcdn.com","default-src 'self' *.","frame-src 'self' *"," *.cloudflare.com","child-src 'none';","worker-src 'none'","'unsafe-inline'"," data: blob:","*.googleapis","connect-src ","unsafe-eval'","child-src *"," *.gstatic","script-src","style-src ","frame-src","facebook","https://"," 'self'"," allow-",".com *.",".net *.","addthis","captcha","gstatic","youtube","defaul","disqus","google","https:","jquery","data:","http:","media","scrip","-src",".com",".net","n.cc"," *.","age","box","str","vic","yti"," '"," *","*.","al","am","an","as","cd","el","es","il","im","in","or","pi","st","ur","wi","wp"," ","-",";",":",".","'","*","/","3","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y"],T=["/homad-global-configs.schneevonmorgen.com/global_config","/videojs-vast-vpaid@2.0.2/bin/videojs_5.vast.vpaid.min","/etc.clientlibs/logitech-common/clientlibs/onetrust.","/pagead/managed/js/adsense/*/show_ads_impl","/pagead/managed/js/gpt/*/pubads_impl","/wrappermessagingwithoutdetection","/pagead/js/adsbygoogle.js","a-z]{8,15}\\.(?:com|net)\\/","/js/sdkloader/ima3.js","/js/sdkloader/ima3_d","/videojs-contrib-ads","/wp-content/plugins/","/wp-content/uploads/","/wp-content/themes/","/detroitchicago/","*/satellitelib-","/appmeasurement","/413gkwmt/init","/cdn-cgi/trace","/^https?:\\/\\/","[a-zA-Z0-9]{","/^https:\\/\\/","notification","\\/[a-z0-9]{","fingerprint","impression","[0-9a-z]{","/plugins/","affiliate","analytics","telemetry","(.+?\\.)?","/assets/","/images/","/pagead/","pageview","template","tracking","/public","300x250","ampaign","captcha","collect","consent","content","counter","default","metrics","privacy","[a-z]{","/embed","728x90","banner","bundle","client","cookie","detect","dn-cgi","google","iframe","module","prebid","script","source","widget",".aspx",".cgi?",".com/",".html","/api/","/beac","/img/","/java","/stat","0x600","block","click","count","event","manag","media","pixel","popup","tegra","theme","track","type=","video","visit",".css",".gif",".jpg",".min",".php",".png","/jqu","/js/","/lib","/log","/web","/wp-","468x","data","gdpr","gi-b","http","ight","mail","play","plug","publ","show","stat","uild","view",".js","/ad","=*&","age","com","ext","jax","key","log","new","sdk","tag","web","ync",":/","*/","*^","/_","/?","/*","/d","/f","/g","/h","/l","/n","/r","/u","/w","ac","ad","al","am","an","ap","ar","as","at","bo","ce","ch","co","de","e/","ec","ed","el","en","er","et","fi","g/","ic","id","im","in","is","it","js","la","le","li","lo","ma","mo","mp","ol","om","on","op","or","ot","re","ro","s_","s-","s?","s/","sp","ss","st","t/","ti","tm","tr","ub","un","ur","us","ut","ve","_","-",",","?",".","}","*","/","\\","&","^","=","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],P=["securepubads.g.doubleclick",".actonservice.com","googlesyndication","imasdk.googleapis",".cloudfront.net","googletagmanag","-1.xx.fbcdn","analytics.","marketing.","tracking.","metrics.","images.",".co.uk","a8clk.","stats.","a8cv.","click","media","track",".com",".net",".xyz","www.",".io",".jp","a8.","app","cdn","new","web",".b",".c",".d",".f",".h",".k",".m",".n",".p",".s",".t","10","24","a-","a1","a2","a4","ab","ac","ad","af","ag","ah","ai","ak","al","am","an","ap","ar","as","at","au","av","aw","ax","ay","az","be","bi","bl","bo","br","bu","ca","ce","ch","ci","ck","cl","cr","ct","cu","de","di","dn","do","dr","ds","du","dy","e-","eb","ec","ed","ef","eg","el","em","en","ep","er","es","et","eu","ev","ew","ex","ey","fe","ff","fi","fo","fr","ft","ge","gh","gi","gn","go","gr","gu","he","ho","ib","ic","id","ie","if","ig","ik","il","im","in","ip","ir","is","it","iv","ix","iz","jo","ks","la","le","li","ll","lo","lu","ly","ma","me","mo","mp","my","no","ok","ol","om","on","oo","op","or","ot","ou","ph","pl","po","pr","pu","qu","re","ri","ro","ru","s-","sc","se","sh","si","sk","sn","so","sp","ss","st","su","sw","sy","t-","ta","te","th","ti","tn","to","tr","ts","tu","ty","ub","ud","ul","um","un","up","ur","us","ut","ve","vi","vo","wa","we","wh","wn","-",".","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],R=["google-analytics.com/analytics.js","googlesyndication_adsbygoogle.js","googletagmanager.com/gtm.js","googletagservices_gpt.js","googletagmanager_gtm.js","fuckadblock.js-3.2.0","amazon_apstag.js","google-analytics","fingerprint2.js","noop-1s.mp4:10","google-ima.js","noop-0.1s.mp3","prebid-ads.js","nobab2.js:10","noopmp3-0.1s","noop-1s.mp4","hd-main.js","noopmp4-1s","32x32.png","noop.html","noopframe","noop.txt","nooptext","1x1.gif","2x2.png","noop.js","noopjs",".com/",".js:5","noop",":10",".js","ads","bea","_a",":5",".0","ar","ch","ic","in","le","ma","on","re","st","_","-",":",".","/","0","1","2","3","4","5","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","r","s","t","u","v","w","x","y","z"],z=[",redirect=google-ima","/js/sdkloader/ima3.j","/wp-content/plugins/",",redirect-rule=noop",".actonservice.com^",".com^$third-party","googlesyndication","imasdk.googleapis",".cloudfront.net^",",redirect-rule=","$script,domain=",",3p,denyallow=",",redirect=noop","xmlhttprequest","^$third-party","||smetrics.","third-party","marketing.","$document","analytics",",domain=","/assets/","metrics.","subdocum","tracking","$script",".co.uk","$ghide","a8clk.","cookie","google","script",".com^",".xyz^","$doma","a8cv.","click","image","media","track",".com",".fr^",".gif",".jp^",".net","/js/","$doc","$xhr","stat","www.",",1p",",3p",".io",".jp",".js","app","cdn","ent","new","web",".b",".c",".d",".f",".h",".m",".n",".p",".s",".t","@@","/*","/p","||","ab","ac","ad","af","ag","ai","ak","al","am","an","ap","ar","as","at","au","av","aw","ax","ay","az","be","bi","bo","br","ca","ce","ch","ck","cl","ct","cu","de","di","do","e-","e^","ec","ed","el","em","en","ep","er","es","et","ev","ew","ex","fe","ff","fi","fo","fr","g^","ge","gi","go","gr","he","hi","ho","hp","ht","ic","id","ig","il","im","in","ip","ir","is","it","ix","js","ke","le","li","lo","lu","ly","me","mo","mp","ne","no","od","ok","ol","om","on","op","or","ot","ow","pl","po","pr","qu","re","ri","ro","ru","s-","s/","sc","se","sh","si","so","sp","ss","st","su","te","th","ti","to","tr","ts","ty","ub","ud","ul","um","un","up","ur","us","ut","ve","vi","_","-",",","?",".","*","/","^","=","|","~","$","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],L=["-webkit-touch-callo",", 1year, , domain, ",", googlesyndication",", SOCS, CAISNQgQEit",":style(overflow: au","##^script:has-text(","9udGVuZHVpc2VydmVyX","GgJmaSADGgYIgOu0sgY","ib3FfaWRlbnRpdHlmcm","position: initial !","set-local-storage-i","set, blurred, false","user-select: text !","zIwMjQwNTE0LjA2X3Aw",'[href^="https://',"rmnt, script, ","ut: default !"," !important)","trusted-set-",", document.",", noopFunc)","##body,html","contextmenu","no-fetch-if","otification",".com##+js(",'="https://',"background","important;"," -webkit-",".*,xhamst","container","AAAAAAAA","nostif, ",",google",":style(","consent","message","nowoif)","privacy","-wrapp",",kayak",".co.uk","[class","##+js(","accept","aopr, ","banner","bottom","cookie","Cookie","google","notice","policy","widget",":has(","##div","block","cript","true)",".co.",".com",".de,",".fr,",".net",".nl,",".pl,",".xyz","#@#.","2%3A","gdpr","html","ight","news","text","to !","wrap","www."," > ",",xh","##.","###","%3D","%7C","ent","lay","web","__","-s",", ",",b",",c",",f",",g",",h",",m",",p",",s",",t",": ",".*",".b",".c",".m",".p",".s",'"]',"##","%2","%5",'="',"00","a-","ab","ac","ad","Ad","af","ag","ak","al","am","an","ap","ar","as","at","au","av","ay","az","bo","ch","ck","cl","ct","de","di","do","e-","ed","el","em","en","er","es","et","ex","fi","fo","he","ic","id","if","ig","il","im","in","is","it","iv","le","lo","mo","ol","om","on","op","or","ot","ov","pl","po","re","ro","s_","s-","se","sh","si","sp","st","t-","th","ti","tr","tv","ub","ul","um","un","up","ur","us","ut","vi"," ","_","-",",",":",".","(",")","[","*","/","^","0","1","2","3","4","5","6","7","8","9","a","b","B","c","C","d","D","e","E","f","F","g","h","i","j","k","l","L","m","M","n","o","p","P","q","r","s","S","t","T","u","v","w","x","y","z"],B=class{constructor(){this.cosmeticSelector=new I(F),this.networkCSP=new I(O),this.networkRedirect=new I(R),this.networkHostname=new I(P),this.networkFilter=new I(T),this.networkRaw=new I(z),this.cosmeticRaw=new I(L)}},U=(()=>{let e=0;const t=new Int32Array(256);for(let o=0;256!==o;o+=1)e=o,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,t[o]=e;return t})();var N=2147483647,V=36,j=1,M=26,D=38,H=700,W=72,q=128,G="-",$=/[^\0-\x7E]/,K=/[\x2E\u3002\uFF0E\uFF61]/g,Q={"invalid-input":"Invalid input","not-basic":"Illegal input >= 0x80 (not a basic code point)",overflow:"Overflow: input needs wider integers to process"},Y=V-j;function X(e){throw new RangeError(Q[e])}function Z(e,t){return e+22+75*(e<26?1:0)-((0!==t?1:0)<<5)}function J(e,t,o){let i=0;for(e=o?Math.floor(e/H):e>>1,e+=Math.floor(e/t);e>Y*M>>1;i+=V)e=Math.floor(e/Y);return Math.floor(i+(Y+1)*e/(e+D))}function ee(e){const t=[],o=e.length;let i=0,n=q,s=W,c=e.lastIndexOf(G);c<0&&(c=0);for(let o=0;o=128&&X("not-basic"),t.push(e.charCodeAt(o));for(let a=c>0?c+1:0;a=o&&X("invalid-input");const c=(r=e.charCodeAt(a++))-48<10?r-22:r-65<26?r-65:r-97<26?r-97:V;(c>=V||c>Math.floor((N-i)/t))&&X("overflow"),i+=c*t;const l=n<=s?j:n>=s+M?M:n-s;if(cMath.floor(N/p)&&X("overflow"),t*=p}const l=t.length+1;s=J(i-c,l,0===c),Math.floor(i/l)>N-n&&X("overflow"),n+=Math.floor(i/l),i%=l,t.splice(i++,0,n)}var r;return String.fromCodePoint.apply(null,t)}function te(e){const t=[],o=function(e){const t=[];let o=0;const i=e.length;for(;o=55296&&n<=56319&&o=n&&iMath.floor((N-s)/i)&&X("overflow"),s+=(e-n)*i,n=e;for(let e=0;eN&&X("overflow"),l===n){let e=s;for(let o=V;;o+=V){const i=o<=c?j:o>=c+M?M:o-c;if(e{const e=new B;return ce=()=>e,e};function re(e){return e<=127?1:5}function ae(e,t){return le(e.length,t)}function le(e,t){return(t?3:0)+e+re(e)}function pe(e){return e.length+re(e.length)}function de(e){const t=te(e).length;return t+re(t)}function ue(e){return e.byteLength+re(e.length)}var he,me=class e{static empty(t){return e.fromUint8Array(ie,t)}static fromUint8Array(t,o){return new e(t,o)}static allocate(t,o){return new e(new Uint8Array(t),o)}constructor(e,{enableCompression:t}){if(!1===se)throw new Error("Adblocker currently does not support Big-endian systems");!0===t&&this.enableCompression(),this.buffer=e,this.pos=0}enableCompression(){this.compression=ce()}checksum(){return function(e,t,o){let i=-1;const n=o-7;let s=t;for(;s>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])];for(;s>>8^U[255&(i^e[s++])];return(-1^i)>>>0}(this.buffer,0,this.pos)}dataAvailable(){return this.pos>>8,this.buffer[this.pos++]=e}getUint16(){return(this.buffer[this.pos++]<<8|this.buffer[this.pos++])>>>0}pushUint32(e){this.buffer[this.pos++]=e>>>24,this.buffer[this.pos++]=e>>>16,this.buffer[this.pos++]=e>>>8,this.buffer[this.pos++]=e}getUint32(){return(this.buffer[this.pos++]<<24>>>0)+(this.buffer[this.pos++]<<16|this.buffer[this.pos++]<<8|this.buffer[this.pos++])>>>0}pushUint32Array(e){this.pushLength(e.length);for(const t of e)this.pushUint32(t)}getUint32Array(){const e=this.getLength(),t=new Uint32Array(e);for(let o=0;othis.buffer.byteLength)throw new Error(`StaticDataView too small: ${this.buffer.byteLength}, but required ${this.pos} bytes`)}pushLength(e){e<=127?this.pushUint8(e):(this.pushUint8(128),this.pushUint32(e))}getLength(){const e=this.getUint8();return 128===e?this.getUint32():e}},Ae=class e{static deserialize(t){return new e({debug:t.getBool(),enableCompression:t.getBool(),enableHtmlFiltering:t.getBool(),enableInMemoryCache:t.getBool(),enableMutationObserver:t.getBool(),enableOptimizations:t.getBool(),enablePushInjectionsOnNavigationEvents:t.getBool(),guessRequestTypeFromUrl:t.getBool(),integrityCheck:t.getBool(),loadCSPFilters:t.getBool(),loadCosmeticFilters:t.getBool(),loadExceptionFilters:t.getBool(),loadExtendedSelectors:t.getBool(),loadGenericCosmeticsFilters:t.getBool(),loadNetworkFilters:t.getBool(),loadPreprocessors:t.getBool()})}constructor({debug:e=!1,enableCompression:t=!1,enableHtmlFiltering:o=!1,enableInMemoryCache:i=!0,enableMutationObserver:n=!0,enableOptimizations:s=!0,enablePushInjectionsOnNavigationEvents:c=!0,guessRequestTypeFromUrl:r=!1,integrityCheck:a=!0,loadCSPFilters:l=!0,loadCosmeticFilters:p=!0,loadExceptionFilters:d=!0,loadExtendedSelectors:u=!1,loadGenericCosmeticsFilters:h=!0,loadNetworkFilters:m=!0,loadPreprocessors:A=!1}={}){this.debug=e,this.enableCompression=t,this.enableHtmlFiltering=o,this.enableInMemoryCache=i,this.enableMutationObserver=n,this.enableOptimizations=s,this.enablePushInjectionsOnNavigationEvents=c,this.guessRequestTypeFromUrl=r,this.integrityCheck=a,this.loadCSPFilters=l,this.loadCosmeticFilters=p,this.loadExceptionFilters=d,this.loadExtendedSelectors=u,this.loadGenericCosmeticsFilters=h,this.loadNetworkFilters=m,this.loadPreprocessors=A}getSerializedSize(){return 16}serialize(e){e.pushBool(this.debug),e.pushBool(this.enableCompression),e.pushBool(this.enableHtmlFiltering),e.pushBool(this.enableInMemoryCache),e.pushBool(this.enableMutationObserver),e.pushBool(this.enableOptimizations),e.pushBool(this.enablePushInjectionsOnNavigationEvents),e.pushBool(this.guessRequestTypeFromUrl),e.pushBool(this.integrityCheck),e.pushBool(this.loadCSPFilters),e.pushBool(this.loadCosmeticFilters),e.pushBool(this.loadExceptionFilters),e.pushBool(this.loadExtendedSelectors),e.pushBool(this.loadGenericCosmeticsFilters),e.pushBool(this.loadNetworkFilters),e.pushBool(this.loadPreprocessors)}},ge="undefined"!=typeof window&&"function"==typeof window.queueMicrotask?e=>window.queueMicrotask(e):e=>(he||(he=Promise.resolve())).then(e).catch((e=>setTimeout((()=>{throw e}),0)));function fe(e,t,o){let i=o.get(e);void 0===i&&(i=[],o.set(e,i)),i.push(t)}function ke(e,t,o){const i=o.get(e);if(void 0!==i){const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}function be(e,t,o){if(0===o.size)return!1;const i=o.get(e);return void 0!==i&&(ge((()=>{for(const e of i)e(...t)})),!0)}var ye=class{constructor(){this.onceListeners=new Map,this.onListeners=new Map}on(e,t){fe(e,t,this.onListeners)}once(e,t){fe(e,t,this.onceListeners)}unsubscribe(e,t){ke(e,t,this.onListeners),ke(e,t,this.onceListeners)}emit(e,...t){be(e,t,this.onListeners),!0===be(e,t,this.onceListeners)&&this.onceListeners.delete(e)}};function we(e,t){return function(e,t){let o=3;const i=()=>e(t).catch((e=>{if(o>0)return o-=1,new Promise(((e,t)=>{setTimeout((()=>{i().then(e).catch(t)}),500)}));throw e}));return i()}(e,t).then((e=>e.text()))}var ve="https://raw.githubusercontent.com/ghostery/adblocker/master/packages/adblocker/assets",_e=[`${ve}/easylist/easylist.txt`,`${ve}/peter-lowe/serverlist.txt`,`${ve}/ublock-origin/badware.txt`,`${ve}/ublock-origin/filters-2020.txt`,`${ve}/ublock-origin/filters-2021.txt`,`${ve}/ublock-origin/filters-2022.txt`,`${ve}/ublock-origin/filters-2023.txt`,`${ve}/ublock-origin/filters-2024.txt`,`${ve}/ublock-origin/filters.txt`,`${ve}/ublock-origin/quick-fixes.txt`,`${ve}/ublock-origin/resource-abuse.txt`,`${ve}/ublock-origin/unbreak.txt`],Ce=[..._e,`${ve}/easylist/easyprivacy.txt`,`${ve}/ublock-origin/privacy.txt`],xe=[...Ce,`${ve}/easylist/easylist-cookie.txt`,`${ve}/ublock-origin/annoyances-others.txt`,`${ve}/ublock-origin/annoyances-cookies.txt`];var Se=new Set(["any","dir","has","host-context","if","if-not","is","matches","not","where"]),Ee={attribute:/\[\s*(?:(?\*|[-\w]*)\|)?(?[-\w\u{0080}-\u{FFFF}]+)\s*(?:(?\W?=)\s*(?.+?)\s*(?[iIsS])?\s*)?\]/gu,id:/#(?(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,class:/\.(?(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,comma:/\s*,\s*/g,combinator:/\s*[\s>+~]\s*/g,"pseudo-element":/::(?[-\w\u{0080}-\u{FFFF}]+)(?:\((?:¶*)\))?/gu,"pseudo-class":/:(?[-\w\u{0080}-\u{FFFF}]+)(?:\((?¶*)\))?/gu,type:/(?:(?\*|[-\w]*)\|)?(?[-\w\u{0080}-\u{FFFF}]+)|\*/gu},Ie=new Set(["pseudo-class","pseudo-element"]),Fe=new Set([...Ie,"attribute"]),Oe=new Set(["combinator","comma"]),Te=Object.assign({},Ee);function Pe(e,t){e.lastIndex=0;const o=e.exec(t);if(null===o)return;const i=o.index-1,n=o[0],s=t.slice(0,i+1),c=t.slice(i+n.length+1);return[s,[n,o.groups||{}],c]}Te["pseudo-element"]=RegExp(Ee["pseudo-element"].source.replace("(?¶*)","(?.*?)"),"gu"),Te["pseudo-class"]=RegExp(Ee["pseudo-class"].source.replace("(?¶*)","(?.*)"),"gu");var Re=[e=>{const t=Pe(Ee.attribute,e);if(void 0===t)return;const[o,[i,{name:n,operator:s,value:c,namespace:r,caseSensitive:a}],l]=t;return void 0!==n?[o,{type:"attribute",content:i,length:i.length,namespace:r,caseSensitive:a,pos:[],name:n,operator:s,value:c},l]:void 0},e=>{const t=Pe(Ee.id,e);if(void 0===t)return;const[o,[i,{name:n}],s]=t;return void 0!==n?[o,{type:"id",content:i,length:i.length,pos:[],name:n},s]:void 0},e=>{const t=Pe(Ee.class,e);if(void 0===t)return;const[o,[i,{name:n}],s]=t;return void 0!==n?[o,{type:"class",content:i,length:i.length,pos:[],name:n},s]:void 0},e=>{const t=Pe(Ee.comma,e);if(void 0===t)return;const[o,[i],n]=t;return[o,{type:"comma",content:i,length:i.length,pos:[]},n]},e=>{const t=Pe(Ee.combinator,e);if(void 0===t)return;const[o,[i],n]=t;return[o,{type:"combinator",content:i,length:i.length,pos:[]},n]},e=>{const t=Pe(Ee["pseudo-element"],e);if(void 0===t)return;const[o,[i,{name:n}],s]=t;return void 0!==n?[o,{type:"pseudo-element",content:i,length:i.length,pos:[],name:n},s]:void 0},e=>{const t=Pe(Ee["pseudo-class"],e);if(void 0===t)return;const[o,[i,{name:n,argument:s}],c]=t;return void 0!==n?[o,{type:"pseudo-class",content:i,length:i.length,pos:[],name:n,argument:s,subtree:void 0},c]:void 0},e=>{const t=Pe(Ee.type,e);if(void 0===t)return;const[o,[i,{name:n,namespace:s}],c]=t;return[o,{type:"type",content:i,length:i.length,namespace:s,pos:[],name:n},c]}];function ze(e,t,o,i){for(const n of t)for(const t of e)if(i.has(t.type)&&t.pos[0]=0&&"\\"===e[t];)o+=1,t-=1;return o%2!=0}function Be(e,t,o){let i=o+1;for(;-1!==(i=e.indexOf(t,i))&&!0===Le(e,i);)i+=1;if(-1!==i)return e.slice(o,i+1)}function Ue(e,t){let o=0;for(let i=t;i0))return;o-=1}if(0===o)return e.slice(t,i+1)}}function Ne(e,t,o,i){const n=[];let s=0;for(;-1!==(s=e.indexOf(o,s));){const o=i(e,s);if(void 0===o)break;n.push({str:o,start:s}),e=`${e.slice(0,s+1)}${t.repeat(o.length-2)}${e.slice(s+o.length-1)}`,s+=o.length}return[n,e]}function Ve(e){if("string"!=typeof e)return[];if(0===(e=e.trim()).length)return[];const[t,o]=Ne(e,"§",'"',((e,t)=>Be(e,'"',t))),[i,n]=Ne(o,"§","'",((e,t)=>Be(e,"'",t))),[s,c]=Ne(n,"¶","(",Ue),r=function(e){if(!e)return[];const t=[e];for(const e of Re)for(let o=0;o0!==e.length)))}}let o=0;for(const e of t)"string"!=typeof e&&(e.pos=[o,o+e.length],Oe.has(e.type)&&(e.content=e.content.trim()||" ")),o+=e.length;return t.every((e=>"string"!=typeof e))?t:[]}(c);return ze(r,s,/\(¶*\)/,Ie),ze(r,t,/"§*"/,Fe),ze(r,i,/'§*'/,Fe),r}function je(e,{list:t=!0}={}){if(!0===t&&e.some((e=>"comma"===e.type))){const t=[],o=[];for(let i=0;i=0;t--){const o=e[t];if("combinator"===o.type){const i=je(e.slice(0,t)),n=je(e.slice(t+1));if(void 0===n)return;if(" "!==o.content&&"~"!==o.content&&"+"!==o.content&&">"!==o.content)return;return{type:"complex",combinator:o.content,left:i,right:n}}}if(0!==e.length)return function(e){return e.every((e=>"comma"!==e.type&&"combinator"!==e.type))}(e)?1===e.length?e[0]:{type:"compound",compound:[...e]}:void 0}function Me(e,t,o,i){if(void 0!==e){if("complex"===e.type)Me(e.left,t,o,e),Me(e.right,t,o,e);else if("compound"===e.type)for(const i of e.compound)Me(i,t,o,e);else"pseudo-class"===e.type&&void 0!==e.subtree&&void 0!==o&&"pseudo-class"===o.type&&void 0!==o.subtree&&Me(e.subtree,t,o,e);t(e,i)}}function De(e,{recursive:t=!0,list:o=!0}={}){const i=Ve(e);if(0===i.length)return;const n=je(i,{list:o});return!0===t&&Me(n,(e=>{"pseudo-class"===e.type&&e.argument&&void 0!==e.name&&Se.has(e.name)&&(e.subtree=De(e.argument,{recursive:!0,list:!0}))})),n}var He,We,qe=new Set(["has","has-text","if"]),Ge=new Set(["active","any","any-link","blank","checked","default","defined","dir","disabled","empty","enabled","first","first-child","first-of-type","focus","focus-visible","focus-within","fullscreen","host","host-context","hover","in-range","indeterminate","invalid","is","lang","last-child","last-of-type","left","link","matches","not","nth-child","nth-last-child","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","placeholder-shown","read-only","read-write","required","right","root","scope","target","valid","visited","where"]),$e=new Set(["after","before","first-letter","first-line"]);function Ke(e){if(-1===e.indexOf(":"))return He.Normal;const t=Ve(e);let o=!1;for(const e of t)if("pseudo-class"===e.type){const{name:t}=e;if(!0===qe.has(t))o=!0;else if(!1===Ge.has(t)&&!1===$e.has(t))return He.Invalid;if(!1===o&&void 0!==e.argument&&!0===Se.has(t)){const t=Ke(e.argument);if(t===He.Invalid)return t;t===He.Extended&&(o=!0)}}return!0===o?He.Extended:He.Normal}(We=He||(He={}))[We.Normal=0]="Normal",We[We.Extended=1]="Extended",We[We.Invalid=2]="Invalid";var Qe=new Set(["htm","html","xhtml"]),Ye=new Set(["eot","otf","sfnt","ttf","woff","woff2"]),Xe=new Set(["apng","bmp","cur","dib","eps","gif","heic","heif","ico","j2k","jfi","jfif","jif","jp2","jpe","jpeg","jpf","jpg","jpm","jpx","mj2","pjp","pjpeg","png","svg","svgz","tif","tiff","webp"]),Ze=new Set(["avi","flv","mp3","mp4","ogg","wav","weba","webm","wmv"]),Je=new Set(["js","ts","jsx","esm"]),et=new Set(["css","scss"]);function tt(e,t){let o=0,i=e.length,n=!1;if(!t){if(e.startsWith("data:"))return null;for(;oo+1&&e.charCodeAt(i-1)<=32;)i-=1;if(47===e.charCodeAt(o)&&47===e.charCodeAt(o+1))o+=2;else{const t=e.indexOf(":/",o);if(-1!==t){const i=t-o,n=e.charCodeAt(o),s=e.charCodeAt(o+1),c=e.charCodeAt(o+2),r=e.charCodeAt(o+3),a=e.charCodeAt(o+4);if(5===i&&104===n&&116===s&&116===c&&112===r&&115===a);else if(4===i&&104===n&&116===s&&116===c&&112===r);else if(3===i&&119===n&&115===s&&115===c);else if(2===i&&119===n&&115===s);else for(let i=o;i=97&&t<=122||t>=48&&t<=57||46===t||45===t||43===t))return null}for(o=t+2;47===e.charCodeAt(o);)o+=1}}let t=-1,s=-1,c=-1;for(let r=o;r=65&&o<=90&&(n=!0)}if(-1!==t&&t>o&&to&&co+1&&46===e.charCodeAt(i-1);)i-=1;const s=0!==o||i!==e.length?e.slice(o,i):e;return n?s.toLowerCase():s}function ot(e){return e>=97&&e<=122||e>=48&&e<=57||e>127}function it(e){if(e.length>255)return!1;if(0===e.length)return!1;if(!ot(e.charCodeAt(0))&&46!==e.charCodeAt(0)&&95!==e.charCodeAt(0))return!1;let t=-1,o=-1;const i=e.length;for(let n=0;n64||46===o||45===o||95===o)return!1;t=n}else if(!ot(i)&&45!==i&&95!==i)return!1;o=i}return i-t-1<=63&&45!==o}var nt=function({allowIcannDomains:e=!0,allowPrivateDomains:t=!1,detectIp:o=!0,extractHostname:i=!0,mixedInputs:n=!0,validHosts:s=null,validateHostname:c=!0}){return{allowIcannDomains:e,allowPrivateDomains:t,detectIp:o,extractHostname:i,mixedInputs:n,validHosts:s,validateHostname:c}}({});function st(e,t,o,i,n){const s=function(e){return void 0===e?nt:function({allowIcannDomains:e=!0,allowPrivateDomains:t=!1,detectIp:o=!0,extractHostname:i=!0,mixedInputs:n=!0,validHosts:s=null,validateHostname:c=!0}){return{allowIcannDomains:e,allowPrivateDomains:t,detectIp:o,extractHostname:i,mixedInputs:n,validHosts:s,validateHostname:c}}(e)}(i);return"string"!=typeof e?n:(s.extractHostname?s.mixedInputs?n.hostname=tt(e,it(e)):n.hostname=tt(e,!1):n.hostname=e,0===t||null===n.hostname||s.detectIp&&(n.isIp=function(e){if(e.length<3)return!1;let t=e.startsWith("[")?1:0,o=e.length;if("]"===e[o-1]&&(o-=1),o-t>39)return!1;let i=!1;for(;t=48&&o<=57||o>=97&&o<=102||o>=65&&o<=90))return!1}return i}(c=n.hostname)||function(e){if(e.length<7)return!1;if(e.length>15)return!1;let t=0;for(let o=0;o57)return!1}return 3===t&&46!==e.charCodeAt(0)&&46!==e.charCodeAt(e.length-1)}(c),n.isIp)?n:s.validateHostname&&s.extractHostname&&!it(n.hostname)?(n.hostname=null,n):(o(n.hostname,s,n),2===t||null===n.publicSuffix?n:(n.domain=function(e,t,o){if(null!==o.validHosts){const e=o.validHosts;for(const o of e)if(function(e,t){return!!e.endsWith(t)&&(e.length===t.length||"."===e[e.length-t.length-1])}(t,o))return o}let i=0;if(t.startsWith("."))for(;i=i)return!1;let n=o,s=i-1;for(;n<=s;){const o=n+s>>>1,i=e[o];if(it))return!0;s=o-1}}return!1}var at=new Uint32Array(20);function lt(e,t,o){if(function(e,t,o){if(!t.allowPrivateDomains&&e.length>3){const t=e.length-1,i=e.charCodeAt(t),n=e.charCodeAt(t-1),s=e.charCodeAt(t-2),c=e.charCodeAt(t-3);if(109===i&&111===n&&99===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="com",!0;if(103===i&&114===n&&111===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="org",!0;if(117===i&&100===n&&101===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="edu",!0;if(118===i&&111===n&&103===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="gov",!0;if(116===i&&101===n&&110===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="net",!0;if(101===i&&100===n&&46===s)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="de",!0}return!1}(e,t,o))return;const{allowIcannDomains:i,allowPrivateDomains:n}=t;let s=-1,c=0,r=0,a=1;const l=function(e,t){let o=5381,i=0;for(let n=e.length-1;n>=0;n-=1){const s=e.charCodeAt(n);if(46===s&&(at[i<<1]=o>>>0,at[1+(i<<1)]=n+1,i+=1,i===t))return i;o=33*o^s}return at[i<<1]=o>>>0,at[1+(i<<1)]=0,i+=1,i}(e,ct[0]);for(let e=0;er;)t.shift();o.publicSuffix=t.join(".")}else o.publicSuffix=e.slice(at[1+(r-2<<1)]);else o.publicSuffix=1===l?e:e.slice(at[1])}function pt(e,t={}){return st(e,5,lt,t,{domain:null,domainWithoutSuffix:null,hostname:null,isIcann:null,isIp:null,isPrivate:null,publicSuffix:null,subdomain:null})}var dt=new class{constructor(e){this.pos=0,this.buffer=new Uint32Array(e)}reset(){this.pos=0}slice(){return this.buffer.slice(0,this.pos)}push(e){this.buffer[this.pos++]=e}empty(){return 0===this.pos}full(){return this.pos===this.buffer.length}remaining(){return this.buffer.length-this.pos}}(1024),ut=37,ht=5011;function mt(e){return 16843009*((e=(858993459&(e-=e>>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135)>>24}function At(e,t){return!!(e&t)}function gt(e,t){return e|t}function ft(e,t){return e&~t}function kt(e,t,o){let i=ht;for(let n=t;n>>0}function bt(e){return"string"!=typeof e||0===e.length?ht:kt(e,0,e.length)}function yt(e){const t=new Uint32Array(e.length);let o=0;for(const i of e)t[o++]=bt(i);return t}function wt(e,t){if(e.length=48&&e<=57}function Ct(e){return e>=97&&e<=122||e>=65&&e<=90}function xt(e){return Ct(e)||_t(e)||37===e||function(e){return e>=192&&e<=450}(e)||function(e){return e>=1024&&e<=1279}(e)}function St(e,t,o,i){const n=Math.min(e.length,2*i.remaining());let s=!1,c=0,r=ht;for(let o=0;o1&&(!1===t||0!==c)&&i.push(r>>>0))}!0===s&&!1===o&&e.length-c>1&&!1===i.full()&&i.push(r>>>0)}function Et(e,t){const o=Math.min(e.length,2*t.remaining());let i=!1,n=0,s=ht;for(let c=0;c1&&t.push(s>>>0))}!0===i&&e.length-n>1&&!1===t.full()&&t.push(s>>>0)}function It(e,t){return-1!==function(e,t){if(0===e.length)return-1;let o=0,i=e.length-1;for(;o<=i;){const n=o+i>>>1,s=e[n];if(st))return n;i=n-1}}return-1}(e,t)}var Ft=/[^\u0000-\u00ff]/;function Ot(e){return Ft.test(e)}var Tt={extractHostname:!0,mixedInputs:!1,validateHostname:!1},Pt={beacon:bt("type:beacon"),cspReport:bt("type:csp"),csp_report:bt("type:csp"),cspviolationreport:bt("type:cspviolationreport"),document:bt("type:document"),eventsource:bt("type:other"),fetch:bt("type:xhr"),font:bt("type:font"),image:bt("type:image"),imageset:bt("type:image"),mainFrame:bt("type:document"),main_frame:bt("type:document"),manifest:bt("type:other"),media:bt("type:media"),object:bt("type:object"),object_subrequest:bt("type:object"),other:bt("type:other"),ping:bt("type:ping"),prefetch:bt("type:other"),preflight:bt("type:preflight"),script:bt("type:script"),signedexchange:bt("type:signedexchange"),speculative:bt("type:other"),stylesheet:bt("type:stylesheet"),subFrame:bt("type:subdocument"),sub_frame:bt("type:subdocument"),texttrack:bt("type:other"),webSocket:bt("type:websocket"),web_manifest:bt("type:other"),websocket:bt("type:websocket"),xhr:bt("type:xhr"),xml_dtd:bt("type:other"),xmlhttprequest:bt("type:xhr"),xslt:bt("type:other")};function Rt(e){let t=ht;for(let o=e.length-1;o>=0;o-=1)t=t*ut^e.charCodeAt(o);return t>>>0}function zt(e,t,o){dt.reset();let i=ht;for(let n=t-1;n>=0;n-=1){const t=e.charCodeAt(n);46===t&&n>>0),i=i*ut^t}return dt.push(i>>>0),dt.slice()}function Lt(e,t){const o=function(e,t){let o=null;const i=t.indexOf(".");if(-1!==i){const n=t.slice(i+1);o=e.slice(0,-n.length-1)}return o}(e,t);return null!==o?zt(o,o.length,o.length):ne}function Bt(e,t){return zt(e,e.length,e.length-t.length)}var Ut=class e{static fromRawDetails({requestId:t="0",tabId:o=0,url:i="",hostname:n,domain:s,sourceUrl:c="",sourceHostname:r,sourceDomain:a,type:l="main_frame",_originalRequestDetails:p}){if(i=i.toLowerCase(),void 0===n||void 0===s){const e=pt(i,Tt);n=n||e.hostname||"",s=s||e.domain||""}if(void 0===r||void 0===a){const e=pt(r||a||c,Tt);r=r||e.hostname||"",a=a||e.domain||r||""}return new e({requestId:t,tabId:o,domain:s,hostname:n,url:i,sourceDomain:a,sourceHostname:r,sourceUrl:c,type:l,_originalRequestDetails:p})}constructor({requestId:e,tabId:t,type:o,domain:i,hostname:n,url:s,sourceDomain:c,sourceHostname:r,_originalRequestDetails:a}){if(this.tokens=void 0,this.hostnameHashes=void 0,this.entityHashes=void 0,this._originalRequestDetails=a,this.id=e,this.tabId=t,this.type=o,this.url=s,this.hostname=n,this.domain=i,this.sourceHostnameHashes=0===r.length?ne:Bt(r,c),this.sourceEntityHashes=0===r.length?ne:Lt(r,c),this.isThirdParty=function(e,t,o,i,n){return"main_frame"!==n&&"mainFrame"!==n&&(0!==t.length&&0!==i.length?t!==i:0!==t.length&&0!==o.length?t!==o:0!==i.length&&0!==e.length&&e!==i)}(n,i,r,c,o),this.isFirstParty=!this.isThirdParty,this.isSupported=!0,"websocket"===this.type||this.url.startsWith("ws:")||this.url.startsWith("wss:"))this.isHttp=!1,this.isHttps=!1,this.type="websocket",this.isSupported=!0;else if(this.url.startsWith("http:"))this.isHttp=!0,this.isHttps=!1;else if(this.url.startsWith("https:"))this.isHttps=!0,this.isHttp=!1;else if(this.url.startsWith("data:")){this.isHttp=!1,this.isHttps=!1;const e=this.url.indexOf(",");-1!==e&&(this.url=this.url.slice(0,e))}else this.isHttp=!1,this.isHttps=!1,this.isSupported=!1}getHostnameHashes(){return void 0===this.hostnameHashes&&(this.hostnameHashes=0===this.hostname.length?ne:Bt(this.hostname,this.domain)),this.hostnameHashes}getEntityHashes(){return void 0===this.entityHashes&&(this.entityHashes=0===this.hostname.length?ne:Lt(this.hostname,this.domain)),this.entityHashes}getTokens(){if(void 0===this.tokens){dt.reset();for(const e of this.sourceHostnameHashes)dt.push(e);dt.push(Pt[this.type]),Et(this.url,dt),this.tokens=dt.slice()}return this.tokens}isMainFrame(){return"main_frame"===this.type||"mainFrame"===this.type}isSubFrame(){return"sub_frame"===this.type||"subFrame"===this.type}guessTypeOfRequest(){const e=this.type;return this.type=function(e){const t=function(e){let t=e.length;const o=e.indexOf("#");-1!==o&&(t=o);const i=e.indexOf("?");-1!==i&&i=0&&(s=e.charCodeAt(n),0!=(s>=65&&s<=90||s>=97&&s<=122||s>=48&&s<=57));n-=1);return 46!==s||n<0||t-n>=10?"":e.slice(n+1,t)}(e);return Xe.has(t)||e.startsWith("data:image/")||e.startsWith("https://frog.wix.com/bt")?"image":Ze.has(t)||e.startsWith("data:audio/")||e.startsWith("data:video/")?"media":et.has(t)||e.startsWith("data:text/css")?"stylesheet":Je.has(t)||e.startsWith("data:")&&(e.startsWith("data:application/ecmascript")||e.startsWith("data:application/javascript")||e.startsWith("data:application/x-ecmascript")||e.startsWith("data:application/x-javascript")||e.startsWith("data:text/ecmascript")||e.startsWith("data:text/javascript")||e.startsWith("data:text/javascript1.0")||e.startsWith("data:text/javascript1.1")||e.startsWith("data:text/javascript1.2")||e.startsWith("data:text/javascript1.3")||e.startsWith("data:text/javascript1.4")||e.startsWith("data:text/javascript1.5")||e.startsWith("data:text/jscript")||e.startsWith("data:text/livescript")||e.startsWith("data:text/x-ecmascript")||e.startsWith("data:text/x-javascript"))||e.startsWith("https://maps.googleapis.com/maps/api/js")||e.startsWith("https://www.googletagmanager.com/gtag/js")?"script":Qe.has(t)||e.startsWith("data:text/html")||e.startsWith("data:application/xhtml")||e.startsWith("https://www.youtube.com/embed/")||e.startsWith("https://www.google.com/gen_204")?"document":Ye.has(t)||e.startsWith("data:font/")?"font":"other"}(this.url),e!==this.type&&(this.tokens=void 0),this.type}},Nt=class e{static parse(t,o=!1){if(0===t.length)return;const i=[],n=[],s=[],c=[];for(let e of t){Ot(e)&&(e=oe(e));const t=126===e.charCodeAt(0),o=42===e.charCodeAt(e.length-1)&&46===e.charCodeAt(e.length-2),r=t?1:0,a=o?e.length-2:e.length,l=Rt(!0===t||!0===o?e.slice(r,a):e);t?o?n.push(l):c.push(l):o?i.push(l):s.push(l)}return new e({entities:0!==i.length?new Uint32Array(i).sort():void 0,hostnames:0!==s.length?new Uint32Array(s).sort():void 0,notEntities:0!==n.length?new Uint32Array(n).sort():void 0,notHostnames:0!==c.length?new Uint32Array(c).sort():void 0,parts:!0===o?t.join(","):void 0})}static deserialize(t){const o=t.getUint8();return new e({entities:1==(1&o)?t.getUint32Array():void 0,hostnames:2==(2&o)?t.getUint32Array():void 0,notEntities:4==(4&o)?t.getUint32Array():void 0,notHostnames:8==(8&o)?t.getUint32Array():void 0,parts:16==(16&o)?t.getUTF8():void 0})}constructor({entities:e,hostnames:t,notEntities:o,notHostnames:i,parts:n}){this.entities=e,this.hostnames=t,this.notEntities=o,this.notHostnames=i,this.parts=n}updateId(e){const{hostnames:t,entities:o,notHostnames:i,notEntities:n}=this;if(void 0!==t)for(const o of t)e=e*ut^o;if(void 0!==o)for(const t of o)e=e*ut^t;if(void 0!==i)for(const t of i)e=e*ut^t;if(void 0!==n)for(const t of n)e=e*ut^t;return e}serialize(e){const t=e.getPos();e.pushUint8(0);let o=0;void 0!==this.entities&&(o|=1,e.pushUint32Array(this.entities)),void 0!==this.hostnames&&(o|=2,e.pushUint32Array(this.hostnames)),void 0!==this.notEntities&&(o|=4,e.pushUint32Array(this.notEntities)),void 0!==this.notHostnames&&(o|=8,e.pushUint32Array(this.notHostnames)),void 0!==this.parts&&(o|=16,e.pushUTF8(this.parts)),e.setByte(t,o)}getSerializedSize(){let e=1;return void 0!==this.entities&&(e+=ue(this.entities)),void 0!==this.hostnames&&(e+=ue(this.hostnames)),void 0!==this.notHostnames&&(e+=ue(this.notHostnames)),void 0!==this.notEntities&&(e+=ue(this.notEntities)),void 0!==this.parts&&(e+=de(this.parts)),e}match(e,t){if(void 0!==this.notHostnames)for(const t of e)if(It(this.notHostnames,t))return!1;if(void 0!==this.notEntities)for(const e of t)if(It(this.notEntities,e))return!1;if(void 0!==this.hostnames||void 0!==this.entities){if(void 0!==this.hostnames)for(const t of e)if(It(this.hostnames,t))return!0;if(void 0!==this.entities)for(const e of t)if(It(this.entities,e))return!0;return!1}return!0}};function Vt(e){if(!1===e.startsWith("^script"))return;const t=":has-text(",o=[];let i=7;for(;e.startsWith(t,i);){i+=10;let t=1;const n=i;let s=-1;for(;i=48&&o<=57||o>=65&&o<=90||o>=97&&o<=122)){if(t{}},t=/^[#.]?[\w-.]+$/;return function(o){if(t.test(o))return!0;try{(t=>{e.matches(t)})(o)}catch(e){return!1}return!0}})();function Yt(e,t){const o=e.getSelector();if(!1===e.isScriptInject())return o;const i=e.parseScript();if(void 0===i)return o;const n=t(i.name);return void 0===n?o:o.replace(i.name,n)}(Kt=$t||($t={}))[Kt.unhide=1]="unhide",Kt[Kt.scriptInject=2]="scriptInject",Kt[Kt.isUnicode=4]="isUnicode",Kt[Kt.isClassSelector=8]="isClassSelector",Kt[Kt.isIdSelector=16]="isIdSelector",Kt[Kt.isHrefSelector=32]="isHrefSelector",Kt[Kt.remove=64]="remove",Kt[Kt.extended=128]="extended";var Xt=class e{static parse(t,o=!1){const i=t;let n,s,c,r=0;const a=t.indexOf("#"),l=a+1;let p=l+1;if(t.length>l&&("@"===t[l]?(r=gt(r,$t.unhide),p+=1):"?"===t[l]&&(p+=1)),p>=t.length)return null;if(a>0&&(s=Nt.parse(t.slice(0,a).split(","),o)),t.endsWith(":remove()"))r=gt(r,$t.remove),r=gt(r,$t.extended),t=t.slice(0,-9);else if(t.length-p>=8&&t.endsWith(")")&&-1!==t.indexOf(":style(",p)){const e=t.indexOf(":style(",p);c=t.slice(e+7,-1),t=t.slice(0,e)}if(94===t.charCodeAt(p)){if(!1===vt(t,"script:has-text(",p+1)||41!==t.charCodeAt(t.length-1))return null;if(n=t.slice(p,t.length),void 0===Vt(n))return null}else if(t.length-p>4&&43===t.charCodeAt(p)&&vt(t,"+js(",p)){if((void 0===s||void 0===s.hostnames&&void 0===s.entities)&&!1===At(r,$t.unhide))return null;if(r=gt(r,$t.scriptInject),n=t.slice(p+4,t.length-1),!1===At(r,$t.unhide)&&0===n.length)return null}else{n=t.slice(p);const e=Ke(n);if(e===He.Extended)r=gt(r,$t.extended);else if(e===He.Invalid||!Qt(n))return null}if(void 0===s&&!0===At(r,$t.extended))return null;if(void 0!==n&&(Ot(n)&&(r=gt(r,$t.isUnicode)),!1===At(r,$t.scriptInject)&&!1===At(r,$t.remove)&&!1===At(r,$t.extended)&&!1===n.startsWith("^"))){const e=n.charCodeAt(0),t=n.charCodeAt(1),o=n.charCodeAt(2);!1===At(r,$t.scriptInject)&&(46===e&&qt(n)?r=gt(r,$t.isClassSelector):35===e&&qt(n)?r=gt(r,$t.isIdSelector):(97===e&&91===t&&104===o&&Gt(n,2)||91===e&&104===t&&Gt(n,1))&&(r=gt(r,$t.isHrefSelector)))}return new e({mask:r,rawLine:!0===o?i:void 0,selector:n,style:c,domains:s})}static deserialize(t){const o=t.getUint8(),i=At(o,$t.isUnicode),n=t.getUint8(),s=i?t.getUTF8():t.getCosmeticSelector();return new e({mask:o,selector:s,domains:1==(1&n)?Nt.deserialize(t):void 0,rawLine:2==(2&n)?t.getRawCosmetic():void 0,style:4==(4&n)?t.getASCII():void 0})}constructor({mask:e,selector:t,domains:o,rawLine:i,style:n}){this.mask=e,this.selector=t,this.domains=o,this.style=n,this.id=void 0,this.rawLine=i,this.scriptletDetails=void 0}isCosmeticFilter(){return!0}isNetworkFilter(){return!1}serialize(e){e.pushUint8(this.mask);const t=e.getPos();e.pushUint8(0),this.isUnicode()?e.pushUTF8(this.selector):e.pushCosmeticSelector(this.selector);let o=0;void 0!==this.domains&&(o|=1,this.domains.serialize(e)),void 0!==this.rawLine&&(o|=2,e.pushRawCosmetic(this.rawLine)),void 0!==this.style&&(o|=4,e.pushASCII(this.style)),e.setByte(t,o)}getSerializedSize(e){let t=2;return this.isUnicode()?t+=de(this.selector):t+=function(e,t){return!0===t?le(ce().cosmeticSelector.getCompressedSize(e),!1):pe(e)}(this.selector,e),void 0!==this.domains&&(t+=this.domains.getSerializedSize()),void 0!==this.rawLine&&(t+=function(e,t){return!0===t?le(ce().cosmeticRaw.getCompressedSize(te(e)),!1):de(e)}(this.rawLine,e)),void 0!==this.style&&(t+=pe(this.style)),t}toString(){if(void 0!==this.rawLine)return this.rawLine;let e="";return void 0!==this.domains&&(void 0!==this.domains.parts?e+=this.domains.parts:e+=""),this.isUnhide()?e+="#@#":e+="##",this.isScriptInject()?(e+="+js(",e+=this.selector,e+=")"):e+=this.selector,e}match(e,t){return!1===this.hasHostnameConstraint()||!(!e&&this.hasHostnameConstraint())&&(void 0===this.domains||this.domains.match(0===e.length?ne:Bt(e,t),0===e.length?ne:Lt(e,t)))}getTokens(){const e=[];if(void 0!==this.domains){const{hostnames:t,entities:o}=this.domains;if(void 0!==t)for(const o of t)e.push(new Uint32Array([o]));if(void 0!==o)for(const t of o)e.push(new Uint32Array([t]))}if(0===e.length&&!1===this.isUnhide())if(this.isIdSelector()||this.isClassSelector()){let t=1;const o=this.selector;for(;t0?n=!0:"'"===p&&e.indexOf("'",o+1)>0?s=!0:"{"===p&&e.indexOf("}",o+1)>0?r+=1:"/"===p&&e.indexOf("/",o+1)>0?c=!0:l=!0)),","===p&&(t.push(e.slice(i+1,o).trim()),i=o,l=!1))),a="\\"===p}if(t.push(e.slice(i+1).trim()),0===t.length)return;const p=t.slice(1).map((e=>e.startsWith("'")&&e.endsWith("'")||e.startsWith('"')&&e.endsWith('"')?e.substring(1,e.length-1):e)).map((e=>e.replace(Dt,",").replace(Ht,"\\").replace(Wt,",")));return this.scriptletDetails={name:t[0],args:p},this.scriptletDetails}getScript(e){const t=this.parseScript();if(void 0===t)return;const{name:o,args:i}=t;let n=e(o);if(void 0!==n){for(let e=0;e>>0}(this.mask,this.selector,this.domains,this.style)),this.id}hasCustomStyle(){return void 0!==this.style}getStyle(e=Mt){return this.style||e}getStyleAttributeHash(){return`s${bt(this.getStyle())}`}getSelector(){return this.selector}getSelectorAST(){return De(this.getSelector())}getExtendedSelector(){return Vt(this.selector)}isExtended(){return At(this.mask,$t.extended)}isRemove(){return At(this.mask,$t.remove)}isUnhide(){return At(this.mask,$t.unhide)}isScriptInject(){return At(this.mask,$t.scriptInject)}isCSS(){return!1===this.isScriptInject()}isIdSelector(){return At(this.mask,$t.isIdSelector)}isClassSelector(){return At(this.mask,$t.isClassSelector)}isHrefSelector(){return At(this.mask,$t.isHrefSelector)}isUnicode(){return At(this.mask,$t.isUnicode)}isHtmlFiltering(){return this.getSelector().startsWith("^")}isGenericHide(){var e,t;return void 0===(null===(e=null==this?void 0:this.domains)||void 0===e?void 0:e.hostnames)&&void 0===(null===(t=null==this?void 0:this.domains)||void 0===t?void 0:t.entities)}},Zt=class{constructor(){this.options=new Set,this.prefix=void 0,this.infix=void 0,this.suffix=void 0,this.redirect=void 0}blockRequestsWithType(e){if(this.options.has(e))throw new Error(`Already blocking type ${e}`);return this.options.add(e),this}images(){return this.blockRequestsWithType("image")}scripts(){return this.blockRequestsWithType("script")}frames(){return this.blockRequestsWithType("frame")}fonts(){return this.blockRequestsWithType("font")}medias(){return this.blockRequestsWithType("media")}styles(){return this.blockRequestsWithType("css")}redirectTo(e){if(void 0!==this.redirect)throw new Error(`Already redirecting: ${this.redirect}`);return this.redirect=`redirect=${e}`,this}urlContains(e){if(void 0!==this.infix)throw new Error(`Already matching pattern: ${this.infix}`);return this.infix=e,this}urlStartsWith(e){if(void 0!==this.prefix)throw new Error(`Already matching prefix: ${this.prefix}`);return this.prefix=`|${e}`,this}urlEndsWith(e){if(void 0!==this.suffix)throw new Error(`Already matching suffix: ${this.suffix}`);return this.suffix=`${e}|`,this}withHostname(e){if(void 0!==this.prefix)throw new Error(`Cannot match hostname if filter already has prefix: ${this.prefix}`);return this.prefix=`||${e}^`,this}toString(){const e=[];void 0!==this.prefix&&e.push(this.prefix),void 0!==this.infix&&e.push(this.infix),void 0!==this.suffix&&e.push(this.suffix);const t=["important"];if(0!==this.options.size)for(const e of this.options)t.push(e);return void 0!==this.redirect&&t.push(this.redirect),`${0===e.length?"*":e.join("*")}$${t.join(",")}`}};function Jt(){return new Zt}var eo,to,oo=bt("http"),io=bt("https");(to=eo||(eo={}))[to.fromDocument=1]="fromDocument",to[to.fromFont=2]="fromFont",to[to.fromHttp=4]="fromHttp",to[to.fromHttps=8]="fromHttps",to[to.fromImage=16]="fromImage",to[to.fromMedia=32]="fromMedia",to[to.fromObject=64]="fromObject",to[to.fromOther=128]="fromOther",to[to.fromPing=256]="fromPing",to[to.fromScript=512]="fromScript",to[to.fromStylesheet=1024]="fromStylesheet",to[to.fromSubdocument=2048]="fromSubdocument",to[to.fromWebsocket=4096]="fromWebsocket",to[to.fromXmlHttpRequest=8192]="fromXmlHttpRequest",to[to.firstParty=16384]="firstParty",to[to.thirdParty=32768]="thirdParty",to[to.isReplace=65536]="isReplace",to[to.isBadFilter=131072]="isBadFilter",to[to.isCSP=262144]="isCSP",to[to.isGenericHide=524288]="isGenericHide",to[to.isImportant=1048576]="isImportant",to[to.isSpecificHide=2097152]="isSpecificHide",to[to.isFullRegex=4194304]="isFullRegex",to[to.isRegex=8388608]="isRegex",to[to.isUnicode=16777216]="isUnicode",to[to.isLeftAnchor=33554432]="isLeftAnchor",to[to.isRightAnchor=67108864]="isRightAnchor",to[to.isException=134217728]="isException",to[to.isHostnameAnchor=268435456]="isHostnameAnchor",to[to.isRedirectRule=536870912]="isRedirectRule",to[to.isRedirect=1073741824]="isRedirect";var no=eo.fromDocument|eo.fromFont|eo.fromImage|eo.fromMedia|eo.fromObject|eo.fromOther|eo.fromPing|eo.fromScript|eo.fromStylesheet|eo.fromSubdocument|eo.fromWebsocket|eo.fromXmlHttpRequest,so={beacon:eo.fromPing,document:eo.fromDocument,cspviolationreport:eo.fromOther,fetch:eo.fromXmlHttpRequest,font:eo.fromFont,image:eo.fromImage,imageset:eo.fromImage,mainFrame:eo.fromDocument,main_frame:eo.fromDocument,media:eo.fromMedia,object:eo.fromObject,object_subrequest:eo.fromObject,ping:eo.fromPing,script:eo.fromScript,stylesheet:eo.fromStylesheet,subFrame:eo.fromSubdocument,sub_frame:eo.fromSubdocument,webSocket:eo.fromWebsocket,websocket:eo.fromWebsocket,xhr:eo.fromXmlHttpRequest,xmlhttprequest:eo.fromXmlHttpRequest,cspReport:eo.fromOther,csp_report:eo.fromOther,eventsource:eo.fromOther,manifest:eo.fromOther,other:eo.fromOther,prefetch:eo.fromOther,preflight:eo.fromOther,signedexchange:eo.fromOther,speculative:eo.fromOther,texttrack:eo.fromOther,web_manifest:eo.fromOther,xml_dtd:eo.fromOther,xslt:eo.fromOther};function co(e){const t=[];return e.fromDocument()&&t.push("document"),e.fromImage()&&t.push("image"),e.fromMedia()&&t.push("media"),e.fromObject()&&t.push("object"),e.fromOther()&&t.push("other"),e.fromPing()&&t.push("ping"),e.fromScript()&&t.push("script"),e.fromStylesheet()&&t.push("stylesheet"),e.fromSubdocument()&&t.push("sub_frame"),e.fromWebsocket()&&t.push("websocket"),e.fromXmlHttpRequest()&&t.push("xhr"),e.fromFont()&&t.push("font"),t}function ro(e,t,o,i,n,s){let c=ht*ut^e;if(void 0!==i&&(c=i.updateId(c)),void 0!==n&&(c=n.updateId(c)),void 0!==t)for(let e=0;e>>0}function ao(e,t,o,i){return!0===i?new RegExp(e.slice(1,e.length-1),"i"):(e=(e=(e=e.replace(/([|.$+?{}()[\]\\])/g,"\\$1")).replace(/\*/g,".*")).replace(/\^/g,"(?:[^\\w\\d_.%-]|$)"),o&&(e=`${e}$`),t&&(e=`^${e}`),new RegExp(e))}function lo(e,t,o){const i=t;for(;t=48&&e<=57||e<=65&&e<=70||e>=97&&e<=102}function mo(e,t,o){const i=e.charCodeAt(t+1);return 44===i||47===i?[t+1,!1]:function(e,t,o){const i=e.charCodeAt(t+1);if(44===i||uo.has(i))return[t+1,!0];if(99===i){const o=e.charCodeAt(t+2);if(o>=65&&o<=90||o>=97&&o<=122)return[t+2,!0]}if(120===i&&ho(e.charCodeAt(t+2))&&ho(e.charCodeAt(t+3)))return[t+3,!0];if(117===i)if(123===e.charCodeAt(t+2)){const o=e.indexOf("}",t+3),i=o-t+3;if(i>=1&&i<=6)return[o,!0]}else if(ho(e.charCodeAt(t+2))&&ho(e.charCodeAt(t+3))&&ho(e.charCodeAt(t+4))&&ho(e.charCodeAt(t+5)))return[t+5,!0];return[t+1,!1]}(e,t)}function Ao(e,t,o){if(47!==e.charCodeAt(t++))return[o,void 0];const i=["","",""];let n=t,s=0;for(;t0&&92===e.charCodeAt(o-1);)o=e.lastIndexOf(t,o-1);return o}(t,"$");if(-1!==u&&47!==t.charCodeAt(u+1)){d=u;for(const e of function(e,t,o){const i=[];let n,s;for(;t0&&(c=p);break;case"ehide":case"elemhide":if(t)return null;r=gt(r,eo.isGenericHide),r=gt(r,eo.isSpecificHide);break;case"shide":case"specifichide":if(t)return null;r=gt(r,eo.isSpecificHide);break;case"ghide":case"generichide":if(t)return null;r=gt(r,eo.isGenericHide);break;case"inline-script":if(t)return null;r=gt(r,eo.isCSP),c="script-src 'self' 'unsafe-eval' http: https: data: blob: mediastream: filesystem:";break;case"inline-font":if(t)return null;r=gt(r,eo.isCSP),c="font-src 'self' 'unsafe-eval' http: https: data: blob: mediastream: filesystem:";break;case"replace":case"content":if(t||(0===p.length?!1===At(r,eo.isException):null===go(p)))return null;r=gt(r,eo.isReplace),c=p;break;default:{let e=0;switch(i){case"all":if(t)return null;break;case"image":e=eo.fromImage;break;case"media":e=eo.fromMedia;break;case"object":case"object-subrequest":e=eo.fromObject;break;case"other":e=eo.fromOther;break;case"ping":case"beacon":e=eo.fromPing;break;case"script":e=eo.fromScript;break;case"css":case"stylesheet":e=eo.fromStylesheet;break;case"frame":case"subdocument":e=eo.fromSubdocument;break;case"xhr":case"xmlhttprequest":e=eo.fromXmlHttpRequest;break;case"websocket":e=eo.fromWebsocket;break;case"font":e=eo.fromFont;break;case"doc":case"document":e=eo.fromDocument;break;default:return null}t?l=ft(l,e):a=gt(a,e);break}}}}let h;if(r|=0===a?l:l===no?a:a&l,d-p>=2&&47===t.charCodeAt(p)&&47===t.charCodeAt(d-1)){h=t.slice(p,d);try{ao(h,!1,!1,!0)}catch(e){return null}r=gt(r,eo.isFullRegex)}else{if(d>0&&124===t.charCodeAt(d-1)&&(r=gt(r,eo.isRightAnchor),d-=1),p0&&42===t.charCodeAt(d-1)&&(d-=1),!1===At(r,eo.isHostnameAnchor)&&d-p>0&&42===t.charCodeAt(p)&&(r=ft(r,eo.isLeftAnchor),p+=1),At(r,eo.isLeftAnchor)&&(d-p==5&&vt(t,"ws://",p)?(r=gt(r,eo.fromWebsocket),r=ft(r,eo.isLeftAnchor),r=ft(r,eo.fromHttp),r=ft(r,eo.fromHttps),p=d):d-p==7&&vt(t,"http://",p)?(r=gt(r,eo.fromHttp),r=ft(r,eo.fromHttps),r=ft(r,eo.isLeftAnchor),p=d):d-p==8&&vt(t,"https://",p)?(r=gt(r,eo.fromHttps),r=ft(r,eo.fromHttp),r=ft(r,eo.isLeftAnchor),p=d):d-p==8&&vt(t,"http*://",p)&&(r=gt(r,eo.fromHttps),r=gt(r,eo.fromHttp),r=ft(r,eo.isLeftAnchor),p=d)),d-p>0&&(h=t.slice(p,d).toLowerCase(),r=bo(r,eo.isUnicode,Ot(h)),!1===At(r,eo.isRegex)&&(r=bo(r,eo.isRegex,function(e,t,o){const i=e.indexOf("^",t);if(-1!==i&&it.length)return!1;if(e.length===t.length)return e===t;const i=t.indexOf(e);if(-1===i)return!1;if(0===i)return!0===o||46===t.charCodeAt(e.length)||46===e.charCodeAt(e.length-1);if(t.length===i+e.length)return 46===t.charCodeAt(i-1)||46===e.charCodeAt(0);return!(!0!==o&&46!==t.charCodeAt(e.length)&&46!==e.charCodeAt(e.length-1)||46!==t.charCodeAt(i-1)&&46!==e.charCodeAt(0))}(i,t.hostname,void 0!==e.filter&&42===e.filter.charCodeAt(0)))return!1;if(e.isRegex())return e.getRegex().test(t.url.slice(t.url.indexOf(i)+i.length));if(e.isRightAnchor()&&e.isLeftAnchor()){return o===t.url.slice(t.url.indexOf(i)+i.length)}if(e.isRightAnchor()){const n=t.hostname;return!1===e.hasFilter()?i.length===n.length||n.endsWith(i):t.url.endsWith(o)}return e.isLeftAnchor()?vt(t.url,o,t.url.indexOf(i)+i.length):!1===e.hasFilter()||-1!==t.url.indexOf(o,t.url.indexOf(i)+i.length)}if(e.isRegex())return e.getRegex().test(t.url);if(e.isLeftAnchor()&&e.isRightAnchor())return t.url===o;if(e.isLeftAnchor())return wt(t.url,o);if(e.isRightAnchor())return t.url.endsWith(o);if(!1===e.hasFilter())return!0;return-1!==t.url.indexOf(o)}(this,e)}serialize(e){e.pushUint32(this.mask);const t=e.getPos();e.pushUint8(0);let o=0;void 0!==this.filter&&(o|=1,this.isUnicode()?e.pushUTF8(this.filter):e.pushNetworkFilter(this.filter)),void 0!==this.hostname&&(o|=2,e.pushNetworkHostname(this.hostname)),void 0!==this.domains&&(o|=4,this.domains.serialize(e)),void 0!==this.rawLine&&(o|=8,e.pushRawNetwork(this.rawLine)),void 0!==this.denyallow&&(o|=16,this.denyallow.serialize(e)),void 0!==this.optionValue&&(o|=32,this.isCSP()?e.pushNetworkCSP(this.optionValue):this.isRedirect()?e.pushNetworkRedirect(this.optionValue):e.pushUTF8(this.optionValue)),e.setByte(t,o)}getSerializedSize(e){let t=5;return void 0!==this.filter&&(!0===this.isUnicode()?t+=de(this.filter):t+=function(e,t){return!0===t?le(ce().networkFilter.getCompressedSize(e),!1):pe(e)}(this.filter,e)),void 0!==this.hostname&&(t+=function(e,t){return!0===t?le(ce().networkHostname.getCompressedSize(e),!1):pe(e)}(this.hostname,e)),void 0!==this.domains&&(t+=this.domains.getSerializedSize()),void 0!==this.rawLine&&(t+=function(e,t){return!0===t?le(ce().networkRaw.getCompressedSize(te(e)),!1):de(e)}(this.rawLine,e)),void 0!==this.denyallow&&(t+=this.denyallow.getSerializedSize()),void 0!==this.optionValue&&(this.isCSP()?t+=function(e,t){return!0===t?le(ce().networkCSP.getCompressedSize(e),!1):pe(e)}(this.optionValue,e):this.isRedirect()?t+=function(e,t){return!0===t?le(ce().networkRedirect.getCompressedSize(e),!1):pe(e)}(this.optionValue,e):t+=de(this.optionValue)),t}toString(e){if(void 0!==this.rawLine)return this.rawLine;let t="";this.isException()&&(t+="@@"),this.isHostnameAnchor()?t+="||":this.fromHttp()!==this.fromHttps()?this.fromHttp()?t+="|http://":t+="|https://":this.isLeftAnchor()&&(t+="|"),this.hasHostname()&&(t+=this.getHostname(),t+="^"),this.isFullRegex()?t+=`/${this.getRegex().source}/`:this.isRegex()?t+=this.getRegex().source:t+=this.getFilter(),this.isRightAnchor()&&"^"!==t[t.length-1]&&(t+="|");const o=[];if(!1===this.fromAny()){const e=mt(this.getCptMask());if(mt(no)-e")),void 0!==this.denyallow&&(void 0!==this.denyallow.parts?o.push(`denyallow=${this.denyallow.parts}`):o.push("denyallow=")),this.isBadFilter()&&o.push("badfilter"),o.length>0&&(t+="function"==typeof e?`$${o.map(e).join(",")}`:`$${o.join(",")}`),t}getIdWithoutBadFilter(){return ro(this.mask&~eo.isBadFilter,this.filter,this.hostname,this.domains,this.denyallow,this.optionValue)}getId(){return void 0===this.id&&(this.id=ro(this.mask,this.filter,this.hostname,this.domains,this.denyallow,this.optionValue)),this.id}hasFilter(){return void 0!==this.filter}hasDomains(){return void 0!==this.domains}getMask(){return this.mask}getCptMask(){return this.getMask()&no}isRedirect(){return At(this.getMask(),eo.isRedirect)}isRedirectRule(){return At(this.mask,eo.isRedirectRule)}getRedirect(){var e;return null!==(e=this.optionValue)&&void 0!==e?e:""}isReplace(){return At(this.getMask(),eo.isReplace)}getHtmlModifier(){var e;return 0===(null===(e=this.optionValue)||void 0===e?void 0:e.length)?null:go(this.optionValue)}isHtmlFilteringRule(){return this.isReplace()}getRedirectResource(){const e=this.getRedirect(),t=e.lastIndexOf(":");return-1===t?e:e.slice(0,t)}getRedirectPriority(){const e=this.getRedirect(),t=e.lastIndexOf(":");return-1===t?0:Number(e.slice(t+1))}hasHostname(){return void 0!==this.hostname}getHostname(){return this.hostname||""}getFilter(){return this.filter||""}getRegex(){return void 0===this.regex&&(this.regex=void 0!==this.filter&&this.isRegex()?ao(this.filter,this.isLeftAnchor(),this.isRightAnchor(),this.isFullRegex()):fo),this.regex}getTokens(){if(dt.reset(),void 0!==this.domains&&void 0!==this.domains.hostnames&&void 0===this.domains.entities&&void 0===this.domains.notHostnames&&void 0===this.domains.notEntities&&1===this.domains.hostnames.length&&dt.push(this.domains.hostnames[0]),!1===this.isFullRegex()){if(void 0!==this.filter){const e=!this.isRightAnchor(),t=!this.isLeftAnchor();!function(e,t,o,i){const n=Math.min(e.length,2*i.remaining());let s=!1,c=0,r=0,a=ht;for(let o=0;o1&&42!==n&&42!==c&&(!1===t||0!==r)&&i.push(a>>>0)),c=n)}!1===o&&!0===s&&42!==c&&e.length-r>1&&!1===i.full()&&i.push(a>>>0)}(this.filter,t,e,dt)}void 0!==this.hostname&&St(this.hostname,!1,void 0!==this.filter&&42===this.filter.charCodeAt(0),dt)}else void 0!==this.filter&&function(e,t){let o=e.length-1,i=1,n=0;for(;i=i;o-=1){const t=e.charCodeAt(o);if(124===t)return;if(41===t||42===t||43===t||63===t||93===t||125===t||46===t&&92!==e.charCodeAt(o-1)||92===t&&Ct(n))break;n=t}if(o1&&St(e.slice(1,i),94!==e.charCodeAt(1),!0,t),oObject.prototype.hasOwnProperty.call(Io,e),Oo=(e,t)=>"true"===e&&!t.has("true")||!("false"===e&&!t.has("false"))&&!!t.get(e),To=(e,t)=>{if(0===e.length)return!1;if((e=>Eo.test(e))(e))return"!"===e[0]?!Oo(e.slice(1),t):Oo(e,t);const o=(e=>e.match(So))(e);if(!o||0===o.length)return!1;if(e.length!==o.reduce(((e,t)=>e+t.length),0))return!1;const i=[],n=[];for(const e of o)if("("===e)n.push(e);else if(")"===e){for(;0!==n.length&&"("!==n[n.length-1];)i.push(n.pop());if(0===n.length)return!1;n.pop()}else if(Fo(e)){for(;n.length&&Fo(n[n.length-1])&&Io[e]<=Io[n[n.length-1]];)i.push(n.pop());n.push(e)}else i.push(Oo(e,t));if("("===n[0]||")"===n[0])return!1;for(;0!==n.length;)i.push(n.pop());for(const e of i)if(!0===e||!1===e)n.push(e);else if("!"===e)n.push(!n.pop());else if(Fo(e)){const t=n.pop(),o=n.pop();"&&"===e?n.push(o&&t):n.push(o||t)}return!0===n[0]},Po=class e{static getCondition(e){return e.slice(5).replace(/\s/g,"")}static parse(t,o){return new this({condition:e.getCondition(t),filterIDs:o})}static deserialize(e){const t=e.getUTF8(),o=new Set;for(let t=0,i=e.getUint32();t2)for(;e4&&32===t.charCodeAt(0)&&32===t.charCodeAt(1)&&32===t.charCodeAt(2)&&32===t.charCodeAt(3)&&32!==t.charCodeAt(4)))break;a+=t.slice(4),e+=1}0!==a.length&&a.charCodeAt(a.length-1)<=32&&(a=a.trim());const l=Ro(a,{extendedNonSupportedTypes:!0});if(l===Co.NETWORK&&!0===t.loadNetworkFilters){const i=ko.parse(a,t.debug);null!==i?(o.push(i),r.length>0&&r[r.length-1].filterIDs.add(i.getId())):n.push({lineNumber:e,filter:a,filterType:l})}else if(l===Co.COSMETIC&&!0===t.loadCosmeticFilters){const o=Xt.parse(a,t.debug);null!==o?!0!==t.loadGenericCosmeticsFilters&&!1!==o.isGenericHide()||(i.push(o),r.length>0&&r[r.length-1].filterIDs.add(o.getId())):n.push({lineNumber:e,filter:a,filterType:Co.COSMETIC})}else if(t.loadPreprocessors){const t=_o(a);if(t===yo.BEGIF)r.length>0?r.push(new Po({condition:`(${r[r.length-1].condition})&&(${Po.getCondition(a)})`})):r.push(Po.parse(a));else if((t===yo.ENDIF||t===yo.ELSE)&&r.length>0){const e=r.pop();c.push(e),t===yo.ELSE&&r.push(new Po({condition:`!(${e.condition})`}))}else l===Co.NOT_SUPPORTED_ADGUARD&&n.push({lineNumber:e,filter:a,filterType:l})}else l===Co.NOT_SUPPORTED_ADGUARD&&n.push({lineNumber:e,filter:a,filterType:l})}return{networkFilters:o,cosmeticFilters:i,preprocessors:c.filter((e=>e.filterIDs.size>0)),notSupportedFilters:n}}(xo=Co||(Co={}))[xo.NOT_SUPPORTED=0]="NOT_SUPPORTED",xo[xo.NETWORK=1]="NETWORK",xo[xo.COSMETIC=2]="COSMETIC",xo[xo.NOT_SUPPORTED_EMPTY=100]="NOT_SUPPORTED_EMPTY",xo[xo.NOT_SUPPORTED_COMMENT=101]="NOT_SUPPORTED_COMMENT",xo[xo.NOT_SUPPORTED_ADGUARD=102]="NOT_SUPPORTED_ADGUARD";var Lo="video/flv",Bo={contentType:`${Lo};base64`,aliases:[Lo,".flv","flv"],body:"RkxWAQEAAAAJAAAAABIAALgAAAAAAAAAAgAKb25NZXRhRGF0YQgAAAAIAAhkdXJhdGlvbgAAAAAAAAAAAAAFd2lkdGgAP/AAAAAAAAAABmhlaWdodAA/8AAAAAAAAAANdmlkZW9kYXRhcmF0ZQBAaGoAAAAAAAAJZnJhbWVyYXRlAEBZAAAAAAAAAAx2aWRlb2NvZGVjaWQAQAAAAAAAAAAAB2VuY29kZXICAA1MYXZmNTcuNDEuMTAwAAhmaWxlc2l6ZQBAaoAAAAAAAAAACQAAAMM="},Uo="image/gif",No={contentType:`${Uo};base64`,aliases:[Uo,".gif","gif"],body:"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"},Vo="text/html",jo={contentType:Vo,aliases:[Vo,".html","html",".htm","htm","noopframe","noop.html"],body:""},Mo="image/vnd.microsoft.icon",Do={contentType:`${Mo};base64`,aliases:[Mo,".ico","ico"],body:"AAABAAEAAQEAAAEAGAAwAAAAFgAAACgAAAABAAAAAgAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA=="},Ho="image/jpeg",Wo={contentType:`${Ho};base64`,aliases:[Ho,".jpg","jpg",".jpeg","jpeg"],body:"/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k="},qo="application/javascript",Go={contentType:qo,aliases:[qo,".js","js","javascript",".jsx","jsx","typescript",".ts","ts","noop.js","noopjs"],body:""},$o="application/json",Ko={contentType:$o,aliases:[$o,".json","json"],body:"0"},Qo="audio/mpeg",Yo={contentType:`${Qo};base64`,aliases:[Qo,".mp3","mp3","noop-0.1s.mp3","noopmp3-0.1s"],body:"/+MYxAAAAANIAAAAAExBTUUzLjk4LjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},Xo="video/mp4",Zo={contentType:`${Xo};base64`,aliases:[Xo,".mp4","mp4",".m4a","m4a",".m4p","m4p",".m4b","m4b",".m4r","m4r",".m4v","m4v","noop-1s.mp4","noopmp4-1s"],body:"AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAC721kYXQhEAUgpBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3pwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcCEQBSCkG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADengAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAsJtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAALwABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAB7HRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAIAAAAAAAAALwAAAAAAAAAAAAAAAQEAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAC8AAAAAAAEAAAAAAWRtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAAKxEAAAIAFXEAAAAAAAtaGRscgAAAAAAAAAAc291bgAAAAAAAAAAAAAAAFNvdW5kSGFuZGxlcgAAAAEPbWluZgAAABBzbWhkAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAADTc3RibAAAAGdzdHNkAAAAAAAAAAEAAABXbXA0YQAAAAAAAAABAAAAAAAAAAAAAgAQAAAAAKxEAAAAAAAzZXNkcwAAAAADgICAIgACAASAgIAUQBUAAAAAAfQAAAHz+QWAgIACEhAGgICAAQIAAAAYc3R0cwAAAAAAAAABAAAAAgAABAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAIAAAABAAAAHHN0c3oAAAAAAAAAAAAAAAIAAAFzAAABdAAAABRzdGNvAAAAAAAAAAEAAAAsAAAAYnVkdGEAAABabWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcmFwcGwAAAAAAAAAAAAAAAAtaWxzdAAAACWpdG9vAAAAHWRhdGEAAAABAAAAAExhdmY1Ni40MC4xMDE="},Jo="application/pdf",ei={contentType:`${Jo};base64`,aliases:[Jo,".pdf","pdf"],body:"JVBERi0xLgoxIDAgb2JqPDwvUGFnZXMgMiAwIFI+PmVuZG9iagoyIDAgb2JqPDwvS2lkc1szIDAgUl0vQ291bnQgMT4+ZW5kb2JqCjMgMCBvYmo8PC9QYXJlbnQgMiAwIFI+PmVuZG9iagp0cmFpbGVyIDw8L1Jvb3QgMSAwIFI+Pg=="},ti="image/png",oi={contentType:`${ti};base64`,aliases:[ti,".png","png"],body:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg=="},ii="image/svg+xml",ni={contentType:ii,aliases:[ii,".svg","svg"],body:"https://raw.githubusercontent.com/mathiasbynens/small/master/svg.svg"},si="text/plain",ci={contentType:si,aliases:[si,".txt","txt","text","nooptext","noop.txt"],body:""},ri="audio/wav",ai={contentType:`${ri};base64`,aliases:[ri,".wav","wav"],body:"UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA="},li="video/webm",pi={contentType:`${li};base64`,aliases:[li,".webm","webm"],body:"GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA="},di="image/webp",ui={contentType:`${di};base64`,aliases:[di,".webp","webp"],body:"UklGRhIAAABXRUJQVlA4TAYAAAAvQWxvAGs="},hi="video/wmv",mi={contentType:`${hi};base64`,aliases:[hi,".wmv","wmv"],body:"MCaydY5mzxGm2QCqAGLObOUBAAAAAAAABQAAAAECodyrjEepzxGO5ADADCBTZWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcCAAAAAAAAAIA+1d6xnQEAAAAAAAAAAMAF2QEAAAAAAAAAAAAAAAAcDAAAAAAAAAIAAACADAAAgAwAAEANAwC1A79fLqnPEY7jAMAMIFNlLgAAAAAAAAAR0tOruqnPEY7mAMAMIFNlBgAAAAAAQKTQ0gfj0hGX8ACgyV6oUGQAAAAAAAAAAQAoAFcATQAvAEUAbgBjAG8AZABpAG4AZwBTAGUAdAB0AGkAbgBnAHMAAAAAABwATABhAHYAZgA1ADcALgA0ADEALgAxADAAMAAAAJEH3Le3qc8RjuYAwAwgU2WBAAAAAAAAAMDvGbxNW88RqP0AgF9cRCsAV/sgVVvPEaj9AIBfXEQrAAAAAAAAAAAzAAAAAAAAAAEAAAAAAAEAAAABAAAAAigAKAAAAAEAAAABAAAAAQAYAE1QNDMDAAAAAAAAAAAAAAAAAAAAAAAAAEBS0YYdMdARo6QAoMkDSPZMAAAAAAAAAEFS0YYdMdARo6QAoMkDSPYBAAAAAQAKAG0AcwBtAHAAZQBnADQAdgAzAAAAAAAEAE1QNDM2JrJ1jmbPEabZAKoAYs5sMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQ=="},Ai=(()=>{const e={};for(const t of[Bo,No,jo,Do,Wo,Go,Ko,Yo,Zo,ei,oi,ni,ci,ai,pi,ui,mi])for(const o of t.aliases)e[o]=t;return e})();function gi(e){return Ai[e]||ci}function fi(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{name:t,aliases:o,body:i,contentType:n}=e;return"string"==typeof t&&(!(!Array.isArray(o)||!o.every((e=>"string"==typeof e)))&&("string"==typeof i&&"string"==typeof n))}function ki(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{name:t,aliases:o,body:i,dependencies:n,executionWorld:s,requiresTrust:c}=e;return"string"==typeof t&&(!(!Array.isArray(o)||!o.every((e=>"string"==typeof e)))&&("string"==typeof i&&(!(!Array.isArray(n)||!n.every((e=>"string"==typeof e)))&&((void 0===s||"MAIN"===s||"ISOLATED"===s)&&(void 0===c||"boolean"==typeof c)))))}var bi=class e{static deserialize(t){const o=t.getASCII(),i=[],n=[];for(let e=0,o=t.getUint16();e["if (typeof scriptletGlobals === 'undefined') { var scriptletGlobals = {}; }",...t,`(${e})(...['{{1}}','{{2}}','{{3}}','{{4}}','{{5}}','{{6}}','{{7}}','{{8}}','{{9}}','{{10}}'].filter((a,i) => a !== '{{'+(i+1)+'}}').map((a) => decodeURIComponent(a)))`].join(";"))(t.body,i),this.scriptletsCache.set(t.name,o),o}getSurrogate(e){const t=this.resourcesByName.get(e.endsWith(".js")?e:`${e}.js`);if(void 0!==t&&"application/javascript"===t.contentType)return t.body}getScriptletCanonicalName(e){var t;return null===(t=this.getRawScriptlet(e))||void 0===t?void 0:t.name}getRawScriptlet(e){if(!e.endsWith(".fn"))return this.scriptletsByName.get(e.endsWith(".js")?e:`${e}.js`)}getScriptletDependencies(e){const t=new Map,o=[...e.dependencies];for(;o.length>0;){const e=o.pop();if(t.has(e))continue;const i=this.scriptletsByName.get(e);t.set(e,i.body),o.push(...i.dependencies)}return Array.from(t.values())}getSerializedSize(){let e=pe(this.checksum);e+=2;for(const{name:t,aliases:o,body:i,contentType:n}of this.resources)e+=pe(t),e+=o.reduce(((e,t)=>e+pe(t)),2),e+=de(i),e+=pe(n);e+=2;for(const{name:t,aliases:o,body:i,dependencies:n}of this.scriptlets)e+=pe(t),e+=o.reduce(((e,t)=>e+pe(t)),2),e+=de(i),e+=1,e+=1,e+=1,e+=1,e+=n.reduce(((e,t)=>e+pe(t)),2);return e}serialize(e){e.pushASCII(this.checksum),e.pushUint16(this.resources.length);for(const{name:t,aliases:o,body:i,contentType:n}of this.resources){e.pushASCII(t),e.pushUint16(o.length);for(const t of o)e.pushASCII(t);e.pushUTF8(i),e.pushASCII(n)}e.pushUint16(this.scriptlets.length);for(const{name:t,aliases:o,body:i,dependencies:n,executionWorld:s,requiresTrust:c}of this.scriptlets){e.pushASCII(t),e.pushUint16(o.length);for(const t of o)e.pushASCII(t);e.pushUTF8(i),e.pushBool(void 0!==s),e.pushBool("ISOLATED"===s),e.pushBool(void 0!==c),e.pushBool(!0===c),e.pushUint16(n.length),n.forEach((t=>e.pushASCII(t)))}}};var yi=new Uint32Array(0);function wi(e){return`(?:${e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")})`}function vi(e,t,o){let i=e.get(t);void 0===i&&(i=[],e.set(t,i)),i.push(o)}function _i(e,t){const o=new Map;for(const i of e)vi(o,t(i),i);return Array.from(o.values())}function Ci(e,t){const o=[],i=[];for(const n of e)t(n)?o.push(n):i.push(n);return{negative:i,positive:o}}var xi=[{description:"Remove duplicated filters by ID",fusion:e=>e[0],groupByCriteria:e=>""+e.getId(),select:()=>!0},{description:"Group idential filter with same mask but different domains in single filters",fusion:e=>{const t=[],o=new Set,i=new Set,n=new Set,s=new Set;for(const{domains:c}of e)if(void 0!==c){if(void 0!==c.parts&&t.push(c.parts),void 0!==c.hostnames)for(const e of c.hostnames)o.add(e);if(void 0!==c.entities)for(const e of c.entities)n.add(e);if(void 0!==c.notHostnames)for(const e of c.notHostnames)i.add(e);if(void 0!==c.notEntities)for(const e of c.notEntities)s.add(e)}return new ko(Object.assign({},e[0],{domains:new Nt({hostnames:0!==o.size?new Uint32Array(o).sort():void 0,entities:0!==n.size?new Uint32Array(n).sort():void 0,notHostnames:0!==i.size?new Uint32Array(i).sort():void 0,notEntities:0!==s.size?new Uint32Array(s).sort():void 0,parts:0!==t.length?t.join(","):void 0}),rawLine:void 0!==e[0].rawLine?e.map((({rawLine:e})=>e)).join(" <+> "):void 0}))},groupByCriteria:e=>{var t;return e.getHostname()+e.getFilter()+e.getMask()+(null!==(t=e.optionValue)&&void 0!==t?t:"")},select:e=>!e.isCSP()&&void 0===e.denyallow&&void 0!==e.domains},{description:"Group simple patterns, into a single filter",fusion:e=>{const t=[];for(const o of e)o.isRegex()?t.push(`(?:${o.getRegex().source})`):o.isRightAnchor()?t.push(`${wi(o.getFilter())}$`):o.isLeftAnchor()?t.push(`^${wi(o.getFilter())}`):t.push(wi(o.getFilter()));return new ko(Object.assign({},e[0],{mask:gt(e[0].mask,eo.isRegex),rawLine:void 0!==e[0].rawLine?e.map((({rawLine:e})=>e)).join(" <+> "):void 0,regex:new RegExp(t.join("|"))}))},groupByCriteria:e=>""+(e.getMask()&~eo.isRegex&~eo.isFullRegex),select:e=>void 0===e.domains&&void 0===e.denyallow&&!e.isHostnameAnchor()&&!e.isRedirect()&&!e.isCSP()}];function Si(e){return e}function Ei(e){return e}function Ii(e){const t=[];let o=e;for(const{select:e,fusion:i,groupByCriteria:n}of xi){const{positive:s,negative:c}=Ci(o,e);o=c;const r=_i(s,n);for(const e of r)e.length>1?t.push(i(e)):o.push(e[0])}for(const e of o)t.push(e);return t}function Fi(e){return e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,e|=e>>16,++e}var Oi=1;var Ti=Number.MAX_SAFE_INTEGER>>>0,Pi=class e{static deserialize(t,o,i,n){const s=t.getUint32(),c=t.getUint32(),r=t.getUint32(),a=me.fromUint8Array(t.getBytes(!0),n),l=a.getUint32ArrayView(s),p=a.getUint32ArrayView(c),d=a.pos;return a.seekZero(),new e({config:n,deserialize:o,filters:[],optimize:i}).updateInternals({bucketsIndex:p,filtersIndexStart:d,numberOfFilters:r,tokensLookupIndex:l,view:a})}constructor({deserialize:e,filters:t,optimize:o,config:i}){this.bucketsIndex=ne,this.filtersIndexStart=0,this.numberOfFilters=0,this.tokensLookupIndex=ne,this.cache=new Map,this.view=me.empty(i),this.deserializeFilter=e,this.optimize=o,this.config=i,0!==t.length&&this.update(t,void 0)}getFilters(){const e=[];if(0===this.numberOfFilters)return e;this.view.setPos(this.filtersIndexStart);for(let t=0;t!t.has(e.getId())||(r-=e.getSerializedSize(o),!1))));for(const t of e)r+=t.getSerializedSize(o),a.push(t)}else{a=e;for(const t of e)r+=t.getSerializedSize(o)}if(0===a.length)return void this.updateInternals({bucketsIndex:ne,filtersIndexStart:0,numberOfFilters:0,tokensLookupIndex:ne,view:me.empty(this.config)});!0===this.config.debug&&a.sort(((e,t)=>e.getId()-t.getId()));const l=new Uint32Array(Math.max(Fi(2*a.length),256));for(const e of a){const t=e.getTokens();s.push(t),c+=2*t.length,n+=t.length;for(const e of t){i+=e.length;for(const t of e)l[t%l.length]+=1}}r+=4*c;const p=Math.max(2,Fi(n)),d=p-1,u=[];for(let e=0;e1?this.optimize(c):c,lastRequestSeen:-1},!0===this.config.enableInMemoryCache&&this.cache.set(e,i)}if(i.lastRequestSeen!==t){i.lastRequestSeen=t;const e=i.filters;for(let t=0;t0){const o=e[t];e[t]=e[t-1],e[t-1]=o}return!1}}return!0}},Ri=new Uint8Array(4),zi=class e{static deserialize(t,o,i){const n=new e({deserialize:o,config:i,filters:[]});return n.filters=t.getBytes(),n}constructor({config:e,deserialize:t,filters:o}){this.deserialize=t,this.filters=Ri,this.config=e,0!==o.length&&this.update(o,void 0)}update(e,t){let o=this.filters.byteLength,i=[];const n=this.config.enableCompression,s=this.getFilters();if(0!==s.length)if(void 0===t||0===t.size)i=s;else for(const e of s)!1===t.has(e.getId())?i.push(e):o-=e.getSerializedSize(n);const c=i.length!==s.length,r=i.length;for(const t of e)o+=t.getSerializedSize(n),i.push(t);const a=i.length>r;if(0===i.length)this.filters=Ri;else if(!0===a||!0===c){const e=me.allocate(o,this.config);e.pushUint32(i.length),!0===this.config.debug&&i.sort(((e,t)=>e.getId()-t.getId()));for(const t of i)t.serialize(e);this.filters=e.buffer}}getSerializedSize(){return ae(this.filters,!1)}serialize(e){e.pushBytes(this.filters)}getFilters(){if(this.filters.byteLength<=4)return[];const e=[],t=me.fromUint8Array(this.filters,this.config),o=t.getUint32();for(let i=0;i(!0!==c&&!0!==o.isScriptInject()||!o.match(t,e)||(null==p?void 0:p(o))||u.push(o),!0))),!0===s&&!0===a){const o=this.getGenericRules(l);for(const i of o)!0!==i.match(t,e)||(null==p?void 0:p(i))||u.push(i)}!0===s&&!0===r&&0!==o.length&&this.classesIndex.iterMatchingFilters(yt(o),(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&u.push(o),!0))),!0===s&&!0===r&&0!==n.length&&this.idsIndex.iterMatchingFilters(yt(n),(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&u.push(o),!0))),!0===s&&!0===r&&0!==i.length&&this.hrefsIndex.iterMatchingFilters(function(e){const t=e.sort();let o=1;for(let e=1;e{return t=e,dt.reset(),Et(t,dt),dt.slice();var t})))),(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&u.push(o),!0)));const h=[];return 0!==u.length&&this.unhideIndex.iterMatchingFilters(d,(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&h.push(o),!0))),{filters:u,unhides:h}}getStylesheetsFromFilters({filters:e,extendedFilters:t},{getBaseRules:o,allowGenericHides:i,hidingStyle:n=Mt}){let s=!1===o||!1===i?"":this.getBaseStylesheet(n);0!==e.length&&(0!==s.length&&(s+="\n\n"),s+=Ui(e,n));const c=[];if(0!==t.length){const e=new Map;for(const o of t){const t=o.getSelectorAST();if(void 0!==t){const i=o.isRemove()?void 0:o.getStyleAttributeHash();void 0!==i&&e.set(o.getStyle(n),i),c.push({ast:t,remove:o.isRemove(),attribute:i})}}0!==e.size&&(0!==s.length&&(s+="\n\n"),s+=[...e.entries()].map((([e,t])=>`[${t}] { ${e} }`)).join("\n\n"))}return{stylesheet:s,extended:c}}getGenericRules(e){return null===this.extraGenericRules?this.lazyPopulateGenericRulesCache(e).genericRules:this.extraGenericRules}getBaseStylesheet(e){return null===this.baseStylesheet?this.lazyPopulateGenericRulesCache(e).baseStylesheet:this.baseStylesheet}lazyPopulateGenericRulesCache(e){if(null===this.baseStylesheet||null===this.extraGenericRules){const t=this.unhideIndex.getFilters(),o=new Set;for(const e of t)o.add(e.getSelector());const i=this.genericRules.getFilters(),n=[],s=[];for(const e of i)e.hasCustomStyle()||e.isScriptInject()||e.hasHostnameConstraint()||o.has(e.getSelector())?s.push(e):n.push(e);this.baseStylesheet=Ui(n,e),this.extraGenericRules=s}return{baseStylesheet:this.baseStylesheet,genericRules:this.extraGenericRules}}},ji=class e{static deserialize(t,o){const i=new e({config:o});return i.index=Pi.deserialize(t,ko.deserialize,o.enableOptimizations?Ii:Si,o),i.badFilters=zi.deserialize(t,ko.deserialize,o),i}constructor({filters:e=[],config:t}){this.index=new Pi({config:t,deserialize:ko.deserialize,filters:[],optimize:t.enableOptimizations?Ii:Si}),this.badFiltersIds=null,this.badFilters=new zi({config:t,deserialize:ko.deserialize,filters:[]}),0!==e.length&&this.update(e,void 0)}getFilters(){return[].concat(this.badFilters.getFilters(),this.index.getFilters())}update(e,t){const o=[],i=[];for(const t of e)t.isBadFilter()?o.push(t):i.push(t);this.badFilters.update(o,t),this.index.update(i,t),this.badFiltersIds=null}getSerializedSize(){return this.badFilters.getSerializedSize()+this.index.getSerializedSize()}serialize(e){this.index.serialize(e),this.badFilters.serialize(e)}matchAll(e,t){const o=[];return this.index.iterMatchingFilters(e.getTokens(),(i=>(i.match(e)&&!1===this.isFilterDisabled(i)&&!(null==t?void 0:t(i))&&o.push(i),!0))),o}match(e,t){let o;return this.index.iterMatchingFilters(e.getTokens(),(i=>!(i.match(e)&&!1===this.isFilterDisabled(i)&&!(null==t?void 0:t(i)))||(o=i,!1))),o}isFilterDisabled(e){if(null===this.badFiltersIds){const e=this.badFilters.getFilters();if(0===e.length)return!1;const t=new Set;for(const o of e)t.add(o.getIdWithoutBadFilter());this.badFiltersIds=t}return this.badFiltersIds.has(e.getId())}},Mi=class e{static deserialize(t,o){const i=new e({config:o});return i.networkIndex=Pi.deserialize(t,ko.deserialize,o.enableOptimizations?Ii:Si,o),i.exceptionsIndex=Pi.deserialize(t,ko.deserialize,o.enableOptimizations?Ii:Si,o),i.cosmeticIndex=Pi.deserialize(t,Xt.deserialize,Ei,o),i.unhideIndex=Pi.deserialize(t,Xt.deserialize,Ei,o),i}constructor({filters:e=[],config:t}){this.config=t,this.networkIndex=new Pi({config:t,deserialize:ko.deserialize,filters:[],optimize:t.enableOptimizations?Ii:Si}),this.exceptionsIndex=new Pi({config:t,deserialize:ko.deserialize,filters:[],optimize:t.enableOptimizations?Ii:Si}),this.cosmeticIndex=new Pi({config:t,deserialize:Xt.deserialize,filters:[],optimize:Ei}),this.unhideIndex=new Pi({config:t,deserialize:Xt.deserialize,filters:[],optimize:Ei}),0!==e.length&&this.update(e,void 0)}update(e,t){const o=[],i=[],n=[],s=[];for(const t of e)t.isNetworkFilter()?t.isException()?i.push(t):o.push(t):t.isCosmeticFilter()&&(t.isUnhide()?s.push(t):n.push(t));this.networkIndex.update(o,t),this.exceptionsIndex.update(i,t),this.cosmeticIndex.update(n,t),this.unhideIndex.update(s,t)}serialize(e){this.networkIndex.serialize(e),this.exceptionsIndex.serialize(e),this.cosmeticIndex.serialize(e),this.unhideIndex.serialize(e)}getSerializedSize(){return this.networkIndex.getSerializedSize()+this.exceptionsIndex.getSerializedSize()+this.cosmeticIndex.getSerializedSize()+this.unhideIndex.getSerializedSize()}getHTMLFilters(e,t){const o=[],i=[],n=[],s=[];if(!0===this.config.loadNetworkFilters&&this.networkIndex.iterMatchingFilters(e.getTokens(),(i=>(i.match(e)&&!(null==t?void 0:t(i))&&o.push(i),!0))),0!==o.length&&this.exceptionsIndex.iterMatchingFilters(e.getTokens(),(o=>(o.match(e)&&!(null==t?void 0:t(o))&&n.push(o),!0))),!0===this.config.loadCosmeticFilters&&e.isMainFrame()){const{hostname:o,domain:n=""}=e,c=Ni(o,n);this.cosmeticIndex.iterMatchingFilters(c,(e=>(e.match(o,n)&&!(null==t?void 0:t(e))&&i.push(e),!0))),0!==i.length&&this.unhideIndex.iterMatchingFilters(c,(e=>(e.match(o,n)&&!(null==t?void 0:t(e))&&s.push(e),!0)))}return{networkFilters:o,cosmeticFilters:i,unhides:s,exceptions:n}}getFilters(){return[].concat(this.networkIndex.getFilters(),this.exceptionsIndex.getFilters(),this.cosmeticIndex.getFilters(),this.unhideIndex.getFilters())}},Di=Number.MAX_SAFE_INTEGER>>>0,Hi=class e{static deserialize(t,o){const i=t.getUint32(),n=t.getUint32(),s=t.getUint32(),c=me.fromUint8Array(t.getBytes(!0),{enableCompression:!1}),r=c.getUint32ArrayView(i),a=c.getUint32ArrayView(n),l=c.pos;return c.seekZero(),new e({deserialize:o,values:[],getKeys:()=>[],getSerializedSize:()=>0,serialize:()=>{}}).updateInternals({bucketsIndex:a,valuesIndexStart:l,numberOfValues:s,tokensLookupIndex:r,view:c})}constructor({serialize:e,deserialize:t,getKeys:o,getSerializedSize:i,values:n}){if(this.cache=new Map,this.bucketsIndex=ne,this.tokensLookupIndex=ne,this.valuesIndexStart=0,this.numberOfValues=0,this.view=me.empty({enableCompression:!1}),this.deserializeValue=t,0!==n.length){const t=[];let s=0,c=0;for(const e of n)c+=i(e);if(0===n.length)return void this.updateInternals({bucketsIndex:ne,valuesIndexStart:0,numberOfValues:0,tokensLookupIndex:ne,view:me.empty({enableCompression:!1})});for(const e of n){const i=o(e);t.push(i),s+=2*i.length}c+=4*s;const r=Math.max(2,Fi(n.length)),a=r-1,l=[];for(let e=0;e[qi(e)],serialize:$i,deserialize:Ki,values:e})}function Yi(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{key:t,name:o,description:i,country:n,website_url:s,privacy_policy_url:c,privacy_contact:r,ghostery_id:a}=e;return"string"==typeof t&&("string"==typeof o&&((null===i||"string"==typeof i)&&((null===n||"string"==typeof n)&&((null===s||"string"==typeof s)&&((null===c||"string"==typeof c)&&((null===r||"string"==typeof r)&&(null===a||"string"==typeof a)))))))}function Xi(e){return bt(e.key)}function Zi(e){return de(e.key)+de(e.name)+de(e.description||"")+de(e.website_url||"")+de(e.country||"")+de(e.privacy_policy_url||"")+de(e.privacy_contact||"")+de(e.ghostery_id||"")}function Ji(e,t){t.pushUTF8(e.key),t.pushUTF8(e.name),t.pushUTF8(e.description||""),t.pushUTF8(e.website_url||""),t.pushUTF8(e.country||""),t.pushUTF8(e.privacy_policy_url||""),t.pushUTF8(e.privacy_contact||""),t.pushUTF8(e.ghostery_id||"")}function en(e){return{key:e.getUTF8(),name:e.getUTF8(),description:e.getUTF8()||null,website_url:e.getUTF8()||null,country:e.getUTF8()||null,privacy_policy_url:e.getUTF8()||null,privacy_contact:e.getUTF8()||null,ghostery_id:e.getUTF8()||null}}function tn(e){return new Hi({getSerializedSize:Zi,getKeys:e=>[Xi(e)],serialize:Ji,deserialize:en,values:e})}function on(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{key:t,name:o,category:i,organization:n,alias:s,website_url:c,domains:r,filters:a}=e;return"string"==typeof t&&("string"==typeof o&&("string"==typeof i&&((null===n||"string"==typeof n)&&(("string"==typeof s||null===s)&&((null===c||"string"==typeof c)&&(!(!Array.isArray(r)||!r.every((e=>"string"==typeof e)))&&!(!Array.isArray(a)||!a.every((e=>"string"==typeof e)))))))))}function nn(e){const t=[];for(const o of e.filters){const e=ko.parse(o);null!==e&&t.push(e.getId())}for(const o of e.domains){const e=ko.parse(`||${o}^`);null!==e&&t.push(e.getId())}return[...new Set(t)]}function sn(e){let t=re(e.domains.length);for(const o of e.domains)t+=de(o);let o=re(e.filters.length);for(const t of e.filters)o+=de(t);return de(e.key)+de(e.name)+de(e.category)+de(e.organization||"")+de(e.alias||"")+de(e.website_url||"")+de(e.ghostery_id||"")+t+o}function cn(e,t){t.pushUTF8(e.key),t.pushUTF8(e.name),t.pushUTF8(e.category),t.pushUTF8(e.organization||""),t.pushUTF8(e.alias||""),t.pushUTF8(e.website_url||""),t.pushUTF8(e.ghostery_id||""),t.pushLength(e.domains.length);for(const o of e.domains)t.pushUTF8(o);t.pushLength(e.filters.length);for(const o of e.filters)t.pushUTF8(o)}function rn(e){const t=e.getUTF8(),o=e.getUTF8(),i=e.getUTF8(),n=e.getUTF8()||null,s=e.getUTF8()||null,c=e.getUTF8()||null,r=e.getUTF8()||null,a=e.getLength(),l=[];for(let t=0;t=2;t.shift()){const e=t.join("."),o=ko.parse(`||${e}^`);if(null===o)continue;const i=this.fromId(o.getId());if(i.length>0)return i}return[]}fromId(e){var t,o;const i=[];for(const n of this.patterns.get(e))i.push({pattern:n,category:null===(t=this.categories.get(qi({key:n.category})))||void 0===t?void 0:t[0],organization:null!==n.organization?null===(o=this.organizations.get(Xi({key:n.organization})))||void 0===o?void 0:o[0]:null});return i}},pn=class{static deserialize(e){const t=new Set;for(let o=0,i=e.getUint32();ot.condition===e.condition));if(t)for(const o of e.filterIDs)t.filterIDs.delete(o)}if(e)for(const t of e){const e=this.preprocessors.find((e=>e.condition===t.condition));if(e)for(const o of t.filterIDs)e.filterIDs.add(o);else this.preprocessors.push(t)}(t&&0!==t.length||e&&0!==e.length)&&this.updateEnv(o)}serialize(e){e.pushUint32(this.excluded.size);for(const t of this.excluded)e.pushUint32(t);e.pushUint32(this.preprocessors.length);for(const t of this.preprocessors)t.serialize(e)}getSerializedSize(){let e=4*(1+this.excluded.size);e+=4;for(const t of this.preprocessors)e+=t.getSerializedSize();return e}};function dn(e){if(0===e.length)return!1;let t,o=0;for(const i of e){const e=(i.isImportant()?4:0)|(i.isException()?1:2);e>=o&&(o=e,t=i)}return void 0!==t&&t.isException()}var un=class extends ye{static fromCached(e,t){if(void 0===t)return e();const{path:o,read:i,write:n}=t;return i(o).then((e=>this.deserialize(e))).catch((()=>e().then((e=>n(o,e.serialize()).then((()=>e))))))}static empty(e={}){return new this({config:e})}static fromLists(e,t,o={},i){return this.fromCached((()=>{const i=function(e,t){return Promise.all(t.map((t=>we(e,t))))}(e,t),n=function(e){return we(e,`${ve}/ublock-origin/resources.json`)}(e);return Promise.all([i,n]).then((([e,t])=>{const i=this.parse(e.join("\n"),o);return void 0!==t&&i.updateResources(t,""+t.length),i}))}),i)}static fromPrebuiltAdsOnly(e=fetch,t){return this.fromLists(e,_e,{},t)}static fromPrebuiltAdsAndTracking(e=fetch,t){return this.fromLists(e,Ce,{},t)}static fromPrebuiltFull(e=fetch,t){return this.fromLists(e,xe,{},t)}static fromTrackerDB(e,t={}){const o=new Ae(t),i=new ln(e),n=[];for(const e of i.getPatterns())n.push(...e.filters);const s=this.parse(n.join("\n"),o);return s.metadata=i,s}static merge(e,{skipResources:t=!1}={}){if(!e||e.length<2)throw new Error("merging engines requires at least two engines");const o=e[0].config,i=new Map,n=new Map,s=new Map,c=[],r={organizations:{},categories:{},patterns:{}},a=[],l=Object.keys(o).filter((function(e){return"boolean"==typeof o[e]&&!a.includes(e)}));for(const t of e){for(const e of l)if(o[e]!==t.config[e])throw new Error(`config "${e}" of all merged engines must be the same`);const e=t.getFilters();for(const t of e.networkFilters)n.set(t.getId(),t);for(const t of e.cosmeticFilters)s.set(t.getId(),t);for(const e of t.preprocessors.preprocessors)c.push(e);for(const[e,o]of t.lists)i.has(e)||i.set(e,o);if(void 0!==t.metadata){for(const e of t.metadata.organizations.getValues())void 0===r.organizations[e.key]&&(r.organizations[e.key]=e);for(const e of t.metadata.categories.getValues())void 0===r.categories[e.key]&&(r.categories[e.key]=e);for(const e of t.metadata.patterns.getValues())void 0===r.patterns[e.key]&&(r.patterns[e.key]=e)}}const p=new this({networkFilters:Array.from(n.values()),cosmeticFilters:Array.from(s.values()),preprocessors:c,lists:i,config:o});if(Object.keys(r.categories).length+Object.keys(r.organizations).length+Object.keys(r.patterns).length!==0&&(p.metadata=new ln(r)),!0!==t){for(const t of e.slice(1))if(t.resources.checksum!==e[0].resources.checksum)throw new Error(`resource checksum of all merged engines must match with the first one: "${e[0].resources.checksum}" but got: "${t.resources.checksum}"`);p.resources=bi.copy(e[0].resources)}return p}static parse(e,t={}){const o=new Ae(t);return new this({...zo(e,o),config:o})}static deserialize(e){const t=me.fromUint8Array(e,{enableCompression:!1}),o=t.getUint16();if(699!==o)throw new Error(`serialized engine version mismatch, expected 699 but got ${o}`);const i=Ae.deserialize(t);if(i.enableCompression&&t.enableCompression(),i.integrityCheck){const o=t.pos;t.pos=e.length-4;const i=t.checksum(),n=t.getUint32();if(i!==n)throw new Error(`serialized engine checksum mismatch, expected ${n} but got ${i}`);t.pos=o}const n=new this({config:i});n.resources=bi.deserialize(t);const s=new Map,c=t.getUint16();for(let e=0;ee.getId()))).concat(o.map((e=>e.getId()))));l.push(new Po({condition:e,filterIDs:n}))}if(void 0!==t.added&&0!==t.added.length){const{networkFilters:o,cosmeticFilters:i}=zo(t.added.join("\n"),this.config),n=new Set([].concat(i.map((e=>e.getId()))).concat(o.map((e=>e.getId()))));c.push(new Po({condition:e,filterIDs:n}))}}return this.update({newCosmeticFilters:n,newNetworkFilters:s,newPreprocessors:c,removedCosmeticFilters:r.map((e=>e.getId())),removedNetworkFilters:a.map((e=>e.getId())),removedPreprocessors:l},i)}getHtmlFilters(e){const t=[];if(!1===this.config.enableHtmlFiltering)return t;const{networkFilters:o,exceptions:i,cosmeticFilters:n,unhides:s}=this.htmlFilters.getHTMLFilters(e,this.isFilterExcluded.bind(this));if(0!==n.length){const o=new Map(s.map((e=>[e.getSelector(),e])));for(const i of n){const n=i.getExtendedSelector();if(void 0===n)continue;const s=o.get(i.getSelector());void 0===s&&t.push(n),this.emit("filter-matched",{filter:i,exception:s},{request:e,filterType:Co.COSMETIC})}}if(0!==o.length){const n=new Map;let s;for(const e of i){const t=e.optionValue;if(""===t){s=e;break}n.set(t,e)}for(const i of o){const o=i.getHtmlModifier();if(null===o)continue;const c=s||n.get(i.optionValue);this.emit("filter-matched",{filter:i,exception:c},{request:e,filterType:Co.NETWORK}),void 0===c&&t.push(["replace",o])}}return 0!==t.length&&this.emit("html-filtered",t,e.url),t}getCosmeticsFilters({url:e,hostname:t,domain:o,classes:i,hrefs:n,ids:s,getBaseRules:c=!0,getInjectionRules:r=!0,getExtendedRules:a=!0,getRulesFromDOM:l=!0,getRulesFromHostname:p=!0,hidingStyle:d,callerContext:u}){if(!1===this.config.loadCosmeticFilters)return{active:!1,extended:[],scripts:[],styles:""};o||(o="");let h=!0,m=!0;const A=this.hideExceptions.matchAll(Ut.fromRawDetails({domain:o,hostname:t,url:e,sourceDomain:"",sourceHostname:"",sourceUrl:""}),this.isFilterExcluded.bind(this)),g=[],f=[];for(const e of A){if(e.isElemHide()){h=!1,m=!1;break}e.isSpecificHide()?f.push(e):e.isGenericHide()&&g.push(e)}!0===h&&(h=!1===dn(g)),!0===m&&(m=!1===dn(f));const{filters:k,unhides:b}=this.cosmetics.getCosmeticsFilters({domain:o,hostname:t,classes:i,hrefs:n,ids:s,allowGenericHides:h,allowSpecificHides:m,getRulesFromDOM:l,getRulesFromHostname:p,hidingStyle:d,isFilterExcluded:this.isFilterExcluded.bind(this)});let y=!1;const w=new Map;for(const e of b)!0===e.isScriptInject()&&!0===e.isUnhide()&&0===e.getSelector().length&&(y=!0),w.set(Yt(e,this.resources.getScriptletCanonicalName.bind(this.resources)),e);const v=[],_=[],C=[];if(0!==k.length)for(const t of k){const o=w.get(Yt(t,this.resources.getScriptletCanonicalName.bind(this.resources)));if(void 0!==o)continue;let i=!1;!0===t.isScriptInject()?!0===r&&!1===y&&(v.push(t),i=!0):t.isExtended()?!0===a&&(C.push(t),i=!0):(_.push(t),i=!0),i&&this.emit("filter-matched",{filter:t,exception:o},{url:e,callerContext:u,filterType:Co.COSMETIC})}const x=[];for(const t of v){const o=t.getScript(this.resources.getScriptlet.bind(this.resources));void 0!==o&&(this.emit("script-injected",o,e),x.push(o))}const{stylesheet:S,extended:E}=this.cosmetics.getStylesheetsFromFilters({filters:_,extendedFilters:C},{getBaseRules:c,allowGenericHides:h,hidingStyle:d});return 0!==S.length&&this.emit("style-injected",S,e),{active:!0,extended:E,scripts:x,styles:S}}matchAll(e){const t=[];return e.isSupported&&(Array.prototype.push.apply(t,this.importants.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.filters.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.exceptions.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.csp.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.hideExceptions.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.redirects.matchAll(e,this.isFilterExcluded.bind(this)))),new Set(t)}getCSPDirectives(e){if(!this.config.loadNetworkFilters)return;if(!0!==e.isSupported||!1===e.isMainFrame())return;const t=this.csp.matchAll(e,this.isFilterExcluded.bind(this));if(0===t.length)return;const o=new Map,i=[];for(const n of t)if(n.isException()){if(void 0===n.csp)return void this.emit("filter-matched",{exception:n},{request:e,filterType:Co.NETWORK});o.set(n.csp,n)}else i.push(n);if(0===i.length)return;const n=new Set;for(const t of i.values()){const i=o.get(t.csp);void 0===i&&n.add(t.csp),this.emit("filter-matched",{filter:t,exception:i},{request:e,filterType:Co.NETWORK})}const s=Array.from(n).join("; ");return s.length>0&&this.emit("csp-injected",e,s),s}match(e,t=!1){const o={exception:void 0,filter:void 0,match:!1,redirect:void 0,metadata:void 0};if(!this.config.loadNetworkFilters)return o;if(e.isSupported){let t,i;if(o.filter=this.importants.match(e,this.isFilterExcluded.bind(this)),void 0===o.filter){const n=this.redirects.matchAll(e,this.isFilterExcluded.bind(this)).sort(((e,t)=>t.getRedirectPriority()-e.getRedirectPriority()));if(0!==n.length)for(const e of n)"none"===e.getRedirectResource()?t=e:e.isRedirectRule()?void 0===i&&(i=e):void 0===o.filter&&(o.filter=e);void 0===o.filter&&(o.filter=this.filters.match(e,this.isFilterExcluded.bind(this)),void 0!==i&&void 0!==o.filter&&(o.filter=i)),void 0!==o.filter&&(o.exception=this.exceptions.match(e,this.isFilterExcluded.bind(this)))}void 0!==o.filter&&void 0===o.exception&&o.filter.isRedirect()&&(void 0!==t?o.exception=t:o.redirect=this.resources.getResource(o.filter.getRedirectResource()))}return o.match=void 0===o.exception&&void 0!==o.filter,o.filter&&this.emit("filter-matched",{filter:o.filter,exception:o.exception},{request:e,filterType:Co.NETWORK}),void 0!==o.exception?this.emit("request-whitelisted",e,o):void 0!==o.redirect?this.emit("request-redirected",e,o):void 0!==o.filter?this.emit("request-blocked",e,o):this.emit("request-allowed",e,o),!0===t&&void 0!==o.filter&&this.metadata&&(o.metadata=this.metadata.fromFilter(o.filter)),o}getPatternMetadata(e,{getDomainMetadata:t=!1}={}){if(void 0===this.metadata)return[];const o=new Set,i=[];for(const t of this.matchAll(e))for(const e of this.metadata.fromFilter(t))o.has(e.pattern.key)||(o.add(e.pattern.key),i.push(e));if(t)for(const t of this.metadata.fromDomain(e.hostname))o.has(t.pattern.key)||(o.add(t.pattern.key),i.push(t));return i}blockScripts(){return this.updateFromDiff({added:[Jt().scripts().redirectTo("javascript").toString()]}),this}blockImages(){return this.updateFromDiff({added:[Jt().images().redirectTo("png").toString()]}),this}blockMedias(){return this.updateFromDiff({added:[Jt().medias().redirectTo("mp4").toString()]}),this}blockFrames(){return this.updateFromDiff({added:[Jt().frames().redirectTo("html").toString()]}),this}blockFonts(){return this.updateFromDiff({added:[Jt().fonts().toString()]}),this}blockStyles(){return this.updateFromDiff({added:[Jt().styles().toString()]}),this}};function hn(e){const t=new Set(["br","head","link","meta","script","style","s"]),o=new Set,i=new Set,n=new Set,s=new Set;for(const c of e)for(const e of[c,...c.querySelectorAll("[id]:not(html):not(body),[class]:not(html):not(body),[href]:not(html):not(body)")]){if(s.has(e))continue;if(s.add(e),t.has(e.nodeName.toLowerCase()))continue;const c=e.getAttribute("id");"string"==typeof c&&n.add(c);const r=e.classList;for(const e of r)o.add(e);const a=e.getAttribute("href");"string"==typeof a&&i.add(a)}return{classes:Array.from(o),hrefs:Array.from(i),ids:Array.from(n)}}function mn(e){try{const t=pt(location.href),o=t.hostname||"",i=t.domain||"";return e.getCosmeticsFilters({url:location.href,hostname:o,domain:i,...hn([document.documentElement]),getBaseRules:!0,getInjectionRules:!1,getExtendedRules:!0,getRulesFromDOM:!0,getRulesFromHostname:!0,hidingStyle:A("opacity")}).styles}catch(e){return console.error("Error getting cosmetic rules",e),""}}var An=new Uint8Array([]);var gn=[{name:"192.com",detectCmp:[{exists:".ont-cookies"}],detectPopup:[{visible:".ont-cookies"}],optIn:[{click:".ont-btn-main.ont-cookies-btn.js-ont-btn-ok2"}],optOut:[{click:".ont-cookes-btn-manage"},{click:".ont-btn-main.ont-cookies-btn.js-ont-btn-choose"}],test:[{eval:"EVAL_ONENINETWO_0"}]},{name:"1password-com",cosmetic:!0,prehideSelectors:['footer #footer-root [aria-label="Cookie Consent"]'],detectCmp:[{exists:'footer #footer-root [aria-label="Cookie Consent"]'}],detectPopup:[{visible:'footer #footer-root [aria-label="Cookie Consent"]'}],optIn:[{click:'footer #footer-root [aria-label="Cookie Consent"] button'}],optOut:[{hide:'footer #footer-root [aria-label="Cookie Consent"]'}]},{name:"aa",vendorUrl:"https://aa.com",prehideSelectors:[],cosmetic:!0,detectCmp:[{exists:"#aa_optoutmulti-Modal,#cookieBannerMessage"}],detectPopup:[{visible:"#aa_optoutmulti-Modal,#cookieBannerMessage"}],optIn:[{hide:"#aa_optoutmulti-Modal,#cookieBannerMessage"},{waitForThenClick:"#aa_optoutmulti_checkBox"},{waitForThenClick:"#aa_optoutmulti-Modal button.optoutmulti_button"}],optOut:[{hide:"#aa_optoutmulti-Modal,#cookieBannerMessage"}]},{name:"abc",vendorUrl:"https://abc.net.au",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?abc\\.net\\.au/"},prehideSelectors:[],detectCmp:[{exists:"[data-component=CookieBanner]"}],detectPopup:[{visible:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptAll]"}],optIn:[{waitForThenClick:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptAll]"}],optOut:[{waitForThenClick:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptABCRequired]"}],test:[{eval:"EVAL_ABC_TEST"}]},{name:"abconcerts.be",vendorUrl:"https://unknown",intermediate:!1,prehideSelectors:["dialog.cookie-consent"],detectCmp:[{exists:"dialog.cookie-consent form.cookie-consent__form"}],detectPopup:[{visible:"dialog.cookie-consent form.cookie-consent__form"}],optIn:[{waitForThenClick:"dialog.cookie-consent form.cookie-consent__form button[value=yes]"}],optOut:[{if:{exists:"dialog.cookie-consent form.cookie-consent__form button[value=no]"},then:[{click:"dialog.cookie-consent form.cookie-consent__form button[value=no]"}],else:[{click:"dialog.cookie-consent form.cookie-consent__form button.cookie-consent__options-toggle"},{waitForThenClick:'dialog.cookie-consent form.cookie-consent__form button[value="save_options"]'}]}]},{name:"acris",prehideSelectors:["div.acris-cookie-consent"],detectCmp:[{exists:"[data-acris-cookie-consent]"}],detectPopup:[{visible:".acris-cookie-consent.is--modal"}],optIn:[{waitForVisible:"#ccConsentAcceptAllButton",check:"any"},{wait:500},{waitForThenClick:"#ccConsentAcceptAllButton"}],optOut:[{waitForVisible:"#ccAcceptOnlyFunctional",check:"any"},{wait:500},{waitForThenClick:"#ccAcceptOnlyFunctional"}]},{name:"activobank.pt",runContext:{urlPattern:"^https://(www\\.)?activobank\\.pt"},prehideSelectors:["aside#cookies,.overlay-cookies"],detectCmp:[{exists:"#cookies .cookies-btn"}],detectPopup:[{visible:"#cookies #submitCookies"}],optIn:[{waitForThenClick:"#cookies #submitCookies"}],optOut:[{waitForThenClick:"#cookies #rejectCookies"}]},{name:"Adroll",prehideSelectors:["#adroll_consent_container"],detectCmp:[{exists:"#adroll_consent_container"}],detectPopup:[{visible:"#adroll_consent_container"}],optIn:[{waitForThenClick:"#adroll_consent_accept"}],optOut:[{waitForThenClick:"#adroll_consent_reject"}],test:[{eval:"EVAL_ADROLL_0"}]},{name:"affinity.serif.com",detectCmp:[{exists:".c-cookie-banner button[data-qa='allow-all-cookies']"}],detectPopup:[{visible:".c-cookie-banner"}],optIn:[{click:'button[data-qa="allow-all-cookies"]'}],optOut:[{click:'button[data-qa="manage-cookies"]'},{waitFor:'.c-cookie-banner ~ [role="dialog"]'},{waitForThenClick:'.c-cookie-banner ~ [role="dialog"] input[type="checkbox"][value="true"]',all:!0},{click:'.c-cookie-banner ~ [role="dialog"] .c-modal__action button'}],test:[{wait:500},{eval:"EVAL_AFFINITY_SERIF_COM_0"}]},{name:"agolde.com",cosmetic:!0,prehideSelectors:["#modal-1 div[data-micromodal-close]"],detectCmp:[{exists:"#modal-1 div[aria-labelledby=modal-1-title]"}],detectPopup:[{exists:"#modal-1 div[data-micromodal-close]"}],optIn:[{click:'button[aria-label="Close modal"]'}],optOut:[{hide:"#modal-1 div[data-micromodal-close]"}]},{name:"aliexpress",vendorUrl:"https://aliexpress.com/",runContext:{urlPattern:"^https://.*\\.aliexpress\\.com/"},prehideSelectors:["#gdpr-new-container"],detectCmp:[{exists:"#gdpr-new-container,#voyager-gdpr > div"}],detectPopup:[{visible:"#gdpr-new-container,#voyager-gdpr > div"}],optIn:[{waitForThenClick:"#gdpr-new-container .btn-accept,#voyager-gdpr > div > div > button:nth-child(1)"}],optOut:[{if:{exists:"#voyager-gdpr > div"},then:[{waitForThenClick:"#voyager-gdpr > div > div > button:nth-child(2)"}],else:[{waitForThenClick:"#gdpr-new-container .btn-more"},{waitFor:"#gdpr-new-container .gdpr-dialog-switcher"},{click:"#gdpr-new-container .switcher-on",all:!0,optional:!0},{click:"#gdpr-new-container .btn-save"}]}]},{name:"almacmp",prehideSelectors:["#alma-cmpv2-container"],detectCmp:[{exists:"#alma-cmpv2-container"}],detectPopup:[{visible:"#alma-cmpv2-container #almacmp-modal-layer1"}],optIn:[{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer1 #almacmp-modalConfirmBtn"}],optOut:[{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer1 #almacmp-modalSettingBtn"},{waitFor:"#alma-cmpv2-container #almacmp-modal-layer2"},{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer2 #almacmp-reject-all-layer2"}],test:[{eval:"EVAL_ALMACMP_0"}]},{name:"altium.com",cosmetic:!0,prehideSelectors:[".altium-privacy-bar"],detectCmp:[{exists:".altium-privacy-bar"}],detectPopup:[{exists:".altium-privacy-bar"}],optIn:[{click:"a.altium-privacy-bar__btn"}],optOut:[{hide:".altium-privacy-bar"}]},{name:"amazon.com",prehideSelectors:['span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'],detectCmp:[{exists:'span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'}],detectPopup:[{visible:'span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'}],optIn:[{waitForVisible:"#sp-cc-accept"},{wait:500},{click:"#sp-cc-accept"}],optOut:[{waitForVisible:"#sp-cc-rejectall-link"},{wait:500},{click:"#sp-cc-rejectall-link"}]},{name:"amex",vendorUrl:"https://www.americanexpress.com/",cosmetic:!1,prehideSelectors:["#user-consent-management-granular-banner-overlay"],detectCmp:[{exists:"#user-consent-management-granular-banner-overlay"}],detectPopup:[{visible:"#user-consent-management-granular-banner-overlay"}],optIn:[{waitForThenClick:"[data-testid=granular-banner-button-accept-all]"}],optOut:[{waitForThenClick:"[data-testid=granular-banner-button-decline-all]"}]},{name:"aquasana.com",prehideSelectors:["#consent-tracking"],detectCmp:[{exists:"#consent-tracking"}],detectPopup:[{exists:"#consent-tracking"}],optIn:[{waitForThenClick:"#consent-tracking .affirm.btn"}],optOut:[{if:{exists:"#consent-tracking .decline.btn"},then:[{click:"#consent-tracking .decline.btn"}],else:[{hide:"#consent-tracking"}]}]},{name:"arbeitsagentur",vendorUrl:"https://www.arbeitsagentur.de/",prehideSelectors:[".modal-open bahf-cookie-disclaimer-dpl3"],detectCmp:[{exists:"bahf-cookie-disclaimer-dpl3"}],detectPopup:[{visible:"bahf-cookie-disclaimer-dpl3"}],optIn:[{waitForThenClick:["bahf-cookie-disclaimer-dpl3","#bahf-cookie-disclaimer-modal .ba-btn-primary"]}],optOut:[{waitForThenClick:["bahf-cookie-disclaimer-dpl3","#bahf-cookie-disclaimer-modal .ba-btn-contrast"]}],test:[{eval:"EVAL_ARBEITSAGENTUR_TEST"}]},{name:"asus",vendorUrl:"https://www.asus.com/",runContext:{urlPattern:"^https://www\\.asus\\.com/"},prehideSelectors:["#cookie-policy-info,#cookie-policy-info-bg"],detectCmp:[{exists:"#cookie-policy-info"}],detectPopup:[{visible:"#cookie-policy-info"}],optIn:[{waitForThenClick:'#cookie-policy-info [data-agree="Accept Cookies"]'}],optOut:[{if:{exists:"#cookie-policy-info .btn-reject"},then:[{waitForThenClick:"#cookie-policy-info .btn-reject"}],else:[{waitForThenClick:"#cookie-policy-info .btn-setting"},{waitForThenClick:'#cookie-policy-lightbox-wrapper [data-agree="Save Settings"]'}]}]},{name:"athlinks-com",runContext:{urlPattern:"^https://(www\\.)?athlinks\\.com/"},cosmetic:!0,prehideSelectors:["#footer-container ~ div"],detectCmp:[{exists:"#footer-container ~ div"}],detectPopup:[{visible:"#footer-container > div"}],optIn:[{click:"#footer-container ~ div button"}],optOut:[{hide:"#footer-container ~ div"}]},{name:"ausopen.com",cosmetic:!0,detectCmp:[{exists:".gdpr-popup__message"}],detectPopup:[{visible:".gdpr-popup__message"}],optOut:[{hide:".gdpr-popup__message"}],optIn:[{click:".gdpr-popup__message button"}]},{name:"automattic-cmp-optout",prehideSelectors:['form[class*="cookie-banner"][method="post"]'],detectCmp:[{exists:'form[class*="cookie-banner"][method="post"]'}],detectPopup:[{visible:'form[class*="cookie-banner"][method="post"]'}],optIn:[{click:'a[class*="accept-all-button"]'}],optOut:[{click:'form[class*="cookie-banner"] div[class*="simple-options"] a[class*="customize-button"]'},{waitForThenClick:"input[type=checkbox][checked]:not([disabled])",all:!0},{click:'a[class*="accept-selection-button"]'}]},{name:"aws.amazon.com",prehideSelectors:["#awsccc-cb-content","#awsccc-cs-container","#awsccc-cs-modalOverlay","#awsccc-cs-container-inner"],detectCmp:[{exists:"#awsccc-cb-content"}],detectPopup:[{visible:"#awsccc-cb-content"}],optIn:[{click:"button[data-id=awsccc-cb-btn-accept"}],optOut:[{click:"button[data-id=awsccc-cb-btn-customize]"},{waitFor:"input[aria-checked]"},{click:"input[aria-checked=true]",all:!0,optional:!0},{click:"button[data-id=awsccc-cs-btn-save]"}]},{name:"axeptio",prehideSelectors:[".axeptio_widget"],detectCmp:[{exists:".axeptio_widget"}],detectPopup:[{visible:".axeptio_widget"}],optIn:[{waitFor:".axeptio-widget--open"},{click:"button#axeptio_btn_acceptAll"}],optOut:[{waitFor:".axeptio-widget--open"},{click:"button#axeptio_btn_dismiss"}],test:[{eval:"EVAL_AXEPTIO_0"}]},{name:"baden-wuerttemberg.de",prehideSelectors:[".cookie-alert.t-dark"],cosmetic:!0,detectCmp:[{exists:".cookie-alert.t-dark"}],detectPopup:[{visible:".cookie-alert.t-dark"}],optIn:[{click:".cookie-alert__form input:not([disabled]):not([checked])"},{click:".cookie-alert__button button"}],optOut:[{hide:".cookie-alert.t-dark"}]},{name:"bahn-de",vendorUrl:"https://www.bahn.de/",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?bahn\\.de/"},intermediate:!1,prehideSelectors:[],detectCmp:[{exists:["body > div:first-child","#consent-layer"]}],detectPopup:[{visible:["body > div:first-child","#consent-layer"]}],optIn:[{waitForThenClick:["body > div:first-child","#consent-layer .js-accept-all-cookies"]}],optOut:[{waitForThenClick:["body > div:first-child","#consent-layer .js-accept-essential-cookies"]}],test:[{eval:"EVAL_BAHN_TEST"}]},{name:"bbb.org",runContext:{urlPattern:"^https://www\\.bbb\\.org/"},cosmetic:!0,prehideSelectors:['div[aria-label="use of cookies on bbb.org"]'],detectCmp:[{exists:'div[aria-label="use of cookies on bbb.org"]'}],detectPopup:[{visible:'div[aria-label="use of cookies on bbb.org"]'}],optIn:[{click:'div[aria-label="use of cookies on bbb.org"] button.bds-button-unstyled span.visually-hidden'}],optOut:[{hide:'div[aria-label="use of cookies on bbb.org"]'}]},{name:"bing.com",prehideSelectors:["#bnp_container"],detectCmp:[{exists:"#bnp_cookie_banner"}],detectPopup:[{visible:"#bnp_cookie_banner"},{visible:"#bnp_btn_accept,#bnp_btn_reject"}],optIn:[{waitForThenClick:"#bnp_btn_accept"}],optOut:[{wait:500},{waitForThenClick:"#bnp_btn_reject"}],test:[{eval:"EVAL_BING_0"}]},{name:"blocksy",vendorUrl:"https://creativethemes.com/blocksy/docs/extensions/cookies-consent/",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,prehideSelectors:[".cookie-notification"],detectCmp:[{exists:"#blocksy-ext-cookies-consent-styles-css"}],detectPopup:[{visible:".cookie-notification"}],optIn:[{click:".cookie-notification .ct-cookies-decline-button"}],optOut:[{waitForThenClick:".cookie-notification .ct-cookies-decline-button"}],test:[{eval:"EVAL_BLOCKSY_0"}]},{name:"borlabs",detectCmp:[{exists:"._brlbs-block-content"}],detectPopup:[{visible:"._brlbs-bar-wrap,._brlbs-box-wrap"}],optIn:[{click:"a[data-cookie-accept-all]"}],optOut:[{click:"a[data-cookie-individual]"},{waitForVisible:".cookie-preference"},{click:"input[data-borlabs-cookie-checkbox]:checked",all:!0,optional:!0},{click:"#CookiePrefSave"},{wait:500}],prehideSelectors:["#BorlabsCookieBox"],test:[{eval:"EVAL_BORLABS_0"}]},{name:"bundesregierung.de",prehideSelectors:[".bpa-cookie-banner"],detectCmp:[{exists:".bpa-cookie-banner"}],detectPopup:[{visible:".bpa-cookie-banner .bpa-module-full-hero"}],optIn:[{click:".bpa-accept-all-button"}],optOut:[{wait:500,comment:"click is not immediately recognized"},{waitForThenClick:".bpa-close-button"}],test:[{eval:"EVAL_BUNDESREGIERUNG_DE_0"}]},{name:"burpee.com",cosmetic:!0,prehideSelectors:["#notice-cookie-block"],detectCmp:[{exists:"#notice-cookie-block"}],detectPopup:[{exists:"#html-body #notice-cookie-block"}],optIn:[{click:"#btn-cookie-allow"}],optOut:[{hide:"#html-body #notice-cookie-block, #notice-cookie"}]},{name:"canva.com",prehideSelectors:['div[role="dialog"] a[data-anchor-id="cookie-policy"]'],detectCmp:[{exists:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'}],detectPopup:[{exists:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'}],optIn:[{click:'div[role="dialog"] button:nth-child(1)'}],optOut:[{if:{exists:'div[role="dialog"] button:nth-child(3)'},then:[{click:'div[role="dialog"] button:nth-child(2)'}],else:[{click:'div[role="dialog"] button:nth-child(2)'},{waitFor:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'},{waitFor:'div[role="dialog"] button[role=switch]'},{click:'div[role="dialog"] button:nth-child(2):not([role])'},{click:'div[role="dialog"] div:last-child button:only-child'}]}],test:[{eval:"EVAL_CANVA_0"}]},{name:"canyon.com",runContext:{urlPattern:"^https://www\\.canyon\\.com/"},prehideSelectors:["div.modal.cookiesModal.is-open"],detectCmp:[{exists:"div.modal.cookiesModal.is-open"}],detectPopup:[{visible:"div.modal.cookiesModal.is-open"}],optIn:[{click:'div.cookiesModal__buttonWrapper > button[data-closecause="close-by-submit"]'}],optOut:[{click:'div.cookiesModal__buttonWrapper > button[data-closecause="close-by-manage-cookies"]'},{waitForThenClick:"button#js-manage-data-privacy-save-button"}]},{name:"cc-banner-springer",prehideSelectors:[".cc-banner[data-cc-banner]"],detectCmp:[{exists:".cc-banner[data-cc-banner]"}],detectPopup:[{visible:".cc-banner[data-cc-banner]"}],optIn:[{waitForThenClick:".cc-banner[data-cc-banner] button[data-cc-action=accept]"}],optOut:[{if:{exists:".cc-banner[data-cc-banner] button[data-cc-action=reject]"},then:[{click:".cc-banner[data-cc-banner] button[data-cc-action=reject]"}],else:[{waitForThenClick:".cc-banner[data-cc-banner] button[data-cc-action=preferences]"},{waitFor:".cc-preferences[data-cc-preferences]"},{click:".cc-preferences[data-cc-preferences] input[type=radio][data-cc-action=toggle-category][value=off]",all:!0,optional:!0},{if:{exists:".cc-preferences[data-cc-preferences] button[data-cc-action=reject]"},then:[{click:".cc-preferences[data-cc-preferences] button[data-cc-action=reject]"}],else:[{click:".cc-preferences[data-cc-preferences] button[data-cc-action=save]"}]}]}],test:[{eval:"EVAL_CC_BANNER2_0"}]},{name:"cc_banner",cosmetic:!0,prehideSelectors:[".cc_banner-wrapper"],detectCmp:[{exists:".cc_banner-wrapper"}],detectPopup:[{visible:".cc_banner"}],optIn:[{click:".cc_btn_accept_all"}],optOut:[{hide:".cc_banner-wrapper"}]},{name:"check24-partnerprogramm-de",prehideSelectors:["[data-modal-content]:has([data-toggle-target^='cookie'])"],detectCmp:[{exists:"[data-toggle-target^='cookie']"}],detectPopup:[{visible:"[data-toggle-target^='cookie']",check:"any"}],optIn:[{waitForThenClick:"[data-cookie-accept-all]"}],optOut:[{waitForThenClick:"[data-cookie-dismiss-all]"}]},{name:"ciaopeople.it",prehideSelectors:["#cp-gdpr-choices"],detectCmp:[{exists:"#cp-gdpr-choices"}],detectPopup:[{visible:"#cp-gdpr-choices"}],optIn:[{waitForThenClick:".gdpr-btm__right > button:nth-child(2)"}],optOut:[{waitForThenClick:".gdpr-top-content > button"},{waitFor:".gdpr-top-back"},{waitForThenClick:".gdpr-btm__right > button:nth-child(1)"}],test:[{visible:"#cp-gdpr-choices",check:"none"}]},{vendorUrl:"https://www.civicuk.com/cookie-control/",name:"civic-cookie-control",prehideSelectors:["#ccc-module,#ccc-overlay"],detectCmp:[{exists:"#ccc-module"}],detectPopup:[{visible:"#ccc"},{visible:"#ccc-module"}],optOut:[{click:"#ccc-reject-settings"}],optIn:[{click:"#ccc-recommended-settings"}]},{name:"click.io",prehideSelectors:["#cl-consent"],detectCmp:[{exists:"#cl-consent"}],detectPopup:[{visible:"#cl-consent"}],optIn:[{waitForThenClick:'#cl-consent [data-role="b_agree"]'}],optOut:[{waitFor:'#cl-consent [data-role="b_options"]'},{wait:500},{click:'#cl-consent [data-role="b_options"]'},{waitFor:'.cl-consent-popup.cl-consent-visible [data-role="alloff"]'},{click:'.cl-consent-popup.cl-consent-visible [data-role="alloff"]',all:!0},{click:'[data-role="b_save"]'}],test:[{eval:"EVAL_CLICKIO_0",comment:"TODO: this only checks if we interacted at all"}]},{name:"clinch",intermediate:!1,runContext:{frame:!1,main:!0},prehideSelectors:[".consent-modal[role=dialog]"],detectCmp:[{exists:".consent-modal[role=dialog]"}],detectPopup:[{visible:".consent-modal[role=dialog]"}],optIn:[{click:"#consent_agree"}],optOut:[{if:{exists:"#consent_reject"},then:[{click:"#consent_reject"}],else:[{click:"#manage_cookie_preferences"},{click:"#cookie_consent_preferences input:checked",all:!0,optional:!0},{click:"#consent_save"}]}],test:[{eval:"EVAL_CLINCH_0"}]},{name:"clustrmaps.com",runContext:{urlPattern:"^https://(www\\.)?clustrmaps\\.com/"},cosmetic:!0,prehideSelectors:["#gdpr-cookie-message"],detectCmp:[{exists:"#gdpr-cookie-message"}],detectPopup:[{visible:"#gdpr-cookie-message"}],optIn:[{click:"button#gdpr-cookie-accept"}],optOut:[{hide:"#gdpr-cookie-message"}]},{name:"coinbase",intermediate:!1,runContext:{frame:!0,main:!0,urlPattern:"^https://(www|help)\\.coinbase\\.com"},prehideSelectors:[],detectCmp:[{exists:"div[class^=CookieBannerContent__Container]"}],detectPopup:[{visible:"div[class^=CookieBannerContent__Container]"}],optIn:[{click:"div[class^=CookieBannerContent__CTA] :nth-last-child(1)"}],optOut:[{click:"button[class^=CookieBannerContent__Settings]"},{click:"div[class^=CookiePreferencesModal__CategoryContainer] input:checked",all:!0,optional:!0},{click:"div[class^=CookiePreferencesModal__ButtonContainer] > button"}],test:[{eval:"EVAL_COINBASE_0"}]},{name:"Complianz banner",prehideSelectors:["#cmplz-cookiebanner-container"],detectCmp:[{exists:"#cmplz-cookiebanner-container .cmplz-cookiebanner"}],detectPopup:[{visible:"#cmplz-cookiebanner-container .cmplz-cookiebanner",check:"any"}],optIn:[{waitForThenClick:".cmplz-cookiebanner .cmplz-accept"}],optOut:[{waitForThenClick:".cmplz-cookiebanner .cmplz-deny"}],test:[{eval:"EVAL_COMPLIANZ_BANNER_0"}]},{name:"Complianz categories",prehideSelectors:['.cc-type-categories[aria-describedby="cookieconsent:desc"]'],detectCmp:[{exists:'.cc-type-categories[aria-describedby="cookieconsent:desc"]'}],detectPopup:[{visible:'.cc-type-categories[aria-describedby="cookieconsent:desc"]'}],optIn:[{any:[{click:".cc-accept-all"},{click:".cc-allow-all"},{click:".cc-allow"},{click:".cc-dismiss"}]}],optOut:[{if:{exists:'.cc-type-categories[aria-describedby="cookieconsent:desc"] .cc-dismiss'},then:[{click:".cc-dismiss"}],else:[{click:".cc-type-categories input[type=checkbox]:not([disabled]):checked",all:!0,optional:!0},{click:".cc-save"}]}]},{name:"Complianz notice",prehideSelectors:['.cc-type-info[aria-describedby="cookieconsent:desc"]'],cosmetic:!0,detectCmp:[{exists:'.cc-type-info[aria-describedby="cookieconsent:desc"] .cc-compliance .cc-btn'}],detectPopup:[{visible:'.cc-type-info[aria-describedby="cookieconsent:desc"] .cc-compliance .cc-btn'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{if:{exists:".cc-deny"},then:[{click:".cc-deny"}],else:[{hide:'[aria-describedby="cookieconsent:desc"]'}]}]},{name:"Complianz opt-both",prehideSelectors:['[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'],detectCmp:[{exists:'[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'}],detectPopup:[{visible:'[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{waitForThenClick:".cc-deny"}]},{name:"Complianz opt-out",prehideSelectors:['[aria-describedby="cookieconsent:desc"].cc-type-opt-out'],detectCmp:[{exists:'[aria-describedby="cookieconsent:desc"].cc-type-opt-out'}],detectPopup:[{visible:'[aria-describedby="cookieconsent:desc"].cc-type-opt-out'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{if:{exists:".cc-deny"},then:[{click:".cc-deny"}],else:[{if:{exists:".cmp-pref-link"},then:[{click:".cmp-pref-link"},{waitForThenClick:".cmp-body [id*=rejectAll]"},{waitForThenClick:".cmp-body .cmp-save-btn"}]}]}]},{name:"Complianz optin",prehideSelectors:['.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'],detectCmp:[{exists:'.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'}],detectPopup:[{visible:'.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'}],optIn:[{any:[{click:".cc-accept-all"},{click:".cc-allow"},{click:".cc-dismiss"}]}],optOut:[{if:{visible:".cc-deny"},then:[{click:".cc-deny"}],else:[{if:{visible:".cc-settings"},then:[{waitForThenClick:".cc-settings"},{waitForVisible:".cc-settings-view"},{click:".cc-settings-view input[type=checkbox]:not([disabled]):checked",all:!0,optional:!0},{click:".cc-settings-view .cc-btn-accept-selected"}],else:[{click:".cc-dismiss"}]}]}]},{name:"cookie-law-info",prehideSelectors:["#cookie-law-info-bar"],detectCmp:[{exists:"#cookie-law-info-bar"},{eval:"EVAL_COOKIE_LAW_INFO_DETECT"}],detectPopup:[{visible:"#cookie-law-info-bar"}],optIn:[{click:'[data-cli_action="accept_all"]'}],optOut:[{hide:"#cookie-law-info-bar"},{eval:"EVAL_COOKIE_LAW_INFO_0"}],test:[{eval:"EVAL_COOKIE_LAW_INFO_1"}]},{name:"cookie-manager-popup",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,detectCmp:[{exists:"#notice-cookie-block #allow-functional-cookies, #notice-cookie-block #btn-cookie-settings"}],detectPopup:[{visible:"#notice-cookie-block"}],optIn:[{click:"#btn-cookie-allow"}],optOut:[{if:{exists:"#allow-functional-cookies"},then:[{click:"#allow-functional-cookies"}],else:[{waitForThenClick:"#btn-cookie-settings"},{waitForVisible:".modal-body"},{click:'.modal-body input:checked, .switch[data-switch="on"]',all:!0,optional:!0},{click:'[role="dialog"] .modal-footer button'}]}],prehideSelectors:["#btn-cookie-settings"],test:[{eval:"EVAL_COOKIE_MANAGER_POPUP_0"}]},{name:"cookie-notice",prehideSelectors:["#cookie-notice"],cosmetic:!0,detectCmp:[{visible:"#cookie-notice .cookie-notice-container"}],detectPopup:[{visible:"#cookie-notice"}],optIn:[{click:"#cn-accept-cookie"}],optOut:[{hide:"#cookie-notice"}]},{name:"cookie-script",vendorUrl:"https://cookie-script.com/",prehideSelectors:["#cookiescript_injected"],detectCmp:[{exists:"#cookiescript_injected"}],detectPopup:[{visible:"#cookiescript_injected"}],optOut:[{if:{exists:"#cookiescript_reject"},then:[{wait:100},{click:"#cookiescript_reject"}],else:[{click:"#cookiescript_manage"},{waitForVisible:".cookiescript_fsd_main"},{waitForThenClick:"#cookiescript_reject"}]}],optIn:[{click:"#cookiescript_accept"}]},{name:"cookieacceptbar",vendorUrl:"https://unknown",cosmetic:!0,prehideSelectors:["#cookieAcceptBar.cookieAcceptBar"],detectCmp:[{exists:"#cookieAcceptBar.cookieAcceptBar"}],detectPopup:[{visible:"#cookieAcceptBar.cookieAcceptBar"}],optIn:[{waitForThenClick:"#cookieAcceptBarConfirm"}],optOut:[{hide:"#cookieAcceptBar.cookieAcceptBar"}]},{name:"cookiealert",intermediate:!1,prehideSelectors:[],runContext:{frame:!0,main:!0},detectCmp:[{exists:".cookie-alert-extended"}],detectPopup:[{visible:".cookie-alert-extended-modal"}],optIn:[{click:"button[data-controller='cookie-alert/extended/button/accept']"},{eval:"EVAL_COOKIEALERT_0"}],optOut:[{click:"a[data-controller='cookie-alert/extended/detail-link']"},{click:".cookie-alert-configuration-input:checked",all:!0,optional:!0},{click:"button[data-controller='cookie-alert/extended/button/configuration']"},{eval:"EVAL_COOKIEALERT_0"}],test:[{eval:"EVAL_COOKIEALERT_2"}]},{name:"cookieconsent2",vendorUrl:"https://www.github.com/orestbida/cookieconsent",comment:"supports v2.x.x of the library",prehideSelectors:["#cc--main"],detectCmp:[{exists:"#cc--main"}],detectPopup:[{visible:"#cm"},{exists:"#s-all-bn"}],optIn:[{waitForThenClick:"#s-all-bn"}],optOut:[{waitForThenClick:"#s-rall-bn"}],test:[{eval:"EVAL_COOKIECONSENT2_TEST"}]},{name:"cookieconsent3",vendorUrl:"https://www.github.com/orestbida/cookieconsent",comment:"supports v3.x.x of the library",prehideSelectors:["#cc-main"],detectCmp:[{exists:"#cc-main"}],detectPopup:[{visible:"#cc-main .cm-wrapper"}],optIn:[{waitForThenClick:".cm__btn[data-role=all]"}],optOut:[{waitForThenClick:".cm__btn[data-role=necessary]"}],test:[{eval:"EVAL_COOKIECONSENT3_TEST"}]},{name:"cookiecuttr",vendorUrl:"https://github.com/cdwharton/cookieCuttr",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:""},prehideSelectors:[".cc-cookies"],detectCmp:[{exists:".cc-cookies .cc-cookie-accept"}],detectPopup:[{visible:".cc-cookies .cc-cookie-accept"}],optIn:[{waitForThenClick:".cc-cookies .cc-cookie-accept"}],optOut:[{if:{exists:".cc-cookies .cc-cookie-decline"},then:[{click:".cc-cookies .cc-cookie-decline"}],else:[{hide:".cc-cookies"}]}]},{name:"cookiefirst.com",prehideSelectors:["#cookiefirst-root,.cookiefirst-root,[aria-labelledby=cookie-preference-panel-title]"],detectCmp:[{exists:"#cookiefirst-root,.cookiefirst-root"}],detectPopup:[{visible:"#cookiefirst-root,.cookiefirst-root"}],optIn:[{click:"button[data-cookiefirst-action=accept]"}],optOut:[{if:{exists:"button[data-cookiefirst-action=adjust]"},then:[{click:"button[data-cookiefirst-action=adjust]"},{waitForVisible:"[data-cookiefirst-widget=modal]",timeout:1e3},{eval:"EVAL_COOKIEFIRST_1"},{wait:1e3},{click:"button[data-cookiefirst-action=save]"}],else:[{click:"button[data-cookiefirst-action=reject]"}]}],test:[{eval:"EVAL_COOKIEFIRST_0"}]},{name:"Cookie Information Banner",prehideSelectors:["#cookie-information-template-wrapper"],detectCmp:[{exists:"#cookie-information-template-wrapper"}],detectPopup:[{visible:"#cookie-information-template-wrapper"}],optIn:[{eval:"EVAL_COOKIEINFORMATION_1"}],optOut:[{hide:"#cookie-information-template-wrapper",comment:"some templates don't hide the banner automatically"},{eval:"EVAL_COOKIEINFORMATION_0"}],test:[{eval:"EVAL_COOKIEINFORMATION_2"}]},{name:"cookieyes",prehideSelectors:[".cky-overlay,.cky-consent-container"],detectCmp:[{exists:".cky-consent-container"}],detectPopup:[{visible:".cky-consent-container"}],optIn:[{waitForThenClick:".cky-consent-container [data-cky-tag=accept-button]"}],optOut:[{if:{exists:".cky-consent-container [data-cky-tag=reject-button]"},then:[{waitForThenClick:".cky-consent-container [data-cky-tag=reject-button]"}],else:[{if:{exists:".cky-consent-container [data-cky-tag=settings-button]"},then:[{click:".cky-consent-container [data-cky-tag=settings-button]"},{waitFor:".cky-modal-open input[type=checkbox]"},{click:".cky-modal-open input[type=checkbox]:checked",all:!0,optional:!0},{waitForThenClick:".cky-modal [data-cky-tag=detail-save-button]"}],else:[{hide:".cky-consent-container,.cky-overlay"}]}]}],test:[{eval:"EVAL_COOKIEYES_0"}]},{name:"corona-in-zahlen.de",prehideSelectors:[".cookiealert"],detectCmp:[{exists:".cookiealert"}],detectPopup:[{visible:".cookiealert"}],optOut:[{click:".configurecookies"},{click:".confirmcookies"}],optIn:[{click:".acceptcookies"}]},{name:"crossfit-com",cosmetic:!0,prehideSelectors:['body #modal > div > div[class^="_wrapper_"]'],detectCmp:[{exists:'body #modal > div > div[class^="_wrapper_"]'}],detectPopup:[{visible:'body #modal > div > div[class^="_wrapper_"]'}],optIn:[{click:'button[aria-label="accept cookie policy"]'}],optOut:[{hide:'body #modal > div > div[class^="_wrapper_"]'}]},{name:"csu-landtag-de",runContext:{urlPattern:"^https://(www\\.|)?csu-landtag\\.de"},prehideSelectors:["#cookie-disclaimer"],detectCmp:[{exists:"#cookie-disclaimer"}],detectPopup:[{visible:"#cookie-disclaimer"}],optIn:[{click:"#cookieall"}],optOut:[{click:"#cookiesel"}]},{name:"dailymotion-us",cosmetic:!0,prehideSelectors:['div[class*="CookiePopup__desktopContainer"]:has(div[class*="CookiePopup"])'],detectCmp:[{exists:'div[class*="CookiePopup__desktopContainer"]'}],detectPopup:[{visible:'div[class*="CookiePopup__desktopContainer"]'}],optIn:[{click:'div[class*="CookiePopup__desktopContainer"] > button > span'}],optOut:[{hide:'div[class*="CookiePopup__desktopContainer"]'}]},{name:"dailymotion.com",runContext:{urlPattern:"^https://(www\\.)?dailymotion\\.com/"},prehideSelectors:['div[class*="Overlay__container"]:has(div[class*="TCF2Popup"])'],detectCmp:[{exists:'div[class*="TCF2Popup"]'}],detectPopup:[{visible:'[class*="TCF2Popup"] a[href^="https://www.dailymotion.com/legal/cookiemanagement"]'}],optIn:[{waitForThenClick:'button[class*="TCF2Popup__button"]:not([class*="TCF2Popup__personalize"])'}],optOut:[{waitForThenClick:'button[class*="TCF2ContinueWithoutAcceptingButton"]'}],test:[{eval:"EVAL_DAILYMOTION_0"}]},{name:"dan-com",vendorUrl:"https://unknown",runContext:{main:!0,frame:!1},prehideSelectors:[],detectCmp:[{exists:".cookie-banner.show .cookie-banner__content-all-btn"}],detectPopup:[{visible:".cookie-banner.show .cookie-banner__content-all-btn"}],optIn:[{waitForThenClick:".cookie-banner__content-all-btn"}],optOut:[{waitForThenClick:".cookie-banner__content-essential-btn"}]},{name:"deepl.com",prehideSelectors:[".dl_cookieBanner_container"],detectCmp:[{exists:".dl_cookieBanner_container"}],detectPopup:[{visible:".dl_cookieBanner_container"}],optOut:[{click:".dl_cookieBanner--buttonSelected"}],optIn:[{click:".dl_cookieBanner--buttonAll"}]},{name:"delta.com",runContext:{urlPattern:"^https://www\\.delta\\.com/"},cosmetic:!0,prehideSelectors:["ngc-cookie-banner"],detectCmp:[{exists:"div.cookie-footer-container"}],detectPopup:[{visible:"div.cookie-footer-container"}],optIn:[{click:" button.cookie-close-icon"}],optOut:[{hide:"div.cookie-footer-container"}]},{name:"dmgmedia-us",prehideSelectors:["#mol-ads-cmp-iframe, div.mol-ads-cmp > form > div"],detectCmp:[{exists:"div.mol-ads-cmp > form > div"}],detectPopup:[{waitForVisible:"div.mol-ads-cmp > form > div"}],optIn:[{waitForThenClick:"button.mol-ads-cmp--btn-primary"}],optOut:[{waitForThenClick:"div.mol-ads-ccpa--message > u > a"},{waitForVisible:".mol-ads-cmp--modal-dialog"},{waitForThenClick:"a.mol-ads-cmp-footer-privacy"},{waitForThenClick:"button.mol-ads-cmp--btn-secondary"}]},{name:"dmgmedia",prehideSelectors:['[data-project="mol-fe-cmp"]'],detectCmp:[{exists:'[data-project="mol-fe-cmp"] [class*=footer]'}],detectPopup:[{visible:'[data-project="mol-fe-cmp"] [class*=footer]'}],optIn:[{waitForThenClick:'[data-project="mol-fe-cmp"] button[class*=primary]'}],optOut:[{waitForThenClick:'[data-project="mol-fe-cmp"] button[class*=basic]'},{waitForVisible:'[data-project="mol-fe-cmp"] div[class*="tabContent"]'},{waitForThenClick:'[data-project="mol-fe-cmp"] div[class*="toggle"][class*="enabled"]',all:!0},{waitForThenClick:['[data-project="mol-fe-cmp"] [class*=footer]',"xpath///button[contains(., 'Save & Exit')]"]}]},{name:"dndbeyond",vendorUrl:"https://www.dndbeyond.com/",runContext:{urlPattern:"^https://(www\\.)?dndbeyond\\.com/"},prehideSelectors:["[id^=cookie-consent-banner]"],detectCmp:[{exists:"[id^=cookie-consent-banner]"}],detectPopup:[{visible:"[id^=cookie-consent-banner]"}],optIn:[{waitForThenClick:"#cookie-consent-granted"}],optOut:[{waitForThenClick:"#cookie-consent-denied"}],test:[{eval:"EVAL_DNDBEYOND_TEST"}]},{name:"dpgmedia-nl",prehideSelectors:["#pg-shadow-root-host"],detectCmp:[{exists:"#pg-shadow-root-host"}],detectPopup:[{visible:["#pg-shadow-root-host","#pg-modal"]}],optIn:[{waitForThenClick:["#pg-shadow-root-host","#pg-accept-btn"]}],optOut:[{waitForThenClick:["#pg-shadow-root-host","#pg-configure-btn"]},{waitForThenClick:["#pg-shadow-root-host","#pg-reject-btn"]}]},{name:"Drupal",detectCmp:[{exists:"#drupalorg-crosssite-gdpr"}],detectPopup:[{visible:"#drupalorg-crosssite-gdpr"}],optOut:[{click:".no"}],optIn:[{click:".yes"}]},{name:"WP DSGVO Tools",link:"https://wordpress.org/plugins/shapepress-dsgvo/",prehideSelectors:[".sp-dsgvo"],cosmetic:!0,detectCmp:[{exists:".sp-dsgvo.sp-dsgvo-popup-overlay"}],detectPopup:[{visible:".sp-dsgvo.sp-dsgvo-popup-overlay",check:"any"}],optIn:[{click:".sp-dsgvo-privacy-btn-accept-all",all:!0}],optOut:[{hide:".sp-dsgvo.sp-dsgvo-popup-overlay"}],test:[{eval:"EVAL_DSGVO_0"}]},{name:"dunelm.com",prehideSelectors:["div[data-testid=cookie-consent-modal-backdrop]"],detectCmp:[{exists:"div[data-testid=cookie-consent-message-contents]"}],detectPopup:[{visible:"div[data-testid=cookie-consent-message-contents]"}],optIn:[{click:'[data-testid="cookie-consent-allow-all"]'}],optOut:[{click:"button[data-testid=cookie-consent-adjust-settings]"},{click:"button[data-testid=cookie-consent-preferences-save]"}],test:[{eval:"EVAL_DUNELM_0"}]},{name:"ebay",vendorUrl:"https://ebay.com",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?ebay\\.([.a-z]+)/"},prehideSelectors:["#gdpr-banner"],detectCmp:[{exists:"#gdpr-banner"}],detectPopup:[{visible:"#gdpr-banner"}],optIn:[{waitForThenClick:"#gdpr-banner-accept"}],optOut:[{waitForThenClick:"#gdpr-banner-decline"}]},{name:"ecosia",vendorUrl:"https://www.ecosia.org/",runContext:{urlPattern:"^https://www\\.ecosia\\.org/"},prehideSelectors:[".cookie-wrapper"],detectCmp:[{exists:".cookie-wrapper > .cookie-notice"}],detectPopup:[{visible:".cookie-wrapper > .cookie-notice"}],optIn:[{waitForThenClick:"[data-test-id=cookie-notice-accept]"}],optOut:[{waitForThenClick:"[data-test-id=cookie-notice-reject]"}]},{name:"Ensighten ensModal",prehideSelectors:[".ensModal"],detectCmp:[{exists:".ensModal"}],detectPopup:[{visible:"#ensModalWrapper[style*=block]"}],optIn:[{waitForThenClick:"#modalAcceptButton"}],optOut:[{wait:500},{visible:"#ensModalWrapper[style*=block]"},{waitForThenClick:".ensCheckbox:checked",all:!0},{waitForThenClick:"#ensSave"}]},{name:"Ensighten ensNotifyBanner",prehideSelectors:["#ensNotifyBanner"],detectCmp:[{exists:"#ensNotifyBanner"}],detectPopup:[{visible:"#ensNotifyBanner[style*=block]"}],optIn:[{waitForThenClick:"#ensCloseBanner"}],optOut:[{wait:500},{visible:"#ensNotifyBanner[style*=block]"},{waitForThenClick:"#ensRejectAll,#rejectAll,#ensRejectBanner,.rejectAll,#ensCloseBanner",timeout:2e3}]},{name:"espace-personnel.agirc-arrco.fr",runContext:{urlPattern:"^https://espace-personnel\\.agirc-arrco\\.fr/"},prehideSelectors:[".cdk-overlay-container"],detectCmp:[{exists:".cdk-overlay-container app-esaa-cookie-component"}],detectPopup:[{visible:".cdk-overlay-container app-esaa-cookie-component"}],optIn:[{waitForThenClick:".btn-cookie-accepter"}],optOut:[{waitForThenClick:".btn-cookie-refuser"}]},{name:"etsy",prehideSelectors:["#gdpr-single-choice-overlay","#gdpr-privacy-settings"],detectCmp:[{exists:"#gdpr-single-choice-overlay"}],detectPopup:[{visible:"#gdpr-single-choice-overlay"}],optOut:[{click:"button[data-gdpr-open-full-settings]"},{waitForVisible:".gdpr-overlay-body input",timeout:3e3},{wait:1e3},{eval:"EVAL_ETSY_0"},{eval:"EVAL_ETSY_1"}],optIn:[{click:"button[data-gdpr-single-choice-accept]"}]},{name:"eu-cookie-compliance-banner",detectCmp:[{exists:"body.eu-cookie-compliance-popup-open"}],detectPopup:[{exists:"body.eu-cookie-compliance-popup-open"}],optIn:[{click:".agree-button"}],optOut:[{if:{visible:".decline-button,.eu-cookie-compliance-save-preferences-button"},then:[{click:".decline-button,.eu-cookie-compliance-save-preferences-button"}]},{hide:".eu-cookie-compliance-banner-info, #sliding-popup"}],test:[{eval:"EVAL_EU_COOKIE_COMPLIANCE_0"}]},{name:"EU Cookie Law",prehideSelectors:[".pea_cook_wrapper,.pea_cook_more_info_popover"],cosmetic:!0,detectCmp:[{exists:".pea_cook_wrapper"}],detectPopup:[{wait:500},{visible:".pea_cook_wrapper"}],optIn:[{click:"#pea_cook_btn"}],optOut:[{hide:".pea_cook_wrapper"}],test:[{eval:"EVAL_EU_COOKIE_LAW_0"}]},{name:"europa-eu",vendorUrl:"https://ec.europa.eu/",runContext:{urlPattern:"^https://[^/]*europa\\.eu/"},prehideSelectors:["#cookie-consent-banner"],detectCmp:[{exists:".cck-container"}],detectPopup:[{visible:".cck-container"}],optIn:[{waitForThenClick:'.cck-actions-button[href="#accept"]'}],optOut:[{waitForThenClick:'.cck-actions-button[href="#refuse"]',hide:".cck-container"}]},{name:"EZoic",prehideSelectors:["#ez-cookie-dialog-wrapper"],detectCmp:[{exists:"#ez-cookie-dialog-wrapper"}],detectPopup:[{visible:"#ez-cookie-dialog-wrapper"}],optIn:[{click:"#ez-accept-all",optional:!0},{eval:"EVAL_EZOIC_0",optional:!0}],optOut:[{wait:500},{click:"#ez-manage-settings"},{waitFor:"#ez-cookie-dialog input[type=checkbox]"},{click:"#ez-cookie-dialog input[type=checkbox]:checked",all:!0},{click:"#ez-save-settings"}],test:[{eval:"EVAL_EZOIC_1"}]},{name:"facebook",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?facebook\\.com/"},prehideSelectors:['div[data-testid="cookie-policy-manage-dialog"]'],detectCmp:[{exists:'div[data-testid="cookie-policy-manage-dialog"]'}],detectPopup:[{visible:'div[data-testid="cookie-policy-manage-dialog"]'}],optIn:[{waitForThenClick:'button[data-cookiebanner="accept_button"]'},{waitForVisible:'div[data-testid="cookie-policy-manage-dialog"]',check:"none"}],optOut:[{waitForThenClick:'button[data-cookiebanner="accept_only_essential_button"]'},{waitForVisible:'div[data-testid="cookie-policy-manage-dialog"]',check:"none"}]},{name:"fides",vendorUrl:"https://github.com/ethyca/fides",prehideSelectors:["#fides-overlay"],detectCmp:[{exists:"#fides-overlay #fides-banner"}],detectPopup:[{visible:"#fides-overlay #fides-banner"},{eval:"EVAL_FIDES_DETECT_POPUP"}],optIn:[{waitForThenClick:"#fides-banner .fides-accept-all-button"}],optOut:[{waitForThenClick:"#fides-banner .fides-reject-all-button"}]},{name:"funding-choices",prehideSelectors:[".fc-consent-root,.fc-dialog-container,.fc-dialog-overlay,.fc-dialog-content"],detectCmp:[{exists:".fc-consent-root"}],detectPopup:[{exists:".fc-dialog-container"}],optOut:[{click:".fc-cta-do-not-consent,.fc-cta-manage-options"},{click:".fc-preference-consent:checked,.fc-preference-legitimate-interest:checked",all:!0,optional:!0},{click:".fc-confirm-choices",optional:!0}],optIn:[{click:".fc-cta-consent"}]},{name:"geeks-for-geeks",runContext:{urlPattern:"^https://www\\.geeksforgeeks\\.org/"},cosmetic:!0,prehideSelectors:[".cookie-consent"],detectCmp:[{exists:".cookie-consent"}],detectPopup:[{visible:".cookie-consent"}],optIn:[{click:".cookie-consent button.consent-btn"}],optOut:[{hide:".cookie-consent"}]},{name:"google-consent-standalone",prehideSelectors:[],detectCmp:[{exists:'a[href^="https://policies.google.com/technologies/cookies"'},{exists:'form[action^="https://consent.google."][action$="/save"]'}],detectPopup:[{visible:'a[href^="https://policies.google.com/technologies/cookies"'}],optIn:[{waitForThenClick:'form[action^="https://consent.google."][action$="/save"]:has(input[name=set_eom][value=false]) button'}],optOut:[{waitForThenClick:'form[action^="https://consent.google."][action$="/save"]:has(input[name=set_eom][value=true]) button'}]},{name:"google-cookiebar",vendorUrl:"https://www.android.com/better-together/quick-share-app/",cosmetic:!1,prehideSelectors:[".glue-cookie-notification-bar"],detectCmp:[{exists:".glue-cookie-notification-bar"}],detectPopup:[{visible:".glue-cookie-notification-bar"}],optIn:[{waitForThenClick:".glue-cookie-notification-bar__accept"}],optOut:[{if:{exists:".glue-cookie-notification-bar__reject"},then:[{click:".glue-cookie-notification-bar__reject"}],else:[{hide:".glue-cookie-notification-bar"}]}],test:[]},{name:"google.com",prehideSelectors:[".HTjtHe#xe7COe"],detectCmp:[{exists:".HTjtHe#xe7COe"},{exists:'.HTjtHe#xe7COe a[href^="https://policies.google.com/technologies/cookies"]'}],detectPopup:[{visible:".HTjtHe#xe7COe button#W0wltc"}],optIn:[{waitForThenClick:".HTjtHe#xe7COe button#L2AGLb"}],optOut:[{waitForThenClick:".HTjtHe#xe7COe button#W0wltc"}],test:[{eval:"EVAL_GOOGLE_0"}]},{name:"gov.uk",detectCmp:[{exists:"#global-cookie-message"}],detectPopup:[{exists:"#global-cookie-message"}],optIn:[{click:"button[data-accept-cookies=true]"}],optOut:[{click:"button[data-reject-cookies=true],#reject-cookies"},{click:"button[data-hide-cookie-banner=true],#hide-cookie-decision"}]},{name:"hashicorp",vendorUrl:"https://hashicorp.com/",runContext:{urlPattern:"^https://[^.]*\\.hashicorp\\.com/"},prehideSelectors:["[data-testid=consent-banner]"],detectCmp:[{exists:"[data-testid=consent-banner]"}],detectPopup:[{visible:"[data-testid=consent-banner]"}],optIn:[{waitForThenClick:"[data-testid=accept]"}],optOut:[{waitForThenClick:"[data-testid=manage-preferences]"},{waitForThenClick:"[data-testid=consent-mgr-dialog] [data-ga-button=save-preferences]"}]},{name:"healthline-media",prehideSelectors:["#modal-host > div.no-hash > div.window-wrapper"],detectCmp:[{exists:"#modal-host > div.no-hash > div.window-wrapper, div[data-testid=qualtrics-container]"}],detectPopup:[{exists:"#modal-host > div.no-hash > div.window-wrapper, div[data-testid=qualtrics-container]"}],optIn:[{click:"#modal-host > div.no-hash > div.window-wrapper > div:last-child button"}],optOut:[{if:{exists:'#modal-host > div.no-hash > div.window-wrapper > div:last-child a[href="/privacy-settings"]'},then:[{click:'#modal-host > div.no-hash > div.window-wrapper > div:last-child a[href="/privacy-settings"]'}],else:[{waitForVisible:"div#__next"},{click:"#__next div:nth-child(1) > button:first-child"}]}]},{name:"hema",prehideSelectors:[".cookie-modal"],detectCmp:[{visible:".cookie-modal .cookie-accept-btn"}],detectPopup:[{visible:".cookie-modal .cookie-accept-btn"}],optIn:[{waitForThenClick:".cookie-modal .cookie-accept-btn"}],optOut:[{waitForThenClick:".cookie-modal .js-cookie-reject-btn"}],test:[{eval:"EVAL_HEMA_TEST_0"}]},{name:"hetzner.com",runContext:{urlPattern:"^https://www\\.hetzner\\.com/"},prehideSelectors:["#CookieConsent"],detectCmp:[{exists:"#CookieConsent"}],detectPopup:[{visible:"#CookieConsent"}],optIn:[{click:"#CookieConsentGiven"}],optOut:[{click:"#CookieConsentDeclined"}]},{name:"hl.co.uk",prehideSelectors:[".cookieModalContent","#cookie-banner-overlay"],detectCmp:[{exists:"#cookie-banner-overlay"}],detectPopup:[{exists:"#cookie-banner-overlay"}],optIn:[{click:"#acceptCookieButton"}],optOut:[{click:"#manageCookie"},{hide:".cookieSettingsModal"},{waitFor:"#AOCookieToggle"},{click:"#AOCookieToggle[aria-pressed=true]",optional:!0},{waitFor:"#TPCookieToggle"},{click:"#TPCookieToggle[aria-pressed=true]",optional:!0},{click:"#updateCookieButton"}]},{name:"holidaymedia",vendorUrl:"https://holidaymedia.nl/",prehideSelectors:["dialog[data-cookie-consent]"],detectCmp:[{exists:"dialog[data-cookie-consent]"}],detectPopup:[{visible:"dialog[data-cookie-consent]"}],optIn:[{waitForThenClick:"button.cookie-consent__button--accept-all"}],optOut:[{waitForThenClick:'a[data-cookie-accept="functional"]',timeout:2e3}]},{name:"hu-manity",vendorUrl:"https://hu-manity.co/",prehideSelectors:["#hu.hu-wrapper"],detectCmp:[{exists:"#hu.hu-visible"}],detectPopup:[{visible:"#hu.hu-visible"}],optIn:[{waitForThenClick:"[data-hu-action=cookies-notice-consent-choices-3]"},{waitForThenClick:"#hu-cookies-save"}],optOut:[{waitForThenClick:"#hu-cookies-save"}]},{name:"hubspot",detectCmp:[{exists:"#hs-eu-cookie-confirmation"}],detectPopup:[{visible:"#hs-eu-cookie-confirmation"}],optIn:[{click:"#hs-eu-confirmation-button"}],optOut:[{click:"#hs-eu-decline-button"}]},{name:"indeed.com",cosmetic:!0,prehideSelectors:["#CookiePrivacyNotice"],detectCmp:[{exists:"#CookiePrivacyNotice"}],detectPopup:[{visible:"#CookiePrivacyNotice"}],optIn:[{click:"#CookiePrivacyNotice button[data-gnav-element-name=CookiePrivacyNoticeOk]"}],optOut:[{hide:"#CookiePrivacyNotice"}]},{name:"ing.de",runContext:{urlPattern:"^https://www\\.ing\\.de/"},cosmetic:!0,prehideSelectors:['div[slot="backdrop"]'],detectCmp:[{exists:'[data-tag-name="ing-cc-dialog-frame"]'}],detectPopup:[{visible:'[data-tag-name="ing-cc-dialog-frame"]'}],optIn:[{click:['[data-tag-name="ing-cc-dialog-level0"]','[data-tag-name="ing-cc-button"][class*="accept"]']}],optOut:[{click:['[data-tag-name="ing-cc-dialog-level0"]','[data-tag-name="ing-cc-button"][class*="more"]']}]},{name:"instagram",vendorUrl:"https://instagram.com",runContext:{urlPattern:"^https://www\\.instagram\\.com/"},prehideSelectors:[],detectCmp:[{exists:'xpath///span[contains(., "Vill du tillåta användningen av cookies från Instagram i den här webbläsaren?") or contains(., "Allow the use of cookies from Instagram on this browser?") or contains(., "Povolit v prohlížeči použití souborů cookie z Instagramu?") or contains(., "Dopustiti upotrebu kolačića s Instagrama na ovom pregledniku?") or contains(., "Разрешить использование файлов cookie от Instagram в этом браузере?") or contains(., "Vuoi consentire l\'uso dei cookie di Instagram su questo browser?") or contains(., "Povoliť používanie cookies zo služby Instagram v tomto prehliadači?") or contains(., "Die Verwendung von Cookies durch Instagram in diesem Browser erlauben?") or contains(., "Sallitaanko Instagramin evästeiden käyttö tällä selaimella?") or contains(., "Engedélyezed az Instagram cookie-jainak használatát ebben a böngészőben?") or contains(., "Het gebruik van cookies van Instagram toestaan in deze browser?") or contains(., "Bu tarayıcıda Instagram\'dan çerez kullanımına izin verilsin mi?") or contains(., "Permitir o uso de cookies do Instagram neste navegador?") or contains(., "Permiţi folosirea modulelor cookie de la Instagram în acest browser?") or contains(., "Autoriser l’utilisation des cookies d’Instagram sur ce navigateur ?") or contains(., "¿Permitir el uso de cookies de Instagram en este navegador?") or contains(., "Zezwolić na użycie plików cookie z Instagramu w tej przeglądarce?") or contains(., "Να επιτρέπεται η χρήση cookies από τo Instagram σε αυτό το πρόγραμμα περιήγησης;") or contains(., "Разрешавате ли използването на бисквитки от Instagram на този браузър?") or contains(., "Vil du tillade brugen af cookies fra Instagram i denne browser?") or contains(., "Vil du tillate bruk av informasjonskapsler fra Instagram i denne nettleseren?")]'}],detectPopup:[{visible:'xpath///span[contains(., "Vill du tillåta användningen av cookies från Instagram i den här webbläsaren?") or contains(., "Allow the use of cookies from Instagram on this browser?") or contains(., "Povolit v prohlížeči použití souborů cookie z Instagramu?") or contains(., "Dopustiti upotrebu kolačića s Instagrama na ovom pregledniku?") or contains(., "Разрешить использование файлов cookie от Instagram в этом браузере?") or contains(., "Vuoi consentire l\'uso dei cookie di Instagram su questo browser?") or contains(., "Povoliť používanie cookies zo služby Instagram v tomto prehliadači?") or contains(., "Die Verwendung von Cookies durch Instagram in diesem Browser erlauben?") or contains(., "Sallitaanko Instagramin evästeiden käyttö tällä selaimella?") or contains(., "Engedélyezed az Instagram cookie-jainak használatát ebben a böngészőben?") or contains(., "Het gebruik van cookies van Instagram toestaan in deze browser?") or contains(., "Bu tarayıcıda Instagram\'dan çerez kullanımına izin verilsin mi?") or contains(., "Permitir o uso de cookies do Instagram neste navegador?") or contains(., "Permiţi folosirea modulelor cookie de la Instagram în acest browser?") or contains(., "Autoriser l’utilisation des cookies d’Instagram sur ce navigateur ?") or contains(., "¿Permitir el uso de cookies de Instagram en este navegador?") or contains(., "Zezwolić na użycie plików cookie z Instagramu w tej przeglądarce?") or contains(., "Να επιτρέπεται η χρήση cookies από τo Instagram σε αυτό το πρόγραμμα περιήγησης;") or contains(., "Разрешавате ли използването на бисквитки от Instagram на този браузър?") or contains(., "Vil du tillade brugen af cookies fra Instagram i denne browser?") or contains(., "Vil du tillate bruk av informasjonskapsler fra Instagram i denne nettleseren?")]'}],optIn:[{waitForThenClick:"xpath///button[contains(., 'Tillad alle cookies') or contains(., 'Alle Cookies erlauben') or contains(., 'Allow all cookies') or contains(., 'Разрешаване на всички бисквитки') or contains(., 'Tillåt alla cookies') or contains(., 'Povolit všechny soubory cookie') or contains(., 'Tüm çerezlere izin ver') or contains(., 'Permite toate modulele cookie') or contains(., 'Να επιτρέπονται όλα τα cookies') or contains(., 'Tillat alle informasjonskapsler') or contains(., 'Povoliť všetky cookies') or contains(., 'Permitir todas las cookies') or contains(., 'Permitir todos os cookies') or contains(., 'Alle cookies toestaan') or contains(., 'Salli kaikki evästeet') or contains(., 'Consenti tutti i cookie') or contains(., 'Az összes cookie engedélyezése') or contains(., 'Autoriser tous les cookies') or contains(., 'Zezwól na wszystkie pliki cookie') or contains(., 'Разрешить все cookie') or contains(., 'Dopusti sve kolačiće')]"}],optOut:[{waitForThenClick:"xpath///button[contains(., 'Отклонить необязательные файлы cookie') or contains(., 'Decline optional cookies') or contains(., 'Refuser les cookies optionnels') or contains(., 'Hylkää valinnaiset evästeet') or contains(., 'Afvis valgfrie cookies') or contains(., 'Odmietnuť nepovinné cookies') or contains(., 'Απόρριψη προαιρετικών cookies') or contains(., 'Neka valfria cookies') or contains(., 'Optionale Cookies ablehnen') or contains(., 'Rifiuta cookie facoltativi') or contains(., 'Odbij neobavezne kolačiće') or contains(., 'Avvis valgfrie informasjonskapsler') or contains(., 'İsteğe bağlı çerezleri reddet') or contains(., 'Recusar cookies opcionais') or contains(., 'Optionele cookies afwijzen') or contains(., 'Rechazar cookies opcionales') or contains(., 'Odrzuć opcjonalne pliki cookie') or contains(., 'Отхвърляне на бисквитките по избор') or contains(., 'Odmítnout volitelné soubory cookie') or contains(., 'Refuză modulele cookie opţionale') or contains(., 'A nem kötelező cookie-k elutasítása')]"},{wait:2e3}]},{name:"ionos.de",prehideSelectors:[".privacy-consent--backdrop",".privacy-consent--modal"],detectCmp:[{exists:".privacy-consent--modal"}],detectPopup:[{visible:".privacy-consent--modal"}],optIn:[{click:"#selectAll"}],optOut:[{click:".footer-config-link"},{click:"#confirmSelection"}]},{name:"itopvpn.com",cosmetic:!0,prehideSelectors:[".pop-cookie"],detectCmp:[{exists:".pop-cookie"}],detectPopup:[{exists:".pop-cookie"}],optIn:[{click:"#_pcookie"}],optOut:[{hide:".pop-cookie"}]},{name:"iubenda",prehideSelectors:["#iubenda-cs-banner"],detectCmp:[{exists:"#iubenda-cs-banner"}],detectPopup:[{visible:".iubenda-cs-accept-btn"}],optIn:[{waitForThenClick:".iubenda-cs-accept-btn"}],optOut:[{waitForThenClick:".iubenda-cs-customize-btn"},{eval:"EVAL_IUBENDA_0"},{waitForThenClick:"#iubFooterBtn"}],test:[{eval:"EVAL_IUBENDA_1"}]},{name:"iWink",prehideSelectors:["body.cookies-request #cookie-bar"],detectCmp:[{exists:"body.cookies-request #cookie-bar"}],detectPopup:[{visible:"body.cookies-request #cookie-bar"}],optIn:[{waitForThenClick:"body.cookies-request #cookie-bar .allow-cookies"}],optOut:[{waitForThenClick:"body.cookies-request #cookie-bar .disallow-cookies"}],test:[{eval:"EVAL_IWINK_TEST"}]},{name:"jdsports",vendorUrl:"https://www.jdsports.co.uk/",runContext:{urlPattern:"^https://(www|m)\\.jdsports\\."},prehideSelectors:[".miniConsent,#PrivacyPolicyBanner"],detectCmp:[{exists:".miniConsent,#PrivacyPolicyBanner"}],detectPopup:[{visible:".miniConsent,#PrivacyPolicyBanner"}],optIn:[{waitForThenClick:".miniConsent .accept-all-cookies"}],optOut:[{if:{exists:"#PrivacyPolicyBanner"},then:[{hide:"#PrivacyPolicyBanner"}],else:[{waitForThenClick:"#cookie-settings"},{waitForThenClick:"#reject-all-cookies"}]}]},{name:"johnlewis.com",prehideSelectors:["div[class^=pecr-cookie-banner-]"],detectCmp:[{exists:"div[class^=pecr-cookie-banner-]"}],detectPopup:[{exists:"div[class^=pecr-cookie-banner-]"}],optOut:[{click:"button[data-test^=manage-cookies]"},{wait:"500"},{click:"label[data-test^=toggle][class*=checked]:not([class*=disabled])",all:!0,optional:!0},{click:"button[data-test=save-preferences]"}],optIn:[{click:"button[data-test=allow-all]"}]},{name:"jquery.cookieBar",vendorUrl:"https://github.com/kovarp/jquery.cookieBar",prehideSelectors:[".cookie-bar"],cosmetic:!0,detectCmp:[{exists:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons"}],detectPopup:[{visible:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons",check:"any"}],optIn:[{click:".cookie-bar .cookie-bar__btn"}],optOut:[{hide:".cookie-bar"}],test:[{visible:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons",check:"none"},{eval:"EVAL_JQUERY_COOKIEBAR_0"}]},{name:"justwatch.com",prehideSelectors:[".consent-banner"],detectCmp:[{exists:".consent-banner .consent-banner__actions"}],detectPopup:[{visible:".consent-banner .consent-banner__actions"}],optIn:[{click:".consent-banner__actions button.basic-button.primary"}],optOut:[{click:".consent-banner__actions button.basic-button.secondary"},{waitForThenClick:".consent-modal__footer button.basic-button.secondary"},{waitForThenClick:".consent-modal ion-content > div > a:nth-child(9)"},{click:"label.consent-switch input[type=checkbox]:checked",all:!0,optional:!0},{waitForVisible:".consent-modal__footer button.basic-button.primary"},{click:".consent-modal__footer button.basic-button.primary"}]},{name:"ketch",vendorUrl:"https://www.ketch.com",runContext:{frame:!1,main:!0},intermediate:!1,prehideSelectors:["#lanyard_root div[role='dialog']"],detectCmp:[{exists:"#lanyard_root div[role='dialog']"}],detectPopup:[{visible:"#lanyard_root div[role='dialog']"}],optIn:[{if:{exists:"#lanyard_root button[class='confirmButton']"},then:[{waitForThenClick:"#lanyard_root div[class*=buttons] > :nth-child(2)"},{click:"#lanyard_root button[class='confirmButton']"}],else:[{waitForThenClick:"#lanyard_root div[class*=buttons] > :nth-child(2)"}]}],optOut:[{if:{exists:"#lanyard_root [aria-describedby=banner-description]"},then:[{waitForThenClick:"#lanyard_root div[class*=buttons] > button[class*=secondaryButton], #lanyard_root button[class*=buttons-secondary]",comment:"can be either settings or reject button"}]},{waitFor:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description], #ketch-preferences",timeout:1e3,optional:!0},{if:{exists:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description], #ketch-preferences"},then:[{waitForThenClick:"#lanyard_root button[class*=rejectButton], #lanyard_root button[class*=rejectAllButton]"},{click:"#lanyard_root button[class*=confirmButton],#lanyard_root div[class*=actions_] > button:nth-child(1), #lanyard_root button[class*=actionButton]"}]}],test:[{eval:"EVAL_KETCH_TEST"}]},{name:"kleinanzeigen-de",runContext:{urlPattern:"^https?://(www\\.)?kleinanzeigen\\.de"},prehideSelectors:["#gdpr-banner-container"],detectCmp:[{any:[{exists:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"},{exists:"#ConsentManagementPage"}]}],detectPopup:[{any:[{visible:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"},{visible:"#ConsentManagementPage"}]}],optIn:[{if:{exists:"#gdpr-banner-container #gdpr-banner"},then:[{click:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-accept]"}],else:[{click:"#ConsentManagementPage .Button-primary"}]}],optOut:[{if:{exists:"#gdpr-banner-container #gdpr-banner"},then:[{click:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"}],else:[{click:"#ConsentManagementPage .Button-secondary"}]}]},{name:"lightbox",prehideSelectors:[".darken-layer.open,.lightbox.lightbox--cookie-consent"],detectCmp:[{exists:"body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"}],detectPopup:[{visible:"body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"}],optOut:[{click:".cookie-consent__footer > button[type='submit']:not([data-button='selectAll'])"}],optIn:[{click:".cookie-consent__footer > button[type='submit'][data-button='selectAll']"}]},{name:"lineagrafica",vendorUrl:"https://addons.prestashop.com/en/legal/8734-eu-cookie-law-gdpr-banner-blocker.html",cosmetic:!0,prehideSelectors:["#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"],detectCmp:[{exists:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}],detectPopup:[{exists:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}],optIn:[{waitForThenClick:"#lgcookieslaw_accept"}],optOut:[{hide:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}]},{name:"linkedin.com",prehideSelectors:[".artdeco-global-alert[type=COOKIE_CONSENT]"],detectCmp:[{exists:".artdeco-global-alert[type=COOKIE_CONSENT]"}],detectPopup:[{visible:".artdeco-global-alert[type=COOKIE_CONSENT]"}],optIn:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=ACCEPT]"},{wait:500},{waitForThenClick:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=ACCEPT]"}],optOut:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=DENY]"},{wait:500},{waitForThenClick:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=DENY]"}],test:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT]",check:"none"}]},{name:"livejasmin",vendorUrl:"https://www.livejasmin.com/",runContext:{urlPattern:"^https://(m|www)\\.livejasmin\\.com/"},prehideSelectors:["#consent_modal"],detectCmp:[{exists:"#consent_modal"}],detectPopup:[{visible:"#consent_modal"}],optIn:[{waitForThenClick:"#consent_modal button[data-testid=ButtonStyledButton]:first-of-type"}],optOut:[{waitForThenClick:"#consent_modal button[data-testid=ButtonStyledButton]:nth-of-type(2)"},{waitForVisible:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent]"},{click:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent] input[data-testid=PrivacyPreferenceCenterWithConsentCookieSwitch]:checked",optional:!0,all:!0},{waitForThenClick:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent] button[data-testid=ButtonStyledButton]:last-child"}]},{name:"macpaw.com",cosmetic:!0,prehideSelectors:['div[data-banner="cookies"]'],detectCmp:[{exists:'div[data-banner="cookies"]'}],detectPopup:[{exists:'div[data-banner="cookies"]'}],optIn:[{click:'button[data-banner-close="cookies"]'}],optOut:[{hide:'div[data-banner="cookies"]'}]},{name:"marksandspencer.com",cosmetic:!0,detectCmp:[{exists:".navigation-cookiebbanner"}],detectPopup:[{visible:".navigation-cookiebbanner"}],optOut:[{hide:".navigation-cookiebbanner"}],optIn:[{click:".navigation-cookiebbanner__submit"}]},{name:"mediamarkt.de",prehideSelectors:["div[aria-labelledby=pwa-consent-layer-title]","div[class^=StyledConsentLayerWrapper-]"],detectCmp:[{exists:"div[aria-labelledby^=pwa-consent-layer-title]"}],detectPopup:[{exists:"div[aria-labelledby^=pwa-consent-layer-title]"}],optOut:[{click:"button[data-test^=pwa-consent-layer-deny-all]"}],optIn:[{click:"button[data-test^=pwa-consent-layer-accept-all"}]},{name:"Mediavine",prehideSelectors:['[data-name="mediavine-gdpr-cmp"]'],detectCmp:[{exists:'[data-name="mediavine-gdpr-cmp"]'}],detectPopup:[{wait:500},{visible:'[data-name="mediavine-gdpr-cmp"]'}],optIn:[{waitForThenClick:'[data-name="mediavine-gdpr-cmp"] [format="primary"]'}],optOut:[{waitForThenClick:'[data-name="mediavine-gdpr-cmp"] [data-view="manageSettings"]'},{waitFor:'[data-name="mediavine-gdpr-cmp"] input[type=checkbox]'},{eval:"EVAL_MEDIAVINE_0",optional:!0},{click:'[data-name="mediavine-gdpr-cmp"] [format="secondary"]'}]},{name:"medium",vendorUrl:"https://medium.com",cosmetic:!0,runContext:{main:!0,frame:!1,urlPattern:"^https://([a-z0-9-]+\\.)?medium\\.com/"},prehideSelectors:[],detectCmp:[{exists:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}],detectPopup:[{visible:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}],optIn:[{waitForThenClick:"[data-testid=close-button]"}],optOut:[{hide:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}]},{name:"microsoft.com",prehideSelectors:["#wcpConsentBannerCtrl"],detectCmp:[{exists:"#wcpConsentBannerCtrl"}],detectPopup:[{exists:"#wcpConsentBannerCtrl"}],optOut:[{eval:"EVAL_MICROSOFT_0"}],optIn:[{eval:"EVAL_MICROSOFT_1"}],test:[{eval:"EVAL_MICROSOFT_2"}]},{name:"midway-usa",runContext:{urlPattern:"^https://www\\.midwayusa\\.com/"},cosmetic:!0,prehideSelectors:["#cookie-container"],detectCmp:[{exists:['div[aria-label="Cookie Policy Banner"]']}],detectPopup:[{visible:"#cookie-container"}],optIn:[{click:"button#cookie-btn"}],optOut:[{hide:'div[aria-label="Cookie Policy Banner"]'}]},{name:"moneysavingexpert.com",detectCmp:[{exists:"dialog[data-testid=accept-our-cookies-dialog]"}],detectPopup:[{visible:"dialog[data-testid=accept-our-cookies-dialog]"}],optIn:[{click:"#banner-accept"}],optOut:[{click:"#banner-manage"},{click:"#pc-confirm"}]},{name:"monzo.com",prehideSelectors:[".cookie-alert, cookie-alert__content"],detectCmp:[{exists:'div.cookie-alert[role="dialog"]'},{exists:'a[href*="monzo"]'}],detectPopup:[{visible:".cookie-alert__content"}],optIn:[{click:".js-accept-cookie-policy"}],optOut:[{click:".js-decline-cookie-policy"}]},{name:"Moove",prehideSelectors:["#moove_gdpr_cookie_info_bar"],detectCmp:[{exists:"#moove_gdpr_cookie_info_bar"}],detectPopup:[{visible:"#moove_gdpr_cookie_info_bar:not(.moove-gdpr-info-bar-hidden)"}],optIn:[{waitForThenClick:".moove-gdpr-infobar-allow-all"}],optOut:[{if:{exists:"#moove_gdpr_cookie_info_bar .change-settings-button"},then:[{click:"#moove_gdpr_cookie_info_bar .change-settings-button"},{waitForVisible:"#moove_gdpr_cookie_modal"},{eval:"EVAL_MOOVE_0"},{click:".moove-gdpr-modal-save-settings"}],else:[{hide:"#moove_gdpr_cookie_info_bar"}]}],test:[{visible:"#moove_gdpr_cookie_info_bar",check:"none"}]},{name:"national-lottery.co.uk",detectCmp:[{exists:".cuk_cookie_consent"}],detectPopup:[{visible:".cuk_cookie_consent",check:"any"}],optOut:[{click:".cuk_cookie_consent_manage_pref"},{click:".cuk_cookie_consent_save_pref"},{click:".cuk_cookie_consent_close"}],optIn:[{click:".cuk_cookie_consent_accept_all"}]},{name:"nba.com",runContext:{urlPattern:"^https://(www\\.)?nba.com/"},cosmetic:!0,prehideSelectors:["#onetrust-banner-sdk"],detectCmp:[{exists:"#onetrust-banner-sdk"}],detectPopup:[{visible:"#onetrust-banner-sdk"}],optIn:[{click:"#onetrust-accept-btn-handler"}],optOut:[{hide:"#onetrust-banner-sdk"}]},{name:"netbeat.de",runContext:{urlPattern:"^https://(www\\.)?netbeat\\.de/"},prehideSelectors:["div#cookieWarning"],detectCmp:[{exists:"div#cookieWarning"}],detectPopup:[{visible:"div#cookieWarning"}],optIn:[{waitForThenClick:"a#btnCookiesAcceptAll"}],optOut:[{waitForThenClick:"a#btnCookiesDenyAll"}]},{name:"netflix.de",detectCmp:[{exists:"#cookie-disclosure"}],detectPopup:[{visible:".cookie-disclosure-message",check:"any"}],optIn:[{click:".btn-accept"}],optOut:[{hide:"#cookie-disclosure"},{click:".btn-reject"}]},{name:"nhs.uk",prehideSelectors:["#nhsuk-cookie-banner"],detectCmp:[{exists:"#nhsuk-cookie-banner"}],detectPopup:[{exists:"#nhsuk-cookie-banner"}],optOut:[{click:"#nhsuk-cookie-banner__link_accept"}],optIn:[{click:"#nhsuk-cookie-banner__link_accept_analytics"}]},{name:"nike",vendorUrl:"https://nike.com",runContext:{urlPattern:"^https://(www\\.)?nike\\.com/"},prehideSelectors:[],detectCmp:[{exists:"[data-testid=cookie-dialog-root]"}],detectPopup:[{visible:"[data-testid=cookie-dialog-root]"}],optIn:[{waitForThenClick:"[data-testid=dialog-accept-button]"}],optOut:[{waitForThenClick:"input[type=radio][id$=-declineLabel]",all:!0},{waitForThenClick:"[data-testid=confirm-choice-button]"}]},{name:"notice-cookie",prehideSelectors:[".button--notice"],cosmetic:!0,detectCmp:[{exists:".notice--cookie"}],detectPopup:[{visible:".notice--cookie"}],optIn:[{click:".button--notice"}],optOut:[{hide:".notice--cookie"}]},{name:"nrk.no",cosmetic:!0,prehideSelectors:[".nrk-masthead__info-banner--cookie"],detectCmp:[{exists:".nrk-masthead__info-banner--cookie"}],detectPopup:[{exists:".nrk-masthead__info-banner--cookie"}],optIn:[{click:"div.nrk-masthead__info-banner--cookie button > span:has(+ svg.nrk-close)"}],optOut:[{hide:".nrk-masthead__info-banner--cookie"}]},{name:"obi.de",prehideSelectors:[".disc-cp--active"],detectCmp:[{exists:".disc-cp-modal__modal"}],detectPopup:[{visible:".disc-cp-modal__modal"}],optIn:[{click:".js-disc-cp-accept-all"}],optOut:[{click:".js-disc-cp-deny-all"}]},{name:"om",vendorUrl:"https://olli-machts.de/en/extension/cookie-manager",prehideSelectors:[".tx-om-cookie-consent"],detectCmp:[{exists:".tx-om-cookie-consent .active[data-omcookie-panel]"}],detectPopup:[{exists:".tx-om-cookie-consent .active[data-omcookie-panel]"}],optIn:[{waitForThenClick:"[data-omcookie-panel-save=all]"}],optOut:[{if:{exists:"[data-omcookie-panel-save=min]"},then:[{waitForThenClick:"[data-omcookie-panel-save=min]"}],else:[{click:"input[data-omcookie-panel-grp]:checked:not(:disabled)",all:!0,optional:!0},{waitForThenClick:"[data-omcookie-panel-save=save]"}]}]},{name:"onlyFans.com",runContext:{urlPattern:"^https://onlyfans\\.com/"},prehideSelectors:["div.b-cookies-informer"],detectCmp:[{exists:"div.b-cookies-informer"}],detectPopup:[{exists:"div.b-cookies-informer"}],optIn:[{click:"div.b-cookies-informer__nav > button:nth-child(2)"}],optOut:[{click:"div.b-cookies-informer__nav > button:nth-child(1)"},{if:{exists:"div.b-cookies-informer__switchers"},then:[{click:"div.b-cookies-informer__switchers input:not([disabled])",all:!0},{click:"div.b-cookies-informer__nav > button"}]}]},{name:"openai",vendorUrl:"https://platform.openai.com/",cosmetic:!1,runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?openai\\.com/"},prehideSelectors:["[data-testid=cookie-consent-banner]"],detectCmp:[{exists:"[data-testid=cookie-consent-banner]"}],detectPopup:[{visible:"[data-testid=cookie-consent-banner]"}],optIn:[{waitForThenClick:"xpath///button[contains(., 'Accept all')]"}],optOut:[{waitForThenClick:"xpath///button[contains(., 'Reject all')]"}],test:[{wait:500},{eval:"EVAL_OPENAI_TEST"}]},{name:"openli",vendorUrl:"https://openli.com",prehideSelectors:[".legalmonster-cleanslate"],detectCmp:[{exists:".legalmonster-cleanslate"}],detectPopup:[{visible:".legalmonster-cleanslate #lm-cookie-wall-container",check:"any"}],optIn:[{waitForThenClick:"#lm-accept-all"}],optOut:[{waitForThenClick:"#lm-accept-necessary"}]},{name:"opera.com",vendorUrl:"https://unknown",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,prehideSelectors:[],detectCmp:[{exists:"#cookie-consent .manage-cookies__btn"}],detectPopup:[{visible:"#cookie-consent .cookie-basic-consent__btn"}],optIn:[{waitForThenClick:"#cookie-consent .cookie-basic-consent__btn"}],optOut:[{waitForThenClick:"#cookie-consent .manage-cookies__btn"},{waitForThenClick:"#cookie-consent .active.marketing_option_switch.cookie-consent__switch",all:!0},{waitForThenClick:"#cookie-consent .cookie-selection__btn"}],test:[{eval:"EVAL_OPERA_0"}]},{name:"osano",prehideSelectors:[".osano-cm-window,.osano-cm-dialog"],detectCmp:[{exists:".osano-cm-window"}],detectPopup:[{visible:".osano-cm-dialog"}],optIn:[{click:".osano-cm-accept-all",optional:!0}],optOut:[{waitForThenClick:".osano-cm-denyAll"}]},{name:"otto.de",prehideSelectors:[".cookieBanner--visibility"],detectCmp:[{exists:".cookieBanner--visibility"}],detectPopup:[{visible:".cookieBanner__wrapper"}],optIn:[{click:".js_cookieBannerPermissionButton"}],optOut:[{click:".js_cookieBannerProhibitionButton"}]},{name:"ourworldindata",vendorUrl:"https://ourworldindata.org/",runContext:{urlPattern:"^https://ourworldindata\\.org/"},prehideSelectors:[".cookie-manager"],detectCmp:[{exists:".cookie-manager"}],detectPopup:[{visible:".cookie-manager .cookie-notice.open"}],optIn:[{waitForThenClick:".cookie-notice [data-test=accept]"}],optOut:[{waitForThenClick:".cookie-notice [data-test=reject]"}]},{name:"pabcogypsum",vendorUrl:"https://unknown",prehideSelectors:[".js-cookie-notice:has(#cookie_settings-form)"],detectCmp:[{exists:".js-cookie-notice #cookie_settings-form"}],detectPopup:[{visible:".js-cookie-notice #cookie_settings-form"}],optIn:[{waitForThenClick:".js-cookie-notice button[value=allow]"}],optOut:[{waitForThenClick:".js-cookie-notice button[value=disable]"}]},{name:"paypal-us",prehideSelectors:["#ccpaCookieContent_wrapper, article.ppvx_modal--overpanel"],detectCmp:[{exists:"#ccpaCookieBanner, .privacy-sheet-content"}],detectPopup:[{visible:"#ccpaCookieBanner, .privacy-sheet-content"}],optIn:[{click:"#acceptAllButton"}],optOut:[{if:{exists:"#bannerDeclineButton"},then:[{click:"#bannerDeclineButton"}],else:[{if:{exists:"a#manageCookiesLink"},then:[{click:"a#manageCookiesLink"}],else:[{waitForVisible:".privacy-sheet-content #formContent"},{click:"#formContent .cookiepref-11m2iee-checkbox_base input:checked",all:!0,optional:!0},{click:".cookieAction.saveCookie,.confirmCookie #submitCookiesBtn"}]}]}]},{name:"paypal.com",prehideSelectors:["#gdprCookieBanner"],detectCmp:[{exists:"#gdprCookieBanner"}],detectPopup:[{visible:"#gdprCookieContent_wrapper"}],optIn:[{click:"#acceptAllButton"}],optOut:[{wait:200},{click:".gdprCookieBanner_decline-button"}],test:[{wait:500},{eval:"EVAL_PAYPAL_0"}]},{name:"pinetools.com",cosmetic:!0,prehideSelectors:["#aviso_cookies"],detectCmp:[{exists:"#aviso_cookies"}],detectPopup:[{exists:".lang_en #aviso_cookies"}],optIn:[{click:"#aviso_cookies .a_boton_cerrar"}],optOut:[{hide:"#aviso_cookies"}]},{name:"pinterest-business",vendorUrl:"https://business.pinterest.com/",runContext:{urlPattern:"^https://.*\\.pinterest\\.com/"},prehideSelectors:[".BusinessCookieConsent"],detectCmp:[{exists:".BusinessCookieConsent"}],detectPopup:[{visible:".BusinessCookieConsent [data-id=cookie-consent-banner-buttons]"}],optIn:[{waitForThenClick:"[data-id=cookie-consent-banner-buttons] > div:nth-child(1) button"}],optOut:[{waitForThenClick:"[data-id=cookie-consent-banner-buttons] > div:nth-child(2) button"}]},{name:"pmc",cosmetic:!0,prehideSelectors:["#pmc-pp-tou--notice"],detectCmp:[{exists:"#pmc-pp-tou--notice"}],detectPopup:[{visible:"#pmc-pp-tou--notice"}],optIn:[{click:"span.pmc-pp-tou--notice-close-btn"}],optOut:[{hide:"#pmc-pp-tou--notice"}]},{name:"pornhub.com",runContext:{urlPattern:"^https://(www\\.)?pornhub\\.com/"},cosmetic:!1,prehideSelectors:["#cookieBanner #cookieBannerContent"],detectCmp:[{exists:"#cookieBanner #cookieBannerContent"}],detectPopup:[{visible:"#cookieBanner #cookieBannerContent"}],optIn:[{waitForThenClick:"#cookieBanner [data-label=accept_all]"}],optOut:[{waitForThenClick:"#cookieBanner [data-label=accept_essential]"}]},{name:"pornpics.com",cosmetic:!0,prehideSelectors:["#cookie-contract"],detectCmp:[{exists:"#cookie-contract"}],detectPopup:[{visible:"#cookie-contract"}],optIn:[{click:"#cookie-contract .icon-cross"}],optOut:[{hide:"#cookie-contract"}]},{name:"PrimeBox CookieBar",prehideSelectors:["#cookie-bar"],detectCmp:[{exists:"#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy"}],detectPopup:[{visible:"#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy",check:"any"}],optIn:[{waitForThenClick:"#cookie-bar .cb-enable"}],optOut:[{click:"#cookie-bar .cb-disable",optional:!0},{hide:"#cookie-bar"}],test:[{eval:"EVAL_PRIMEBOX_0"}]},{name:"privacymanager.io",prehideSelectors:["#gdpr-consent-tool-wrapper",'iframe[src^="https://cmp-consent-tool.privacymanager.io"]'],runContext:{urlPattern:"^https://cmp-consent-tool\\.privacymanager\\.io/",main:!1,frame:!0},detectCmp:[{exists:"button#save"}],detectPopup:[{visible:"button#save"}],optIn:[{click:"button#save"}],optOut:[{if:{exists:"#denyAll"},then:[{click:"#denyAll"},{waitForThenClick:".okButton"}],else:[{waitForThenClick:"#manageSettings"},{waitFor:".purposes-overview-list"},{waitFor:"button#saveAndExit"},{click:"span[role=checkbox][aria-checked=true]",all:!0,optional:!0},{click:"button#saveAndExit"}]}]},{name:"productz.com",vendorUrl:"https://productz.com/",runContext:{urlPattern:"^https://productz\\.com/"},prehideSelectors:[],detectCmp:[{exists:".c-modal.is-active"}],detectPopup:[{visible:".c-modal.is-active"}],optIn:[{waitForThenClick:".c-modal.is-active .is-accept"}],optOut:[{waitForThenClick:".c-modal.is-active .is-dismiss"}]},{name:"pubtech",prehideSelectors:["#pubtech-cmp"],detectCmp:[{exists:"#pubtech-cmp"}],detectPopup:[{visible:"#pubtech-cmp #pt-actions"}],optIn:[{if:{exists:"#pt-accept-all"},then:[{click:"#pubtech-cmp #pt-actions #pt-accept-all"}],else:[{click:"#pubtech-cmp #pt-actions button:nth-of-type(2)"}]}],optOut:[{click:"#pubtech-cmp #pt-close"}],test:[{eval:"EVAL_PUBTECH_0"}]},{name:"quantcast",prehideSelectors:["#qc-cmp2-main,#qc-cmp2-container"],detectCmp:[{exists:"#qc-cmp2-container"}],detectPopup:[{visible:"#qc-cmp2-ui"}],optOut:[{waitFor:'.qc-cmp2-summary-buttons > button[mode="secondary"]',timeout:2e3},{if:{exists:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(2)'},then:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(2)'}],else:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(1)'},{waitFor:"#qc-cmp2-ui"},{click:'.qc-cmp2-toggle-switch > button[aria-checked="true"]',all:!0,optional:!0},{click:'.qc-cmp2-main button[aria-label="REJECT ALL"]',optional:!0},{waitForThenClick:'.qc-cmp2-main button[aria-label="SAVE & EXIT"],.qc-cmp2-buttons-desktop > button[mode="primary"]',timeout:5e3}]}],optIn:[{click:'.qc-cmp2-summary-buttons > button[mode="primary"]'}]},{name:"reddit.com",runContext:{urlPattern:"^https://www\\.reddit\\.com/"},prehideSelectors:["[bundlename=reddit_cookie_banner]"],detectCmp:[{exists:"reddit-cookie-banner"}],detectPopup:[{visible:"reddit-cookie-banner"}],optIn:[{waitForThenClick:["reddit-cookie-banner","#accept-all-cookies-button > button"]}],optOut:[{waitForThenClick:["reddit-cookie-banner","#reject-nonessential-cookies-button > button"]}],test:[{eval:"EVAL_REDDIT_0"}]},{name:"roblox",vendorUrl:"https://roblox.com",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?roblox\\.com/"},prehideSelectors:[],detectCmp:[{exists:".cookie-banner-wrapper"}],detectPopup:[{visible:".cookie-banner-wrapper .cookie-banner"}],optIn:[{waitForThenClick:".cookie-banner-wrapper button.btn-cta-lg"}],optOut:[{waitForThenClick:".cookie-banner-wrapper button.btn-secondary-lg"}],test:[{eval:"EVAL_ROBLOX_TEST"}]},{name:"rog-forum.asus.com",runContext:{urlPattern:"^https://rog-forum\\.asus\\.com/"},prehideSelectors:["#cookie-policy-info"],detectCmp:[{exists:"#cookie-policy-info"}],detectPopup:[{visible:"#cookie-policy-info"}],optIn:[{click:'div.cookie-btn-box > div[aria-label="Accept"]'}],optOut:[{click:'div.cookie-btn-box > div[aria-label="Reject"]'},{waitForThenClick:'.cookie-policy-lightbox-bottom > div[aria-label="Save Settings"]'}]},{name:"roofingmegastore.co.uk",runContext:{urlPattern:"^https://(www\\.)?roofingmegastore\\.co\\.uk"},prehideSelectors:["#m-cookienotice"],detectCmp:[{exists:"#m-cookienotice"}],detectPopup:[{visible:"#m-cookienotice"}],optIn:[{click:"#accept-cookies"}],optOut:[{click:"#manage-cookies"},{waitForThenClick:"#accept-selected"}]},{name:"samsung.com",runContext:{urlPattern:"^https://www\\.samsung\\.com/"},cosmetic:!0,prehideSelectors:["div.cookie-bar"],detectCmp:[{exists:"div.cookie-bar"}],detectPopup:[{visible:"div.cookie-bar"}],optIn:[{click:"div.cookie-bar__manage > a"}],optOut:[{hide:"div.cookie-bar"}]},{name:"setapp.com",vendorUrl:"https://setapp.com/",cosmetic:!0,runContext:{urlPattern:"^https://setapp\\.com/"},prehideSelectors:[],detectCmp:[{exists:".cookie-banner.js-cookie-banner"}],detectPopup:[{visible:".cookie-banner.js-cookie-banner"}],optIn:[{waitForThenClick:".cookie-banner.js-cookie-banner button"}],optOut:[{hide:".cookie-banner.js-cookie-banner"}]},{name:"sibbo",prehideSelectors:["sibbo-cmp-layout"],detectCmp:[{exists:"sibbo-cmp-layout"}],detectPopup:[{visible:"#rejectAllMain"}],optIn:[{click:"#acceptAllMain"}],optOut:[{click:"#rejectAllMain"}]},{name:"similarweb.com",cosmetic:!0,prehideSelectors:[".app-cookies-notification"],detectCmp:[{exists:".app-cookies-notification"}],detectPopup:[{exists:".app-layout .app-cookies-notification"}],optIn:[{click:"button.app-cookies-notification__dismiss"}],optOut:[{hide:".app-layout .app-cookies-notification"}]},{name:"Sirdata",cosmetic:!1,prehideSelectors:["#sd-cmp"],detectCmp:[{exists:"#sd-cmp"}],detectPopup:[{visible:"#sd-cmp"}],optIn:[{waitForThenClick:"#sd-cmp .sd-cmp-3cRQ2"}],optOut:[{waitForThenClick:["#sd-cmp","xpath///span[contains(., 'Do not accept') or contains(., 'Acceptera inte') or contains(., 'No aceptar') or contains(., 'Ikke acceptere') or contains(., 'Nicht akzeptieren') or contains(., 'Не приемам') or contains(., 'Να μην γίνει αποδοχή') or contains(., 'Niet accepteren') or contains(., 'Nepřijímat') or contains(., 'Nie akceptuj') or contains(., 'Nu acceptați') or contains(., 'Não aceitar') or contains(., 'Continuer sans accepter') or contains(., 'Non accettare') or contains(., 'Nem fogad el')]"]}]},{name:"snigel",detectCmp:[{exists:".snigel-cmp-framework"}],detectPopup:[{visible:".snigel-cmp-framework"}],optOut:[{click:"#sn-b-custom"},{click:"#sn-b-save"}],test:[{eval:"EVAL_SNIGEL_0"}],optIn:[{click:".snigel-cmp-framework #accept-choices"}]},{name:"steampowered.com",detectCmp:[{exists:".cookiepreferences_popup"},{visible:".cookiepreferences_popup"}],detectPopup:[{visible:".cookiepreferences_popup"}],optOut:[{click:"#rejectAllButton"}],optIn:[{click:"#acceptAllButton"}],test:[{wait:1e3},{eval:"EVAL_STEAMPOWERED_0"}]},{name:"strato.de",prehideSelectors:[".consent__wrapper"],runContext:{urlPattern:"^https://www\\.strato\\.de/"},detectCmp:[{exists:".consent"}],detectPopup:[{visible:".consent"}],optIn:[{click:"button.consentAgree"}],optOut:[{click:"button.consentSettings"},{waitForThenClick:"button#consentSubmit"}]},{name:"svt.se",vendorUrl:"https://www.svt.se/",runContext:{urlPattern:"^https://www\\.svt\\.se/"},prehideSelectors:["[class*=CookieConsent__root___]"],detectCmp:[{exists:"[class*=CookieConsent__root___]"}],detectPopup:[{visible:"[class*=CookieConsent__modal___]"}],optIn:[{waitForThenClick:"[class*=CookieConsent__modal___] > div > button[class*=primary]"}],optOut:[{waitForThenClick:"[class*=CookieConsent__modal___] > div > button[class*=secondary]:nth-child(2)"}],test:[{eval:"EVAL_SVT_TEST"}]},{name:"takealot.com",cosmetic:!0,prehideSelectors:['div[class^="cookies-banner-module_"]'],detectCmp:[{exists:'div[class^="cookies-banner-module_cookie-banner_"]'}],detectPopup:[{exists:'div[class^="cookies-banner-module_cookie-banner_"]'}],optIn:[{click:'button[class*="cookies-banner-module_dismiss-button_"]'}],optOut:[{hide:'div[class^="cookies-banner-module_"]'},{if:{exists:'div[class^="cookies-banner-module_small-cookie-banner_"]'},then:[{eval:"EVAL_TAKEALOT_0"}],else:[]}]},{name:"tarteaucitron.js",prehideSelectors:["#tarteaucitronRoot"],detectCmp:[{exists:"#tarteaucitronRoot"}],detectPopup:[{visible:"#tarteaucitronRoot #tarteaucitronAlertBig",check:"any"}],optIn:[{eval:"EVAL_TARTEAUCITRON_1"}],optOut:[{eval:"EVAL_TARTEAUCITRON_0"}],test:[{eval:"EVAL_TARTEAUCITRON_2",comment:"sometimes there are required categories, so we check that at least something is false"}]},{name:"taunton",vendorUrl:"https://www.taunton.com/",prehideSelectors:["#taunton-user-consent__overlay"],detectCmp:[{exists:"#taunton-user-consent__overlay"}],detectPopup:[{exists:"#taunton-user-consent__overlay:not([aria-hidden=true])"}],optIn:[{click:"#taunton-user-consent__toolbar input[type=checkbox]:not(:checked)"},{click:"#taunton-user-consent__toolbar button[type=submit]"}],optOut:[{click:"#taunton-user-consent__toolbar input[type=checkbox]:checked",optional:!0,all:!0},{click:"#taunton-user-consent__toolbar button[type=submit]"}],test:[{eval:"EVAL_TAUNTON_TEST"}]},{name:"Tealium",prehideSelectors:["#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs,#__tealiumImplicitmodal,#consent-layer"],detectCmp:[{exists:"#__tealiumGDPRecModal *,#__tealiumGDPRcpPrefs *,#__tealiumImplicitmodal *"},{eval:"EVAL_TEALIUM_0"}],detectPopup:[{visible:"#__tealiumGDPRecModal *,#__tealiumGDPRcpPrefs *,#__tealiumImplicitmodal *",check:"any"}],optOut:[{eval:"EVAL_TEALIUM_1"},{eval:"EVAL_TEALIUM_DONOTSELL"},{hide:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs,#__tealiumImplicitmodal"},{waitForThenClick:"#cm-acceptNone,.js-accept-essential-cookies",timeout:1e3,optional:!0}],optIn:[{hide:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs"},{eval:"EVAL_TEALIUM_2"}],test:[{eval:"EVAL_TEALIUM_3"},{eval:"EVAL_TEALIUM_DONOTSELL_CHECK"},{visible:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs",check:"none"}]},{name:"temu",vendorUrl:"https://temu.com",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?temu\\.com/"},prehideSelectors:[],detectCmp:[{exists:'div > div > div > div > span[href*="/cookie-and-similar-technologies-policy.html"]'}],detectPopup:[{visible:'div > div > div > div > span[href*="/cookie-and-similar-technologies-policy.html"]'}],optIn:[{waitForThenClick:'div > div > div:has(> div > span[href*="/cookie-and-similar-technologies-policy.html"]) > [role=button]:nth-child(3)'}],optOut:[{if:{exists:"xpath///span[contains(., 'Alle afwijzen') or contains(., 'Reject all') or contains(., 'Tümünü reddet') or contains(., 'Odrzuć wszystko')]"},then:[{waitForThenClick:"xpath///span[contains(., 'Alle afwijzen') or contains(., 'Reject all') or contains(., 'Tümünü reddet') or contains(., 'Odrzuć wszystko')]"}],else:[{waitForThenClick:'div > div > div:has(> div > span[href*="/cookie-and-similar-technologies-policy.html"]) > [role=button]:nth-child(2)'}]}]},{name:"Termly",prehideSelectors:["#termly-code-snippet-support"],detectCmp:[{exists:"#termly-code-snippet-support"}],detectPopup:[{visible:"#termly-code-snippet-support div"}],optIn:[{waitForThenClick:'[data-tid="banner-accept"]'}],optOut:[{if:{exists:'[data-tid="banner-decline"]'},then:[{click:'[data-tid="banner-decline"]'}],else:[{click:".t-preference-button"},{wait:500},{if:{exists:".t-declineAllButton"},then:[{click:".t-declineAllButton"}],else:[{waitForThenClick:".t-preference-modal input[type=checkbox][checked]:not([disabled])",all:!0},{waitForThenClick:".t-saveButton"}]}]}]},{name:"termsfeed",vendorUrl:"https://termsfeed.com",comment:"v4.x.x",prehideSelectors:[".termsfeed-com---nb"],detectCmp:[{exists:".termsfeed-com---nb"}],detectPopup:[{visible:".termsfeed-com---nb"}],optIn:[{waitForThenClick:".cc-nb-okagree"}],optOut:[{waitForThenClick:".cc-nb-reject"}]},{name:"termsfeed3",vendorUrl:"https://termsfeed.com",comment:"v3.x.x",prehideSelectors:[".cc_dialog.cc_css_reboot,.cc_overlay_lock"],detectCmp:[{exists:".cc_dialog.cc_css_reboot"}],detectPopup:[{visible:".cc_dialog.cc_css_reboot"}],optIn:[{waitForThenClick:".cc_dialog.cc_css_reboot .cc_b_ok"}],optOut:[{if:{exists:".cc_dialog.cc_css_reboot .cc_b_cp"},then:[{click:".cc_dialog.cc_css_reboot .cc_b_cp"},{waitForVisible:".cookie-consent-preferences-dialog .cc_cp_f_save button"},{waitForThenClick:".cookie-consent-preferences-dialog .cc_cp_f_save button"}],else:[{hide:".cc_dialog.cc_css_reboot,.cc_overlay_lock"}]}]},{name:"tesco",vendorUrl:"https://www.tesco.com",cosmetic:!1,runContext:{urlPattern:"^https://(www\\.)?tesco\\.com/"},prehideSelectors:["[class*=CookieBanner__Sizer]"],detectCmp:[{exists:"[aria-label=consent-banner]"}],detectPopup:[{visible:"[aria-label=consent-banner]"}],optIn:[{wait:1e3},{waitForThenClick:"xpath///button[contains(., 'Accept all')]"}],optOut:[{wait:1e3},{waitForThenClick:"xpath///button[contains(., 'Reject all')]"}]},{name:"tesla",vendorUrl:"https://tesla.com/",runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?tesla\\.com/"},prehideSelectors:[],detectCmp:[{exists:"#cookie_banner"}],detectPopup:[{visible:"#cookie_banner"}],optIn:[{waitForThenClick:"#tsla-accept-cookie"}],optOut:[{waitForThenClick:"#tsla-reject-cookie"}],test:[{eval:"EVAL_TESLA_TEST"}]},{name:"Test page cosmetic CMP",cosmetic:!0,prehideSelectors:["#privacy-test-page-cmp-test-prehide"],detectCmp:[{exists:"#privacy-test-page-cmp-test-banner"}],detectPopup:[{visible:"#privacy-test-page-cmp-test-banner"}],optIn:[{waitFor:"#accept-all"},{click:"#accept-all"}],optOut:[{hide:"#privacy-test-page-cmp-test-banner"}],test:[{wait:500},{eval:"EVAL_TESTCMP_COSMETIC_0"}]},{name:"Test page CMP",prehideSelectors:["#reject-all"],detectCmp:[{exists:"#privacy-test-page-cmp-test"}],detectPopup:[{visible:"#privacy-test-page-cmp-test"}],optIn:[{waitFor:"#accept-all"},{click:"#accept-all"}],optOut:[{waitFor:"#reject-all"},{click:"#reject-all"}],test:[{eval:"EVAL_TESTCMP_0"}]},{name:"thalia.de",prehideSelectors:[".consent-banner-box"],detectCmp:[{exists:"consent-banner[component=consent-banner]"}],detectPopup:[{visible:".consent-banner-box"}],optIn:[{click:".button-zustimmen"}],optOut:[{click:"button[data-consent=disagree]"}]},{name:"thefreedictionary.com",prehideSelectors:["#cmpBanner"],detectCmp:[{exists:"#cmpBanner"}],detectPopup:[{visible:"#cmpBanner"}],optIn:[{eval:"EVAL_THEFREEDICTIONARY_1"}],optOut:[{eval:"EVAL_THEFREEDICTIONARY_0"}]},{name:"theverge",runContext:{frame:!1,main:!0,urlPattern:"^https://(www)?\\.theverge\\.com"},intermediate:!1,prehideSelectors:[".duet--cta--cookie-banner"],detectCmp:[{exists:".duet--cta--cookie-banner"}],detectPopup:[{visible:".duet--cta--cookie-banner"}],optIn:[{click:".duet--cta--cookie-banner button.tracking-12",all:!1}],optOut:[{click:".duet--cta--cookie-banner button.tracking-12 > span"}],test:[{eval:"EVAL_THEVERGE_0"}]},{name:"tidbits-com",cosmetic:!0,prehideSelectors:["#eu_cookie_law_widget-2"],detectCmp:[{exists:"#eu_cookie_law_widget-2"}],detectPopup:[{visible:"#eu_cookie_law_widget-2"}],optIn:[{click:"#eu-cookie-law form > input.accept"}],optOut:[{hide:"#eu_cookie_law_widget-2"}]},{name:"tractor-supply",runContext:{urlPattern:"^https://www\\.tractorsupply\\.com/"},cosmetic:!0,prehideSelectors:[".tsc-cookie-banner"],detectCmp:[{exists:".tsc-cookie-banner"}],detectPopup:[{visible:".tsc-cookie-banner"}],optIn:[{click:"#cookie-banner-cancel"}],optOut:[{hide:".tsc-cookie-banner"}]},{name:"trader-joes-com",cosmetic:!0,prehideSelectors:['div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'],detectCmp:[{exists:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}],detectPopup:[{visible:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}],optIn:[{click:'div[class^="CookiesAlert_cookiesAlert__container__"] button'}],optOut:[{hide:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}]},{name:"transcend",vendorUrl:"https://unknown",cosmetic:!0,prehideSelectors:["#transcend-consent-manager"],detectCmp:[{exists:"#transcend-consent-manager"}],detectPopup:[{visible:"#transcend-consent-manager"}],optIn:[{waitForThenClick:["#transcend-consent-manager","#consentManagerMainDialog .inner-container button"]}],optOut:[{hide:"#transcend-consent-manager"}]},{name:"transip-nl",runContext:{urlPattern:"^https://www\\.transip\\.nl/"},prehideSelectors:["#consent-modal"],detectCmp:[{any:[{exists:"#consent-modal"},{exists:"#privacy-settings-content"}]}],detectPopup:[{any:[{visible:"#consent-modal"},{visible:"#privacy-settings-content"}]}],optIn:[{click:'button[type="submit"]'}],optOut:[{if:{exists:"#privacy-settings-content"},then:[{click:'button[type="submit"]'}],else:[{click:"div.one-modal__action-footer-column--secondary > a"}]}]},{name:"tropicfeel-com",prehideSelectors:["#shopify-section-cookies-controller"],detectCmp:[{exists:"#shopify-section-cookies-controller"}],detectPopup:[{visible:"#shopify-section-cookies-controller #cookies-controller-main-pane",check:"any"}],optIn:[{waitForThenClick:"#cookies-controller-main-pane form[data-form-allow-all] button"}],optOut:[{click:"#cookies-controller-main-pane a[data-tab-target=manage-cookies]"},{waitFor:"#manage-cookies-pane.active"},{click:"#manage-cookies-pane.active input[type=checkbox][checked]:not([disabled])",all:!0},{click:"#manage-cookies-pane.active button[type=submit]"}],test:[]},{name:"true-car",runContext:{urlPattern:"^https://www\\.truecar\\.com/"},cosmetic:!0,prehideSelectors:[['div[aria-labelledby="cookie-banner-heading"]']],detectCmp:[{exists:'div[aria-labelledby="cookie-banner-heading"]'}],detectPopup:[{visible:'div[aria-labelledby="cookie-banner-heading"]'}],optIn:[{click:'div[aria-labelledby="cookie-banner-heading"] > button[aria-label="Close"]'}],optOut:[{hide:'div[aria-labelledby="cookie-banner-heading"]'}]},{name:"truyo",prehideSelectors:["#truyo-consent-module"],detectCmp:[{exists:"#truyo-cookieBarContent"}],detectPopup:[{visible:"#truyo-consent-module"}],optIn:[{click:"button#acceptAllCookieButton"}],optOut:[{click:"button#declineAllCookieButton"}]},{name:"twcc",vendorUrl:"https://unknown",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:""},prehideSelectors:["#twcc__mechanism"],detectCmp:[{exists:"#twcc__mechanism .twcc__notice"}],detectPopup:[{visible:"#twcc__mechanism .twcc__notice"}],optIn:[{waitForThenClick:"#twcc__accept-button"}],optOut:[{waitForThenClick:"#twcc__decline-button"}],test:[{eval:"EVAL_TWCC_TEST"}]},{name:"twitch-mobile",vendorUrl:"https://m.twitch.tv/",cosmetic:!0,runContext:{urlPattern:"^https?://m\\.twitch\\.tv"},prehideSelectors:[],detectCmp:[{exists:'.ReactModal__Overlay [href="https://www.twitch.tv/p/cookie-policy"]'}],detectPopup:[{visible:'.ReactModal__Overlay [href="https://www.twitch.tv/p/cookie-policy"]'}],optIn:[{waitForThenClick:'.ReactModal__Overlay:has([href="https://www.twitch.tv/p/cookie-policy"]) button'}],optOut:[{hide:'.ReactModal__Overlay:has([href="https://www.twitch.tv/p/cookie-policy"])'}]},{name:"twitch.tv",runContext:{urlPattern:"^https?://(www\\.)?twitch\\.tv"},prehideSelectors:["div:has(> .consent-banner .consent-banner__content--gdpr-v2),.ReactModalPortal:has([data-a-target=consent-modal-save])"],detectCmp:[{exists:".consent-banner .consent-banner__content--gdpr-v2"}],detectPopup:[{visible:".consent-banner .consent-banner__content--gdpr-v2"}],optIn:[{click:'button[data-a-target="consent-banner-accept"]'}],optOut:[{hide:"div:has(> .consent-banner .consent-banner__content--gdpr-v2)"},{click:'button[data-a-target="consent-banner-manage-preferences"]'},{waitFor:"input[type=checkbox][data-a-target=tw-checkbox]"},{click:"input[type=checkbox][data-a-target=tw-checkbox][checked]:not([disabled])",all:!0,optional:!0},{waitForThenClick:"[data-a-target=consent-modal-save]"},{waitForVisible:".ReactModalPortal:has([data-a-target=consent-modal-save])",check:"none"}]},{name:"twitter",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?(twitter|x)\\.com/"},prehideSelectors:['[data-testid="BottomBar"]'],detectCmp:[{exists:'[data-testid="BottomBar"] div'}],detectPopup:[{visible:'[data-testid="BottomBar"] div'}],optIn:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>button[role=button]>span) > div:last-child > button[role=button]:first-child'}],optOut:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>button[role=button]>span) > div:last-child > button[role=button]:last-child'}],TODOtest:[{eval:"EVAL_document.cookie.includes('d_prefs=MjoxLGNvbnNlbnRfdmVyc2lvbjoy')"}]},{name:"ubuntu.com",prehideSelectors:["dialog.cookie-policy"],detectCmp:[{any:[{exists:"dialog.cookie-policy header"},{exists:'xpath///*[@id="modal"]/div/header'}]}],detectPopup:[{any:[{visible:"dialog header"},{visible:'xpath///*[@id="modal"]/div/header'}]}],optIn:[{any:[{waitForThenClick:"#cookie-policy-button-accept"},{waitForThenClick:'xpath///*[@id="cookie-policy-button-accept"]'}]}],optOut:[{any:[{waitForThenClick:"button.js-manage"},{waitForThenClick:'xpath///*[@id="cookie-policy-content"]/p[4]/button[2]'}]},{waitForThenClick:"dialog.cookie-policy .p-switch__input:checked",optional:!0,all:!0,timeout:500},{any:[{waitForThenClick:"dialog.cookie-policy .js-save-preferences"},{waitForThenClick:'xpath///*[@id="modal"]/div/button'}]}],test:[{eval:"EVAL_UBUNTU_COM_0"}]},{name:"UK Cookie Consent",prehideSelectors:["#catapult-cookie-bar"],cosmetic:!0,detectCmp:[{exists:"#catapult-cookie-bar"}],detectPopup:[{exists:".has-cookie-bar #catapult-cookie-bar"}],optIn:[{click:"#catapultCookie"}],optOut:[{hide:"#catapult-cookie-bar"}],test:[{eval:"EVAL_UK_COOKIE_CONSENT_0"}]},{name:"urbanarmorgear-com",cosmetic:!0,prehideSelectors:['div[class^="Layout__CookieBannerContainer-"]'],detectCmp:[{exists:'div[class^="Layout__CookieBannerContainer-"]'}],detectPopup:[{visible:'div[class^="Layout__CookieBannerContainer-"]'}],optIn:[{click:'button[class^="CookieBanner__AcceptButton"]'}],optOut:[{hide:'div[class^="Layout__CookieBannerContainer-"]'}]},{name:"usercentrics-api",detectCmp:[{exists:"#usercentrics-root,#usercentrics-cmp-ui"}],detectPopup:[{eval:"EVAL_USERCENTRICS_API_0"},{if:{exists:"#usercentrics-cmp-ui"},then:[{waitForVisible:"#usercentrics-cmp-ui",timeout:2e3}],else:[{exists:["#usercentrics-root","[data-testid=uc-container]"]},{waitForVisible:"#usercentrics-root",timeout:2e3}]}],optIn:[{eval:"EVAL_USERCENTRICS_API_3"},{eval:"EVAL_USERCENTRICS_API_1"},{eval:"EVAL_USERCENTRICS_API_5"}],optOut:[{eval:"EVAL_USERCENTRICS_API_1"},{eval:"EVAL_USERCENTRICS_API_2"}],test:[{eval:"EVAL_USERCENTRICS_API_6"}]},{name:"usercentrics-button",detectCmp:[{exists:"#usercentrics-button"}],detectPopup:[{visible:"#usercentrics-button #uc-btn-accept-banner"}],optIn:[{click:"#usercentrics-button #uc-btn-accept-banner"}],optOut:[{click:"#usercentrics-button #uc-btn-deny-banner"}],test:[{eval:"EVAL_USERCENTRICS_BUTTON_0"}]},{name:"uswitch.com",runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?uswitch\\.com/"},prehideSelectors:[".ucb"],detectCmp:[{exists:".ucb-banner"}],detectPopup:[{visible:".ucb-banner"}],optIn:[{waitForThenClick:".ucb-banner .ucb-btn-accept"}],optOut:[{waitForThenClick:".ucb-banner .ucb-btn-save"}]},{name:"vodafone.de",runContext:{urlPattern:"^https://www\\.vodafone\\.de/"},prehideSelectors:[".dip-consent,.dip-consent-container"],detectCmp:[{exists:".dip-consent-container"}],detectPopup:[{visible:".dip-consent-content"}],optOut:[{click:'.dip-consent-btn[tabindex="2"]'}],optIn:[{click:'.dip-consent-btn[tabindex="1"]'}]},{name:"waitrose.com",prehideSelectors:["div[aria-labelledby=CookieAlertModalHeading]","section[data-test=initial-waitrose-cookie-consent-banner]","section[data-test=cookie-consent-modal]"],detectCmp:[{exists:"section[data-test=initial-waitrose-cookie-consent-banner]"}],detectPopup:[{visible:"section[data-test=initial-waitrose-cookie-consent-banner]"}],optIn:[{click:"button[data-test=accept-all]"}],optOut:[{click:"button[data-test=manage-cookies]"},{wait:200},{eval:"EVAL_WAITROSE_0"},{click:"button[data-test=submit]"}],test:[{eval:"EVAL_WAITROSE_1"}]},{name:"webflow",vendorUrl:"https://webflow.com/",prehideSelectors:[".fs-cc-components"],detectCmp:[{exists:".fs-cc-components"}],detectPopup:[{visible:".fs-cc-components"},{visible:"[fs-cc=banner]"}],optIn:[{wait:500},{waitForThenClick:"[fs-cc=banner] [fs-cc=allow]"}],optOut:[{wait:500},{waitForThenClick:"[fs-cc=banner] [fs-cc=deny]"}]},{name:"wetransfer.com",detectCmp:[{exists:".welcome__cookie-notice"}],detectPopup:[{visible:".welcome__cookie-notice"}],optIn:[{click:".welcome__button--accept"}],optOut:[{click:".welcome__button--decline"}]},{name:"whitepages.com",runContext:{urlPattern:"^https://www\\.whitepages\\.com/"},cosmetic:!0,prehideSelectors:[".cookie-wrapper, .cookie-overlay"],detectCmp:[{exists:".cookie-wrapper"}],detectPopup:[{visible:".cookie-overlay"}],optIn:[{click:'button[aria-label="Got it"]'}],optOut:[{hide:".cookie-wrapper"}]},{name:"wolframalpha",vendorUrl:"https://www.wolframalpha.com",prehideSelectors:[],cosmetic:!0,runContext:{urlPattern:"^https://www\\.wolframalpha\\.com/"},detectCmp:[{exists:"section._a_yb"}],detectPopup:[{visible:"section._a_yb"}],optIn:[{waitForThenClick:"section._a_yb button"}],optOut:[{hide:"section._a_yb"}]},{name:"woo-commerce-com",prehideSelectors:[".wccom-comp-privacy-banner .wccom-privacy-banner"],detectCmp:[{exists:".wccom-comp-privacy-banner .wccom-privacy-banner"}],detectPopup:[{exists:".wccom-comp-privacy-banner .wccom-privacy-banner"}],optIn:[{click:".wccom-privacy-banner__content-buttons button.is-primary"}],optOut:[{click:".wccom-privacy-banner__content-buttons button.is-secondary"},{waitForThenClick:"input[type=checkbox][checked]:not([disabled])",all:!0},{click:"div.wccom-modal__footer > button"}]},{name:"WP Cookie Notice for GDPR",vendorUrl:"https://wordpress.org/plugins/gdpr-cookie-consent/",prehideSelectors:["#gdpr-cookie-consent-bar"],detectCmp:[{exists:"#gdpr-cookie-consent-bar"}],detectPopup:[{visible:"#gdpr-cookie-consent-bar"}],optIn:[{waitForThenClick:"#gdpr-cookie-consent-bar #cookie_action_accept"}],optOut:[{waitForThenClick:"#gdpr-cookie-consent-bar #cookie_action_reject"}],test:[{eval:"EVAL_WP_COOKIE_NOTICE_0"}]},{name:"wpcc",cosmetic:!0,prehideSelectors:[".wpcc-container"],detectCmp:[{exists:".wpcc-container"}],detectPopup:[{exists:".wpcc-container .wpcc-message"}],optIn:[{click:".wpcc-compliance .wpcc-btn"}],optOut:[{hide:".wpcc-container"}]},{name:"xe.com",vendorUrl:"https://www.xe.com/",runContext:{urlPattern:"^https://www\\.xe\\.com/"},prehideSelectors:["[class*=ConsentBanner]"],detectCmp:[{exists:"[class*=ConsentBanner]"}],detectPopup:[{visible:"[class*=ConsentBanner]"}],optIn:[{waitForThenClick:"[class*=ConsentBanner] .egnScw"}],optOut:[{wait:1e3},{waitForThenClick:"[class*=ConsentBanner] .frDWEu"},{waitForThenClick:"[class*=ConsentBanner] .hXIpFU"}],test:[{eval:"EVAL_XE_TEST"}]},{name:"xhamster-eu",prehideSelectors:[".cookies-modal"],detectCmp:[{exists:".cookies-modal"}],detectPopup:[{exists:".cookies-modal"}],optIn:[{click:"button.cmd-button-accept-all"}],optOut:[{click:"button.cmd-button-reject-all"}]},{name:"xhamster-us",runContext:{urlPattern:"^https://(www\\.)?xhamster\\d?\\.com"},cosmetic:!0,prehideSelectors:[".cookie-announce"],detectCmp:[{exists:".cookie-announce"}],detectPopup:[{visible:".cookie-announce .announce-text"}],optIn:[{click:".cookie-announce button.xh-button"}],optOut:[{hide:".cookie-announce"}]},{name:"xing.com",detectCmp:[{exists:"div[class^=cookie-consent-CookieConsent]"}],detectPopup:[{exists:"div[class^=cookie-consent-CookieConsent]"}],optIn:[{click:"#consent-accept-button"}],optOut:[{click:"#consent-settings-button"},{click:".consent-banner-button-accept-overlay"}],test:[{eval:"EVAL_XING_0"}]},{name:"xnxx-com",cosmetic:!0,prehideSelectors:["#cookies-use-alert"],detectCmp:[{exists:"#cookies-use-alert"}],detectPopup:[{visible:"#cookies-use-alert"}],optIn:[{click:"#cookies-use-alert .close"}],optOut:[{hide:"#cookies-use-alert"}]},{name:"xvideos",vendorUrl:"https://xvideos.com",runContext:{urlPattern:"^https://[^/]*xvideos\\.com/"},prehideSelectors:[],detectCmp:[{exists:".disclaimer-opened #disclaimer-cookies"}],detectPopup:[{visible:".disclaimer-opened #disclaimer-cookies"}],optIn:[{waitForThenClick:"#disclaimer-accept_cookies"}],optOut:[{waitForThenClick:"#disclaimer-reject_cookies"}]},{name:"Yahoo",runContext:{urlPattern:"^https://consent\\.yahoo\\.com/v2/"},prehideSelectors:["#reject-all"],detectCmp:[{exists:"#consent-page"}],detectPopup:[{visible:"#consent-page"}],optIn:[{waitForThenClick:"#consent-page button[value=agree]"}],optOut:[{waitForThenClick:"#consent-page button[value=reject]"}]},{name:"youporn.com",cosmetic:!0,prehideSelectors:[".euCookieModal, #js_euCookieModal"],detectCmp:[{exists:".euCookieModal"}],detectPopup:[{exists:".euCookieModal, #js_euCookieModal"}],optIn:[{click:'button[name="user_acceptCookie"]'}],optOut:[{hide:".euCookieModal"}]},{name:"youtube-desktop",prehideSelectors:["tp-yt-iron-overlay-backdrop.opened","ytd-consent-bump-v2-lightbox"],detectCmp:[{exists:"ytd-consent-bump-v2-lightbox tp-yt-paper-dialog"},{exists:'ytd-consent-bump-v2-lightbox tp-yt-paper-dialog a[href^="https://consent.youtube.com/"]'}],detectPopup:[{visible:"ytd-consent-bump-v2-lightbox tp-yt-paper-dialog"}],optIn:[{waitForThenClick:"ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:last-child #button,ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:last-child button"},{wait:500}],optOut:[{waitForThenClick:"ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:first-child #button,ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:first-child button"},{wait:500}],test:[{wait:500},{eval:"EVAL_YOUTUBE_DESKTOP_0"}]},{name:"youtube-mobile",prehideSelectors:[".consent-bump-v2-lightbox"],detectCmp:[{exists:"ytm-consent-bump-v2-renderer"}],detectPopup:[{visible:"ytm-consent-bump-v2-renderer"}],optIn:[{waitForThenClick:"ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons c3-material-button:first-child button, ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons ytm-button-renderer:first-child button"},{wait:500}],optOut:[{waitForThenClick:"ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons c3-material-button:nth-child(2) button, ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons ytm-button-renderer:nth-child(2) button"},{wait:500}],test:[{wait:500},{eval:"EVAL_YOUTUBE_MOBILE_0"}]},{name:"zdf",prehideSelectors:["#zdf-cmp-banner-sdk"],detectCmp:[{exists:"#zdf-cmp-banner-sdk"}],detectPopup:[{visible:"#zdf-cmp-main.zdf-cmp-show"}],optIn:[{waitForThenClick:"#zdf-cmp-main #zdf-cmp-accept-btn"}],optOut:[{waitForThenClick:"#zdf-cmp-main #zdf-cmp-deny-btn"}],test:[]},{name:"zentralruf-de",runContext:{urlPattern:"^https://(www\\.)?zentralruf\\.de"},prehideSelectors:["#cookie_modal_wrapper"],detectCmp:[{exists:"#cookie_modal_wrapper"}],detectPopup:[{visible:"#cookie_modal_wrapper"}],optIn:[{waitForThenClick:"#cookie_modal_wrapper #cookie_modal_button_consent_all"}],optOut:[{waitForThenClick:"#cookie_modal_wrapper #cookie_modal_button_choose"}]}],fn={"didomi.io":{detectors:[{presentMatcher:{target:{selector:"#didomi-host, #didomi-notice"},type:"css"},showingMatcher:{target:{selector:"body.didomi-popup-open, .didomi-notice-banner"},type:"css"}}],methods:[{action:{target:{selector:".didomi-popup-notice-buttons .didomi-button:not(.didomi-button-highlight), .didomi-notice-banner .didomi-learn-more-button"},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{retries:50,target:{selector:"#didomi-purpose-cookies"},type:"waitcss",waitTime:50},{consents:[{description:"Share (everything) with others",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-share_whith_others]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-share_whith_others]:last-child"},type:"click"},type:"X"},{description:"Information storage and access",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-cookies]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-cookies]:last-child"},type:"click"},type:"D"},{description:"Content selection, offers and marketing",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-CL-T1Rgm7]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-CL-T1Rgm7]:last-child"},type:"click"},type:"E"},{description:"Analytics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-analytics]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-analytics]:last-child"},type:"click"},type:"B"},{description:"Analytics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-M9NRHJe3G]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-M9NRHJe3G]:last-child"},type:"click"},type:"B"},{description:"Ad and content selection",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-advertising_personalization]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-advertising_personalization]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection",falseAction:{parent:{childFilter:{target:{selector:"#didomi-purpose-pub-ciblee"}},selector:".didomi-consent-popup-data-processing, .didomi-components-accordion-label-container"},target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-pub-ciblee]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-pub-ciblee]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - basics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-q4zlJqdcD]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-q4zlJqdcD]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - partners and subsidiaries",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-partenaire-cAsDe8jC]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-partenaire-cAsDe8jC]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-p4em9a8m]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-p4em9a8m]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - others",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-autres-pub]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-autres-pub]:last-child"},type:"click"},type:"F"},{description:"Social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-reseauxsociaux]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-reseauxsociaux]:last-child"},type:"click"},type:"A"},{description:"Social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-social_media]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-social_media]:last-child"},type:"click"},type:"A"},{description:"Content selection",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-content_personalization]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-content_personalization]:last-child"},type:"click"},type:"E"},{description:"Ad delivery",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-ad_delivery]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-ad_delivery]:last-child"},type:"click"},type:"F"}],type:"consent"},{action:{consents:[{matcher:{childFilter:{target:{selector:":not(.didomi-components-radio__option--selected)"}},type:"css"},trueAction:{target:{selector:":nth-child(2)"},type:"click"},falseAction:{target:{selector:":first-child"},type:"click"},type:"X"}],type:"consent"},target:{selector:".didomi-components-radio"},type:"foreach"}],type:"list"},name:"DO_CONSENT"},{action:{parent:{selector:".didomi-consent-popup-footer .didomi-consent-popup-actions"},target:{selector:".didomi-components-button:first-child"},type:"click"},name:"SAVE_CONSENT"}]},oil:{detectors:[{presentMatcher:{target:{selector:".as-oil-content-overlay"},type:"css"},showingMatcher:{target:{selector:".as-oil-content-overlay"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".as-js-advanced-settings"},type:"click"},{retries:"10",target:{selector:".as-oil-cpc__purpose-container"},type:"waitcss",waitTime:"250"}],type:"list"},name:"OPEN_OPTIONS"},{action:{actions:[{consents:[{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Information storage and access","Opbevaring af og adgang til oplysninger på din enhed"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Information storage and access","Opbevaring af og adgang til oplysninger på din enhed"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"D"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personlige annoncer","Personalisation"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personlige annoncer","Personalisation"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"E"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Annoncevalg, levering og rapportering","Ad selection, delivery, reporting"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Annoncevalg, levering og rapportering","Ad selection, delivery, reporting"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"F"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personalisering af indhold","Content selection, delivery, reporting"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personalisering af indhold","Content selection, delivery, reporting"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"E"},{matcher:{parent:{childFilter:{target:{selector:".as-oil-cpc__purpose-header",textFilter:["Måling","Measurement"]}},selector:".as-oil-cpc__purpose-container"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{childFilter:{target:{selector:".as-oil-cpc__purpose-header",textFilter:["Måling","Measurement"]}},selector:".as-oil-cpc__purpose-container"},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"B"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:"Google"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:"Google"},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"F"}],type:"consent"}],type:"list"},name:"DO_CONSENT"},{action:{target:{selector:".as-oil__btn-optin"},type:"click"},name:"SAVE_CONSENT"},{action:{target:{selector:"div.as-oil"},type:"hide"},name:"HIDE_CMP"}]},optanon:{detectors:[{presentMatcher:{target:{selector:"#optanon-menu, .optanon-alert-box-wrapper"},type:"css"},showingMatcher:{target:{displayFilter:!0,selector:".optanon-alert-box-wrapper"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".optanon-alert-box-wrapper .optanon-toggle-display, a[onclick*='OneTrust.ToggleInfoDisplay()'], a[onclick*='Optanon.ToggleInfoDisplay()']"},type:"click"}],type:"list"},name:"OPEN_OPTIONS"},{action:{actions:[{target:{selector:".preference-menu-item #Your-privacy"},type:"click"},{target:{selector:"#optanon-vendor-consent-text"},type:"click"},{action:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},target:{selector:"#optanon-vendor-consent-list .vendor-item"},type:"foreach"},{target:{selector:".vendor-consent-back-link"},type:"click"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-performance"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-performance"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-functional"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-functional"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-advertising"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-advertising"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-social"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-social"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Social Media Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Social Media Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalisation"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalisation"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Site monitoring cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Site monitoring cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Third party privacy-enhanced content"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Third party privacy-enhanced content"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Performance & Advertising Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Performance & Advertising Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Information storage and access"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Information storage and access"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"D"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad selection, delivery, reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad selection, delivery, reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content selection, delivery, reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content selection, delivery, reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Measurement"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Measurement"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Recommended Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Recommended Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Unclassified Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Unclassified Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Analytical Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Analytical Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Marketing Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Marketing Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalization"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalization"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad Selection, Delivery & Reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad Selection, Delivery & Reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content Selection, Delivery & Reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content Selection, Delivery & Reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"}],type:"list"},name:"DO_CONSENT"},{action:{parent:{selector:".optanon-save-settings-button"},target:{selector:".optanon-white-button-middle"},type:"click"},name:"SAVE_CONSENT"},{action:{actions:[{target:{selector:"#optanon-popup-wrapper"},type:"hide"},{target:{selector:"#optanon-popup-bg"},type:"hide"},{target:{selector:".optanon-alert-box-wrapper"},type:"hide"}],type:"list"},name:"HIDE_CMP"}]},quantcast2:{detectors:[{presentMatcher:{target:{selector:"[data-tracking-opt-in-overlay]"},type:"css"},showingMatcher:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-learn-more]"},type:"css"}}],methods:[{action:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-learn-more]"},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{type:"wait",waitTime:500},{action:{actions:[{target:{selector:"div",textFilter:["Information storage and access"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"D"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Personalization"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"F"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Ad selection, delivery, reporting"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"F"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Content selection, delivery, reporting"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"E"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Measurement"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"B"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Other Partners"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},type:"ifcss"}],type:"list"},parent:{childFilter:{target:{selector:"input"}},selector:"[data-tracking-opt-in-overlay] > div > div"},target:{childFilter:{target:{selector:"input"}},selector:":scope > div"},type:"foreach"}],type:"list"},name:"DO_CONSENT"},{action:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-save]"},type:"click"},name:"SAVE_CONSENT"}]},springer:{detectors:[{presentMatcher:{parent:null,target:{selector:".cmp-app_gdpr"},type:"css"},showingMatcher:{parent:null,target:{displayFilter:!0,selector:".cmp-popup_popup"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".cmp-intro_rejectAll"},type:"click"},{type:"wait",waitTime:250},{target:{selector:".cmp-purposes_purposeItem:not(.cmp-purposes_selectedPurpose)"},type:"click"}],type:"list"},name:"OPEN_OPTIONS"},{action:{consents:[{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Przechowywanie informacji na urządzeniu lub dostęp do nich",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Przechowywanie informacji na urządzeniu lub dostęp do nich",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"D"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór podstawowych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór podstawowych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"F"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"F"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"E"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"E"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Stosowanie badań rynkowych w celu generowania opinii odbiorców",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Stosowanie badań rynkowych w celu generowania opinii odbiorców",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"X"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Opracowywanie i ulepszanie produktów",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Opracowywanie i ulepszanie produktów",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"X"}],type:"consent"},name:"DO_CONSENT"},{action:{target:{selector:".cmp-details_save"},type:"click"},name:"SAVE_CONSENT"}]},wordpressgdpr:{detectors:[{presentMatcher:{parent:null,target:{selector:".wpgdprc-consent-bar"},type:"css"},showingMatcher:{parent:null,target:{displayFilter:!0,selector:".wpgdprc-consent-bar"},type:"css"}}],methods:[{action:{parent:null,target:{selector:".wpgdprc-consent-bar .wpgdprc-consent-bar__settings",textFilter:null},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{target:{selector:".wpgdprc-consent-modal .wpgdprc-button",textFilter:"Eyeota"},type:"click"},{consents:[{description:"Eyeota Cookies",matcher:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Eyeota"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Eyeota"},target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},{target:{selector:".wpgdprc-consent-modal .wpgdprc-button",textFilter:"Advertising"},type:"click"},{consents:[{description:"Advertising Cookies",matcher:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Advertising"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Advertising"},target:{selector:"label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},name:"DO_CONSENT"},{action:{parent:null,target:{selector:".wpgdprc-button",textFilter:"Save my settings"},type:"click"},name:"SAVE_CONSENT"}]}},kn={autoconsent:gn,consentomatic:fn},bn=Object.freeze({__proto__:null,autoconsent:gn,consentomatic:fn,default:kn}); +/*! Bundled license information: + + @ghostery/adblocker/dist/esm/codebooks/cosmetic-selector.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/codebooks/network-csp.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/codebooks/network-filter.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/codebooks/network-hostname.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/codebooks/network-redirect.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/codebooks/raw-network.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/codebooks/raw-cosmetic.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/compression.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/punycode.js: + (*! + * Copyright Mathias Bynens + * + * 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. + *) + + @ghostery/adblocker/dist/esm/data-view.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/config.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/events.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/fetch.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker-extended-selectors/dist/esm/types.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker-extended-selectors/dist/esm/parse.js: + (*! + * Based on parsel. Extended by Rémi Berson for Ghostery (2021). + * https://github.com/LeaVerou/parsel + * + * MIT License + * + * Copyright (c) 2020 Lea Verou + * + * 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. + *) + + @ghostery/adblocker-extended-selectors/dist/esm/eval.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker-extended-selectors/dist/esm/extended.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker-extended-selectors/dist/esm/index.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/tokens-buffer.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/utils.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/request.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/domains.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/html-filtering.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/filters/cosmetic.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/filters/dsl.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/filters/network.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/lists.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/resources.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/compact-set.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/optimizer.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/reverse-index.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/bucket/filters.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/bucket/cosmetic.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/bucket/network.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/map.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/metadata/categories.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/metadata/organizations.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/metadata/patterns.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/metadata.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/engine/engine.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker/dist/esm/encoding.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + (*! + * Copyright (c) 2008-2009 Bjoern Hoehrmann + * + * 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. + *) + + @ghostery/adblocker/dist/esm/index.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + + @ghostery/adblocker-content/dist/esm/index.js: + (*! + * Copyright (c) 2017-present Ghostery GmbH. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + *) + */const yn=new class{constructor(e,t=null,o=null){if(this.id=c(),this.rules=[],this.foundCmp=null,this.state={cosmeticFiltersOn:!1,lifecycle:"loading",prehideOn:!1,findCmpAttempts:0,detectedCmps:[],detectedPopups:[],selfTest:null},a.sendContentMessage=e,this.sendContentMessage=e,this.rules=[],this.updateState({lifecycle:"loading"}),this.addDynamicRules(),t)this.initialize(t,o);else{o&&this.parseDeclarativeRules(o);e({type:"init",url:window.location.href}),this.updateState({lifecycle:"waitingForInitResponse"})}this.domActions=new _(this)}initialize(e,t){const o=b(e);if(o.logs.lifecycle&&console.log("autoconsent init",window.location.href),this.config=o,o.enabled){if(t&&this.parseDeclarativeRules(t),e.enableFilterList){try{An&&An.length>0&&(this.filtersEngine=un.deserialize(An))}catch(e){console.error("Error parsing filter list",e)}"loading"===document.readyState?window.addEventListener("DOMContentLoaded",(()=>{this.applyCosmeticFilters()})):this.applyCosmeticFilters()}if(this.rules=function(e,t){return e.filter((e=>(!t.disabledCmps||!t.disabledCmps.includes(e.name))&&(t.enableCosmeticRules||!e.isCosmetic)))}(this.rules,o),e.enablePrehide)if(document.documentElement)this.prehideElements();else{const e=()=>{window.removeEventListener("DOMContentLoaded",e),this.prehideElements()};window.addEventListener("DOMContentLoaded",e)}if("loading"===document.readyState){const e=()=>{window.removeEventListener("DOMContentLoaded",e),this.start()};window.addEventListener("DOMContentLoaded",e)}else this.start();this.updateState({lifecycle:"initialized"})}else o.logs.lifecycle&&console.log("autoconsent is disabled")}addDynamicRules(){v.forEach((e=>{this.rules.push(new e(this))}))}parseDeclarativeRules(e){e.consentomatic&&Object.keys(e.consentomatic).forEach((t=>{this.addConsentomaticCMP(t,e.consentomatic[t])})),e.autoconsent&&e.autoconsent.forEach((e=>{this.addDeclarativeCMP(e)}))}addDeclarativeCMP(e){this.rules.push(new u(e,this))}addConsentomaticCMP(e,t){this.rules.push(new h(`com_${e}`,t))}start(){window.requestIdleCallback?window.requestIdleCallback((()=>this._start()),{timeout:500}):this._start()}async _start(){const e=this.config.logs;e.lifecycle&&console.log(`Detecting CMPs on ${window.location.href}`),this.updateState({lifecycle:"started"});const t=await this.findCmp(this.config.detectRetries);if(this.updateState({detectedCmps:t.map((e=>e.name))}),0===t.length)return e.lifecycle&&console.log("no CMP found",location.href),this.config.enablePrehide&&this.undoPrehide(),this.filterListFallback();this.updateState({lifecycle:"cmpDetected"});const o=[],i=[];for(const e of t)e.isCosmetic?i.push(e):o.push(e);let n=!1,s=await this.detectPopups(o,(async e=>{n=await this.handlePopup(e)}));if(0===s.length&&(s=await this.detectPopups(i,(async e=>{n=await this.handlePopup(e)}))),0===s.length)return e.lifecycle&&console.log("no popup found"),this.config.enablePrehide&&this.undoPrehide(),!1;if(s.length>1){const t={msg:"Found multiple CMPs, check the detection rules.",cmps:s.map((e=>e.name))};e.errors&&console.warn(t.msg,t.cmps),this.sendContentMessage({type:"autoconsentError",details:t})}return n}async findCmp(e){const t=this.config.logs;this.updateState({findCmpAttempts:this.state.findCmpAttempts+1});const o=[];for(const e of this.rules)try{if(!e.checkRunContext())continue;await e.detectCmp()&&(t.lifecycle&&console.log(`Found CMP: ${e.name} ${window.location.href}`),this.sendContentMessage({type:"cmpDetected",url:location.href,cmp:e.name}),o.push(e))}catch(o){t.errors&&console.warn(`error detecting ${e.name}`,o)}return 0===o.length&&e>0?(await this.domActions.wait(500),this.findCmp(e-1)):o}async detectPopup(e){if(await this.waitForPopup(e).catch((t=>(this.config.logs.errors&&console.warn(`error waiting for a popup for ${e.name}`,t),!1))))return this.updateState({detectedPopups:this.state.detectedPopups.concat([e.name])}),this.sendContentMessage({type:"popupFound",cmp:e.name,url:location.href}),e;throw new Error("Popup is not shown")}async detectPopups(e,t){const o=e.map((e=>this.detectPopup(e)));await Promise.any(o).then((e=>{t(e)})).catch((()=>null));const i=await Promise.allSettled(o),n=[];for(const e of i)"fulfilled"===e.status&&n.push(e.value);return n}async handlePopup(e){return this.updateState({lifecycle:"openPopupDetected"}),this.config.enablePrehide&&!this.state.prehideOn&&this.prehideElements(),this.state.cosmeticFiltersOn&&this.undoCosmetics(),this.foundCmp=e,"optOut"===this.config.autoAction?await this.doOptOut():"optIn"===this.config.autoAction?await this.doOptIn():(this.config.logs.lifecycle&&console.log("waiting for opt-out signal...",location.href),!0)}async doOptOut(){const e=this.config.logs;let t;return this.updateState({lifecycle:"runningOptOut"}),this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: opt out on ${window.location.href}`),t=await this.foundCmp.optOut(),e.lifecycle&&console.log(`${this.foundCmp.name}: opt out result ${t}`)):(e.errors&&console.log("no CMP to opt out"),t=!1),this.config.enablePrehide&&this.undoPrehide(),this.sendContentMessage({type:"optOutResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,scheduleSelfTest:this.foundCmp&&this.foundCmp.hasSelfTest,url:location.href}),t&&!this.foundCmp.isIntermediate?(this.sendContentMessage({type:"autoconsentDone",cmp:this.foundCmp.name,isCosmetic:this.foundCmp.isCosmetic,url:location.href}),this.updateState({lifecycle:"done"})):this.updateState({lifecycle:t?"optOutSucceeded":"optOutFailed"}),t}async doOptIn(){const e=this.config.logs;let t;return this.updateState({lifecycle:"runningOptIn"}),this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: opt in on ${window.location.href}`),t=await this.foundCmp.optIn(),e.lifecycle&&console.log(`${this.foundCmp.name}: opt in result ${t}`)):(e.errors&&console.log("no CMP to opt in"),t=!1),this.config.enablePrehide&&this.undoPrehide(),this.sendContentMessage({type:"optInResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,scheduleSelfTest:!1,url:location.href}),t&&!this.foundCmp.isIntermediate?(this.sendContentMessage({type:"autoconsentDone",cmp:this.foundCmp.name,isCosmetic:this.foundCmp.isCosmetic,url:location.href}),this.updateState({lifecycle:"done"})):this.updateState({lifecycle:t?"optInSucceeded":"optInFailed"}),t}async doSelfTest(){const e=this.config.logs;let t;return this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: self-test on ${window.location.href}`),t=await this.foundCmp.test()):(e.errors&&console.log("no CMP to self test"),t=!1),this.sendContentMessage({type:"selfTestResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,url:location.href}),this.updateState({selfTest:t}),t}async waitForPopup(e,t=5,o=500){const i=this.config.logs;i.lifecycle&&console.log("checking if popup is open...",e.name);const n=await e.detectPopup().catch((t=>(i.errors&&console.warn(`error detecting popup for ${e.name}`,t),!1)));return!n&&t>0?(await this.domActions.wait(o),this.waitForPopup(e,t-1,o)):(i.lifecycle&&console.log(e.name,"popup is "+(n?"open":"not open")),n)}prehideElements(){const e=this.config.logs,t=this.rules.filter((e=>e.prehideSelectors&&e.checkRunContext())).reduce(((e,t)=>[...e,...t.prehideSelectors]),["#didomi-popup,.didomi-popup-container,.didomi-popup-notice,.didomi-consent-popup-preferences,#didomi-notice,.didomi-popup-backdrop,.didomi-screen-medium"]);return this.updateState({prehideOn:!0}),setTimeout((()=>{this.config.enablePrehide&&this.state.prehideOn&&!["runningOptOut","runningOptIn"].includes(this.state.lifecycle)&&(e.lifecycle&&console.log("Process is taking too long, unhiding elements"),this.undoPrehide())}),this.config.prehideTimeout||2e3),this.domActions.prehide(t.join(","))}undoPrehide(){return this.updateState({prehideOn:!1}),this.domActions.undoPrehide()}async applyCosmeticFilters(e){if(!this.filtersEngine)return!1;const t=this.config?.logs;e||(e=mn(this.filtersEngine)),this.updateState({cosmeticFiltersOn:!0});try{this.cosmeticStyleSheet=await this.domActions.createOrUpdateStyleSheet(e,this.cosmeticStyleSheet),t?.lifecycle&&console.log("[cosmetics]",this.cosmeticStyleSheet,location.href),document.adoptedStyleSheets.push(this.cosmeticStyleSheet)}catch(e){return this.config.logs&&console.error("Error applying cosmetic filters",e),!1}return!0}undoCosmetics(){this.updateState({cosmeticFiltersOn:!1}),this.config.logs.lifecycle&&console.log("[undocosmetics]",this.cosmeticStyleSheet,location.href),this.domActions.removeStyleSheet(this.cosmeticStyleSheet)}filterListFallback(){if(!this.filtersEngine)return this.updateState({lifecycle:"nothingDetected"}),!1;const e=mn(this.filtersEngine),t=this.domActions.elementVisible(function(e){if(e)return e.replace(/\s*{[^\\}]*}\s*/g,",").replace(/,$/,"");return""}(e),"any"),o=this.config?.logs;return t?(this.applyCosmeticFilters(e),o?.lifecycle&&console.log("Keeping cosmetic filters",location.href),this.updateState({lifecycle:"cosmeticFiltersDetected"}),this.sendContentMessage({type:"cmpDetected",url:location.href,cmp:"filterList"}),this.sendContentMessage({type:"popupFound",cmp:"filterList",url:location.href}),this.sendContentMessage({type:"optOutResult",cmp:"filterList",result:!0,scheduleSelfTest:!1,url:location.href}),this.updateState({lifecycle:"done"}),this.sendContentMessage({type:"autoconsentDone",cmp:"filterList",isCosmetic:!0,url:location.href}),!0):(o?.lifecycle&&console.log("Cosmetic filters didn't work, removing them",location.href),this.undoCosmetics(),this.updateState({lifecycle:"nothingDetected"}),!1)}updateState(e){Object.assign(this.state,e),this.sendContentMessage({type:"report",instanceId:this.id,url:window.location.href,mainFrame:window.top===window.self,state:this.state})}async receiveMessageCallback(e){const t=this.config?.logs;switch(t?.messages&&console.log("received from background",e,window.location.href),e.type){case"initResp":this.initialize(e.config,e.rules);break;case"optIn":await this.doOptIn();break;case"optOut":await this.doOptOut();break;case"selfTest":await this.doSelfTest();break;case"evalResp":!function(e,t){const o=a.pending.get(e);o?(a.pending.delete(e),o.timer&&window.clearTimeout(o.timer),o.resolve(t)):console.warn("no eval #",e)}(e.id,e.result)}}}((e=>{window.webkit.messageHandlers[e.type]&&window.webkit.messageHandlers[e.type].postMessage(e).then((e=>{yn.receiveMessageCallback(e)}))}),null,bn);window.autoconsentMessageCallback=e=>{yn.receiveMessageCallback(e)}}(); diff --git a/package-lock.json b/package-lock.json index e61ff6afe9..ebc52c9d11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "ios", "version": "1.0.0", "dependencies": { - "@duckduckgo/autoconsent": "^10.17.0" + "@duckduckgo/autoconsent": "^11.5.0" }, "devDependencies": { "@rollup/plugin-json": "^4.1.0", @@ -121,14 +121,45 @@ } }, "node_modules/@duckduckgo/autoconsent": { - "version": "10.17.0", - "resolved": "https://registry.npmjs.org/@duckduckgo/autoconsent/-/autoconsent-10.17.0.tgz", - "integrity": "sha512-zMB4BE5fpiqvjXPA0k8bCorWgh6eFMlkedRfuRVQYhbWqwLgrnsA7lv4U0ORTIJkvbBjABuYaprwr1yd/15D/w==", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/@duckduckgo/autoconsent/-/autoconsent-11.5.0.tgz", + "integrity": "sha512-mjMVTtJuHKPnX+poz5ZOPpUCPtoVh7nQeO7oXtsYEXZNSEIO/UIK9ozEWUI3Ta1utzQm4pN5wJwmsgmxNUXi/w==", "license": "MPL-2.0", "dependencies": { - "tldts-experimental": "^6.1.37" + "@ghostery/adblocker": "^2.0.4", + "@ghostery/adblocker-content": "^2.0.4", + "tldts-experimental": "^6.1.41" } }, + "node_modules/@ghostery/adblocker": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@ghostery/adblocker/-/adblocker-2.0.4.tgz", + "integrity": "sha512-n2z0IHzEfK/J7sBz2R6R69o9W7NdVJGc6IPMztMvGloPyJDv5D9mZNIfiz9EoLI9YHRIJd/lV3bMI7VJWVR1YA==", + "license": "MPL-2.0", + "dependencies": { + "@ghostery/adblocker-content": "^2.0.4", + "@ghostery/adblocker-extended-selectors": "^2.0.4", + "@remusao/guess-url-type": "^1.3.0", + "@remusao/small": "^1.2.1", + "@remusao/smaz": "^1.9.1", + "tldts-experimental": "^6.0.14" + } + }, + "node_modules/@ghostery/adblocker-content": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@ghostery/adblocker-content/-/adblocker-content-2.0.4.tgz", + "integrity": "sha512-IhYx/5FY210+VfWlLZ7tPzo54XA2cAYzQesxjyGkVr4hl6gwV/ubeQzxzY3RdThS9v+ArbWGM/rGGpJjZtrTZA==", + "license": "MPL-2.0", + "dependencies": { + "@ghostery/adblocker-extended-selectors": "^2.0.4" + } + }, + "node_modules/@ghostery/adblocker-extended-selectors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@ghostery/adblocker-extended-selectors/-/adblocker-extended-selectors-2.0.4.tgz", + "integrity": "sha512-HIhTFpPn3lepYaudC2/yUxAFe1LhGzQCgPjv9kN2f7L9zwr96w1T+iL0jtaXnsrxLKeJ/krYR3gmNKhFcdsnEA==", + "license": "MPL-2.0" + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -187,6 +218,49 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@remusao/guess-url-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@remusao/guess-url-type/-/guess-url-type-1.3.0.tgz", + "integrity": "sha512-SNSJGxH5ckvxb3EUHj4DqlAm/bxNxNv2kx/AESZva/9VfcBokwKNS+C4D1lQdWIDM1R3d3UG+xmVzlkNG8CPTQ==", + "license": "MPL-2.0" + }, + "node_modules/@remusao/small": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@remusao/small/-/small-1.3.0.tgz", + "integrity": "sha512-bydAhJI+ywmg5xMUcbqoR8KahetcfkFywEZpsyFZ8EBofilvWxbXnMSe4vnjDI1Y+SWxnNhR4AL/2BAXkf4b8A==", + "license": "MPL-2.0" + }, + "node_modules/@remusao/smaz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@remusao/smaz/-/smaz-1.10.0.tgz", + "integrity": "sha512-GQzCxmmMpLkyZwcwNgz8TpuBEWl0RUQa8IcvKiYlPxuyYKqyqPkCr0hlHI15ckn3kDUPS68VmTVgyPnLNrdVmg==", + "license": "MPL-2.0", + "dependencies": { + "@remusao/smaz-compress": "^1.10.0", + "@remusao/smaz-decompress": "^1.10.0" + } + }, + "node_modules/@remusao/smaz-compress": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@remusao/smaz-compress/-/smaz-compress-1.10.0.tgz", + "integrity": "sha512-E/lC8OSU+3bQrUl64vlLyPzIxo7dxF2RvNBe9KzcM4ax43J/d+YMinmMztHyCIHqRbz7rBCtkp3c0KfeIbHmEg==", + "license": "MPL-2.0", + "dependencies": { + "@remusao/trie": "^1.5.0" + } + }, + "node_modules/@remusao/smaz-decompress": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@remusao/smaz-decompress/-/smaz-decompress-1.10.0.tgz", + "integrity": "sha512-aA5ImUH480Pcs5/cOgToKmFnzi7osSNG6ft+7DdmQTaQEEst3nLq3JLlBEk+gwidURymjbx6DYs60LHaZ415VQ==", + "license": "MPL-2.0" + }, + "node_modules/@remusao/trie": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@remusao/trie/-/trie-1.5.0.tgz", + "integrity": "sha512-UX+3utJKgwCsg6sUozjxd38gNMVRXrY4TNX9VvCdSrlZBS1nZjRPi98ON3QjRAdf6KCguJFyQARRsulTeqQiPg==", + "license": "MPL-2.0" + }, "node_modules/@rollup/plugin-json": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", @@ -591,18 +665,18 @@ } }, "node_modules/tldts-core": { - "version": "6.1.37", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.37.tgz", - "integrity": "sha512-q6M/RBjZcUoF/KRhHFuGrcnaXLaXH8kHKH/e8XaAd9ULGYYhB32kr1ceIXR77a57OxRB/NR471BcYwU7jf4PAg==", + "version": "6.1.61", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.61.tgz", + "integrity": "sha512-In7VffkDWUPgwa+c9picLUxvb0RltVwTkSgMNFgvlGSWveCzGBemBqTsgJCL4EDFWZ6WH0fKTsot6yNhzy3ZzQ==", "license": "MIT" }, "node_modules/tldts-experimental": { - "version": "6.1.37", - "resolved": "https://registry.npmjs.org/tldts-experimental/-/tldts-experimental-6.1.37.tgz", - "integrity": "sha512-GnuPXda/PzXoPqq4KCiXsiYoKBXV/oonfEY97hwadYmHzK6wJxLF8FPeRDGQPHP5RkphfcDGnAIMZthvqYrfSA==", + "version": "6.1.61", + "resolved": "https://registry.npmjs.org/tldts-experimental/-/tldts-experimental-6.1.61.tgz", + "integrity": "sha512-1plwEyCpyYtVsZVtC169C5bStRlDk3cIniMHUeNmAJOjmQGx7SnLM8kS06PQAHx9PPY4Jm1VS6IXZzPC53XpbQ==", "license": "MIT", "dependencies": { - "tldts-core": "^6.1.37" + "tldts-core": "^6.1.61" } } } diff --git a/package.json b/package.json index 7cb35376c5..c20bb4c42f 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,6 @@ "rollup-plugin-terser": "^7.0.2" }, "dependencies": { - "@duckduckgo/autoconsent": "^10.17.0" + "@duckduckgo/autoconsent": "^11.5.0" } } From f7be389502d8613c7b9dcf752202948cf472cf59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Wed, 20 Nov 2024 15:43:41 +0100 Subject: [PATCH 36/56] Fix invalid OmniBar state transition on loading (#3599) Task/Issue URL: https://app.asana.com/0/1206226850447395/1208790263070149/f Tech Design URL: CC: **Description**: Caused by https://github.com/duckduckgo/iOS/pull/3553. Unnecessary text field clean was performed when `OmniBarState` changed the internal value of `isLoading` without changing the state kind. This caused suggestion tray controller with favorites to appear. **Steps to test this PR**: 1. Turn off automatic data clearing on app exit. 2. Add at least one favorite. 3. Open tab with some url address. 4. Relaunch the app. 5. Verify suggestions tray is not shown and favorites are not visible while the tab is loading. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? **Orientation Testing**: * [ ] Portrait * [ ] Landscape **Device Testing**: * [ ] iPhone SE (1st Gen) * [ ] iPhone 8 * [ ] iPhone X * [ ] iPhone 14 Pro * [ ] iPad --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- DuckDuckGo.xcodeproj/project.pbxproj | 4 + DuckDuckGo/OmniBar.swift | 14 ++- DuckDuckGo/OmniBarState.swift | 16 ++- .../OmniBarEqualityCheckTests.swift | 113 ++++++++++++++++++ 4 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 DuckDuckGoTests/OmniBarEqualityCheckTests.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index d1904a4881..b75cfb8da3 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -315,6 +315,7 @@ 6F64AA5F2C49463C00CF4489 /* ShortcutsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F64AA5E2C49463C00CF4489 /* ShortcutsModel.swift */; }; 6F655BE22BAB289E00AC3597 /* DefaultTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F655BE12BAB289E00AC3597 /* DefaultTheme.swift */; }; 6F691CCA2C4979EC002E9553 /* FavoritesTooltip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F691CC92C4979EC002E9553 /* FavoritesTooltip.swift */; }; + 6F7BACD42CEE084B00F561D8 /* OmniBarEqualityCheckTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7BACD32CEE084100F561D8 /* OmniBarEqualityCheckTests.swift */; }; 6F7FB8E12C660B3E00867DA7 /* NewTabPageFavoritesModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7FB8DF2C660B1A00867DA7 /* NewTabPageFavoritesModelTests.swift */; }; 6F7FB8E32C660BF300867DA7 /* DailyPixelFiring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7FB8E22C660BF300867DA7 /* DailyPixelFiring.swift */; }; 6F7FB8E52C66158D00867DA7 /* NewTabPageShortcutsSettingsModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F7FB8E42C66158D00867DA7 /* NewTabPageShortcutsSettingsModelTests.swift */; }; @@ -1623,6 +1624,7 @@ 6F64AA5E2C49463C00CF4489 /* ShortcutsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsModel.swift; sourceTree = ""; }; 6F655BE12BAB289E00AC3597 /* DefaultTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultTheme.swift; sourceTree = ""; }; 6F691CC92C4979EC002E9553 /* FavoritesTooltip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesTooltip.swift; sourceTree = ""; }; + 6F7BACD32CEE084100F561D8 /* OmniBarEqualityCheckTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBarEqualityCheckTests.swift; sourceTree = ""; }; 6F7FB8DF2C660B1A00867DA7 /* NewTabPageFavoritesModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageFavoritesModelTests.swift; sourceTree = ""; }; 6F7FB8E22C660BF300867DA7 /* DailyPixelFiring.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyPixelFiring.swift; sourceTree = ""; }; 6F7FB8E42C66158D00867DA7 /* NewTabPageShortcutsSettingsModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageShortcutsSettingsModelTests.swift; sourceTree = ""; }; @@ -6348,6 +6350,7 @@ isa = PBXGroup; children = ( 6F3529FE2CDCEDF700A59170 /* OmniBarLoadingStateBearerTests.swift */, + 6F7BACD32CEE084100F561D8 /* OmniBarEqualityCheckTests.swift */, BBFF18B02C76448100C48D7D /* QuerySubmittedTests.swift */, 8588026424E4209900C24AB6 /* LargeOmniBarStateTests.swift */, 85F20005221702F7006BB258 /* AddressDisplayHelperTests.swift */, @@ -8090,6 +8093,7 @@ 85D2187224BF24F2004373D2 /* NotFoundCachingDownloaderTests.swift in Sources */, C1935A242C89CC6D001AD72D /* AutofillHeaderViewFactoryTests.swift in Sources */, C111B26927F579EF006558B1 /* BookmarkOrFolderTests.swift in Sources */, + 6F7BACD42CEE084B00F561D8 /* OmniBarEqualityCheckTests.swift in Sources */, 6F7FB8E72C66197E00867DA7 /* NewTabPageSectionsSettingsModelTests.swift in Sources */, 851CD674244D7E6000331B98 /* UserDefaultsExtension.swift in Sources */, 569437362BE5160600C0881B /* SyncSettingsViewControllerErrorTests.swift in Sources */, diff --git a/DuckDuckGo/OmniBar.swift b/DuckDuckGo/OmniBar.swift index 91a1214bd4..fda9757981 100644 --- a/DuckDuckGo/OmniBar.swift +++ b/DuckDuckGo/OmniBar.swift @@ -360,15 +360,19 @@ class OmniBar: UIView { } fileprivate func refreshState(_ newState: any OmniBarState) { - if !newState.isEquivalent(to: state) { + if state.requiresUpdate(transitioningInto: newState) { Logger.general.debug("OmniBar entering \(newState.description) from \(self.state.description)") - if newState.clearTextOnStart { - clear() + + if state.isDifferentState(than: newState) { + if newState.clearTextOnStart { + clear() + } + cancelAllAnimations() } + state = newState - cancelAllAnimations() } - + searchFieldContainer.adjustTextFieldOffset(for: state) setVisibility(privacyInfoContainer, hidden: !state.showPrivacyIcon) diff --git a/DuckDuckGo/OmniBarState.swift b/DuckDuckGo/OmniBarState.swift index 3e486652c5..6dbba113b3 100644 --- a/DuckDuckGo/OmniBarState.swift +++ b/DuckDuckGo/OmniBarState.swift @@ -29,7 +29,7 @@ protocol OmniBarState: CustomStringConvertible { var showForwardButton: Bool { get } var showBookmarksButton: Bool { get } var showShareButton: Bool { get } - + var clearTextOnStart: Bool { get } var allowsTrackersAnimation: Bool { get } var showSearchLoupe: Bool { get } @@ -61,12 +61,20 @@ protocol OmniBarState: CustomStringConvertible { func withLoading() -> Self func withoutLoading() -> Self - func isEquivalent(to other: OmniBarState) -> Bool + func requiresUpdate(transitioningInto other: OmniBarState) -> Bool + func isDifferentState(than other: OmniBarState) -> Bool } extension OmniBarState { - func isEquivalent(to other: OmniBarState) -> Bool { - name == other.name && isLoading == other.isLoading + /// Returns if new state requires UI update + func requiresUpdate(transitioningInto other: OmniBarState) -> Bool { + name != other.name || isLoading != other.isLoading + } + + /// Checks whether the state type is different. + /// If `true` it may require transitioning to a different appearance and/or cancelling pending animations. + func isDifferentState(than other: OmniBarState) -> Bool { + name != other.name } var description: String { diff --git a/DuckDuckGoTests/OmniBarEqualityCheckTests.swift b/DuckDuckGoTests/OmniBarEqualityCheckTests.swift new file mode 100644 index 0000000000..c10e468259 --- /dev/null +++ b/DuckDuckGoTests/OmniBarEqualityCheckTests.swift @@ -0,0 +1,113 @@ +// +// OmniBarEqualityCheckTests.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import XCTest +@testable import DuckDuckGo + +final class OmniBarEqualityCheckTests: XCTestCase { + func testRequiresUpdateChecksForIsLoading() { + let loadingOmniBarState = DummyOmniBarState(isLoading: true) + let notLoadingOmniBarState = DummyOmniBarState(isLoading: false) + + XCTAssertTrue(loadingOmniBarState.requiresUpdate(transitioningInto: notLoadingOmniBarState)) + } + + func testRequiresUpdateChecksForName() { + let fooOmniBarState = DummyOmniBarState(name: "foo") + let barOmniBarState = DummyOmniBarState(name: "bar") + + XCTAssertTrue(fooOmniBarState.requiresUpdate(transitioningInto: barOmniBarState)) + } + + func testIsDifferentStateChecksForName() { + let fooOmniBarState = DummyOmniBarState(name: "foo") + let barOmniBarState = DummyOmniBarState(name: "bar") + + XCTAssertTrue(fooOmniBarState.isDifferentState(than: barOmniBarState)) + } + + func testIsDifferentStateIgnoresOtherProperties() { + let fooOmniBarState = DummyOmniBarState() + var barOmniBarState = DummyOmniBarState() + + barOmniBarState.hasLargeWidth = !fooOmniBarState.hasLargeWidth + barOmniBarState.showBackButton = !fooOmniBarState.showBackButton + barOmniBarState.showForwardButton = !fooOmniBarState.showForwardButton + barOmniBarState.showBookmarksButton = !fooOmniBarState.showBookmarksButton + barOmniBarState.showShareButton = !fooOmniBarState.showShareButton + barOmniBarState.clearTextOnStart = !fooOmniBarState.clearTextOnStart + barOmniBarState.allowsTrackersAnimation = !fooOmniBarState.allowsTrackersAnimation + barOmniBarState.showSearchLoupe = !fooOmniBarState.showSearchLoupe + barOmniBarState.showCancel = !fooOmniBarState.showCancel + barOmniBarState.showPrivacyIcon = !fooOmniBarState.showPrivacyIcon + barOmniBarState.showBackground = !fooOmniBarState.showBackground + barOmniBarState.showClear = !fooOmniBarState.showClear + barOmniBarState.showRefresh = !fooOmniBarState.showRefresh + barOmniBarState.showMenu = !fooOmniBarState.showMenu + barOmniBarState.showSettings = !fooOmniBarState.showSettings + barOmniBarState.showVoiceSearch = !fooOmniBarState.showVoiceSearch + barOmniBarState.showAbort = !fooOmniBarState.showAbort + + XCTAssertFalse(fooOmniBarState.isDifferentState(than: barOmniBarState)) + } +} + +private struct DummyOmniBarState: OmniBarState, OmniBarLoadingBearerStateCreating { + var name: String + var isLoading: Bool + var voiceSearchHelper: VoiceSearchHelperProtocol + + var hasLargeWidth = false + var showBackButton = false + var showForwardButton = false + var showBookmarksButton = false + var showShareButton = false + var clearTextOnStart = false + var allowsTrackersAnimation = false + var showSearchLoupe = false + var showCancel = false + var showPrivacyIcon = false + var showBackground = false + var showClear = false + var showRefresh = false + var showMenu = false + var showSettings = false + var showVoiceSearch = false + var showAbort = false + + var onEditingStoppedState: OmniBarState { DummyOmniBarState() } + var onEditingStartedState: OmniBarState { DummyOmniBarState() } + var onTextClearedState: OmniBarState { DummyOmniBarState() } + var onTextEnteredState: OmniBarState { DummyOmniBarState() } + var onBrowsingStartedState: OmniBarState { DummyOmniBarState() } + var onBrowsingStoppedState: OmniBarState { DummyOmniBarState() } + var onEnterPhoneState: OmniBarState { DummyOmniBarState() } + var onEnterPadState: OmniBarState { DummyOmniBarState() } + var onReloadState: OmniBarState { DummyOmniBarState() } + + init(voiceSearchHelper: VoiceSearchHelperProtocol, isLoading: Bool) { + self.init(isLoading: isLoading, voiceSearchHelper: voiceSearchHelper) + } + + init(name: String = "DummyOmniBarState", isLoading: Bool = false, voiceSearchHelper: VoiceSearchHelperProtocol = MockVoiceSearchHelper()) { + self.name = name + self.isLoading = isLoading + self.voiceSearchHelper = voiceSearchHelper + } +} From 4876918b383b5be5fa9e82fde769daa7bd85a573 Mon Sep 17 00:00:00 2001 From: amddg44 Date: Wed, 20 Nov 2024 16:04:36 +0100 Subject: [PATCH 37/56] Fix autofill search authentication looping (#3598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1203822806345703/1208755477452311/f Tech Design URL: CC: **Description**: Fixes an issue where if the Passwords screen is dismissed while in search mode, UISearchController prevented the Passwords screen from being released from memory. I’ve also found and fixed a memory leak with the autofill breakage reporter. --- ...ofillLoginSettingsListViewController.swift | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/DuckDuckGo/AutofillLoginSettingsListViewController.swift b/DuckDuckGo/AutofillLoginSettingsListViewController.swift index 11e2934c0a..49884b187b 100644 --- a/DuckDuckGo/AutofillLoginSettingsListViewController.swift +++ b/DuckDuckGo/AutofillLoginSettingsListViewController.swift @@ -228,6 +228,7 @@ final class AutofillLoginSettingsListViewController: UIViewController { super.viewDidLoad() title = UserText.autofillLoginListTitle extendedLayoutIncludesOpaqueBars = true + navigationController?.presentationController?.delegate = self setupCancellables() installSubviews() installConstraints() @@ -449,6 +450,11 @@ final class AutofillLoginSettingsListViewController: UIViewController { } } + private func dismissSearchIfRequired() { + guard searchController.isActive else { return } + searchController.dismiss(animated: false) + } + private func presentDeleteConfirmation(for title: String, domain: String) { let message = title.isEmpty ? UserText.autofillLoginListLoginDeletedToastMessageNoTitle : UserText.autofillLoginListLoginDeletedToastMessage(for: title) @@ -805,11 +811,11 @@ final class AutofillLoginSettingsListViewController: UIViewController { let cell = tableView.dequeueCell(ofType: AutofillBreakageReportTableViewCell.self, for: indexPath) let contentView = AutofillBreakageReportCellContentView(onReport: { [weak self] in - guard let alert = self?.viewModel.createBreakageReporterAlert() else { + guard let self = self, let alert = self.viewModel.createBreakageReporterAlert() else { return } - self?.present(controller: alert, fromView: tableView) + self.present(controller: alert, fromView: self.tableView) Pixel.fire(pixel: .autofillLoginsReportConfirmationPromptDisplayed) }) @@ -1125,6 +1131,16 @@ extension AutofillLoginSettingsListViewController: UISearchBarDelegate { } } +// MARK: UIAdaptivePresentationControllerDelegate + +extension AutofillLoginSettingsListViewController: UIAdaptivePresentationControllerDelegate { + + func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { + dismissSearchIfRequired() + } + +} + // MARK: Keyboard extension AutofillLoginSettingsListViewController { From 8d8b38aeaba623b0b0dbe8f75c51e225f50f2283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Wed, 20 Nov 2024 16:15:45 +0100 Subject: [PATCH 38/56] Release 7.146.0-1 (#3600) Please make sure all GH checks passed before merging. It can take around 20 minutes. Briefly review this PR to see if there are no issues or red flags and then merge it. --- DuckDuckGo.xcodeproj/project.pbxproj | 56 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index b75cfb8da3..c87afcfbce 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9257,7 +9257,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -9294,7 +9294,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9384,7 +9384,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9411,7 +9411,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9558,7 +9558,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9583,7 +9583,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9652,7 +9652,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -9686,7 +9686,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9719,7 +9719,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9749,7 +9749,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10059,7 +10059,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10090,7 +10090,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10118,7 +10118,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10151,7 +10151,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -10181,7 +10181,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -10214,11 +10214,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 0; + DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10450,7 +10450,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10478,7 +10478,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10510,7 +10510,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10547,7 +10547,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10582,7 +10582,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10617,11 +10617,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 0; + DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10794,11 +10794,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 0; + DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10827,10 +10827,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 0; + CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 0; + DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; From f004d3d04becf91e4bacee1e611bebc49bd3e661 Mon Sep 17 00:00:00 2001 From: Lorenzo Mattei Date: Wed, 20 Nov 2024 17:04:08 +0100 Subject: [PATCH 39/56] Run Sync e2e tests only on latest version (#3602) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1204165176092271/1208804974015520/f Tech Design URL: CC: **Description**: We have experienced reliability issues with e2e tests lately due to CI instability. The system seems to be more stable on iOS 17, so this PR temporarily disable runs on older ones to increase reliability until we figure out a solution to the CI issues. **Steps to test this PR**: 1. Make sure CI is green - This is the run of sync tests from this branch: https://github.com/duckduckgo/iOS/actions/runs/11936363646 --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- .github/workflows/sync-end-to-end.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-end-to-end.yml b/.github/workflows/sync-end-to-end.yml index b2ea9a8661..c70dc3ef37 100644 --- a/.github/workflows/sync-end-to-end.yml +++ b/.github/workflows/sync-end-to-end.yml @@ -72,7 +72,7 @@ jobs: timeout-minutes: 90 strategy: matrix: - os-version: [15, 16, 17] + os-version: [17] #[15, 16, 17] max-parallel: 1 # Uncomment this line to run tests sequentially. fail-fast: false From e036dcd8d456e3e98e448617f8553b536f738ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Wed, 20 Nov 2024 18:29:02 +0100 Subject: [PATCH 40/56] Fix running BoolFileMarkerTest on device (#3601) Task/Issue URL: https://app.asana.com/0/414709148257752/1208808387106647/f Tech Design URL: CC: **Description**: `BoolFileMarkerTests` test failed when run on device. This PR fixes it. **Steps to test this PR**: 1. Check `BoolFileMarkerTests` pass when run on a device. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- Core/BoolFileMarkerTests.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Core/BoolFileMarkerTests.swift b/Core/BoolFileMarkerTests.swift index 23893a5668..5ad4aa0910 100644 --- a/Core/BoolFileMarkerTests.swift +++ b/Core/BoolFileMarkerTests.swift @@ -41,7 +41,11 @@ final class BoolFileMarkerTests: XCTestCase { let fileURL = try XCTUnwrap(testFileURL) let attributes = try FileManager.default.attributesOfItem(atPath: fileURL.path) +#if targetEnvironment(simulator) XCTAssertNil(attributes[.protectionKey]) +#else + XCTAssertEqual(attributes[.protectionKey] as? FileProtectionType, FileProtectionType.none) +#endif XCTAssertTrue(FileManager.default.fileExists(atPath: fileURL.path)) XCTAssertEqual(marker.isPresent, true) } From 20c6e114b381107c779aa37c83a17321154b9540 Mon Sep 17 00:00:00 2001 From: Jonathan Jackson Date: Wed, 20 Nov 2024 13:17:28 -0500 Subject: [PATCH 41/56] Re-prompt for crash reporting (#3595) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1208592102886666/1208630312625695/f Tech Design URL: https://app.asana.com/0/1208592102886666/1208660326715650/f **Description**: - Introduce a feature flag for use with this project overall, currently set to internal only - Introduce a new UserDefaults value (```crashCollectionShouldRevertOptedInStatusTrigger```) that can be used to force the client to revert the existing ```crashCollectionOptInStatus``` to .unknown, only if the value is currently .optedIn. This new trigger is implemented as an Int, so that we can ensure the user’s Opt-In state will be reverted only once after the feature is turned on. In the future if we need this functionality again, we’d simply bump the garget value and the opt-in state would be reset again. See asana task for specific requirements, and the parent project for more context if necessary. --- Core/FeatureFlag.swift | 5 +++++ DuckDuckGo/AppSettings.swift | 1 + DuckDuckGo/AppUserDefaults.swift | 14 ++++++++++++++ DuckDuckGo/CrashCollectionOnboarding.swift | 20 +++++++++++++++++++- DuckDuckGoTests/AppSettingsMock.swift | 2 ++ 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Core/FeatureFlag.swift b/Core/FeatureFlag.swift index 81e9b34dd4..da04bcfaf6 100644 --- a/Core/FeatureFlag.swift +++ b/Core/FeatureFlag.swift @@ -53,6 +53,9 @@ public enum FeatureFlag: String { /// https://app.asana.com/0/72649045549333/1208617860225199/f case networkProtectionEnforceRoutes + + /// https://app.asana.com/0/1208592102886666/1208613627589762/f + case crashReportOptInStatusResetting } extension FeatureFlag: FeatureFlagDescribing { @@ -118,6 +121,8 @@ extension FeatureFlag: FeatureFlagDescribing { return .remoteDevelopment(.subfeature(NetworkProtectionSubfeature.enforceRoutes)) case .adAttributionReporting: return .remoteReleasable(.feature(.adAttributionReporting)) + case .crashReportOptInStatusResetting: + return .internalOnly } } } diff --git a/DuckDuckGo/AppSettings.swift b/DuckDuckGo/AppSettings.swift index 4c7c9d8991..f7242d9a88 100644 --- a/DuckDuckGo/AppSettings.swift +++ b/DuckDuckGo/AppSettings.swift @@ -79,6 +79,7 @@ protocol AppSettings: AnyObject, AppDebugSettings { var autoconsentEnabled: Bool { get set } var crashCollectionOptInStatus: CrashCollectionOptInStatus { get set } + var crashCollectionShouldRevertOptedInStatusTrigger: Int { get set } var duckPlayerMode: DuckPlayerMode { get set } var duckPlayerAskModeOverlayHidden: Bool { get set } diff --git a/DuckDuckGo/AppUserDefaults.swift b/DuckDuckGo/AppUserDefaults.swift index 559a521900..2c17e2ac1e 100644 --- a/DuckDuckGo/AppUserDefaults.swift +++ b/DuckDuckGo/AppUserDefaults.swift @@ -75,6 +75,7 @@ public class AppUserDefaults: AppSettings { static let favoritesDisplayMode = "com.duckduckgo.ios.favoritesDisplayMode" static let crashCollectionOptInStatus = "com.duckduckgo.ios.crashCollectionOptInStatus" + static let crashCollectionShouldRevertOptedInStatusTrigger = "com.duckduckgo.ios.crashCollectionShouldRevertOptedInStatusTrigger" static let duckPlayerMode = "com.duckduckgo.ios.duckPlayerMode" static let duckPlayerAskModeOverlayHidden = "com.duckduckgo.ios.duckPlayerAskModeOverlayHidden" @@ -399,6 +400,19 @@ public class AppUserDefaults: AppSettings { } } + var crashCollectionShouldRevertOptedInStatusTrigger: Int { + get { + if let resetTrigger = userDefaults?.integer(forKey: Keys.crashCollectionShouldRevertOptedInStatusTrigger) { + return resetTrigger + } else { + return 0 + } + } + set { + userDefaults?.setValue(newValue, forKey: Keys.crashCollectionShouldRevertOptedInStatusTrigger) + } + } + var duckPlayerMode: DuckPlayerMode { get { if let value = userDefaults?.string(forKey: Keys.duckPlayerMode), diff --git a/DuckDuckGo/CrashCollectionOnboarding.swift b/DuckDuckGo/CrashCollectionOnboarding.swift index 98a364220b..dd9e54af7c 100644 --- a/DuckDuckGo/CrashCollectionOnboarding.swift +++ b/DuckDuckGo/CrashCollectionOnboarding.swift @@ -20,6 +20,7 @@ import Combine import Foundation import SwiftUI +import BrowserServicesKit enum CrashCollectionOptInStatus: String { case undetermined, optedIn, optedOut @@ -35,16 +36,33 @@ final class CrashCollectionOnboardingViewController: UIHostingController Void) { let isCurrentlyPresenting = viewController.presentedViewController != nil + + if featureFlagger.isFeatureOn(.crashReportOptInStatusResetting) { + if appSettings.crashCollectionOptInStatus == .optedIn && + appSettings.crashCollectionShouldRevertOptedInStatusTrigger < crashCollectionShouldRevertOptedInStatusTriggerTargetValue { + appSettings.crashCollectionOptInStatus = .undetermined + appSettings.crashCollectionShouldRevertOptedInStatusTrigger = crashCollectionShouldRevertOptedInStatusTriggerTargetValue + } + } + guard shouldPresentOnboarding, !isCurrentlyPresenting else { if appSettings.crashCollectionOptInStatus == .optedIn { sendReport() diff --git a/DuckDuckGoTests/AppSettingsMock.swift b/DuckDuckGoTests/AppSettingsMock.swift index 4d9b09321e..13ced3eb65 100644 --- a/DuckDuckGoTests/AppSettingsMock.swift +++ b/DuckDuckGoTests/AppSettingsMock.swift @@ -82,6 +82,8 @@ class AppSettingsMock: AppSettings { var autoconsentEnabled = true var crashCollectionOptInStatus: CrashCollectionOptInStatus = .undetermined + + var crashCollectionShouldRevertOptedInStatusTrigger: Int = 0 var newTabPageSectionsEnabled: Bool = false From 499d81e67ccbaad245bbc22f3701e9d86fa7ee63 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Thu, 21 Nov 2024 12:52:42 +0100 Subject: [PATCH 42/56] Update Content Scope Scripts to 6.38.0 (#3605) Task/Issue URL: https://app.asana.com/0/72649045549333/1208814396151376/f Description: This release adds new APIs for HTML New Tab Page. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index c87afcfbce..59d4404378 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -11040,7 +11040,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 211.0.0; + version = 211.1.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index cdb32f0f44..bb0f553a9f 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "7033b0d6f166ac8152cff602f1a1301641f4da60", - "version" : "211.0.0" + "revision" : "ce0223a5cc5e404867be5e691f5df1de9ea24387", + "version" : "211.1.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "f2caf4ff814f4714d07d6fc2cf02498cb54a1389", - "version" : "6.36.0" + "revision" : "6f8b28d98bee6e15c4020d46577143d49619c248", + "version" : "6.38.0" } }, { From f5f0a13fbe3a396ffb27eb470de025f7a80f7638 Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Thu, 21 Nov 2024 12:18:37 +0000 Subject: [PATCH 43/56] remove widget favicon coupling and move favicon code from core to the app (#3590) Task/Issue URL: https://app.asana.com/0/414709148257752/1208785980508806/f Tech Design URL: CC: **Description**: Moves the favicon code the app bundle to make future refactoring easier. Includes refactoring from #3593 **Steps to test this PR**: 1. Run an old version of the app and add some favorites 3. Add the favorites widget and validate favicons appear 2. Upgrade to this version of the app 4. Open some tabs and ensure that the favicons appear in the tab switcher. 5. Check the cache location for the images. Look for `favicons tabs location` in Xcode console and go to the parent of that directory. 6. Also check the `favicons fireproof location` 7. Use the fire button. 8. Ensure that images are removed from the tabs location but not from the fireproof location 9. Repeat with a clean install --- Core/CookieStorage.swift | 4 +- Core/FaviconHasher.swift | 31 ++++ Core/FaviconRequestModifier.swift | 1 + Core/FaviconsCacheType.swift | 43 +++++ Core/FaviconsHelper.swift | 34 ---- ...reserveLogins.swift => Fireproofing.swift} | 26 ++- Core/NotFoundCachingDownloader.swift | 1 + Core/SyncBookmarksAdapter.swift | 8 +- Core/SyncDataProviders.swift | 6 +- Core/UserDefaultsPropertyWrapper.swift | 6 +- Core/WebCacheManager.swift | 4 +- DuckDuckGo.xcodeproj/project.pbxproj | 100 +++++----- DuckDuckGo/AppDelegate.swift | 3 +- DuckDuckGo/Base.lproj/Settings.storyboard | 14 +- DuckDuckGo/ContentBlockingUpdating.swift | 2 +- DuckDuckGo/CookieDebugViewController.swift | 12 +- DuckDuckGo/FaviconViewModel.swift | 4 +- DuckDuckGo/Favicons.swift | 173 ++++++++---------- DuckDuckGo/FaviconsHelper.swift | 15 +- DuckDuckGo/FireproofFaviconUpdater.swift | 4 +- ...insAlert.swift => FireproofingAlert.swift} | 32 ++-- ... FireproofingSettingsViewController.swift} | 47 +++-- ...Worker.swift => FireproofingWorking.swift} | 17 +- .../ImageCacheDebugViewController.swift | 13 +- DuckDuckGo/MainViewController.swift | 8 +- DuckDuckGo/RootDebugViewController.swift | 6 +- DuckDuckGo/ScriptSourceProviding.swift | 11 +- DuckDuckGo/SettingsLegacyViewProvider.swift | 46 +++-- .../PrivacyProDataReporting.swift | 5 +- DuckDuckGo/TabManager.swift | 4 +- DuckDuckGo/TabViewController.swift | 31 ++-- ...bViewControllerBrowsingMenuExtension.swift | 2 +- DuckDuckGo/UIImageViewExtension.swift | 2 +- DuckDuckGo/UserText.swift | 20 +- .../ContentBlockingUpdatingTests.swift | 4 +- DuckDuckGoTests/CookieStorageTests.swift | 48 ++--- .../FaviconRequestModifierTests.swift | 1 + .../FaviconSourcesProviderTests.swift | 2 + DuckDuckGoTests/FaviconsTests.swift | 3 +- .../FireButtonReferenceTests.swift | 16 +- .../FireproofFaviconUpdaterTests.swift | 4 +- DuckDuckGoTests/MockFaviconStore.swift | 30 +++ .../NotFoundCachingDownloaderTests.swift | 9 +- .../OnboardingDaxFavouritesTests.swift | 3 +- .../OnboardingNavigationDelegateTests.swift | 3 +- .../SyncBookmarksAdapterTests.swift | 3 +- ...SyncSettingsViewControllerErrorTests.swift | 3 +- ...ft => UserDefaultsFireproofingTests.swift} | 16 +- DuckDuckGoTests/WebCacheManagerTests.swift | 42 ++--- Widgets/Widgets.swift | 4 +- 50 files changed, 538 insertions(+), 388 deletions(-) create mode 100644 Core/FaviconHasher.swift create mode 100644 Core/FaviconsCacheType.swift delete mode 100644 Core/FaviconsHelper.swift rename Core/{PreserveLogins.swift => Fireproofing.swift} (70%) rename DuckDuckGo/{PreserveLoginsAlert.swift => FireproofingAlert.swift} (68%) rename DuckDuckGo/{PreserveLoginsSettingsViewController.swift => FireproofingSettingsViewController.swift} (86%) rename DuckDuckGo/{PreserveLoginsWorker.swift => FireproofingWorking.swift} (84%) create mode 100644 DuckDuckGoTests/MockFaviconStore.swift rename DuckDuckGoTests/{PreserveLoginsTests.swift => UserDefaultsFireproofingTests.swift} (67%) diff --git a/Core/CookieStorage.swift b/Core/CookieStorage.swift index aca9ce7975..978d69197a 100644 --- a/Core/CookieStorage.swift +++ b/Core/CookieStorage.swift @@ -95,7 +95,7 @@ public class CookieStorage { /// Update ALL cookies. The absence of cookie domains here indicateds they have been removed by the website, so be sure to call this with all cookies that might need to be persisted even if those websites have not been visited yet. @discardableResult - func updateCookies(_ cookies: [HTTPCookie], keepingPreservedLogins preservedLogins: PreserveLogins) -> CookieDomainsOnUpdateDiagnostic { + func updateCookies(_ cookies: [HTTPCookie], preservingFireproofedDomains fireproofing: Fireproofing) -> CookieDomainsOnUpdateDiagnostic { guard isConsumed else { return .notConsumed } isConsumed = false @@ -130,7 +130,7 @@ public class CookieStorage { persistedCookiesByDomain.keys.forEach { guard !URL.isDuckDuckGo(domain: $0) else { return } // DDG cookies are for SERP settings only - if !preservedLogins.isAllowed(cookieDomain: $0) { + if !fireproofing.isAllowed(cookieDomain: $0) { persistedCookiesByDomain.removeValue(forKey: $0) } } diff --git a/Core/FaviconHasher.swift b/Core/FaviconHasher.swift new file mode 100644 index 0000000000..1a71f594d5 --- /dev/null +++ b/Core/FaviconHasher.swift @@ -0,0 +1,31 @@ +// +// FaviconHasher.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + + +import Foundation +import Kingfisher + +public struct FaviconHasher { + + static let salt = "DDGSalt:" + public static func createHash(ofDomain domain: String) -> String { + return "\(Self.salt)\(domain)".sha256() + } + +} diff --git a/Core/FaviconRequestModifier.swift b/Core/FaviconRequestModifier.swift index bc9ab68205..899ad75c19 100644 --- a/Core/FaviconRequestModifier.swift +++ b/Core/FaviconRequestModifier.swift @@ -17,6 +17,7 @@ // limitations under the License. // +import Core import Kingfisher class FaviconRequestModifier: ImageDownloadRequestModifier { diff --git a/Core/FaviconsCacheType.swift b/Core/FaviconsCacheType.swift new file mode 100644 index 0000000000..38dfbee948 --- /dev/null +++ b/Core/FaviconsCacheType.swift @@ -0,0 +1,43 @@ +// +// FaviconsCacheType.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation + +public enum FaviconsCacheType: String { + + static let faviconsFolderName = "Favicons" + + case tabs + case fireproof + + public func cacheLocation() -> URL? { + return baseCacheURL()?.appendingPathComponent(Self.faviconsFolderName) + } + + private func baseCacheURL() -> URL? { + switch self { + case .fireproof: + let groupName = BookmarksDatabase.Constants.bookmarksGroupID + return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupName) + + case .tabs: + return FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first + } + } +} diff --git a/Core/FaviconsHelper.swift b/Core/FaviconsHelper.swift deleted file mode 100644 index 478da57e54..0000000000 --- a/Core/FaviconsHelper.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// FaviconsHelper.swift -// DuckDuckGo -// -// Copyright © 2022 DuckDuckGo. All rights reserved. -// -// 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. -// - -import Foundation -import Kingfisher - -struct FaviconsHelper { - - // this function is now static and outside of Favicons, otherwise there is a circular dependency between - // Favicons and NotFoundCachingDownloader - public static func defaultResource(forDomain domain: String?, sourcesProvider: FaviconSourcesProvider) -> KF.ImageResource? { - guard let domain = domain, - let source = sourcesProvider.mainSource(forDomain: domain) else { return nil } - - let key = Favicons.createHash(ofDomain: domain) - return KF.ImageResource(downloadURL: source, cacheKey: key) - } -} diff --git a/Core/PreserveLogins.swift b/Core/Fireproofing.swift similarity index 70% rename from Core/PreserveLogins.swift rename to Core/Fireproofing.swift index 6ce320e0ef..166c04c562 100644 --- a/Core/PreserveLogins.swift +++ b/Core/Fireproofing.swift @@ -1,5 +1,5 @@ // -// PreserveLogins.swift +// Fireproofing.swift // Core // // Copyright © 2020 DuckDuckGo. All rights reserved. @@ -19,18 +19,32 @@ import Foundation -public class PreserveLogins { +public protocol Fireproofing { + + var loginDetectionEnabled: Bool { get set } + var allowedDomains: [String] { get } + + func isAllowed(cookieDomain: String) -> Bool + func isAllowed(fireproofDomain domain: String) -> Bool + func addToAllowed(domain: String) + func remove(domain: String) + func clearAll() + +} + +// This class is not final because we override allowed domains in WebCacheManagerTests +public class UserDefaultsFireproofing: Fireproofing { + + public static let shared: Fireproofing = UserDefaultsFireproofing() public struct Notifications { public static let loginDetectionStateChanged = Foundation.Notification.Name("com.duckduckgo.ios.PreserveLogins.loginDetectionStateChanged") } - public static let shared = PreserveLogins() - - @UserDefaultsWrapper(key: .preserveLoginsAllowedDomains, defaultValue: []) + @UserDefaultsWrapper(key: .fireproofingAllowedDomains, defaultValue: []) private(set) public var allowedDomains: [String] - @UserDefaultsWrapper(key: .preserveLoginsDetectionEnabled, defaultValue: false) + @UserDefaultsWrapper(key: .fireproofingDetectionEnabled, defaultValue: false) public var loginDetectionEnabled: Bool { didSet { NotificationCenter.default.post(name: Notifications.loginDetectionStateChanged, object: nil) diff --git a/Core/NotFoundCachingDownloader.swift b/Core/NotFoundCachingDownloader.swift index c9ba6daa67..16a957c625 100644 --- a/Core/NotFoundCachingDownloader.swift +++ b/Core/NotFoundCachingDownloader.swift @@ -17,6 +17,7 @@ // limitations under the License. // +import Core import Kingfisher class NotFoundCachingDownloader: ImageDownloader { diff --git a/Core/SyncBookmarksAdapter.swift b/Core/SyncBookmarksAdapter.swift index a50d7315c8..0eb8525d82 100644 --- a/Core/SyncBookmarksAdapter.swift +++ b/Core/SyncBookmarksAdapter.swift @@ -66,6 +66,7 @@ public final class SyncBookmarksAdapter { public let databaseCleaner: BookmarkDatabaseCleaner public let syncDidCompletePublisher: AnyPublisher let syncErrorHandler: SyncErrorHandling + private let faviconStoring: FaviconStoring @UserDefaultsWrapper(key: .syncDidMigrateToImprovedListsHandling, defaultValue: false) private var didMigrateToImprovedListsHandling: Bool @@ -88,10 +89,13 @@ public final class SyncBookmarksAdapter { public init(database: CoreDataDatabase, favoritesDisplayModeStorage: FavoritesDisplayModeStoring, - syncErrorHandler: SyncErrorHandling) { + syncErrorHandler: SyncErrorHandling, + faviconStoring: FaviconStoring) { self.database = database self.favoritesDisplayModeStorage = favoritesDisplayModeStorage self.syncErrorHandler = syncErrorHandler + self.faviconStoring = faviconStoring + syncDidCompletePublisher = syncDidCompleteSubject.eraseToAnyPublisher() databaseCleaner = BookmarkDatabaseCleaner( bookmarkDatabase: database, @@ -172,7 +176,7 @@ public final class SyncBookmarksAdapter { database: database, stateStore: stateStore, fetcher: FaviconFetcher(), - faviconStore: Favicons.shared, + faviconStore: faviconStoring, errorEvents: BookmarksFaviconsFetcherErrorHandler() ) } diff --git a/Core/SyncDataProviders.swift b/Core/SyncDataProviders.swift index fd7c595947..a32f3b8508 100644 --- a/Core/SyncDataProviders.swift +++ b/Core/SyncDataProviders.swift @@ -100,14 +100,16 @@ public class SyncDataProviders: DataProvidersSource { secureVaultErrorReporter: SecureVaultReporting, settingHandlers: [SettingSyncHandler], favoritesDisplayModeStorage: FavoritesDisplayModeStoring, - syncErrorHandler: SyncErrorHandling + syncErrorHandler: SyncErrorHandling, + faviconStoring: FaviconStoring ) { self.bookmarksDatabase = bookmarksDatabase self.secureVaultFactory = secureVaultFactory self.secureVaultErrorReporter = secureVaultErrorReporter bookmarksAdapter = SyncBookmarksAdapter(database: bookmarksDatabase, favoritesDisplayModeStorage: favoritesDisplayModeStorage, - syncErrorHandler: syncErrorHandler) + syncErrorHandler: syncErrorHandler, + faviconStoring: faviconStoring) credentialsAdapter = SyncCredentialsAdapter(secureVaultFactory: secureVaultFactory, secureVaultErrorReporter: secureVaultErrorReporter, syncErrorHandler: syncErrorHandler) diff --git a/Core/UserDefaultsPropertyWrapper.swift b/Core/UserDefaultsPropertyWrapper.swift index ac6a5a6bdf..4858ad964d 100644 --- a/Core/UserDefaultsPropertyWrapper.swift +++ b/Core/UserDefaultsPropertyWrapper.swift @@ -37,9 +37,9 @@ public struct UserDefaultsWrapper { case gridViewEnabled = "com.duckduckgo.ios.tabs.grid" case gridViewSeen = "com.duckduckgo.ios.tabs.seen" - case preserveLoginsAllowedDomains = "com.duckduckgo.ios.PreserveLogins.userDecision.allowedDomains2" - case preserveLoginsDetectionEnabled = "com.duckduckgo.ios.PreserveLogins.detectionEnabled" - case preserveLoginsLegacyAllowedDomains = "com.duckduckgo.ios.PreserveLogins.userDecision.allowedDomains" + case fireproofingAllowedDomains = "com.duckduckgo.ios.PreserveLogins.userDecision.allowedDomains2" + case fireproofingDetectionEnabled = "com.duckduckgo.ios.PreserveLogins.detectionEnabled" + case fireproofingLegacyAllowedDomains = "com.duckduckgo.ios.PreserveLogins.userDecision.allowedDomains" case daxIsDismissed = "com.duckduckgo.ios.daxOnboardingIsDismissed" case daxHomeScreenMessagesSeen = "com.duckduckgo.ios.daxOnboardingHomeScreenMessagesSeen" diff --git a/Core/WebCacheManager.swift b/Core/WebCacheManager.swift index b6655f82b6..13ce952ba8 100644 --- a/Core/WebCacheManager.swift +++ b/Core/WebCacheManager.swift @@ -78,7 +78,7 @@ public class WebCacheManager { } public func clear(cookieStorage: CookieStorage = CookieStorage(), - logins: PreserveLogins = PreserveLogins.shared, + fireproofing: Fireproofing = UserDefaultsFireproofing.shared, dataStoreIdManager: DataStoreIdManaging = DataStoreIdManager.shared) async { var cookiesToUpdate = [HTTPCookie]() @@ -92,7 +92,7 @@ public class WebCacheManager { // Perform legacy clearing to migrate to new container cookiesToUpdate += await legacyDataClearing() ?? [] - cookieStorage.updateCookies(cookiesToUpdate, keepingPreservedLogins: logins) + cookieStorage.updateCookies(cookiesToUpdate, preservingFireproofedDomains: fireproofing) // Attempt to clean up leftover stores again after a delay // This should not be a problem as these containers are not supposed to be used anymore. diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 59d4404378..654bc03135 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -405,7 +405,7 @@ 85047B8A1F69692C002A95D8 /* contentblocker.js in Resources */ = {isa = PBXBuildFile; fileRef = 85047B891F69692C002A95D8 /* contentblocker.js */; }; 85047C772A0D5D3D00D2FF3F /* SyncSettingsViewController+SyncDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85047C762A0D5D3D00D2FF3F /* SyncSettingsViewController+SyncDelegate.swift */; }; 850559C923C61B5D0055C0D5 /* login-form-detection.js in Resources */ = {isa = PBXBuildFile; fileRef = 850559C823C61B5D0055C0D5 /* login-form-detection.js */; }; - 850559D023CF647C0055C0D5 /* PreserveLogins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850559CF23CF647C0055C0D5 /* PreserveLogins.swift */; }; + 850559D023CF647C0055C0D5 /* Fireproofing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850559CF23CF647C0055C0D5 /* Fireproofing.swift */; }; 850559D223CF710C0055C0D5 /* WebCacheManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850559D123CF710C0055C0D5 /* WebCacheManagerTests.swift */; }; 85058366219AE9EA00ED4EDB /* HomePageConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85058365219AE9EA00ED4EDB /* HomePageConfiguration.swift */; }; 85058369219F424500ED4EDB /* UIColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B745211E549D550072547E /* UIColorExtension.swift */; }; @@ -469,10 +469,10 @@ 853A717620F62FE800FE60BC /* Pixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 853A717520F62FE800FE60BC /* Pixel.swift */; }; 853A717820F645FB00FE60BC /* PixelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 853A717720F645FB00FE60BC /* PixelTests.swift */; }; 853C5F6121C277C7001F7A05 /* global.swift in Sources */ = {isa = PBXBuildFile; fileRef = 853C5F6021C277C7001F7A05 /* global.swift */; }; - 8540BBA22440857A00017FE4 /* PreserveLoginsWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8540BBA12440857A00017FE4 /* PreserveLoginsWorker.swift */; }; - 8540BD5223D8C2220057FDD2 /* PreserveLoginsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8540BD5123D8C2220057FDD2 /* PreserveLoginsTests.swift */; }; - 8540BD5423D8D5080057FDD2 /* PreserveLoginsAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8540BD5323D8D5080057FDD2 /* PreserveLoginsAlert.swift */; }; - 8540BD5623D9E9C20057FDD2 /* PreserveLoginsSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8540BD5523D9E9C20057FDD2 /* PreserveLoginsSettingsViewController.swift */; }; + 8540BBA22440857A00017FE4 /* FireproofingWorking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8540BBA12440857A00017FE4 /* FireproofingWorking.swift */; }; + 8540BD5223D8C2220057FDD2 /* UserDefaultsFireproofingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8540BD5123D8C2220057FDD2 /* UserDefaultsFireproofingTests.swift */; }; + 8540BD5423D8D5080057FDD2 /* FireproofingAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8540BD5323D8D5080057FDD2 /* FireproofingAlert.swift */; }; + 8540BD5623D9E9C20057FDD2 /* FireproofingSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8540BD5523D9E9C20057FDD2 /* FireproofingSettingsViewController.swift */; }; 85449EF523FDA02800512AAF /* KeyboardSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85449EF423FDA02800512AAF /* KeyboardSettingsViewController.swift */; }; 85449EFB23FDA0BC00512AAF /* UserDefaultsPropertyWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85449EFA23FDA0BC00512AAF /* UserDefaultsPropertyWrapper.swift */; }; 85449EFD23FDA71F00512AAF /* KeyboardSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85449EFC23FDA71F00512AAF /* KeyboardSettings.swift */; }; @@ -522,6 +522,14 @@ 8590CB67268A2E520089F6BF /* RootDebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590CB66268A2E520089F6BF /* RootDebugViewController.swift */; }; 8590CB69268A4E190089F6BF /* DebugEtagStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8590CB68268A4E190089F6BF /* DebugEtagStorage.swift */; }; 8596C30D2B7EB1800058EF90 /* DataStoreWarmup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8596C30C2B7EB1800058EF90 /* DataStoreWarmup.swift */; }; + 8598D2DC2CEB93AD00C45685 /* FaviconsCacheType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8598D2DB2CEB93A600C45685 /* FaviconsCacheType.swift */; }; + 8598D2DE2CEB97BE00C45685 /* FaviconHasher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8598D2DD2CEB97BE00C45685 /* FaviconHasher.swift */; }; + 8598D2E02CEB98B500C45685 /* Favicons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CA53A324B9F2BD00A6288C /* Favicons.swift */; }; + 8598D2E12CEB98B500C45685 /* NotFoundCachingDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CA53A924BB376800A6288C /* NotFoundCachingDownloader.swift */; }; + 8598D2E22CEB98B500C45685 /* FaviconRequestModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CA53AB24BBD39300A6288C /* FaviconRequestModifier.swift */; }; + 8598D2E32CEB98B500C45685 /* FaviconUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */; }; + 8598D2E42CEB98B500C45685 /* FaviconSourcesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187524BF6164004373D2 /* FaviconSourcesProvider.swift */; }; + 8598D2E62CEBAA1F00C45685 /* MockFaviconStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8598D2E52CEBAA1B00C45685 /* MockFaviconStore.swift */; }; 8598F67B2405EB8D00FBC70C /* KeyboardSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8598F6792405EB8600FBC70C /* KeyboardSettingsTests.swift */; }; 8599690F29D2F1C100DBF9FA /* DDGSync in Frameworks */ = {isa = PBXBuildFile; productRef = 8599690E29D2F1C100DBF9FA /* DDGSync */; }; 859DB8132CE6263C001F7210 /* TextZoomStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859DB80D2CE6263B001F7210 /* TextZoomStorage.swift */; }; @@ -557,15 +565,10 @@ 85C2971A248162CA0063A335 /* DaxOnboardingPadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C29719248162CA0063A335 /* DaxOnboardingPadViewController.swift */; }; 85C8E61D2B0E47380029A6BD /* BookmarksDatabaseSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C8E61C2B0E47380029A6BD /* BookmarksDatabaseSetup.swift */; }; 85C91CA224671F4C00A11132 /* AppDeepLinkSchemes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F17D723B1E8BB374003E8B0E /* AppDeepLinkSchemes.swift */; }; - 85CA53A824BB343700A6288C /* Favicons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CA53A324B9F2BD00A6288C /* Favicons.swift */; }; - 85CA53AA24BB376800A6288C /* NotFoundCachingDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CA53A924BB376800A6288C /* NotFoundCachingDownloader.swift */; }; - 85CA53AC24BBD39300A6288C /* FaviconRequestModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CA53AB24BBD39300A6288C /* FaviconRequestModifier.swift */; }; 85D2187024BF24DB004373D2 /* FaviconRequestModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2186F24BF24DB004373D2 /* FaviconRequestModifierTests.swift */; }; 85D2187224BF24F2004373D2 /* NotFoundCachingDownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187124BF24F2004373D2 /* NotFoundCachingDownloaderTests.swift */; }; 85D2187424BF25CD004373D2 /* FaviconsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187324BF25CD004373D2 /* FaviconsTests.swift */; }; - 85D2187624BF6164004373D2 /* FaviconSourcesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187524BF6164004373D2 /* FaviconSourcesProvider.swift */; }; 85D2187924BF6B8B004373D2 /* FaviconSourcesProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187724BF6B88004373D2 /* FaviconSourcesProviderTests.swift */; }; - 85D2187B24BF9F85004373D2 /* FaviconUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */; }; 85D598872927F84C00FA3B1B /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 85D598862927F84C00FA3B1B /* Crashes */; }; 85DB12EB2A1FE2A4000A4A72 /* LockScreenWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DB12EA2A1FE2A4000A4A72 /* LockScreenWidgets.swift */; }; 85DB12ED2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85DB12EC2A1FED0C000A4A72 /* AppDelegate+AppDeepLinks.swift */; }; @@ -926,7 +929,6 @@ C1BF0BA529B63D7200482B73 /* AutofillLoginPromptHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */; }; C1BF0BA929B63E2200482B73 /* AutofillLoginPromptViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */; }; C1BF26152C74D10F00F6405E /* SyncPromoManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF26142C74D10F00F6405E /* SyncPromoManager.swift */; }; - C1CCCBA7283E101500CF3791 /* FaviconsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CCCBA6283E101500CF3791 /* FaviconsHelper.swift */; }; C1CDA3162AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */; }; C1CDA31E2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CDA31D2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift */; }; C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */; }; @@ -1409,7 +1411,6 @@ 1E7A711B2934EEBC00B7EA19 /* OmniBarNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmniBarNotification.swift; sourceTree = ""; }; 1E8146A728C8AB3F00D1AF63 /* TrackerAnimationLogicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackerAnimationLogicTests.swift; sourceTree = ""; }; 1E8146A928C8AB8200D1AF63 /* PrivacyIconLogicTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyIconLogicTests.swift; sourceTree = ""; }; - 1E865AEF272042DB001C74F3 /* TextSizeSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextSizeSettingsViewController.swift; sourceTree = ""; }; 1E87615828A1517200C7C5CE /* PrivacyDashboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardViewController.swift; sourceTree = ""; }; 1E8AD1C627BE9B2900ABA377 /* DownloadsListDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsListDataSource.swift; sourceTree = ""; }; 1E8AD1C827BFAD1500ABA377 /* DirectoryMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectoryMonitor.swift; sourceTree = ""; }; @@ -1730,7 +1731,7 @@ 85047B891F69692C002A95D8 /* contentblocker.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = contentblocker.js; sourceTree = ""; }; 85047C762A0D5D3D00D2FF3F /* SyncSettingsViewController+SyncDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SyncSettingsViewController+SyncDelegate.swift"; sourceTree = ""; }; 850559C823C61B5D0055C0D5 /* login-form-detection.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "login-form-detection.js"; sourceTree = ""; }; - 850559CF23CF647C0055C0D5 /* PreserveLogins.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreserveLogins.swift; sourceTree = ""; }; + 850559CF23CF647C0055C0D5 /* Fireproofing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fireproofing.swift; sourceTree = ""; }; 850559D123CF710C0055C0D5 /* WebCacheManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebCacheManagerTests.swift; sourceTree = ""; }; 85058365219AE9EA00ED4EDB /* HomePageConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomePageConfiguration.swift; sourceTree = ""; }; 850ABD002AC3961100A733DF /* MainViewController+Segues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainViewController+Segues.swift"; sourceTree = ""; }; @@ -1784,10 +1785,10 @@ 853A717520F62FE800FE60BC /* Pixel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pixel.swift; sourceTree = ""; }; 853A717720F645FB00FE60BC /* PixelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelTests.swift; sourceTree = ""; }; 853C5F6021C277C7001F7A05 /* global.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = global.swift; sourceTree = ""; }; - 8540BBA12440857A00017FE4 /* PreserveLoginsWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreserveLoginsWorker.swift; sourceTree = ""; }; - 8540BD5123D8C2220057FDD2 /* PreserveLoginsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreserveLoginsTests.swift; sourceTree = ""; }; - 8540BD5323D8D5080057FDD2 /* PreserveLoginsAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreserveLoginsAlert.swift; sourceTree = ""; }; - 8540BD5523D9E9C20057FDD2 /* PreserveLoginsSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreserveLoginsSettingsViewController.swift; sourceTree = ""; }; + 8540BBA12440857A00017FE4 /* FireproofingWorking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FireproofingWorking.swift; sourceTree = ""; }; + 8540BD5123D8C2220057FDD2 /* UserDefaultsFireproofingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsFireproofingTests.swift; sourceTree = ""; }; + 8540BD5323D8D5080057FDD2 /* FireproofingAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FireproofingAlert.swift; sourceTree = ""; }; + 8540BD5523D9E9C20057FDD2 /* FireproofingSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FireproofingSettingsViewController.swift; sourceTree = ""; }; 85449EF423FDA02800512AAF /* KeyboardSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardSettingsViewController.swift; sourceTree = ""; }; 85449EFA23FDA0BC00512AAF /* UserDefaultsPropertyWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsPropertyWrapper.swift; sourceTree = ""; }; 85449EFC23FDA71F00512AAF /* KeyboardSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardSettings.swift; sourceTree = ""; }; @@ -1838,6 +1839,9 @@ 8590CB66268A2E520089F6BF /* RootDebugViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootDebugViewController.swift; sourceTree = ""; }; 8590CB68268A4E190089F6BF /* DebugEtagStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugEtagStorage.swift; sourceTree = ""; }; 8596C30C2B7EB1800058EF90 /* DataStoreWarmup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStoreWarmup.swift; sourceTree = ""; }; + 8598D2DB2CEB93A600C45685 /* FaviconsCacheType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconsCacheType.swift; sourceTree = ""; }; + 8598D2DD2CEB97BE00C45685 /* FaviconHasher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconHasher.swift; sourceTree = ""; }; + 8598D2E52CEBAA1B00C45685 /* MockFaviconStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFaviconStore.swift; sourceTree = ""; }; 8598F6792405EB8600FBC70C /* KeyboardSettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardSettingsTests.swift; sourceTree = ""; }; 859DB80D2CE6263B001F7210 /* TextZoomStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextZoomStorage.swift; sourceTree = ""; }; 859DB80E2CE6263B001F7210 /* TextZoomController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextZoomController.swift; sourceTree = ""; }; @@ -1873,15 +1877,15 @@ 85C29709247EB7AA0063A335 /* Text.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Text.xcassets; sourceTree = ""; }; 85C29719248162CA0063A335 /* DaxOnboardingPadViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaxOnboardingPadViewController.swift; sourceTree = ""; }; 85C8E61C2B0E47380029A6BD /* BookmarksDatabaseSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksDatabaseSetup.swift; sourceTree = ""; }; - 85CA53A324B9F2BD00A6288C /* Favicons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Favicons.swift; path = ../DuckDuckGo/Favicons.swift; sourceTree = ""; }; - 85CA53A924BB376800A6288C /* NotFoundCachingDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotFoundCachingDownloader.swift; sourceTree = ""; }; - 85CA53AB24BBD39300A6288C /* FaviconRequestModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconRequestModifier.swift; sourceTree = ""; }; + 85CA53A324B9F2BD00A6288C /* Favicons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Favicons.swift; sourceTree = ""; }; + 85CA53A924BB376800A6288C /* NotFoundCachingDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = NotFoundCachingDownloader.swift; path = ../Core/NotFoundCachingDownloader.swift; sourceTree = ""; }; + 85CA53AB24BBD39300A6288C /* FaviconRequestModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FaviconRequestModifier.swift; path = ../Core/FaviconRequestModifier.swift; sourceTree = ""; }; 85D2186F24BF24DB004373D2 /* FaviconRequestModifierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconRequestModifierTests.swift; sourceTree = ""; }; 85D2187124BF24F2004373D2 /* NotFoundCachingDownloaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotFoundCachingDownloaderTests.swift; sourceTree = ""; }; 85D2187324BF25CD004373D2 /* FaviconsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconsTests.swift; sourceTree = ""; }; - 85D2187524BF6164004373D2 /* FaviconSourcesProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconSourcesProvider.swift; sourceTree = ""; }; + 85D2187524BF6164004373D2 /* FaviconSourcesProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FaviconSourcesProvider.swift; path = ../Core/FaviconSourcesProvider.swift; sourceTree = ""; }; 85D2187724BF6B88004373D2 /* FaviconSourcesProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconSourcesProviderTests.swift; sourceTree = ""; }; - 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconUserScript.swift; sourceTree = ""; }; + 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FaviconUserScript.swift; path = ../Core/FaviconUserScript.swift; sourceTree = ""; }; 85D33FCB25C97B6E002B91A6 /* IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85D33FCF25C97B6E002B91A6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 85DB12EA2A1FE2A4000A4A72 /* LockScreenWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockScreenWidgets.swift; sourceTree = ""; }; @@ -2737,7 +2741,6 @@ C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptHelper.swift; sourceTree = ""; }; C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptViewModelTests.swift; sourceTree = ""; }; C1BF26142C74D10F00F6405E /* SyncPromoManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPromoManager.swift; sourceTree = ""; }; - C1CCCBA6283E101500CF3791 /* FaviconsHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconsHelper.swift; sourceTree = ""; }; C1CDA3152AFB9C7F006D1476 /* AutofillNeverPromptWebsitesManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillNeverPromptWebsitesManager.swift; sourceTree = ""; }; C1CDA31D2AFBF811006D1476 /* AutofillNeverPromptWebsitesManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillNeverPromptWebsitesManagerTests.swift; sourceTree = ""; }; C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSession.swift; sourceTree = ""; }; @@ -3545,6 +3548,11 @@ 3157B43627F4C8380042D3D7 /* Favicons */ = { isa = PBXGroup; children = ( + 85CA53A324B9F2BD00A6288C /* Favicons.swift */, + 85CA53A924BB376800A6288C /* NotFoundCachingDownloader.swift */, + 85CA53AB24BBD39300A6288C /* FaviconRequestModifier.swift */, + 85D2187524BF6164004373D2 /* FaviconSourcesProvider.swift */, + 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */, 3157B43727F4C8490042D3D7 /* FaviconsHelper.swift */, ); name = Favicons; @@ -4388,8 +4396,7 @@ 98F0FC1F21FF18E700CE77AB /* AutoClearSettingsViewController.swift */, 1EE7C298294227EC0026C8CB /* AutoconsentSettingsViewController.swift */, 85449EF423FDA02800512AAF /* KeyboardSettingsViewController.swift */, - 8540BD5523D9E9C20057FDD2 /* PreserveLoginsSettingsViewController.swift */, - 1E865AEF272042DB001C74F3 /* TextSizeSettingsViewController.swift */, + 8540BD5523D9E9C20057FDD2 /* FireproofingSettingsViewController.swift */, 8531A08D1F9950E6000484F0 /* UnprotectedSitesViewController.swift */, 6FBF0F8A2BD7C0A900136CF0 /* AllProtectedCell.swift */, D6E83C672B23B6A3006C8AFB /* FontSettings.swift */, @@ -4577,12 +4584,8 @@ 85CA53A724BB342B00A6288C /* Favicons */ = { isa = PBXGroup; children = ( - C1CCCBA6283E101500CF3791 /* FaviconsHelper.swift */, - 85CA53A324B9F2BD00A6288C /* Favicons.swift */, - 85CA53A924BB376800A6288C /* NotFoundCachingDownloader.swift */, - 85CA53AB24BBD39300A6288C /* FaviconRequestModifier.swift */, - 85D2187524BF6164004373D2 /* FaviconSourcesProvider.swift */, - 85D2187A24BF9F85004373D2 /* FaviconUserScript.swift */, + 8598D2DB2CEB93A600C45685 /* FaviconsCacheType.swift */, + 8598D2DD2CEB97BE00C45685 /* FaviconHasher.swift */, ); name = Favicons; sourceTree = ""; @@ -5811,6 +5814,7 @@ 98559FD0267099F400A83094 /* ContentBlocker */, 31C138A127A334F600FFD4B2 /* Downloads */, D62EC3B72C24695800FC9D04 /* DuckPlayer */, + 85D2186E24BF24BA004373D2 /* Favicons */, 83134D7F20E2E013006CE65D /* Feedback */, 8588026724E4249800C24AB6 /* iPad */, 851DFD88212C5ED600D95F20 /* Main */, @@ -5908,7 +5912,7 @@ 83004E872193E8C700DA013C /* TabViewControllerLongPressMenuExtension.swift */, 8C47244F2217A14B004C9B2D /* TabViewControllerLongPressBookmarkExtension.swift */, 98999D5822FDA41500CBBE1B /* BasicAuthenticationAlert.swift */, - 8540BBA12440857A00017FE4 /* PreserveLoginsWorker.swift */, + 8540BBA12440857A00017FE4 /* FireproofingWorking.swift */, 8548D95D25262B1B005AAE49 /* ViewHighlighter.swift */, 8548D96725262C33005AAE49 /* view_highlight.json */, 31B524562715BB23002225AB /* WebJSAlert.swift */, @@ -6015,7 +6019,7 @@ 85BDC3132434D8F80053DB07 /* DebugUserScript.swift */, 4B60ACA0252EC0B100E8D219 /* FullScreenVideoUserScript.swift */, 85BDC3182436161C0053DB07 /* LoginFormDetectionUserScript.swift */, - 850559CF23CF647C0055C0D5 /* PreserveLogins.swift */, + 850559CF23CF647C0055C0D5 /* Fireproofing.swift */, 4B75EA9126A266CB00018634 /* PrintingUserScript.swift */, 988F3DCE237D5C0F00AEE34C /* SchemeHandler.swift */, 836A941C247F23C600BF8EF5 /* UserAgentManager.swift */, @@ -6070,6 +6074,7 @@ F17669A91E412A17003D3222 /* Mocks */ = { isa = PBXGroup; children = ( + 8598D2E52CEBAA1B00C45685 /* MockFaviconStore.swift */, 9F4CC51A2C48C0C7006A96EB /* MockTabDelegate.swift */, C14882E927F20DD000D59F0C /* MockBookmarksCoreDataStorage.swift */, C158AC7A297AB5DC0008723A /* MockSecureVault.swift */, @@ -6158,7 +6163,7 @@ isa = PBXGroup; children = ( 834DF990248FDDF60075EA48 /* UserAgentTests.swift */, - 8540BD5123D8C2220057FDD2 /* PreserveLoginsTests.swift */, + 8540BD5123D8C2220057FDD2 /* UserDefaultsFireproofingTests.swift */, 850559D123CF710C0055C0D5 /* WebCacheManagerTests.swift */, 981C49AF2C8FA61D00DF11E8 /* DataStoreIdManagerTests.swift */, F198D7971E3A45D90088DA8A /* WKWebViewConfigurationExtensionTests.swift */, @@ -6309,7 +6314,7 @@ 98EF177C21837E35006750C1 /* new_tab_dark.json */, 85371D232121B9D400920548 /* new_tab.json */, 31B2F11E287846320040427A /* NoMicPermissionAlert.swift */, - 8540BD5323D8D5080057FDD2 /* PreserveLoginsAlert.swift */, + 8540BD5323D8D5080057FDD2 /* FireproofingAlert.swift */, 850ABD022AC4D46C00A733DF /* SuggestionTray.storyboard */, 85864FBB24D31EF300E756FF /* SuggestionTrayViewController.swift */, 851DFD86212C39D300D95F20 /* TabSwitcherButton.swift */, @@ -6424,7 +6429,6 @@ 830FA79B1F8E81FB00FCE105 /* ContentBlocker */, F17D722C1E8B3563003E8B0E /* Domain */, EE3B226929DE0EE10082298A /* FeatureFlags */, - 85D2186E24BF24BA004373D2 /* Favicons */, F1134EC91F40E74800B73467 /* Statistics */, F198D78F1E3976300088DA8A /* Utilities */, F198D7961E3A45C00088DA8A /* Web */, @@ -7422,7 +7426,7 @@ 6F64AA592C4818D700CF4489 /* NewTabPageShortcut.swift in Sources */, 3132FA2627A0784600DD7A12 /* FilePreviewHelper.swift in Sources */, 9820FF502244FECC008D4782 /* UIScrollViewExtension.swift in Sources */, - 8540BD5423D8D5080057FDD2 /* PreserveLoginsAlert.swift in Sources */, + 8540BD5423D8D5080057FDD2 /* FireproofingAlert.swift in Sources */, 1E87615928A1517200C7C5CE /* PrivacyDashboardViewController.swift in Sources */, 6F03CAFE2C32DD08004179A8 /* HomePageMessagesConfiguration.swift in Sources */, 851952682CE2522700578553 /* AutocompleteSuggestionsDataSource.swift in Sources */, @@ -7438,7 +7442,7 @@ 31669B9A28020A460071CC18 /* SaveLoginViewModel.swift in Sources */, EE4FB1882A28D11900E5CBA7 /* NetworkProtectionStatusViewModel.swift in Sources */, 6FB1FE9E2C24D41D0075B68B /* NewTabPageSectionsDebugView.swift in Sources */, - 8540BD5623D9E9C20057FDD2 /* PreserveLoginsSettingsViewController.swift in Sources */, + 8540BD5623D9E9C20057FDD2 /* FireproofingSettingsViewController.swift in Sources */, 7B8E0EC62CC81B4900B2B722 /* TipKitController.swift in Sources */, 7B1604EC2CB68BDA00A44EC6 /* TipKitController+ConvenienceInitializers.swift in Sources */, 851672D12BED1FC900592F24 /* AutocompleteView.swift in Sources */, @@ -7758,6 +7762,11 @@ EEC02C142B0519DE0045CE11 /* NetworkProtectionVPNLocationViewModel.swift in Sources */, D63FF8962C1B67E9006DE24D /* YoutubeOverlayUserScript.swift in Sources */, F13B4BC01F180D8A00814661 /* TabsModel.swift in Sources */, + 8598D2E02CEB98B500C45685 /* Favicons.swift in Sources */, + 8598D2E12CEB98B500C45685 /* NotFoundCachingDownloader.swift in Sources */, + 8598D2E22CEB98B500C45685 /* FaviconRequestModifier.swift in Sources */, + 8598D2E32CEB98B500C45685 /* FaviconUserScript.swift in Sources */, + 8598D2E42CEB98B500C45685 /* FaviconSourcesProvider.swift in Sources */, BD862E052B30DB250073E2EE /* VPNFeedbackCategory.swift in Sources */, 85AE6690209724120014CF04 /* NotificationView.swift in Sources */, BDE91CE02C6515420005CB74 /* UnifiedFeedbackFormViewModel.swift in Sources */, @@ -7877,7 +7886,7 @@ D6ACEA322BBD55BF008FADDF /* TabURLInterceptor.swift in Sources */, C13F3F6A2B7F883A0083BE40 /* AuthConfirmationPromptViewController.swift in Sources */, 851624C72B96389D002D5CD7 /* HistoryDebugViewController.swift in Sources */, - 8540BBA22440857A00017FE4 /* PreserveLoginsWorker.swift in Sources */, + 8540BBA22440857A00017FE4 /* FireproofingWorking.swift in Sources */, 0283A2012C6E46E300508FBD /* BrokenSitePromptLimiterStore.swift in Sources */, 85DFEDF924CF3D0E00973FE7 /* TabsBarCell.swift in Sources */, 851672D32BED23FE00592F24 /* AutocompleteViewModel.swift in Sources */, @@ -8032,6 +8041,7 @@ F1134EBC1F40D45700B73467 /* MockStatisticsStore.swift in Sources */, 9FCFCD802C6AF56D006EB7A0 /* LaunchOptionsHandlerTests.swift in Sources */, 983C52E72C2C0ACB007B5747 /* BookmarkStateRepairTests.swift in Sources */, + 8598D2E62CEBAA1F00C45685 /* MockFaviconStore.swift in Sources */, 31C138AC27A403CB00FFD4B2 /* DownloadManagerTests.swift in Sources */, BDE219EA2C457B46005D5884 /* PrivacyProDataReporterTests.swift in Sources */, EEFE9C732A603CE9005B0A26 /* NetworkProtectionStatusViewModelTests.swift in Sources */, @@ -8209,7 +8219,7 @@ 9FEA22352C327226006B03BF /* MockTimer.swift in Sources */, EE7917912A83DE93008DFF28 /* CombineTestUtilities.swift in Sources */, 6FD0C41F2C5BF097000561C9 /* NewTabPageIntroMessageSetupTests.swift in Sources */, - 8540BD5223D8C2220057FDD2 /* PreserveLoginsTests.swift in Sources */, + 8540BD5223D8C2220057FDD2 /* UserDefaultsFireproofingTests.swift in Sources */, 85F200072217032E006BB258 /* AddressDisplayHelperTests.swift in Sources */, B6AD9E3728D4510A0019CDE9 /* ContentBlockingUpdatingTests.swift in Sources */, C14882E427F20D9A00D59F0C /* BookmarksImporterTests.swift in Sources */, @@ -8312,7 +8322,6 @@ CB258D1E29A52AF900DEBA24 /* FileStore.swift in Sources */, F1075C921E9EF827006BE8A8 /* UserDefaultsExtension.swift in Sources */, 851624C22B95F8BD002D5CD7 /* HistoryCapture.swift in Sources */, - 85CA53AC24BBD39300A6288C /* FaviconRequestModifier.swift in Sources */, CB258D1D29A52AF900DEBA24 /* EtagStorage.swift in Sources */, 31B2F10F2C92FECC00CD30E3 /* MarketplaceAdPostbackManager.swift in Sources */, C1B7B52D2894469D0098FD6A /* DefaultVariantManager.swift in Sources */, @@ -8339,10 +8348,9 @@ 85372447220DD103009D09CD /* UIKeyCommandExtension.swift in Sources */, 85A1B3B220C6CD9900C18F15 /* CookieStorage.swift in Sources */, 9856A1992933D2EB00ACB44F /* BookmarksModelsErrorHandling.swift in Sources */, - 850559D023CF647C0055C0D5 /* PreserveLogins.swift in Sources */, + 850559D023CF647C0055C0D5 /* Fireproofing.swift in Sources */, 4B27FBAE2C924EC6007E21A7 /* PersistentPixelStoring.swift in Sources */, 6F7FB8E32C660BF300867DA7 /* DailyPixelFiring.swift in Sources */, - C1CCCBA7283E101500CF3791 /* FaviconsHelper.swift in Sources */, 9813F79822BA71AA00A80EDB /* StorageCache.swift in Sources */, B603974929C19F6F00902A34 /* Assertions.swift in Sources */, F1134EB51F40AEEA00B73467 /* StatisticsLoader.swift in Sources */, @@ -8360,13 +8368,13 @@ 85449EFB23FDA0BC00512AAF /* UserDefaultsPropertyWrapper.swift in Sources */, 56D8556A2BEA9169009F9698 /* CurrentDateProviding.swift in Sources */, 830381C01F850AAF00863075 /* WKWebViewConfigurationExtension.swift in Sources */, - 85CA53AA24BB376800A6288C /* NotFoundCachingDownloader.swift in Sources */, 4B60ACA1252EC0B100E8D219 /* FullScreenVideoUserScript.swift in Sources */, F1A886781F29394E0096251E /* WebCacheManager.swift in Sources */, 6F03CB072C32F173004179A8 /* PixelFiring.swift in Sources */, C14882DA27F2011C00D59F0C /* BookmarksExporter.swift in Sources */, 854858E32937BC550063610B /* CollectionExtension.swift in Sources */, 85528AA72C7CA95D0017BCCA /* UsageSegmentationCalculator.swift in Sources */, + 8598D2DC2CEB93AD00C45685 /* FaviconsCacheType.swift in Sources */, 1E6A4D692984208800A371D3 /* LocaleExtension.swift in Sources */, 98F6EA472863124100720957 /* ContentBlockerRulesLists.swift in Sources */, 566B73732BECE4F200FF1959 /* SyncErrorHandling.swift in Sources */, @@ -8384,7 +8392,6 @@ 85011867290028C400BDEE27 /* BookmarksDatabase.swift in Sources */, 1D8F727F2BA86D8000E31493 /* PixelExperiment.swift in Sources */, 56D8556C2BEA91C4009F9698 /* SyncAlertsPresenting.swift in Sources */, - 85D2187B24BF9F85004373D2 /* FaviconUserScript.swift in Sources */, 37FD780F2A29E28B00B36DB1 /* SyncErrorHandler.swift in Sources */, 85F21DC621145DD5002631A6 /* global.swift in Sources */, 372A0FF02B2389590033BF7F /* SyncMetricsEventsHandler.swift in Sources */, @@ -8392,12 +8399,10 @@ F4F6DFBA26EFF28A00ED7E12 /* BookmarkObjects.swift in Sources */, EE7A92872AC6DE4700832A36 /* NetworkProtectionNotificationIdentifier.swift in Sources */, 836A941D247F23C600BF8EF5 /* UserAgentManager.swift in Sources */, - 85CA53A824BB343700A6288C /* Favicons.swift in Sources */, F143C3181E4A99D200CFDE3A /* Link.swift in Sources */, 6F03CB092C32F331004179A8 /* PixelFiringAsync.swift in Sources */, 37CEFCAC2A673B90001EF741 /* CredentialsCleanupErrorHandling.swift in Sources */, CB2A7EF128410DF700885F67 /* PixelEvent.swift in Sources */, - 85D2187624BF6164004373D2 /* FaviconSourcesProvider.swift in Sources */, 98B000532915C46E0034BCA0 /* LegacyBookmarksStoreMigration.swift in Sources */, 6F04224D2CD2A3AD00729FA6 /* StorageInconsistencyMonitor.swift in Sources */, 85200FA11FBC5BB5001AF290 /* DDGPersistenceContainer.swift in Sources */, @@ -8423,6 +8428,7 @@ 9887DC252354D2AA005C85F5 /* Database.swift in Sources */, F143C3171E4A99D200CFDE3A /* AppURLs.swift in Sources */, C1963863283794A000298D4D /* BookmarksCachingSearch.swift in Sources */, + 8598D2DE2CEB97BE00C45685 /* FaviconHasher.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index 185cf88fa1..8020b7ad4b 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -272,7 +272,8 @@ import os.log secureVaultErrorReporter: SecureVaultReporter(), settingHandlers: [FavoritesDisplayModeSyncHandler()], favoritesDisplayModeStorage: FavoritesDisplayModeStorage(), - syncErrorHandler: syncErrorHandler + syncErrorHandler: syncErrorHandler, + faviconStoring: Favicons.shared ) let syncService = DDGSync( diff --git a/DuckDuckGo/Base.lproj/Settings.storyboard b/DuckDuckGo/Base.lproj/Settings.storyboard index 39927df63a..22cf4b4816 100644 --- a/DuckDuckGo/Base.lproj/Settings.storyboard +++ b/DuckDuckGo/Base.lproj/Settings.storyboard @@ -1,9 +1,9 @@ - + - + @@ -467,12 +467,12 @@ - + - + @@ -514,7 +514,7 @@ - + @@ -553,7 +553,7 @@ - + @@ -572,7 +572,7 @@ - + diff --git a/DuckDuckGo/ContentBlockingUpdating.swift b/DuckDuckGo/ContentBlockingUpdating.swift index 95002bca9e..dc3b8a720d 100644 --- a/DuckDuckGo/ContentBlockingUpdating.swift +++ b/DuckDuckGo/ContentBlockingUpdating.swift @@ -84,7 +84,7 @@ public final class ContentBlockingUpdating { // prefs changes notifications with initially published value for combineLatest to work. // Not all of these will trigger Tab reload, // refer TabViewController.swift:2116 for the list of notifications triggering reload - .combineLatest(onNotificationWithInitial(PreserveLogins.Notifications.loginDetectionStateChanged), combine) + .combineLatest(onNotificationWithInitial(UserDefaultsFireproofing.Notifications.loginDetectionStateChanged), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.doNotSellStatusChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.autofillEnabledChange), combine) .combineLatest(onNotificationWithInitial(AppUserDefaults.Notifications.didVerifyInternalUser), combine) diff --git a/DuckDuckGo/CookieDebugViewController.swift b/DuckDuckGo/CookieDebugViewController.swift index ed2b84fb16..4efc382742 100644 --- a/DuckDuckGo/CookieDebugViewController.swift +++ b/DuckDuckGo/CookieDebugViewController.swift @@ -39,7 +39,17 @@ class CookieDebugViewController: UITableViewController { } var loaded = false + let fireproofing: Fireproofing + init(fireproofing: Fireproofing = UserDefaultsFireproofing.shared) { + self.fireproofing = fireproofing + super.init() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { super.viewDidLoad() fetchCookies() @@ -66,7 +76,7 @@ class CookieDebugViewController: UITableViewController { .reversed()) let domainName = domain + - (PreserveLogins.shared.isAllowed(cookieDomain: domain) ? " 👩‍🚒" : "") + (fireproofing.isAllowed(cookieDomain: domain) ? " 👩‍🚒" : "") tmp.append(DomainCookies(domain: domainName, cookies: domainCookies)) } diff --git a/DuckDuckGo/FaviconViewModel.swift b/DuckDuckGo/FaviconViewModel.swift index 2b9ee92dd7..a7516dbf50 100644 --- a/DuckDuckGo/FaviconViewModel.swift +++ b/DuckDuckGo/FaviconViewModel.swift @@ -25,12 +25,12 @@ final class FaviconViewModel { private let domain: String private let useFakeFavicon: Bool - private let cacheType: Favicons.CacheType + private let cacheType: FaviconsCacheType private let preferredFaviconLetters: String? internal init(domain: String, useFakeFavicon: Bool = true, - cacheType: Favicons.CacheType = .tabs, + cacheType: FaviconsCacheType = .tabs, preferredFakeFaviconLetters: String? = nil) { self.domain = domain diff --git a/DuckDuckGo/Favicons.swift b/DuckDuckGo/Favicons.swift index ba17101c97..719b1fa2cd 100644 --- a/DuckDuckGo/Favicons.swift +++ b/DuckDuckGo/Favicons.swift @@ -24,104 +24,26 @@ import UIKit import LinkPresentation import WidgetKit import os.log +import Core public class Favicons { public struct Constants { - static let salt = "DDGSalt:" - static let faviconsFolderName = "Favicons" static let requestModifier = FaviconRequestModifier() - static let fireproofCache = CacheType.fireproof.create() - static let tabsCache = CacheType.tabs.create() + static let fireproofCache = FaviconsCacheType.fireproof.create() + static let tabsCache = FaviconsCacheType.tabs.create() static let targetImageSizePoints: CGFloat = 64 public static let tabsCachePath = "com.onevcat.Kingfisher.ImageCache.tabs" public static let maxFaviconSize: CGSize = CGSize(width: 192, height: 192) public static let caches = [ - CacheType.fireproof: fireproofCache, - CacheType.tabs: tabsCache + FaviconsCacheType.fireproof: fireproofCache, + FaviconsCacheType.tabs: tabsCache ] } - public enum CacheType: String { - - case tabs - case fireproof - - func create() -> ImageCache { - - // If unable to create cache in desired location default to Kingfisher's default location which is Library/Cache. Images may disappear - // but at least the app won't crash. This should not happen. - let cache = createCacheInDesiredLocation() ?? ImageCache(name: rawValue) - - // We hash the resource key when loading the resource so don't use Kingfisher's hashing which is md5 based - cache.diskStorage.config.usesHashedFileName = false - - if self == .fireproof { - migrateBookmarksCacheContents(to: cache.diskStorage.directoryURL) - } - - return cache - } - - public func cacheLocation() -> URL? { - return baseCacheURL()?.appendingPathComponent(Constants.faviconsFolderName) - } - - private func createCacheInDesiredLocation() -> ImageCache? { - - guard var url = cacheLocation() else { return nil } - - if !FileManager.default.fileExists(atPath: url.path) { - try? FileManager.default.createDirectory(at: url, - withIntermediateDirectories: true, - attributes: nil) - - // Exclude from backup - var resourceValues = URLResourceValues() - resourceValues.isExcludedFromBackup = true - try? url.setResourceValues(resourceValues) - } - - Logger.general.debug("favicons \(rawValue) location \(url.absoluteString)") - return try? ImageCache(name: self.rawValue, cacheDirectoryURL: url) - } - - private func baseCacheURL() -> URL? { - switch self { - case .fireproof: - let groupName = BookmarksDatabase.Constants.bookmarksGroupID - return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupName) - - case .tabs: - return FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first - } - } - - private func migrateBookmarksCacheContents(to url: URL) { - guard let cacheUrl = CacheType.fireproof.cacheLocation() else { return } - - // Using hardcoded path as this is a one time migration - let bookmarksCache = cacheUrl.appendingPathComponent("com.onevcat.Kingfisher.ImageCache.bookmarks") - guard FileManager.default.fileExists(atPath: bookmarksCache.path) else { return } - - if let contents = try? FileManager.default.contentsOfDirectory(at: bookmarksCache, includingPropertiesForKeys: nil, options: []) { - contents.forEach { - let destination = url.appendingPathComponent($0.lastPathComponent) - try? FileManager.default.moveItem(at: $0, to: destination) - } - } - - do { - try FileManager.default.removeItem(at: bookmarksCache) - } catch { - Logger.general.error("Failed to remove favicon bookmarks cache: \(error.localizedDescription, privacy: .public)") - } - } - } - public static let shared = Favicons() @UserDefaultsWrapper(key: .faviconSizeNeedsMigration, defaultValue: true) @@ -129,13 +51,16 @@ public class Favicons { let sourcesProvider: FaviconSourcesProvider let downloader: NotFoundCachingDownloader + let fireproofing: Fireproofing let userAgentManager: UserAgentManager = DefaultUserAgentManager.shared init(sourcesProvider: FaviconSourcesProvider = DefaultFaviconSourcesProvider(), - downloader: NotFoundCachingDownloader = NotFoundCachingDownloader()) { + downloader: NotFoundCachingDownloader = NotFoundCachingDownloader(), + fireproofing: Fireproofing = UserDefaultsFireproofing.shared) { self.sourcesProvider = sourcesProvider self.downloader = downloader + self.fireproofing = fireproofing // Prevents the caches being cleaned up NotificationCenter.default.removeObserver(Constants.fireproofCache) @@ -219,7 +144,7 @@ public class Favicons { } } - public func clearCache(_ cacheType: CacheType, clearMemoryCache: Bool = false) { + public func clearCache(_ cacheType: FaviconsCacheType, clearMemoryCache: Bool = false) { Constants.caches[cacheType]?.clearDiskCache() if clearMemoryCache { @@ -227,17 +152,17 @@ public class Favicons { } } - private func removeFavicon(forDomain domain: String, fromCache cacheType: CacheType) { + private func removeFavicon(forDomain domain: String, fromCache cacheType: FaviconsCacheType) { let key = defaultResource(forDomain: domain)?.cacheKey ?? domain Constants.caches[cacheType]?.removeImage(forKey: key, fromDisk: true) } - private func removeFavicon(forCacheKey key: String, fromCache cacheType: CacheType) { + private func removeFavicon(forCacheKey key: String, fromCache cacheType: FaviconsCacheType) { Constants.caches[cacheType]?.removeImage(forKey: key, fromDisk: true) } public func removeBookmarkFavicon(forDomain domain: String) { - guard !PreserveLogins.shared.isAllowed(fireproofDomain: domain) else { return } + guard !fireproofing.isAllowed(fireproofDomain: domain) else { return } removeFavicon(forDomain: domain, fromCache: .fireproof) } @@ -253,7 +178,7 @@ public class Favicons { removeFavicon(forCacheKey: key, fromCache: .tabs) } - private func copyFavicon(forDomain domain: String, fromCache: CacheType, toCache: CacheType, completion: ((UIImage?) -> Void)? = nil) { + private func copyFavicon(forDomain domain: String, fromCache: FaviconsCacheType, toCache: FaviconsCacheType, completion: ((UIImage?) -> Void)? = nil) { guard let resource = defaultResource(forDomain: domain), let options = kfOptions(forDomain: domain, usingCache: toCache) else { return } @@ -277,8 +202,8 @@ public class Favicons { // e.g. if launching a bookmark, or clicking on a tab. public func loadFavicon(forDomain domain: String?, fromURL url: URL? = nil, - intoCache targetCacheType: CacheType, - fromCache: CacheType? = nil, + intoCache targetCacheType: FaviconsCacheType, + fromCache: FaviconsCacheType? = nil, queue: DispatchQueue? = OperationQueue.current?.underlyingQueue, completion: ((UIImage?) -> Void)? = nil) { @@ -441,7 +366,7 @@ public class Favicons { return FaviconsHelper.defaultResource(forDomain: domain, sourcesProvider: sourcesProvider) } - public func kfOptions(forDomain domain: String?, withURL url: URL? = nil, usingCache cacheType: CacheType) -> KingfisherOptionsInfo? { + public func kfOptions(forDomain domain: String?, withURL url: URL? = nil, usingCache cacheType: FaviconsCacheType) -> KingfisherOptionsInfo? { guard let domain = domain else { return nil } @@ -473,10 +398,6 @@ public class Favicons { ] } - public static func createHash(ofDomain domain: String) -> String { - return "\(Constants.salt)\(domain)".sha256() - } - } extension Favicons: Bookmarks.FaviconStoring { @@ -509,3 +430,63 @@ extension Favicons: Bookmarks.FaviconStoring { } } } + +extension FaviconsCacheType { + + func create() -> ImageCache { + + // If unable to create cache in desired location default to Kingfisher's default location which is Library/Cache. Images may disappear + // but at least the app won't crash. This should not happen. + let cache = createCacheInDesiredLocation() ?? ImageCache(name: rawValue) + + // We hash the resource key when loading the resource so don't use Kingfisher's hashing which is md5 based + cache.diskStorage.config.usesHashedFileName = false + + if self == .fireproof { + migrateBookmarksCacheContents(to: cache.diskStorage.directoryURL) + } + + return cache + } + + private func createCacheInDesiredLocation() -> ImageCache? { + + guard var url = cacheLocation() else { return nil } + + if !FileManager.default.fileExists(atPath: url.path) { + try? FileManager.default.createDirectory(at: url, + withIntermediateDirectories: true, + attributes: nil) + + // Exclude from backup + var resourceValues = URLResourceValues() + resourceValues.isExcludedFromBackup = true + try? url.setResourceValues(resourceValues) + } + + Logger.general.debug("favicons \(rawValue) location \(url.absoluteString)") + return try? ImageCache(name: self.rawValue, cacheDirectoryURL: url) + } + + private func migrateBookmarksCacheContents(to url: URL) { + guard let cacheUrl = FaviconsCacheType.fireproof.cacheLocation() else { return } + + // Using hardcoded path as this is a one time migration + let bookmarksCache = cacheUrl.appendingPathComponent("com.onevcat.Kingfisher.ImageCache.bookmarks") + guard FileManager.default.fileExists(atPath: bookmarksCache.path) else { return } + + if let contents = try? FileManager.default.contentsOfDirectory(at: bookmarksCache, includingPropertiesForKeys: nil, options: []) { + contents.forEach { + let destination = url.appendingPathComponent($0.lastPathComponent) + try? FileManager.default.moveItem(at: $0, to: destination) + } + } + + do { + try FileManager.default.removeItem(at: bookmarksCache) + } catch { + Logger.general.error("Failed to remove favicon bookmarks cache: \(error.localizedDescription, privacy: .public)") + } + } + +} diff --git a/DuckDuckGo/FaviconsHelper.swift b/DuckDuckGo/FaviconsHelper.swift index 051acccb6a..b319e5146c 100644 --- a/DuckDuckGo/FaviconsHelper.swift +++ b/DuckDuckGo/FaviconsHelper.swift @@ -27,7 +27,7 @@ struct FaviconsHelper { private static let tld: TLD = AppDependencyProvider.shared.storageCache.tld static func loadFaviconSync(forDomain domain: String?, - usingCache cacheType: Favicons.CacheType, + usingCache cacheType: FaviconsCacheType, useFakeFavicon: Bool, preferredFakeFaviconLetters: String? = nil) -> (image: UIImage?, isFake: Bool) { @@ -90,7 +90,7 @@ struct FaviconsHelper { } static func loadFaviconSync(forDomain domain: String?, - usingCache cacheType: Favicons.CacheType, + usingCache cacheType: FaviconsCacheType, useFakeFavicon: Bool, preferredFakeFaviconLetters: String? = nil, completion: ((UIImage?, Bool) -> Void)? = nil) { @@ -142,5 +142,14 @@ struct FaviconsHelper { return icon.withRenderingMode(.alwaysOriginal) } - + // this function is now static and outside of Favicons, otherwise there is a circular dependency between + // Favicons and NotFoundCachingDownloader + public static func defaultResource(forDomain domain: String?, sourcesProvider: FaviconSourcesProvider) -> KF.ImageResource? { + guard let domain = domain, + let source = sourcesProvider.mainSource(forDomain: domain) else { return nil } + + let key = FaviconHasher.createHash(ofDomain: domain) + return KF.ImageResource(downloadURL: source, cacheKey: key) + } + } diff --git a/DuckDuckGo/FireproofFaviconUpdater.swift b/DuckDuckGo/FireproofFaviconUpdater.swift index 09cc60f967..6d7de2439a 100644 --- a/DuckDuckGo/FireproofFaviconUpdater.swift +++ b/DuckDuckGo/FireproofFaviconUpdater.swift @@ -31,14 +31,14 @@ extension Tab: TabNotifying {} protocol FaviconProviding { - func loadFavicon(forDomain domain: String, fromURL url: URL?, intoCache cacheType: Favicons.CacheType, completion: ((UIImage?) -> Void)?) + func loadFavicon(forDomain domain: String, fromURL url: URL?, intoCache cacheType: FaviconsCacheType, completion: ((UIImage?) -> Void)?) func replaceFireproofFavicon(forDomain domain: String?, withImage: UIImage) } extension Favicons: FaviconProviding { - func loadFavicon(forDomain domain: String, fromURL url: URL?, intoCache cacheType: CacheType, completion: ((UIImage?) -> Void)?) { + func loadFavicon(forDomain domain: String, fromURL url: URL?, intoCache cacheType: FaviconsCacheType, completion: ((UIImage?) -> Void)?) { self.loadFavicon(forDomain: domain, fromURL: url, intoCache: cacheType, fromCache: nil, completion: completion) } diff --git a/DuckDuckGo/PreserveLoginsAlert.swift b/DuckDuckGo/FireproofingAlert.swift similarity index 68% rename from DuckDuckGo/PreserveLoginsAlert.swift rename to DuckDuckGo/FireproofingAlert.swift index 9bdc020ebe..593f376eb6 100644 --- a/DuckDuckGo/PreserveLoginsAlert.swift +++ b/DuckDuckGo/FireproofingAlert.swift @@ -1,5 +1,5 @@ // -// PreserveLoginsAlert.swift +// FireproofingAlert.swift // DuckDuckGo // // Copyright © 2020 DuckDuckGo. All rights reserved. @@ -20,22 +20,22 @@ import Foundation import Core -class PreserveLoginsAlert { +class FireproofingAlert { static func showFireproofDisabledMessage(usingController controller: UIViewController, - worker: PreserveLoginsWorker, + worker: FireproofingWorking, forDomain domain: String) { - let message = UserText.preserveLoginsRemovalConfirmMessage.format(arguments: domain.droppingWwwPrefix()) + let message = UserText.fireproofingRemovalConfirmMessage.format(arguments: domain.droppingWwwPrefix()) ActionMessageView.present(message: message, actionTitle: UserText.actionGenericUndo, onAction: { worker.handleUserEnablingFireproofing(forDomain: domain) }) } static func showFireproofEnabledMessage(usingController controller: UIViewController, - worker: PreserveLoginsWorker, + worker: FireproofingWorking, forDomain domain: String) { - let message = UserText.preserveLoginsFireproofConfirmMessage.format(arguments: domain.droppingWwwPrefix()) + let message = UserText.fireproofingConfirmMessage.format(arguments: domain.droppingWwwPrefix()) ActionMessageView.present(message: message, actionTitle: UserText.actionGenericUndo, onAction: { worker.handleUserDisablingFireproofing(forDomain: domain) }) @@ -44,10 +44,10 @@ class PreserveLoginsAlert { static func showConfirmFireproofWebsite(usingController controller: UIViewController, forDomain domain: String, onConfirmHandler: @escaping () -> Void) { - let prompt = UIAlertController(title: UserText.preserveLoginsFireproofAskTitle.format(arguments: domain.droppingWwwPrefix()), - message: UserText.preserveLoginsFireproofAskMessage, + let prompt = UIAlertController(title: UserText.fireproofingAskTitle.format(arguments: domain.droppingWwwPrefix()), + message: UserText.fireproofingAskMessage, preferredStyle: controller.isPad ? .alert : .actionSheet) - prompt.addAction(title: UserText.preserveLoginsFireproofConfirmAction, style: .default) { + prompt.addAction(title: UserText.FireproofingConfirmAction, style: .default) { onConfirmHandler() } prompt.addAction(title: UserText.actionCancel, style: .cancel) @@ -57,21 +57,21 @@ class PreserveLoginsAlert { static func showFireproofWebsitePrompt(usingController controller: UIViewController, forDomain domain: String, onConfirmHandler: @escaping () -> Void) { - let prompt = UIAlertController(title: UserText.preserveLoginsFireproofAskTitle.format(arguments: domain.droppingWwwPrefix()), - message: UserText.preserveLoginsFireproofAskMessage, + let prompt = UIAlertController(title: UserText.fireproofingAskTitle.format(arguments: domain.droppingWwwPrefix()), + message: UserText.fireproofingAskMessage, preferredStyle: controller.isPad ? .alert : .actionSheet) - prompt.addAction(title: UserText.preserveLoginsFireproofConfirmAction) { + prompt.addAction(title: UserText.FireproofingConfirmAction) { onConfirmHandler() } - prompt.addAction(title: UserText.preserveLoginsFireproofDefer, style: .cancel) + prompt.addAction(title: UserText.fireproofingDeferAction, style: .cancel) controller.present(prompt, animated: true) } static func showClearAllAlert(usingController controller: UIViewController, cancelled: @escaping () -> Void, confirmed: @escaping () -> Void) { if controller.isPad { - let alert = UIAlertController(title: UserText.preserveLoginsRemoveAll, message: nil, preferredStyle: .alert) - alert.addAction(title: UserText.preserveLoginsRemoveAllOk, style: .destructive) { + let alert = UIAlertController(title: UserText.fireproofingRemoveAllTitle, message: nil, preferredStyle: .alert) + alert.addAction(title: UserText.fireproofingRemoveAllOk, style: .destructive) { confirmed() } alert.addAction(title: UserText.actionCancel, style: .cancel) { @@ -80,7 +80,7 @@ class PreserveLoginsAlert { controller.present(alert, animated: true) } else { let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - alert.addAction(title: UserText.preserveLoginsRemoveAll, style: .destructive) { + alert.addAction(title: UserText.fireproofingRemoveAllTitle, style: .destructive) { confirmed() } alert.addAction(title: UserText.actionCancel, style: .cancel) { diff --git a/DuckDuckGo/PreserveLoginsSettingsViewController.swift b/DuckDuckGo/FireproofingSettingsViewController.swift similarity index 86% rename from DuckDuckGo/PreserveLoginsSettingsViewController.swift rename to DuckDuckGo/FireproofingSettingsViewController.swift index 3de524b611..08bc88b0c7 100644 --- a/DuckDuckGo/PreserveLoginsSettingsViewController.swift +++ b/DuckDuckGo/FireproofingSettingsViewController.swift @@ -1,5 +1,5 @@ // -// PreserveLoginsSettingsViewController.swift +// FireproofingSettingsViewController.swift // DuckDuckGo // // Copyright © 2020 DuckDuckGo. All rights reserved. @@ -21,7 +21,7 @@ import UIKit import Core import WebKit -class PreserveLoginsSettingsViewController: UITableViewController { +class FireproofingSettingsViewController: UITableViewController { enum Section: Int, CaseIterable { case info @@ -35,6 +35,17 @@ class PreserveLoginsSettingsViewController: UITableViewController { var model = [String]() private var shouldShowRemoveAll = false + + private let fireproofing: Fireproofing + + init?(coder: NSCoder, fireproofing: Fireproofing) { + self.fireproofing = fireproofing + super.init(coder: coder) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } override func viewDidLoad() { super.viewDidLoad() @@ -114,7 +125,7 @@ class PreserveLoginsSettingsViewController: UITableViewController { override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { switch Section(rawValue: section) { case .some(.domainList): - return UserText.preserveLoginsListTitle + return UserText.fireproofingListTitle default: return nil @@ -124,7 +135,7 @@ class PreserveLoginsSettingsViewController: UITableViewController { override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { switch Section(rawValue: section) { case .some(.info): - return UserText.preserveLoginsListFooter + return UserText.fireproofingListFooter default: return nil @@ -144,7 +155,7 @@ class PreserveLoginsSettingsViewController: UITableViewController { guard editingStyle == .delete else { return } let domain = model.remove(at: indexPath.row) - PreserveLogins.shared.remove(domain: domain) + fireproofing.remove(domain: domain) Favicons.shared.removeFireproofFavicon(forDomain: domain) if self.model.isEmpty { @@ -171,19 +182,20 @@ class PreserveLoginsSettingsViewController: UITableViewController { } func createSwitchCell(forTableView tableView: UITableView, withTheme theme: Theme) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCell(withIdentifier: "SettingCell") as? PreserveLoginsSwitchCell else { + guard let cell = tableView.dequeueReusableCell(withIdentifier: "SettingCell") as? FireproofingSwitchCell else { fatalError("Cell should be dequeued") } cell.label.textColor = theme.tableCellTextColor cell.toggle.onTintColor = theme.buttonTintColor - cell.toggle.isOn = PreserveLogins.shared.loginDetectionEnabled + cell.toggle.isOn = fireproofing.loginDetectionEnabled + cell.fireproofing = fireproofing cell.controller = self cell.decorate(with: theme) return cell } func createDomainCell(forTableView tableView: UITableView, withTheme theme: Theme, forIndex index: Int) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCell(withIdentifier: "DomainCell") as? PreserveLoginDomainCell else { + guard let cell = tableView.dequeueReusableCell(withIdentifier: "DomainCell") as? FireproofingDomainCell else { fatalError("Cell should be dequeued") } cell.label.textColor = theme.tableCellTextColor @@ -209,12 +221,12 @@ class PreserveLoginsSettingsViewController: UITableViewController { func clearAll() { guard !model.isEmpty else { return } - PreserveLoginsAlert.showClearAllAlert(usingController: self, cancelled: { [weak self] in + FireproofingAlert.showClearAllAlert(usingController: self, cancelled: { [weak self] in self?.refreshModel() }, confirmed: { [weak self] in Task { @MainActor in await WebCacheManager.shared.removeCookies(forDomains: self?.model ?? [], dataStore: WKWebsiteDataStore.current()) - PreserveLogins.shared.clearAll() + self?.fireproofing.clearAll() self?.refreshModel() self?.endEditing() } @@ -222,14 +234,14 @@ class PreserveLoginsSettingsViewController: UITableViewController { } func refreshModel() { - model = PreserveLogins.shared.allowedDomains.sorted(by: { (lhs, rhs) -> Bool in + model = fireproofing.allowedDomains.sorted(by: { (lhs, rhs) -> Bool in return lhs.droppingWwwPrefix() < rhs.droppingWwwPrefix() }) tableView.reloadData() } } -extension PreserveLoginsSettingsViewController { +extension FireproofingSettingsViewController { private func decorate() { let theme = ThemeManager.shared.currentTheme @@ -243,20 +255,21 @@ extension PreserveLoginsSettingsViewController { } -class PreserveLoginsSwitchCell: UITableViewCell { +class FireproofingSwitchCell: UITableViewCell { @IBOutlet weak var toggle: UISwitch! @IBOutlet weak var label: UILabel! - weak var controller: PreserveLoginsSettingsViewController! + weak var controller: FireproofingSettingsViewController! + var fireproofing: Fireproofing? @IBAction func onToggle() { - PreserveLogins.shared.loginDetectionEnabled = toggle.isOn + fireproofing?.loginDetectionEnabled = toggle.isOn } } -class PreserveLoginDomainCell: UITableViewCell { +class FireproofingDomainCell: UITableViewCell { @IBOutlet weak var faviconImage: UIImageView! @IBOutlet weak var label: UILabel! @@ -265,7 +278,7 @@ class PreserveLoginDomainCell: UITableViewCell { private extension IndexPath { - func isInSection(section: PreserveLoginsSettingsViewController.Section) -> Bool { + func isInSection(section: FireproofingSettingsViewController.Section) -> Bool { return self.section == section.rawValue } diff --git a/DuckDuckGo/PreserveLoginsWorker.swift b/DuckDuckGo/FireproofingWorking.swift similarity index 84% rename from DuckDuckGo/PreserveLoginsWorker.swift rename to DuckDuckGo/FireproofingWorking.swift index 54e98f8f58..53a976c619 100644 --- a/DuckDuckGo/PreserveLoginsWorker.swift +++ b/DuckDuckGo/FireproofingWorking.swift @@ -1,5 +1,5 @@ // -// PreserveLoginsWorker.swift +// FireproofingWorking.swift // DuckDuckGo // // Copyright © 2017 DuckDuckGo. All rights reserved. @@ -20,18 +20,19 @@ import UIKit import Core -struct PreserveLoginsWorker { +struct FireproofingWorking { private struct Constants { static let timeForAutofillToBlockFireproofPrompt = 10.0 } weak var controller: UIViewController? + let fireproofing: Fireproofing func handleLoginDetection(detectedURL: URL?, currentURL: URL?, isAutofillEnabled: Bool, saveLoginPromptLastDismissed: Date?, saveLoginPromptIsPresenting: Bool) -> Bool { guard let detectedURL = detectedURL, let currentURL = currentURL else { return false } guard let domain = detectedURL.host, domainOrPathDidChange(detectedURL, currentURL) else { return false } - guard !PreserveLogins.shared.isAllowed(fireproofDomain: domain) else { return false } + guard !fireproofing.isAllowed(fireproofDomain: domain) else { return false } if isAutofillEnabled && autofillShouldBlockPrompt(saveLoginPromptLastDismissed, saveLoginPromptIsPresenting: saveLoginPromptIsPresenting) { return false } @@ -72,23 +73,23 @@ struct PreserveLoginsWorker { private func promptToFireproof(_ domain: String) { guard let controller = controller else { return } - PreserveLoginsAlert.showFireproofWebsitePrompt(usingController: controller, forDomain: domain) { + FireproofingAlert.showFireproofWebsitePrompt(usingController: controller, forDomain: domain) { self.addDomain(domain) } } private func addDomain(_ domain: String) { guard let controller = controller else { return } - PreserveLogins.shared.addToAllowed(domain: domain) + fireproofing.addToAllowed(domain: domain) Favicons.shared.loadFavicon(forDomain: domain, intoCache: .fireproof, fromCache: .tabs) - PreserveLoginsAlert.showFireproofEnabledMessage(usingController: controller, worker: self, forDomain: domain) + FireproofingAlert.showFireproofEnabledMessage(usingController: controller, worker: self, forDomain: domain) } private func removeDomain(_ domain: String) { guard let controller = controller else { return } - PreserveLogins.shared.remove(domain: domain) + fireproofing.remove(domain: domain) Favicons.shared.removeFireproofFavicon(forDomain: domain) - PreserveLoginsAlert.showFireproofDisabledMessage(usingController: controller, worker: self, forDomain: domain) + FireproofingAlert.showFireproofDisabledMessage(usingController: controller, worker: self, forDomain: domain) } } diff --git a/DuckDuckGo/ImageCacheDebugViewController.swift b/DuckDuckGo/ImageCacheDebugViewController.swift index 1c6cd52b1c..37c6a838fe 100644 --- a/DuckDuckGo/ImageCacheDebugViewController.swift +++ b/DuckDuckGo/ImageCacheDebugViewController.swift @@ -49,6 +49,7 @@ class ImageCacheDebugViewController: UITableViewController { private let tabsModel = TabsModel.get() ?? TabsModel(desktop: false) private let bookmarksContext: NSManagedObjectContext + private let fireproofing: Fireproofing private var fireproofFavicons = [String: UIImage]() private var tabFavicons = [String: UIImage]() @@ -59,9 +60,11 @@ class ImageCacheDebugViewController: UITableViewController { private var tabs = [String: String]() init?(coder: NSCoder, - bookmarksDatabase: CoreDataDatabase) { + bookmarksDatabase: CoreDataDatabase, + fireproofing: Fireproofing = UserDefaultsFireproofing.shared) { bookmarksContext = bookmarksDatabase.makeContext(concurrencyType: .mainQueueConcurrencyType) + self.fireproofing = fireproofing super.init(coder: coder) } @@ -89,13 +92,13 @@ class ImageCacheDebugViewController: UITableViewController { } private func loadAllFireproofFavicons() { - guard let cacheUrl = Favicons.CacheType.fireproof.cacheLocation() else { return } + guard let cacheUrl = FaviconsCacheType.fireproof.cacheLocation() else { return } let fireproofCacheUrl = cacheUrl.appendingPathComponent(Constants.fireproofCachePath) fireproofFavicons = loadFaviconImages(from: fireproofCacheUrl) } private func loadAllTabFavicons() { - guard let cacheUrl = Favicons.CacheType.tabs.cacheLocation() else { return } + guard let cacheUrl = FaviconsCacheType.tabs.cacheLocation() else { return } let tabCacheUrl = cacheUrl.appendingPathComponent(Constants.tabsCachePath) tabFavicons = loadFaviconImages(from: tabCacheUrl) } @@ -141,8 +144,8 @@ class ImageCacheDebugViewController: UITableViewController { } private func loadAllFireproofSites() { - let preservedLoginSites = PreserveLogins.shared.allowedDomains - for site in preservedLoginSites { + let allowedDomains = fireproofing.allowedDomains + for site in allowedDomains { if let imageResource = Favicons.shared.defaultResource(forDomain: site) { fireproofSites[imageResource.cacheKey] = site } diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index 29364843b7..c6b5f59729 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -177,7 +177,7 @@ class MainViewController: UIViewController { fatalError("Use init?(code:") } - let preserveLogins: PreserveLogins + let fireproofing: Fireproofing let textZoomCoordinator: TextZoomCoordinating var historyManager: HistoryManaging @@ -204,7 +204,7 @@ class MainViewController: UIViewController { subscriptionFeatureAvailability: SubscriptionFeatureAvailability, voiceSearchHelper: VoiceSearchHelperProtocol, featureFlagger: FeatureFlagger, - preserveLogins: PreserveLogins = .shared, + fireproofing: Fireproofing = UserDefaultsFireproofing.shared, subscriptionCookieManager: SubscriptionCookieManaging, textZoomCoordinator: TextZoomCoordinating ) { @@ -243,7 +243,7 @@ class MainViewController: UIViewController { self.statisticsStore = statisticsStore self.subscriptionFeatureAvailability = subscriptionFeatureAvailability self.voiceSearchHelper = voiceSearchHelper - self.preserveLogins = preserveLogins + self.fireproofing = fireproofing self.subscriptionCookieManager = subscriptionCookieManager self.textZoomCoordinator = textZoomCoordinator @@ -2749,7 +2749,7 @@ extension MainViewController: AutoClearWorker { } private func forgetTextZoom() { - let allowedDomains = preserveLogins.allowedDomains + let allowedDomains = fireproofing.allowedDomains textZoomCoordinator.resetTextZoomLevels(excludingDomains: allowedDomains) } diff --git a/DuckDuckGo/RootDebugViewController.swift b/DuckDuckGo/RootDebugViewController.swift index 0283c332dd..58258a5a07 100644 --- a/DuckDuckGo/RootDebugViewController.swift +++ b/DuckDuckGo/RootDebugViewController.swift @@ -250,13 +250,15 @@ protocol DiagnosticReportDataSourceDelegate: AnyObject { class DiagnosticReportDataSource: UIActivityItemProvider { weak var delegate: DiagnosticReportDataSourceDelegate? + var fireproofing: Fireproofing? @UserDefaultsWrapper(key: .lastConfigurationRefreshDate, defaultValue: .distantPast) private var lastRefreshDate: Date - convenience init(delegate: DiagnosticReportDataSourceDelegate) { + convenience init(delegate: DiagnosticReportDataSourceDelegate, fireproofing: Fireproofing = UserDefaultsFireproofing.shared) { self.init(placeholderItem: "") self.delegate = delegate + self.fireproofing = fireproofing } override var item: Any { @@ -288,7 +290,7 @@ class DiagnosticReportDataSource: UIActivityItemProvider { } func fireproofingReport() -> String { - let allowedDomains = PreserveLogins.shared.allowedDomains.map { "* \($0)" } + let allowedDomains = fireproofing?.allowedDomains.map { "* \($0)" } ?? [] let allowedDomainsEntry = ["### Allowed Domains"] + (allowedDomains.isEmpty ? [""] : allowedDomains) diff --git a/DuckDuckGo/ScriptSourceProviding.swift b/DuckDuckGo/ScriptSourceProviding.swift index 9d1d79a2c4..61a47e794f 100644 --- a/DuckDuckGo/ScriptSourceProviding.swift +++ b/DuckDuckGo/ScriptSourceProviding.swift @@ -38,7 +38,7 @@ protocol ScriptSourceProviding { struct DefaultScriptSourceProvider: ScriptSourceProviding { - var loginDetectionEnabled: Bool { PreserveLogins.shared.loginDetectionEnabled } + var loginDetectionEnabled: Bool { fireproofing.loginDetectionEnabled } let sendDoNotSell: Bool let contentBlockerRulesConfig: ContentBlockerUserScriptConfig @@ -50,16 +50,19 @@ struct DefaultScriptSourceProvider: ScriptSourceProviding { let privacyConfigurationManager: PrivacyConfigurationManaging let contentBlockingManager: ContentBlockerRulesManagerProtocol + let fireproofing: Fireproofing init(appSettings: AppSettings = AppDependencyProvider.shared.appSettings, privacyConfigurationManager: PrivacyConfigurationManaging = ContentBlocking.shared.privacyConfigurationManager, - contentBlockingManager: ContentBlockerRulesManagerProtocol = ContentBlocking.shared.contentBlockingManager) { - + contentBlockingManager: ContentBlockerRulesManagerProtocol = ContentBlocking.shared.contentBlockingManager, + fireproofing: Fireproofing = UserDefaultsFireproofing.shared) { + sendDoNotSell = appSettings.sendDoNotSell self.privacyConfigurationManager = privacyConfigurationManager self.contentBlockingManager = contentBlockingManager - + self.fireproofing = fireproofing + contentBlockerRulesConfig = Self.buildContentBlockerRulesConfig(contentBlockingManager: contentBlockingManager, privacyConfigurationManager: privacyConfigurationManager) surrogatesConfig = Self.buildSurrogatesConfig(contentBlockingManager: contentBlockingManager, diff --git a/DuckDuckGo/SettingsLegacyViewProvider.swift b/DuckDuckGo/SettingsLegacyViewProvider.swift index dee451e380..3b74346f78 100644 --- a/DuckDuckGo/SettingsLegacyViewProvider.swift +++ b/DuckDuckGo/SettingsLegacyViewProvider.swift @@ -28,25 +28,34 @@ import Common class SettingsLegacyViewProvider: ObservableObject { + enum StoryboardName { + static let settings = "Settings" + static let homeRow = "HomeRow" + static let feedback = "Feedback" + } + let syncService: DDGSyncing let syncDataProviders: SyncDataProviders let appSettings: AppSettings let bookmarksDatabase: CoreDataDatabase let tabManager: TabManager let syncPausedStateManager: any SyncPausedStateManaging + let fireproofing: Fireproofing init(syncService: any DDGSyncing, syncDataProviders: SyncDataProviders, appSettings: any AppSettings, bookmarksDatabase: CoreDataDatabase, tabManager: TabManager, - syncPausedStateManager: any SyncPausedStateManaging) { + syncPausedStateManager: any SyncPausedStateManaging, + fireproofing: Fireproofing = UserDefaultsFireproofing.shared) { self.syncService = syncService self.syncDataProviders = syncDataProviders self.appSettings = appSettings self.bookmarksDatabase = bookmarksDatabase self.tabManager = tabManager self.syncPausedStateManager = syncPausedStateManager + self.fireproofing = fireproofing } enum LegacyView { @@ -63,28 +72,37 @@ class SettingsLegacyViewProvider: ObservableObject { feedback, debug } - + private func instantiate(_ identifier: String, fromStoryboard name: String) -> UIViewController { let storyboard = UIStoryboard(name: name, bundle: nil) return storyboard.instantiateViewController(withIdentifier: identifier) } - - // Legacy UIKit Views (Pushed unmodified) - var addToDock: UIViewController { instantiate( "instructions", fromStoryboard: "HomeRow") } - var appIcon: UIViewController { instantiate("AppIcon", fromStoryboard: "Settings") } - var gpc: UIViewController { instantiate("DoNotSell", fromStoryboard: "Settings") } - var autoConsent: UIViewController { instantiate("AutoconsentSettingsViewController", fromStoryboard: "Settings") } - var unprotectedSites: UIViewController { instantiate("UnprotectedSites", fromStoryboard: "Settings") } - var fireproofSites: UIViewController { instantiate("FireProofSites", fromStoryboard: "Settings") } - var keyboard: UIViewController { instantiate("Keyboard", fromStoryboard: "Settings") } - var feedback: UIViewController { instantiate("Feedback", fromStoryboard: "Feedback") } - var autoclearData: UIViewController { - let storyboard = UIStoryboard(name: "Settings", bundle: nil) + + private func instantiateFireproofingController() -> UIViewController { + let storyboard = UIStoryboard(name: StoryboardName.settings, bundle: nil) + return storyboard.instantiateViewController(identifier: "FireProofSites") { coder in + return FireproofingSettingsViewController(coder: coder, fireproofing: self.fireproofing) + } + } + + private func instantiateAutoClearController() -> UIViewController { + let storyboard = UIStoryboard(name: StoryboardName.settings, bundle: nil) return storyboard.instantiateViewController(identifier: "AutoClearSettingsViewController", creator: { coder in return AutoClearSettingsViewController(appSettings: self.appSettings, coder: coder) }) } + // Legacy UIKit Views (Pushed unmodified) + var addToDock: UIViewController { instantiate( "instructions", fromStoryboard: StoryboardName.homeRow) } + var appIcon: UIViewController { instantiate("AppIcon", fromStoryboard: StoryboardName.settings) } + var gpc: UIViewController { instantiate("DoNotSell", fromStoryboard: StoryboardName.settings) } + var autoConsent: UIViewController { instantiate("AutoconsentSettingsViewController", fromStoryboard: StoryboardName.settings) } + var unprotectedSites: UIViewController { instantiate("UnprotectedSites", fromStoryboard: StoryboardName.settings) } + var fireproofSites: UIViewController { instantiateFireproofingController() } + var keyboard: UIViewController { instantiate("Keyboard", fromStoryboard: StoryboardName.settings) } + var feedback: UIViewController { instantiate("Feedback", fromStoryboard: StoryboardName.feedback) } + var autoclearData: UIViewController { instantiateAutoClearController() } + @MainActor func syncSettings(source: String? = nil) -> SyncSettingsViewController { return SyncSettingsViewController(syncService: self.syncService, diff --git a/DuckDuckGo/Subscription/PrivacyProDataReporting.swift b/DuckDuckGo/Subscription/PrivacyProDataReporting.swift index a873629777..43c2150504 100644 --- a/DuckDuckGo/Subscription/PrivacyProDataReporting.swift +++ b/DuckDuckGo/Subscription/PrivacyProDataReporting.swift @@ -110,6 +110,7 @@ final class PrivacyProDataReporter: PrivacyProDataReporting { private let secureVaultMaker: () -> (any AutofillSecureVault)? private var syncService: DDGSyncing? private var tabsModel: TabsModel? + private let fireproofing: Fireproofing private let dateGenerator: () -> Date private var secureVault: (any AutofillSecureVault)? @@ -126,6 +127,7 @@ final class PrivacyProDataReporter: PrivacyProDataReporting { secureVaultMaker: @escaping () -> (any AutofillSecureVault)? = { try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter()) }, syncService: DDGSyncing? = nil, tabsModel: TabsModel? = nil, + fireproofing: Fireproofing = UserDefaultsFireproofing.shared, dateGenerator: @escaping () -> Date = Date.init) { self.configurationManager = configurationManager self.variantManager = variantManager @@ -139,6 +141,7 @@ final class PrivacyProDataReporter: PrivacyProDataReporting { self.secureVaultMaker = secureVaultMaker self.syncService = syncService self.tabsModel = tabsModel + self.fireproofing = fireproofing self.dateGenerator = dateGenerator } @@ -293,7 +296,7 @@ final class PrivacyProDataReporter: PrivacyProDataReporting { } var _fireproofedDomainsCount: Int { - PreserveLogins.shared.allowedDomains.count + fireproofing.allowedDomains.count } var _lastSessionEnded: Date? { diff --git a/DuckDuckGo/TabManager.swift b/DuckDuckGo/TabManager.swift index 9f9786fecb..2690c7b518 100644 --- a/DuckDuckGo/TabManager.swift +++ b/DuckDuckGo/TabManager.swift @@ -311,7 +311,7 @@ class TabManager { DispatchQueue.global(qos: .background).async { [weak self] in guard let self = self, - let tabsCacheUrl = Favicons.CacheType.tabs.cacheLocation()?.appendingPathComponent(Favicons.Constants.tabsCachePath), + let tabsCacheUrl = FaviconsCacheType.tabs.cacheLocation()?.appendingPathComponent(Favicons.Constants.tabsCachePath), let contents = try? FileManager.default.contentsOfDirectory(at: tabsCacheUrl, includingPropertiesForKeys: nil, options: []), !contents.isEmpty else { return } @@ -327,7 +327,7 @@ class TabManager { }) // hash the unique tab hosts - let tabLinksHashed = tabLink.map { Favicons.createHash(ofDomain: $0) } + let tabLinksHashed = tabLink.map { FaviconHasher.createHash(ofDomain: $0) } // filter images that don't have a corresponding tab let toDelete = imageDomainURLs.filter { !tabLinksHashed.contains($0) } diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index 2f8e8f90b8..a5bbd41846 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -128,7 +128,7 @@ class TabViewController: UIViewController { private var performanceMetrics: PerformanceMetricsSubfeature? private var detectedLoginURL: URL? - private var preserveLoginsWorker: PreserveLoginsWorker? + private var fireproofingWorker: FireproofingWorking? private var trackersInfoWorkItem: DispatchWorkItem? @@ -370,6 +370,7 @@ class TabViewController: UIViewController { let contextualOnboardingLogic: ContextualOnboardingLogic let onboardingPixelReporter: OnboardingCustomInteractionPixelReporting let textZoomCoordinator: TextZoomCoordinating + let fireproofing: Fireproofing required init?(coder aDecoder: NSCoder, tabModel: Tab, @@ -386,7 +387,8 @@ class TabViewController: UIViewController { urlCredentialCreator: URLCredentialCreating = URLCredentialCreator(), featureFlagger: FeatureFlagger, subscriptionCookieManager: SubscriptionCookieManaging, - textZoomCoordinator: TextZoomCoordinating) { + textZoomCoordinator: TextZoomCoordinating, + fireproofing: Fireproofing = UserDefaultsFireproofing.shared) { self.tabModel = tabModel self.appSettings = appSettings self.bookmarksDatabase = bookmarksDatabase @@ -407,6 +409,7 @@ class TabViewController: UIViewController { self.featureFlagger = featureFlagger self.subscriptionCookieManager = subscriptionCookieManager self.textZoomCoordinator = textZoomCoordinator + self.fireproofing = fireproofing super.init(coder: aDecoder) @@ -421,7 +424,7 @@ class TabViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - preserveLoginsWorker = PreserveLoginsWorker(controller: self) + fireproofingWorker = FireproofingWorking(controller: self, fireproofing: fireproofing) initAttributionLogic() decorate() addTextZoomObserver() @@ -794,14 +797,14 @@ class TabViewController: UIViewController { } func enableFireproofingForDomain(_ domain: String) { - PreserveLoginsAlert.showConfirmFireproofWebsite(usingController: self, forDomain: domain) { [weak self] in + FireproofingAlert.showConfirmFireproofWebsite(usingController: self, forDomain: domain) { [weak self] in Pixel.fire(pixel: .browsingMenuFireproof) - self?.preserveLoginsWorker?.handleUserEnablingFireproofing(forDomain: domain) + self?.fireproofingWorker?.handleUserEnablingFireproofing(forDomain: domain) } } func disableFireproofingForDomain(_ domain: String) { - preserveLoginsWorker?.handleUserDisablingFireproofing(forDomain: domain) + fireproofingWorker?.handleUserDisablingFireproofing(forDomain: domain) } func dismissContextualDaxFireDialog() { @@ -1621,18 +1624,18 @@ extension TabViewController: WKNavigationDelegate { } private func checkLoginDetectionAfterNavigation() { - if preserveLoginsWorker?.handleLoginDetection(detectedURL: detectedLoginURL, - currentURL: url, - isAutofillEnabled: AutofillSettingStatus.isAutofillEnabledInSettings, - saveLoginPromptLastDismissed: saveLoginPromptLastDismissed, - saveLoginPromptIsPresenting: saveLoginPromptIsPresenting) - ?? false { + if fireproofingWorker?.handleLoginDetection(detectedURL: detectedLoginURL, + currentURL: url, + isAutofillEnabled: AutofillSettingStatus.isAutofillEnabledInSettings, + saveLoginPromptLastDismissed: saveLoginPromptLastDismissed, + saveLoginPromptIsPresenting: saveLoginPromptIsPresenting) ?? false { + detectedLoginURL = nil saveLoginPromptLastDismissed = nil saveLoginPromptIsPresenting = false } } - + func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { Logger.general.debug("didFailNavigation; error: \(error)") adClickAttributionDetection.onDidFailNavigation() @@ -2569,7 +2572,7 @@ extension TabViewController: UserContentControllerDelegate { let tdsKey = DefaultContentBlockerRulesListsSource.Constants.trackerDataSetRulesListName let notificationsTriggeringReload = [ - PreserveLogins.Notifications.loginDetectionStateChanged, + UserDefaultsFireproofing.Notifications.loginDetectionStateChanged, AppUserDefaults.Notifications.doNotSellStatusChange ] if updateEvent.changes[tdsKey]?.contains(.unprotectedSites) == true diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index fe193e42a0..d76c6c18b2 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -173,7 +173,7 @@ extension TabViewController { private func buildKeepSignInEntry(forLink link: Link) -> BrowsingMenuEntry? { guard let domain = link.url.host, !link.url.isDuckDuckGo else { return nil } - let isFireproofed = PreserveLogins.shared.isAllowed(cookieDomain: domain) + let isFireproofed = fireproofing.isAllowed(cookieDomain: domain) if isFireproofed { return BrowsingMenuEntry.regular(name: UserText.disablePreservingLogins, diff --git a/DuckDuckGo/UIImageViewExtension.swift b/DuckDuckGo/UIImageViewExtension.swift index dc2f7bf4e0..0678c54e78 100644 --- a/DuckDuckGo/UIImageViewExtension.swift +++ b/DuckDuckGo/UIImageViewExtension.swift @@ -25,7 +25,7 @@ extension UIImageView { /// Load a favicon from the cache in to this uiview. This will not load the favicon from the network. func loadFavicon(forDomain domain: String?, - usingCache cacheType: Favicons.CacheType, + usingCache cacheType: FaviconsCacheType, useFakeFavicon: Bool = true, preferredFakeFaviconLetters: String? = nil, completion: ((UIImage?, Bool) -> Void)? = nil) { diff --git a/DuckDuckGo/UserText.swift b/DuckDuckGo/UserText.swift index 43e48a8762..b601eb9f28 100644 --- a/DuckDuckGo/UserText.swift +++ b/DuckDuckGo/UserText.swift @@ -229,19 +229,19 @@ public struct UserText { public static let onboardingDefaultBrowserTitle = NSLocalizedString("onboardingDefaultBrowserTitle", value: "Make DuckDuckGo your default browser.", comment: "") public static let onboardingDefaultBrowserMaybeLater = NSLocalizedString("onboardingDefaultBrowserMaybeLater", value: "Maybe Later", comment: "") - public static let preserveLoginsListTitle = NSLocalizedString("preserveLogins.domain.list.title", value: "Fireproof Sites", comment: "Section header above Fireproofed websites list") - public static let preserveLoginsListFooter = NSLocalizedString("preserveLogins.domain.list.footer", value: "Websites rely on cookies to keep you signed in. When you Fireproof a site, cookies won’t be erased and you’ll stay signed in, even after using the Fire Button. We still block third-party trackers found on Fireproof websites.", comment: "") - public static let preserveLoginsRemoveAll = NSLocalizedString("preserveLogins.remove.all", value: "Remove All", comment: "Alert title") - public static let preserveLoginsRemoveAllOk = NSLocalizedString("preserveLogins.remove.all.ok", value: "OK", comment: "Confirmation button in alert") + public static let fireproofingListTitle = NSLocalizedString("preserveLogins.domain.list.title", value: "Fireproof Sites", comment: "Section header above Fireproofed websites list") + public static let fireproofingListFooter = NSLocalizedString("preserveLogins.domain.list.footer", value: "Websites rely on cookies to keep you signed in. When you Fireproof a site, cookies won’t be erased and you’ll stay signed in, even after using the Fire Button. We still block third-party trackers found on Fireproof websites.", comment: "") + public static let fireproofingRemoveAllTitle = NSLocalizedString("preserveLogins.remove.all", value: "Remove All", comment: "Alert title") + public static let fireproofingRemoveAllOk = NSLocalizedString("preserveLogins.remove.all.ok", value: "OK", comment: "Confirmation button in alert") - public static let preserveLoginsFireproofAskTitle = NSLocalizedString("preserveLogins.fireproof.title", value: "Fireproof %@ to stay signed in?", comment: "Parameter is a string - domain name. Alert title prompting user to fireproof a site so they can stay signed in") - public static let preserveLoginsFireproofAskMessage = NSLocalizedString("preserveLogins.fireproof.message", value: "Fireproofing this site will keep you signed in after using the Fire Button.", comment: "Alert message explaining to users that the benefit of fireproofing a site is that they will be kept signed in") + public static let fireproofingAskTitle = NSLocalizedString("preserveLogins.fireproof.title", value: "Fireproof %@ to stay signed in?", comment: "Parameter is a string - domain name. Alert title prompting user to fireproof a site so they can stay signed in") + public static let fireproofingAskMessage = NSLocalizedString("preserveLogins.fireproof.message", value: "Fireproofing this site will keep you signed in after using the Fire Button.", comment: "Alert message explaining to users that the benefit of fireproofing a site is that they will be kept signed in") public static let enablePreservingLogins = NSLocalizedString("preserveLogins.menu.enable", value: "Fireproof This Site", comment: "Enable fireproofing for site") public static let disablePreservingLogins = NSLocalizedString("preserveLogins.menu.disable", value: "Remove Fireproofing", comment: "Disable fireproofing for site") - public static let preserveLoginsFireproofConfirmAction = NSLocalizedString("preserveLogins.menu.confirm", value: "Fireproof", comment: "Confirm fireproofing action") - public static let preserveLoginsFireproofDefer = NSLocalizedString("preserveLogins.menu.defer", value: "Not Now", comment: "Deny fireproofing action") - public static let preserveLoginsFireproofConfirmMessage = NSLocalizedString("preserveLogins.menu.confirm.message", value: "%@ is now Fireproof", comment: "Parameter is a website URL. Messege confirms that given website has been fireproofed.") - public static let preserveLoginsRemovalConfirmMessage = NSLocalizedString("preserveLogins.menu.removal.message", value: "Fireproofing removed", comment: " Messege confirms that website is no longer fireproofed.") + public static let FireproofingConfirmAction = NSLocalizedString("preserveLogins.menu.confirm", value: "Fireproof", comment: "Confirm fireproofing action") + public static let fireproofingDeferAction = NSLocalizedString("preserveLogins.menu.defer", value: "Not Now", comment: "Deny fireproofing action") + public static let fireproofingConfirmMessage = NSLocalizedString("preserveLogins.menu.confirm.message", value: "%@ is now Fireproof", comment: "Parameter is a website URL. Messege confirms that given website has been fireproofed.") + public static let fireproofingRemovalConfirmMessage = NSLocalizedString("preserveLogins.menu.removal.message", value: "Fireproofing removed", comment: " Messege confirms that website is no longer fireproofed.") public static let homeTabSearchAndFavorites = NSLocalizedString("homeTab.searchAndFavorites", value: "Search or enter address", comment: "This describes empty tab") public static let homeTabTitle = NSLocalizedString("homeTab.title", value: "Home", comment: "Home tab title") diff --git a/DuckDuckGoTests/ContentBlockingUpdatingTests.swift b/DuckDuckGoTests/ContentBlockingUpdatingTests.swift index dc68adcd9e..522187cfe0 100644 --- a/DuckDuckGoTests/ContentBlockingUpdatingTests.swift +++ b/DuckDuckGoTests/ContentBlockingUpdatingTests.swift @@ -120,7 +120,7 @@ final class ContentBlockingUpdatingTests: XCTestCase { } } - func testWhenPreserveLoginsNotificationSentThenUserScriptsAreRebuild() { + func testWhenFireproffingNotificationSentThenUserScriptsAreRebuild() { let e1 = expectation(description: "should post initial update") var e2: XCTestExpectation! @@ -141,7 +141,7 @@ final class ContentBlockingUpdatingTests: XCTestCase { withExtendedLifetime(c) { waitForExpectations(timeout: 1, handler: nil) e2 = expectation(description: "should rebuild user scripts") - NotificationCenter.default.post(name: PreserveLogins.Notifications.loginDetectionStateChanged, object: nil) + NotificationCenter.default.post(name: UserDefaultsFireproofing.Notifications.loginDetectionStateChanged, object: nil) waitForExpectations(timeout: 1, handler: nil) } } diff --git a/DuckDuckGoTests/CookieStorageTests.swift b/DuckDuckGoTests/CookieStorageTests.swift index 07927f155c..f200fc251e 100644 --- a/DuckDuckGoTests/CookieStorageTests.swift +++ b/DuckDuckGoTests/CookieStorageTests.swift @@ -26,8 +26,8 @@ public class CookieStorageTests: XCTestCase { var storage: CookieStorage! // This is updated by the `make` function which preserves any cookies added as part of this test - let logins = PreserveLogins.shared - + let fireproofing = UserDefaultsFireproofing.shared + static let userDefaultsSuiteName = "test" public override func setUp() { @@ -36,20 +36,20 @@ public class CookieStorageTests: XCTestCase { defaults.removePersistentDomain(forName: Self.userDefaultsSuiteName) storage = CookieStorage(userDefaults: defaults) storage.isConsumed = true - logins.clearAll() + fireproofing.clearAll() } func testWhenDomainRemovesAllCookesThenTheyAreClearedFromPersisted() { - logins.addToAllowed(domain: "example.com") + fireproofing.addToAllowed(domain: "example.com") XCTAssertEqual(storage.updateCookies([ make("example.com", name: "x", value: "1"), - ], keepingPreservedLogins: logins), .empty) + ], preservingFireproofedDomains: fireproofing), .empty) XCTAssertEqual(1, storage.cookies.count) storage.isConsumed = true - storage.updateCookies([], keepingPreservedLogins: logins) + storage.updateCookies([], preservingFireproofedDomains: fireproofing) XCTAssertEqual(0, storage.cookies.count) @@ -58,7 +58,7 @@ public class CookieStorageTests: XCTestCase { func testWhenUpdatedThenDuckDuckGoCookiesAreNotRemoved() { storage.updateCookies([ make("duckduckgo.com", name: "x", value: "1"), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(1, storage.cookies.count) @@ -66,7 +66,7 @@ public class CookieStorageTests: XCTestCase { storage.updateCookies([ make("duckduckgo.com", name: "x", value: "1"), make("test.com", name: "x", value: "1"), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(2, storage.cookies.count) @@ -75,7 +75,7 @@ public class CookieStorageTests: XCTestCase { make("usedev1.duckduckgo.com", name: "x", value: "1"), make("duckduckgo.com", name: "x", value: "1"), make("test.com", name: "x", value: "1"), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(3, storage.cookies.count) @@ -85,7 +85,7 @@ public class CookieStorageTests: XCTestCase { storage.updateCookies([ make("test.com", name: "x", value: "1", expires: .distantFuture), make("example.com", name: "x", value: "1"), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(2, storage.cookies.count) XCTAssertTrue(storage.cookies.contains(where: { $0.domain == "test.com" })) @@ -102,7 +102,7 @@ public class CookieStorageTests: XCTestCase { storage.isConsumed = true storage.updateCookies([ make("example.com", name: "x", value: "1"), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(1, storage.cookies.count) XCTAssertFalse(storage.cookies.contains(where: { $0.domain == "test.com" })) @@ -114,24 +114,24 @@ public class CookieStorageTests: XCTestCase { storage.updateCookies([ make("example.com", name: "x", value: "1", expires: Date(timeIntervalSinceNow: -100)), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(0, storage.cookies.count) } - func testWhenUpdatedThenNoLongerPreservedDomainsAreCleared() { + func testWhenUpdatedThenNoLongerFireproofedDomainsAreCleared() { storage.updateCookies([ make("test.com", name: "x", value: "1"), make("example.com", name: "x", value: "1"), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) - logins.remove(domain: "test.com") + fireproofing.remove(domain: "test.com") storage.isConsumed = true storage.updateCookies([ make("example.com", name: "x", value: "1"), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(1, storage.cookies.count) XCTAssertFalse(storage.cookies.contains(where: { $0.domain == "test.com" })) @@ -148,14 +148,14 @@ public class CookieStorageTests: XCTestCase { XCTAssertTrue(storage.isConsumed) storage.updateCookies([ make("test.com", name: "x", value: "1") - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertFalse(storage.isConsumed) } func testWhenStorageIsReinstanciatedThenUsesStoredData() { storage.updateCookies([ make("test.com", name: "x", value: "1") - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) storage.isConsumed = true let otherStorage = CookieStorage(userDefaults: UserDefaults(suiteName: Self.userDefaultsSuiteName)!) @@ -166,20 +166,20 @@ public class CookieStorageTests: XCTestCase { func testWhenStorageIsUpdatedThenUpdatingAddsNewCookies() { storage.updateCookies([ make("test.com", name: "x", value: "1") - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(1, storage.cookies.count) } func testWhenStorageHasMatchingDOmainThenUpdatingReplacesCookies() { storage.updateCookies([ make("test.com", name: "x", value: "1") - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) storage.isConsumed = true storage.updateCookies([ make("test.com", name: "x", value: "2"), make("test.com", name: "y", value: "3"), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(2, storage.cookies.count) XCTAssertFalse(storage.cookies.contains(where: { $0.domain == "test.com" && $0.name == "x" && $0.value == "1" })) @@ -190,18 +190,18 @@ public class CookieStorageTests: XCTestCase { func testWhenStorageUpdatedAndNotConsumedThenNothingHappens() { storage.updateCookies([ make("test.com", name: "x", value: "1") - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) storage.updateCookies([ make("example.com", name: "y", value: "3"), - ], keepingPreservedLogins: logins) + ], preservingFireproofedDomains: fireproofing) XCTAssertEqual(1, storage.cookies.count) XCTAssertTrue(storage.cookies.contains(where: { $0.domain == "test.com" && $0.name == "x" && $0.value == "1" })) } func make(_ domain: String, name: String, value: String, expires: Date? = nil) -> HTTPCookie { - logins.addToAllowed(domain: domain) + fireproofing.addToAllowed(domain: domain) return HTTPCookie(properties: [ .domain: domain, .name: name, diff --git a/DuckDuckGoTests/FaviconRequestModifierTests.swift b/DuckDuckGoTests/FaviconRequestModifierTests.swift index a13b3ec0bd..53d31c1472 100644 --- a/DuckDuckGoTests/FaviconRequestModifierTests.swift +++ b/DuckDuckGoTests/FaviconRequestModifierTests.swift @@ -21,6 +21,7 @@ import BrowserServicesKit import XCTest @testable import Core +@testable import DuckDuckGo class MockEmbeddedDataProvider: EmbeddedDataProvider { var embeddedDataEtag: String diff --git a/DuckDuckGoTests/FaviconSourcesProviderTests.swift b/DuckDuckGoTests/FaviconSourcesProviderTests.swift index e7f6aa5932..7e15e0f72a 100644 --- a/DuckDuckGoTests/FaviconSourcesProviderTests.swift +++ b/DuckDuckGoTests/FaviconSourcesProviderTests.swift @@ -18,7 +18,9 @@ // import XCTest + @testable import Core +@testable import DuckDuckGo class FaviconSourcesProviderTests: XCTestCase { diff --git a/DuckDuckGoTests/FaviconsTests.swift b/DuckDuckGoTests/FaviconsTests.swift index ddbb966caf..68a1303c33 100644 --- a/DuckDuckGoTests/FaviconsTests.swift +++ b/DuckDuckGoTests/FaviconsTests.swift @@ -23,6 +23,7 @@ import Kingfisher import XCTest @testable import Core +@testable import DuckDuckGo class FaviconsTests: XCTestCase { @@ -110,7 +111,7 @@ class FaviconsTests: XCTestCase { func testWhenGeneratingKingfisherResourceThenCorrectKeyAndURLAreGenerated() { let resource = favicons.defaultResource(forDomain: Constants.exampleDomain) - XCTAssertEqual(resource?.cacheKey, "\(Favicons.Constants.salt)\(Constants.exampleDomain)".sha256()) + XCTAssertEqual(resource?.cacheKey, "\(FaviconHasher.salt)\(Constants.exampleDomain)".sha256()) XCTAssertEqual(resource?.downloadURL, URL(string: "https://example.com/apple-touch-icon.png")) } diff --git a/DuckDuckGoTests/FireButtonReferenceTests.swift b/DuckDuckGoTests/FireButtonReferenceTests.swift index 2a92662ec5..5ab2d225c3 100644 --- a/DuckDuckGoTests/FireButtonReferenceTests.swift +++ b/DuckDuckGoTests/FireButtonReferenceTests.swift @@ -48,13 +48,13 @@ final class FireButtonReferenceTests: XCTestCase { @MainActor func testClearDataUsingLegacyContainer() async throws { // Using WKWebsiteDataStore(forIdentifier:) doesn't persist cookies in a testable way, so use the legacy container here. - let preservedLogins = PreserveLogins.shared - preservedLogins.clearAll() + let fireproofing = UserDefaultsFireproofing.shared + fireproofing.clearAll() for site in testData.fireButtonFireproofing.fireproofedSites { let sanitizedSite = sanitizedSite(site) print("Adding %s to fireproofed sites", sanitizedSite) - preservedLogins.addToAllowed(domain: sanitizedSite) + fireproofing.addToAllowed(domain: sanitizedSite) } let referenceTests = testData.fireButtonFireproofing.tests.filter { @@ -75,7 +75,7 @@ final class FireButtonReferenceTests: XCTestCase { // Pretend the webview was loaded and the cookies were previously consumed cookieStorage.isConsumed = true - await WebCacheManager.shared.clear(cookieStorage: cookieStorage, logins: preservedLogins, dataStoreIdManager: DataStoreIdManager(store: MockKeyValueStore())) + await WebCacheManager.shared.clear(cookieStorage: cookieStorage, fireproofing: fireproofing, dataStoreIdManager: DataStoreIdManager(store: MockKeyValueStore())) let testCookie = cookieStorage.cookies.filter { $0.name == test.cookieName }.first @@ -92,13 +92,13 @@ final class FireButtonReferenceTests: XCTestCase { } func testCookieStorage() throws { - let preservedLogins = PreserveLogins.shared - preservedLogins.clearAll() + let fireproofing = UserDefaultsFireproofing.shared + fireproofing.clearAll() for site in testData.fireButtonFireproofing.fireproofedSites { let sanitizedSite = sanitizedSite(site) print("Adding %s to fireproofed sites", sanitizedSite) - preservedLogins.addToAllowed(domain: sanitizedSite) + fireproofing.addToAllowed(domain: sanitizedSite) } let referenceTests = testData.fireButtonFireproofing.tests.filter { @@ -116,7 +116,7 @@ final class FireButtonReferenceTests: XCTestCase { // This simulates loading the cookies from the current web view data stores and updating the storage cookieStorage.updateCookies([ cookie - ], keepingPreservedLogins: preservedLogins) + ], preservingFireproofedDomains: fireproofing) let testCookie = cookieStorage.cookies.filter { $0.name == test.cookieName }.first diff --git a/DuckDuckGoTests/FireproofFaviconUpdaterTests.swift b/DuckDuckGoTests/FireproofFaviconUpdaterTests.swift index 3a1925f62d..eceebc598c 100644 --- a/DuckDuckGoTests/FireproofFaviconUpdaterTests.swift +++ b/DuckDuckGoTests/FireproofFaviconUpdaterTests.swift @@ -34,7 +34,7 @@ class FireproofFaviconUpdaterTests: XCTestCase, TabNotifying, FaviconProviding { var loadFaviconDomain: String? var loadFaviconURL: URL? - var loadFaviconCache: Favicons.CacheType? + var loadFaviconCache: FaviconsCacheType? var image: UIImage? @@ -120,7 +120,7 @@ class FireproofFaviconUpdaterTests: XCTestCase, TabNotifying, FaviconProviding { didUpdateFaviconCalled = true } - func loadFavicon(forDomain domain: String, fromURL url: URL?, intoCache cacheType: Favicons.CacheType, completion: ((UIImage?) -> Void)?) { + func loadFavicon(forDomain domain: String, fromURL url: URL?, intoCache cacheType: FaviconsCacheType, completion: ((UIImage?) -> Void)?) { loadFaviconDomain = domain loadFaviconURL = url loadFaviconCache = cacheType diff --git a/DuckDuckGoTests/MockFaviconStore.swift b/DuckDuckGoTests/MockFaviconStore.swift new file mode 100644 index 0000000000..087fbd4fb3 --- /dev/null +++ b/DuckDuckGoTests/MockFaviconStore.swift @@ -0,0 +1,30 @@ +// +// MockFaviconStore.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation +@testable import Bookmarks + +class MockFaviconStore: FaviconStoring { + func hasFavicon(for domain: String) -> Bool { + return false + } + + func storeFavicon(_ imageData: Data, with url: URL?, for documentURL: URL) async throws { + } +} diff --git a/DuckDuckGoTests/NotFoundCachingDownloaderTests.swift b/DuckDuckGoTests/NotFoundCachingDownloaderTests.swift index 661e14f46e..85112a9274 100644 --- a/DuckDuckGoTests/NotFoundCachingDownloaderTests.swift +++ b/DuckDuckGoTests/NotFoundCachingDownloaderTests.swift @@ -20,6 +20,7 @@ import XCTest @testable import Core +@testable import DuckDuckGo class NotFoundCachingDownloaderTests: XCTestCase { @@ -38,6 +39,12 @@ class NotFoundCachingDownloaderTests: XCTestCase { super.tearDown() } + // If this test fails... ask yourself why have you changed the salt? + // If it was intentional, then please update this test. + func testSaltValueHasNotChanged() { + XCTAssertEqual("DDGSalt:", FaviconHasher.salt) + } + func testWhenURLSavedNotStoredInPlainText() { downloader.noFaviconsFound(forDomain: "example.com") @@ -49,7 +56,7 @@ class NotFoundCachingDownloaderTests: XCTestCase { XCTAssertEqual(1, domains.count) domains.forEach { - XCTAssertEqual($0.key, "\(Favicons.Constants.salt)example.com".sha256()) + XCTAssertEqual($0.key, "\(FaviconHasher.salt)example.com".sha256()) } } diff --git a/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift b/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift index 99ad0e1b60..3aa6866fb5 100644 --- a/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift +++ b/DuckDuckGoTests/OnboardingDaxFavouritesTests.swift @@ -44,7 +44,8 @@ final class OnboardingDaxFavouritesTests: XCTestCase { secureVaultErrorReporter: SecureVaultReporter(), settingHandlers: [], favoritesDisplayModeStorage: MockFavoritesDisplayModeStoring(), - syncErrorHandler: SyncErrorHandler() + syncErrorHandler: SyncErrorHandler(), + faviconStoring: MockFaviconStore() ) let remoteMessagingClient = RemoteMessagingClient( diff --git a/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift b/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift index 3f1762975b..52e2da5b9a 100644 --- a/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift +++ b/DuckDuckGoTests/OnboardingNavigationDelegateTests.swift @@ -44,7 +44,8 @@ final class OnboardingNavigationDelegateTests: XCTestCase { secureVaultErrorReporter: SecureVaultReporter(), settingHandlers: [], favoritesDisplayModeStorage: MockFavoritesDisplayModeStoring(), - syncErrorHandler: SyncErrorHandler() + syncErrorHandler: SyncErrorHandler(), + faviconStoring: MockFaviconStore() ) let remoteMessagingClient = RemoteMessagingClient( diff --git a/DuckDuckGoTests/SyncBookmarksAdapterTests.swift b/DuckDuckGoTests/SyncBookmarksAdapterTests.swift index acf9a6da12..89e2050513 100644 --- a/DuckDuckGoTests/SyncBookmarksAdapterTests.swift +++ b/DuckDuckGoTests/SyncBookmarksAdapterTests.swift @@ -48,7 +48,8 @@ final class SyncBookmarksAdapterTests: XCTestCase { options: [:]) adapter = SyncBookmarksAdapter(database: database, favoritesDisplayModeStorage: MockFavoriteDisplayModeStorage(), - syncErrorHandler: errorHandler) + syncErrorHandler: errorHandler, + faviconStoring: MockFaviconStore()) cancellables = [] } diff --git a/DuckDuckGoTests/SyncSettingsViewControllerErrorTests.swift b/DuckDuckGoTests/SyncSettingsViewControllerErrorTests.swift index 42b94cc253..9d3e2fb551 100644 --- a/DuckDuckGoTests/SyncSettingsViewControllerErrorTests.swift +++ b/DuckDuckGoTests/SyncSettingsViewControllerErrorTests.swift @@ -49,7 +49,8 @@ final class SyncSettingsViewControllerErrorTests: XCTestCase { let bookmarksAdapter = SyncBookmarksAdapter( database: database, favoritesDisplayModeStorage: MockFavoritesDisplayModeStoring(), - syncErrorHandler: CapturingAdapterErrorHandler()) + syncErrorHandler: CapturingAdapterErrorHandler(), + faviconStoring: MockFaviconStore()) let credentialsAdapter = SyncCredentialsAdapter( secureVaultErrorReporter: MockSecureVaultReporting(), syncErrorHandler: CapturingAdapterErrorHandler()) diff --git a/DuckDuckGoTests/PreserveLoginsTests.swift b/DuckDuckGoTests/UserDefaultsFireproofingTests.swift similarity index 67% rename from DuckDuckGoTests/PreserveLoginsTests.swift rename to DuckDuckGoTests/UserDefaultsFireproofingTests.swift index 921fad110f..58154219d1 100644 --- a/DuckDuckGoTests/PreserveLoginsTests.swift +++ b/DuckDuckGoTests/UserDefaultsFireproofingTests.swift @@ -1,5 +1,5 @@ // -// PreserveLoginsTests.swift +// UserDefaultsFireproofingTests.swift // UnitTests // // Copyright © 2020 DuckDuckGo. All rights reserved. @@ -20,7 +20,7 @@ import XCTest @testable import Core -class PreserveLoginsTests: XCTestCase { +class UserDefaultsFireproofingTests: XCTestCase { override func setUp() { super.setUp() @@ -29,15 +29,15 @@ class PreserveLoginsTests: XCTestCase { } func testWhenAllowedDomainsContainsFireproofedDomainThenReturnsTrue() { - let logins = PreserveLogins() - XCTAssertFalse(logins.isAllowed(fireproofDomain: "example.com")) - logins.addToAllowed(domain: "example.com") - XCTAssertTrue(logins.isAllowed(fireproofDomain: "example.com")) + let fireproofing = UserDefaultsFireproofing() + XCTAssertFalse(fireproofing.isAllowed(fireproofDomain: "example.com")) + fireproofing.addToAllowed(domain: "example.com") + XCTAssertTrue(fireproofing.isAllowed(fireproofDomain: "example.com")) } func testWhenNewThenAllowedDomainsIsEmpty() { - let logins = PreserveLogins() - XCTAssertTrue(logins.allowedDomains.isEmpty) + let fireproofing = UserDefaultsFireproofing() + XCTAssertTrue(fireproofing.allowedDomains.isEmpty) } } diff --git a/DuckDuckGoTests/WebCacheManagerTests.swift b/DuckDuckGoTests/WebCacheManagerTests.swift index 94c1f7dd20..196762db89 100644 --- a/DuckDuckGoTests/WebCacheManagerTests.swift +++ b/DuckDuckGoTests/WebCacheManagerTests.swift @@ -41,19 +41,20 @@ class WebCacheManagerTests: XCTestCase { @available(iOS 17, *) @MainActor func testEnsureIdAllocatedAfterClearing() async throws { - let logins = MockPreservedLogins(domains: []) + let fireproofing = MockFireproofing(domains: []) + let storage = CookieStorage() let inMemoryDataStoreIdManager = DataStoreIdManager(store: MockKeyValueStore()) XCTAssertNil(inMemoryDataStoreIdManager.currentId) - await WebCacheManager.shared.clear(cookieStorage: storage, logins: logins, dataStoreIdManager: inMemoryDataStoreIdManager) + await WebCacheManager.shared.clear(cookieStorage: storage, fireproofing: fireproofing, dataStoreIdManager: inMemoryDataStoreIdManager) XCTAssertNotNil(inMemoryDataStoreIdManager.currentId) let oldId = inMemoryDataStoreIdManager.currentId?.uuidString XCTAssertNotNil(oldId) - await WebCacheManager.shared.clear(cookieStorage: storage, logins: logins, dataStoreIdManager: inMemoryDataStoreIdManager) + await WebCacheManager.shared.clear(cookieStorage: storage, fireproofing: fireproofing, dataStoreIdManager: inMemoryDataStoreIdManager) XCTAssertNotNil(inMemoryDataStoreIdManager.currentId) XCTAssertNotEqual(inMemoryDataStoreIdManager.currentId?.uuidString, oldId) @@ -62,9 +63,7 @@ class WebCacheManagerTests: XCTestCase { @available(iOS 17, *) @MainActor func testWhenCookiesHaveSubDomainsOnSubDomainsAndWidlcardsThenOnlyMatchingCookiesRetained() async throws { - let logins = MockPreservedLogins(domains: [ - "mobile.twitter.com" - ]) + let fireproofing = MockFireproofing(domains: ["mobile.twitter.com"]) let defaultStore = WKWebsiteDataStore.default() await defaultStore.removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: .distantPast) @@ -82,7 +81,7 @@ class WebCacheManagerTests: XCTestCase { XCTAssertEqual(5, loadedCount) let cookieStore = CookieStorage() - await WebCacheManager.shared.clear(cookieStorage: cookieStore, logins: logins, dataStoreIdManager: DataStoreIdManager(store: MockKeyValueStore())) + await WebCacheManager.shared.clear(cookieStorage: cookieStore, fireproofing: fireproofing, dataStoreIdManager: DataStoreIdManager(store: MockKeyValueStore())) let cookies = await defaultStore.httpCookieStore.allCookies() XCTAssertEqual(cookies.count, 0) @@ -113,9 +112,7 @@ class WebCacheManagerTests: XCTestCase { @MainActor func testWhenClearedThenCookiesWithParentDomainsAreRetained() async { - let logins = MockPreservedLogins(domains: [ - "www.example.com" - ]) + let fireproofing = MockFireproofing(domains: ["www.example.com"]) let defaultStore = WKWebsiteDataStore.default() await defaultStore.removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: .distantPast) @@ -130,7 +127,7 @@ class WebCacheManagerTests: XCTestCase { let cookieStorage = CookieStorage() await WebCacheManager.shared.clear(cookieStorage: cookieStorage, - logins: logins, + fireproofing: fireproofing, dataStoreIdManager: DataStoreIdManager(store: MockKeyValueStore())) let cookies = await defaultStore.httpCookieStore.allCookies() @@ -150,9 +147,7 @@ class WebCacheManagerTests: XCTestCase { @MainActor func testWhenClearedWithLegacyContainerThenDDGCookiesAreRetained() async { - let logins = MockPreservedLogins(domains: [ - "www.example.com" - ]) + let fireproofing = MockFireproofing(domains: ["www.example.com"]) let cookieStore = WKWebsiteDataStore.default().httpCookieStore await cookieStore.setCookie(.make(name: "name", value: "value", domain: "duckduckgo.com")) @@ -161,7 +156,7 @@ class WebCacheManagerTests: XCTestCase { let storage = CookieStorage() storage.isConsumed = true - await WebCacheManager.shared.clear(cookieStorage: storage, logins: logins, dataStoreIdManager: DataStoreIdManager(store: MockKeyValueStore())) + await WebCacheManager.shared.clear(cookieStorage: storage, fireproofing: fireproofing, dataStoreIdManager: DataStoreIdManager(store: MockKeyValueStore())) XCTAssertEqual(storage.cookies.count, 2) XCTAssertTrue(storage.cookies.contains(where: { $0.domain == "duckduckgo.com" })) @@ -170,9 +165,7 @@ class WebCacheManagerTests: XCTestCase { @MainActor func testWhenClearedThenCookiesForLoginsAreRetained() async { - let logins = MockPreservedLogins(domains: [ - "www.example.com" - ]) + let fireproofing = MockFireproofing(domains: ["www.example.com"]) let defaultStore = WKWebsiteDataStore.default() await defaultStore.removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: .distantPast) @@ -188,7 +181,7 @@ class WebCacheManagerTests: XCTestCase { let cookieStore = CookieStorage() - await WebCacheManager.shared.clear(cookieStorage: cookieStore, logins: logins, dataStoreIdManager: DataStoreIdManager(store: MockKeyValueStore())) + await WebCacheManager.shared.clear(cookieStorage: cookieStore, fireproofing: fireproofing, dataStoreIdManager: DataStoreIdManager(store: MockKeyValueStore())) let cookies = await defaultStore.httpCookieStore.allCookies() XCTAssertEqual(cookies.count, 0) @@ -202,21 +195,18 @@ class WebCacheManagerTests: XCTestCase { let pool = WebCacheManager.shared.getValidDatabasePool() XCTAssertNotNil(pool, "DatabasePool should not be nil") } - + // MARK: Mocks - class MockPreservedLogins: PreserveLogins { - - let domains: [String] - + class MockFireproofing: UserDefaultsFireproofing { override var allowedDomains: [String] { return domains } - + + let domains: [String] init(domains: [String]) { self.domains = domains } - } } diff --git a/Widgets/Widgets.swift b/Widgets/Widgets.swift index 4972055a03..8e545bb352 100644 --- a/Widgets/Widgets.swift +++ b/Widgets/Widgets.swift @@ -142,8 +142,8 @@ class Provider: TimelineProvider { private func loadImageFromCache(forDomain domain: String?) -> UIImage? { guard let domain = domain else { return nil } - let key = Favicons.createHash(ofDomain: domain) - guard let cacheUrl = Favicons.CacheType.fireproof.cacheLocation() else { return nil } + let key = FaviconHasher.createHash(ofDomain: domain) + guard let cacheUrl = FaviconsCacheType.fireproof.cacheLocation() else { return nil } // Slight leap here to avoid loading Kingisher as a library for the widgets. // Once dependency management is fixed, link it and use Favicons directly. From f457a126b9351a8b26b53bed68db1e0c33d9d378 Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Thu, 21 Nov 2024 18:14:54 +0100 Subject: [PATCH 44/56] Update BSK with a C-S-S fix (#3608) Task/Issue URL: https://app.asana.com/0/0/1208817367615044/f Description: This change updates BSK to a fixed version of C-S-S. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index c87afcfbce..6de16b80d8 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -11040,7 +11040,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 211.0.0; + version = "211.0.0-1"; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index cdb32f0f44..698266001d 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "7033b0d6f166ac8152cff602f1a1301641f4da60", - "version" : "211.0.0" + "revision" : "135c63a3058b975cbc2d00ce637f3b9727b717ae", + "version" : "211.0.0-1" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "f2caf4ff814f4714d07d6fc2cf02498cb54a1389", - "version" : "6.36.0" + "revision" : "dfef00ef77f5181d1d8a4f7cc88f7b7c0514dd34", + "version" : "6.39.0" } }, { From 5d783283ae005e949565a20ae9457a409df6775c Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Thu, 21 Nov 2024 18:46:42 +0100 Subject: [PATCH 45/56] Bump BSK to 211.1.1 (#3609) Task/Issue URL: https://app.asana.com/0/414235014887631/1208817367615044/f Description: This bumps BSK dependency to the latest version including 211.0.0-1 hotfix. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 654bc03135..d0ed57f355 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -11046,7 +11046,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 211.1.0; + version = 211.1.1; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index bb0f553a9f..b5441c5a73 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "ce0223a5cc5e404867be5e691f5df1de9ea24387", - "version" : "211.1.0" + "revision" : "b18e710f5377f494b98b91019b774d79f2cfaf2a", + "version" : "211.1.1" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "6f8b28d98bee6e15c4020d46577143d49619c248", - "version" : "6.38.0" + "revision" : "dfef00ef77f5181d1d8a4f7cc88f7b7c0514dd34", + "version" : "6.39.0" } }, { From 9e63dd35fe6d686e2c02805327ea9bbdc73f4567 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Thu, 21 Nov 2024 15:28:27 -0800 Subject: [PATCH 46/56] Release 7.146.0-2 (#3610) Please make sure all GH checks passed before merging. It can take around 20 minutes. Briefly review this PR to see if there are no issues or red flags and then merge it. --- DuckDuckGo.xcodeproj/project.pbxproj | 56 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 6de16b80d8..cfdce4641b 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9257,7 +9257,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -9294,7 +9294,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9384,7 +9384,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9411,7 +9411,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9558,7 +9558,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9583,7 +9583,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9652,7 +9652,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -9686,7 +9686,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9719,7 +9719,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9749,7 +9749,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10059,7 +10059,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10090,7 +10090,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10118,7 +10118,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10151,7 +10151,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -10181,7 +10181,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -10214,11 +10214,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10450,7 +10450,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10478,7 +10478,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10510,7 +10510,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10547,7 +10547,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10582,7 +10582,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10617,11 +10617,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10794,11 +10794,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10827,10 +10827,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; From 3525099a8798d10c138fdafc1b38feda7118e59e Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Thu, 21 Nov 2024 17:59:34 -0800 Subject: [PATCH 47/56] Expand persistent pixel usage (#3596) Task/Issue URL: https://app.asana.com/0/72649045549333/1208802635345012/f Tech Design URL: CC: Description: This PR updates pixel persistence to cover server migration and tunnel updates. --- ...etworkProtectionPacketTunnelProvider.swift | 50 +++++++++++++------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift b/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift index 5f8d7d5f19..1f485fb540 100644 --- a/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift +++ b/PacketTunnelProvider/NetworkProtection/NetworkProtectionPacketTunnelProvider.swift @@ -212,15 +212,26 @@ final class NetworkProtectionPacketTunnelProvider: PacketTunnelProvider { switch step { case .begin: - DailyPixel.fireDailyAndCount(pixel: .networkProtectionTunnelUpdateAttempt, - pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes) + persistentPixel.fireDailyAndCount( + pixel: .networkProtectionTunnelUpdateAttempt, + pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes, + error: nil, + withAdditionalParameters: [:], + includedParameters: [.appVersion]) { _ in } case .failure(let error): - DailyPixel.fireDailyAndCount(pixel: .networkProtectionTunnelUpdateFailure, - pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes, - error: error) + persistentPixel.fireDailyAndCount( + pixel: .networkProtectionTunnelUpdateFailure, + pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes, + error: error, + withAdditionalParameters: [:], + includedParameters: [.appVersion]) { _ in } case .success: - DailyPixel.fireDailyAndCount(pixel: .networkProtectionTunnelUpdateSuccess, - pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes) + persistentPixel.fireDailyAndCount( + pixel: .networkProtectionTunnelUpdateSuccess, + pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes, + error: nil, + withAdditionalParameters: [:], + includedParameters: [.appVersion]) { _ in } } case .tunnelWakeAttempt(let step): vpnLogger.log(step, named: "Tunnel Wake") @@ -259,15 +270,26 @@ final class NetworkProtectionPacketTunnelProvider: PacketTunnelProvider { switch step { case .begin: - DailyPixel.fireDailyAndCount(pixel: .networkProtectionServerMigrationAttempt, - pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes) + persistentPixel.fireDailyAndCount( + pixel: .networkProtectionServerMigrationAttempt, + pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes, + error: nil, + withAdditionalParameters: [:], + includedParameters: [.appVersion]) { _ in } case .failure(let error): - DailyPixel.fireDailyAndCount(pixel: .networkProtectionServerMigrationAttemptFailure, - pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes, - error: error) + persistentPixel.fireDailyAndCount( + pixel: .networkProtectionServerMigrationAttemptFailure, + pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes, + error: error, + withAdditionalParameters: [:], + includedParameters: [.appVersion]) { _ in } case .success: - DailyPixel.fireDailyAndCount(pixel: .networkProtectionServerMigrationAttemptSuccess, - pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes) + persistentPixel.fireDailyAndCount( + pixel: .networkProtectionServerMigrationAttemptSuccess, + pixelNameSuffixes: DailyPixel.Constant.legacyDailyPixelSuffixes, + error: nil, + withAdditionalParameters: [:], + includedParameters: [.appVersion]) { _ in } } case .tunnelStartOnDemandWithoutAccessToken: vpnLogger.logStartingWithoutAuthToken() From 079d76d6b16db7942a4c310ac0dc945adff41160 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Thu, 21 Nov 2024 19:04:39 -0800 Subject: [PATCH 48/56] Add delay when shutting down VPN due to error (#3579) Task/Issue URL: https://app.asana.com/0/1207603085593419/1208772807738114/f Tech Design URL: CC: Description: This PR adds a short delay before shutting down the VPN due to an error. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 53adb02176..da4d366057 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -11046,7 +11046,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 211.1.1; + version = 211.1.2; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b5441c5a73..99e58d2d10 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/DuckDuckGo/BrowserServicesKit", "state" : { - "revision" : "b18e710f5377f494b98b91019b774d79f2cfaf2a", - "version" : "211.1.1" + "revision" : "deacf613553334f35053a2092d4e062e4775544c", + "version" : "211.1.2" } }, { From 6abbc1148eddf4ee345917768252f10e8922ee90 Mon Sep 17 00:00:00 2001 From: Lorenzo Mattei Date: Fri, 22 Nov 2024 15:15:17 +0100 Subject: [PATCH 49/56] Disable asana reporting on test failures (#3603) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/0/1208804974015521/f Tech Design URL: CC: **Description**: We have experienced issues with e2e tests reliability due to CI instability for quite a long time now and we are at a point where we don't investigate failures anymore. Because of this, reporting test failures in Asana only adds noise for the maintenance DRI. This PR disables reporting, while we work to stabilise the tests. **Steps to test this PR**: 1. Verify CI is green. --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- .github/workflows/end-to-end.yml | 26 +++++++++++++------------- .github/workflows/sync-end-to-end.yml | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/end-to-end.yml b/.github/workflows/end-to-end.yml index cd3cbe1299..20ed48ea18 100644 --- a/.github/workflows/end-to-end.yml +++ b/.github/workflows/end-to-end.yml @@ -95,17 +95,17 @@ jobs: run: | export PATH="$PATH":"$HOME/.maestro/bin"; maestro cloud --apiKey ${{ secrets.MAESTRO_CLOUD_API_KEY }} -e ONBOARDING_COMPLETED=true --fail-on-timeout=true --fail-on-cancellation=true --timeout=150 --ios-version=17 --include-tags=${{ matrix.test-tag }} DerivedData/Build/Products/Debug-iphonesimulator/DuckDuckGo.app .maestro/ - notify-failure: - name: Notify on failure - if: ${{ always() && contains(join(needs.*.result, ','), 'failure') && github.ref_name == 'main' }} - needs: [build-end-to-end-tests, end-to-end-tests] - runs-on: ubuntu-latest + # notify-failure: + # name: Notify on failure + # if: ${{ always() && contains(join(needs.*.result, ','), 'failure') && github.ref_name == 'main' }} + # needs: [build-end-to-end-tests, end-to-end-tests] + # runs-on: ubuntu-latest - steps: - - name: Create Asana task when workflow failed - run: | - curl -s "https://app.asana.com/api/1.0/tasks" \ - --header "Accept: application/json" \ - --header "Authorization: Bearer ${{ secrets.ASANA_ACCESS_TOKEN }}" \ - --header "Content-Type: application/json" \ - --data ' { "data": { "name": "GH Workflow Failure - End to end tests", "workspace": "${{ vars.GH_ASANA_WORKSPACE_ID }}", "projects": [ "${{ vars.GH_ASANA_IOS_APP_PROJECT_ID }}" ], "notes" : "The end to end workflow has failed. See https://github.com/duckduckgo/iOS/actions/runs/${{ github.run_id }}. For instructions on how to handle the failure(s), check https://app.asana.com/0/0/1206423571874502/f" } }' + # steps: + # - name: Create Asana task when workflow failed + # run: | + # curl -s "https://app.asana.com/api/1.0/tasks" \ + # --header "Accept: application/json" \ + # --header "Authorization: Bearer ${{ secrets.ASANA_ACCESS_TOKEN }}" \ + # --header "Content-Type: application/json" \ + # --data ' { "data": { "name": "GH Workflow Failure - End to end tests", "workspace": "${{ vars.GH_ASANA_WORKSPACE_ID }}", "projects": [ "${{ vars.GH_ASANA_IOS_APP_PROJECT_ID }}" ], "notes" : "The end to end workflow has failed. See https://github.com/duckduckgo/iOS/actions/runs/${{ github.run_id }}. For instructions on how to handle the failure(s), check https://app.asana.com/0/0/1206423571874502/f" } }' diff --git a/.github/workflows/sync-end-to-end.yml b/.github/workflows/sync-end-to-end.yml index c70dc3ef37..e96a5769ef 100644 --- a/.github/workflows/sync-end-to-end.yml +++ b/.github/workflows/sync-end-to-end.yml @@ -108,20 +108,20 @@ jobs: run: | git checkout .maestro/config.yaml - notify-failure: - name: Notify on failure - if: ${{ always() && contains(join(needs.*.result, ','), 'failure') && github.ref_name == 'main' }} - needs: [build-for-sync-end-to-end-tests, sync-end-to-end-tests] - runs-on: ubuntu-latest + # notify-failure: + # name: Notify on failure + # if: ${{ always() && contains(join(needs.*.result, ','), 'failure') && github.ref_name == 'main' }} + # needs: [build-for-sync-end-to-end-tests, sync-end-to-end-tests] + # runs-on: ubuntu-latest - steps: - - name: Create Asana task when workflow failed - run: | - curl -s "https://app.asana.com/api/1.0/tasks" \ - --header "Accept: application/json" \ - --header "Authorization: Bearer ${{ secrets.ASANA_ACCESS_TOKEN }}" \ - --header "Content-Type: application/json" \ - --data ' { "data": { "name": "GH Workflow Failure - Sync End to end tests", "workspace": "${{ vars.GH_ASANA_WORKSPACE_ID }}", "projects": [ "${{ vars.GH_ASANA_IOS_APP_PROJECT_ID }}" ], "notes" : "The end to end workflow has failed. See https://github.com/duckduckgo/iOS/actions/runs/${{ github.run_id }}" } }' + # steps: + # - name: Create Asana task when workflow failed + # run: | + # curl -s "https://app.asana.com/api/1.0/tasks" \ + # --header "Accept: application/json" \ + # --header "Authorization: Bearer ${{ secrets.ASANA_ACCESS_TOKEN }}" \ + # --header "Content-Type: application/json" \ + # --data ' { "data": { "name": "GH Workflow Failure - Sync End to end tests", "workspace": "${{ vars.GH_ASANA_WORKSPACE_ID }}", "projects": [ "${{ vars.GH_ASANA_IOS_APP_PROJECT_ID }}" ], "notes" : "The end to end workflow has failed. See https://github.com/duckduckgo/iOS/actions/runs/${{ github.run_id }}" } }' From 3f3e9aae1183011213d9de4d4eeed43f08b1b8a8 Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Fri, 22 Nov 2024 21:59:03 -0800 Subject: [PATCH 50/56] Read underlying errors recursively (#3604) Task/Issue URL: https://app.asana.com/0/414235014887631/1208811744276031/f Tech Design URL: CC: Description: This PR updates the pixel error handling to read underlying errors recursively. --- Core/Pixel.swift | 29 ++++++++++++++++++++++----- DuckDuckGoTests/PixelTests.swift | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/Core/Pixel.swift b/Core/Pixel.swift index fc2e7f3945..be9771b5d2 100644 --- a/Core/Pixel.swift +++ b/Core/Pixel.swift @@ -302,18 +302,37 @@ private extension Pixel.Event { } extension Dictionary where Key == String, Value == String { + mutating func appendErrorPixelParams(error: Error) { let nsError = error as NSError self[PixelParameters.errorCode] = "\(nsError.code)" self[PixelParameters.errorDomain] = nsError.domain - if let underlyingError = nsError.userInfo["NSUnderlyingError"] as? NSError { - self[PixelParameters.underlyingErrorCode] = "\(underlyingError.code)" - self[PixelParameters.underlyingErrorDomain] = underlyingError.domain + let underlyingErrorParameters = underlyingErrorParameters(for: error as NSError) + self.merge(underlyingErrorParameters) { first, _ in first } + } + + private func underlyingErrorParameters(for nsError: NSError, level: Int = 0) -> [String: String] { + if let underlyingError = nsError.userInfo[NSUnderlyingErrorKey] as? NSError { + let errorCodeParameterName = PixelParameters.underlyingErrorCode + (level == 0 ? "" : String(level + 1)) + let errorDomainParameterName = PixelParameters.underlyingErrorDomain + (level == 0 ? "" : String(level + 1)) + + let currentUnderlyingErrorParameters = [ + errorCodeParameterName: "\(underlyingError.code)", + errorDomainParameterName: underlyingError.domain + ] + + let additionalParameters = underlyingErrorParameters(for: underlyingError, level: level + 1) + return currentUnderlyingErrorParameters.merging(additionalParameters) { first, _ in first } } else if let sqlErrorCode = nsError.userInfo["NSSQLiteErrorDomain"] as? NSNumber { - self[PixelParameters.underlyingErrorCode] = "\(sqlErrorCode.intValue)" - self[PixelParameters.underlyingErrorDomain] = "NSSQLiteErrorDomain" + return [ + PixelParameters.underlyingErrorCode: "\(sqlErrorCode.intValue)", + PixelParameters.underlyingErrorDomain: "NSSQLiteErrorDomain" + ] } + + return [:] } + } diff --git a/DuckDuckGoTests/PixelTests.swift b/DuckDuckGoTests/PixelTests.swift index 28a9b29158..acbd4c756b 100644 --- a/DuckDuckGoTests/PixelTests.swift +++ b/DuckDuckGoTests/PixelTests.swift @@ -193,4 +193,38 @@ class PixelTests: XCTestCase { wait(for: [firstFireExpectation, thirdFireExpectation], timeout: Double(debounceInterval + 4)) } + func testWhenDefiningUnderlyingErrorParametersThenNestedErrorsAreIncluded() { + let underlyingError4 = NSError(domain: "underlyingError4", code: 5, userInfo: [:]) + let underlyingError3 = NSError(domain: "underlyingError3", code: 4, userInfo: [NSUnderlyingErrorKey: underlyingError4]) + let underlyingError2 = NSError(domain: "underlyingError2", code: 3, userInfo: [NSUnderlyingErrorKey: underlyingError3]) + let underlyingError1 = NSError(domain: "underlyingError1", code: 2, userInfo: [NSUnderlyingErrorKey: underlyingError2]) + let error = NSError(domain: "error", code: 1, userInfo: [NSUnderlyingErrorKey: underlyingError1]) + + var parameters: [String: String] = [:] + parameters.appendErrorPixelParams(error: error) + + XCTAssertEqual(parameters.count, 10) + XCTAssertEqual(parameters["d"], error.domain) + XCTAssertEqual(parameters["e"], String(error.code)) + XCTAssertEqual(parameters["ud"], underlyingError1.domain) + XCTAssertEqual(parameters["ue"], String(underlyingError1.code)) + XCTAssertEqual(parameters["ud2"], underlyingError2.domain) + XCTAssertEqual(parameters["ue2"], String(underlyingError2.code)) + XCTAssertEqual(parameters["ud3"], underlyingError3.domain) + XCTAssertEqual(parameters["ue3"], String(underlyingError3.code)) + XCTAssertEqual(parameters["ud4"], underlyingError4.domain) + XCTAssertEqual(parameters["ue4"], String(underlyingError4.code)) + } + + func testWhenDefiningUnderlyingErrorParametersAndThereIsNoUnderlyingErrorThenOnlyTopLevelParametersAreIncluded() { + let error = NSError(domain: "error", code: 1, userInfo: [:]) + + var parameters: [String: String] = [:] + parameters.appendErrorPixelParams(error: error) + + XCTAssertEqual(parameters.count, 2) + XCTAssertEqual(parameters["d"], error.domain) + XCTAssertEqual(parameters["e"], String(error.code)) + } + } From f00e313df31d4f7df4af91bcfc3d7d076194c2cf Mon Sep 17 00:00:00 2001 From: Michal Smaga Date: Sat, 23 Nov 2024 17:32:59 +0100 Subject: [PATCH 51/56] Apply the hotfix version changes (#3614) Task/Issue URL: https://app.asana.com/0/414709148257752/1208829922317861/f **Description**: Applying hotfix changes from https://github.com/duckduckgo/iOS/pull/3613 --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- DuckDuckGo/AppDelegate.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index 185cf88fa1..f23f5a1949 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -441,15 +441,15 @@ import os.log // Keep track of feature flag changes subscriptionCookieManagerFeatureFlagCancellable = privacyConfigurationManager.updatesPublisher + .receive(on: DispatchQueue.main) .sink { [weak self, weak privacyConfigurationManager] in - guard let self, let privacyConfigurationManager else { return } + guard let self, !self.appIsLaunching, let privacyConfigurationManager else { return } let isEnabled = privacyConfigurationManager.privacyConfig.isSubfeatureEnabled(PrivacyProSubfeature.setAccessTokenCookieForSubscriptionDomains) - Task { [weak self] in + Task { @MainActor [weak self] in if isEnabled { self?.subscriptionCookieManager.enableSettingSubscriptionCookie() - await self?.subscriptionCookieManager.refreshSubscriptionCookie() } else { await self?.subscriptionCookieManager.disableSettingSubscriptionCookie() } From df2abf7b27e7e67797907e7878d16bef103e7201 Mon Sep 17 00:00:00 2001 From: Michal Smaga Date: Sat, 23 Nov 2024 17:34:42 +0100 Subject: [PATCH 52/56] Do not refresh cookie on config update (#3613) Task/Issue URL: https://app.asana.com/0/414709148257752/1208829922317861/f CC: @bwaresiak **Description**: - Do not refresh the cookie on config change when flag was detected enabled - Guard the code not to execute while the app is still launching / has not completed launching - Make the task for interaction with `subscriptionCookieManager` use main actor **Steps to test this PR**: Test enabling and disabling the `setAccessTokenCookieForSubscriptionDomains` feature flag. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- DuckDuckGo/AppDelegate.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index 52bc2e1ac9..45cd06e6f2 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -430,15 +430,15 @@ import os.log // Keep track of feature flag changes subscriptionCookieManagerFeatureFlagCancellable = privacyConfigurationManager.updatesPublisher + .receive(on: DispatchQueue.main) .sink { [weak self, weak privacyConfigurationManager] in - guard let self, let privacyConfigurationManager else { return } + guard let self, !self.appIsLaunching, let privacyConfigurationManager else { return } let isEnabled = privacyConfigurationManager.privacyConfig.isSubfeatureEnabled(PrivacyProSubfeature.setAccessTokenCookieForSubscriptionDomains) - Task { [weak self] in + Task { @MainActor [weak self] in if isEnabled { self?.subscriptionCookieManager.enableSettingSubscriptionCookie() - await self?.subscriptionCookieManager.refreshSubscriptionCookie() } else { await self?.subscriptionCookieManager.disableSettingSubscriptionCookie() } From 274719441ad0955faaf6cac3c4df2463f1738fcb Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Sat, 23 Nov 2024 09:19:51 -0800 Subject: [PATCH 53/56] Release 7.145.1-0 (#3615) Please make sure all GH checks passed before merging. It can take around 20 minutes. Briefly review this PR to see if there are no issues or red flags and then merge it. --- Configuration/Version.xcconfig | 2 +- DuckDuckGo.xcodeproj/project.pbxproj | 56 +++++++++++++-------------- DuckDuckGo/Settings.bundle/Root.plist | 2 +- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig index a31bce32d5..8942758a7c 100644 --- a/Configuration/Version.xcconfig +++ b/Configuration/Version.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 7.145.0 +MARKETING_VERSION = 7.145.1 diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 6f8db18707..8b53f5f54e 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9191,7 +9191,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -9228,7 +9228,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9318,7 +9318,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9345,7 +9345,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9494,7 +9494,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9519,7 +9519,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9588,7 +9588,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -9622,7 +9622,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9655,7 +9655,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9685,7 +9685,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9995,7 +9995,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10026,7 +10026,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10054,7 +10054,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10087,7 +10087,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -10117,7 +10117,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -10150,11 +10150,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10387,7 +10387,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10414,7 +10414,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10446,7 +10446,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10483,7 +10483,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10518,7 +10518,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10553,11 +10553,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10730,11 +10730,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10763,10 +10763,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 0; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 0; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/DuckDuckGo/Settings.bundle/Root.plist b/DuckDuckGo/Settings.bundle/Root.plist index cac348ca4f..b5fc9541d0 100644 --- a/DuckDuckGo/Settings.bundle/Root.plist +++ b/DuckDuckGo/Settings.bundle/Root.plist @@ -6,7 +6,7 @@ DefaultValue - 7.145.0 + 7.145.1 Key version Title From 9d38d01b75163885239238a4b8cded6b1aaf686d Mon Sep 17 00:00:00 2001 From: Sam Symons Date: Sat, 23 Nov 2024 19:55:55 -0800 Subject: [PATCH 54/56] Release 7.146.0-3 (#3616) Please make sure all GH checks passed before merging. It can take around 20 minutes. Briefly review this PR to see if there are no issues or red flags and then merge it. --- DuckDuckGo.xcodeproj/project.pbxproj | 56 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index cfdce4641b..42c29bd3dd 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -9257,7 +9257,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -9294,7 +9294,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9384,7 +9384,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9411,7 +9411,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9558,7 +9558,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9583,7 +9583,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9652,7 +9652,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -9686,7 +9686,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9719,7 +9719,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -9749,7 +9749,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10059,7 +10059,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10090,7 +10090,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10118,7 +10118,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -10151,7 +10151,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -10181,7 +10181,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -10214,11 +10214,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 3; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10450,7 +10450,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10478,7 +10478,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10510,7 +10510,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10547,7 +10547,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -10582,7 +10582,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -10617,11 +10617,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 3; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10794,11 +10794,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 3; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -10827,10 +10827,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 2; + DYLIB_CURRENT_VERSION = 3; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; From acc750b127753b857c3e9f7bbadb768f4b0fef1a Mon Sep 17 00:00:00 2001 From: Dax Mobile <44842493+daxmobile@users.noreply.github.com> Date: Tue, 26 Nov 2024 01:51:33 +1100 Subject: [PATCH 55/56] Update autoconsent to v12.0.0 (#3611) Task/Issue URL: https://app.asana.com/0/1208828457680754/1208828457680754 Autoconsent Release: https://github.com/duckduckgo/autoconsent/releases/tag/v12.0.0 ## Description Updates Autoconsent to version [v12.0.0](https://github.com/duckduckgo/autoconsent/releases/tag/v12.0.0). ### Autoconsent v12.0.0 release notes See release notes [here](https://github.com/duckduckgo/autoconsent/blob/v12.0.0/CHANGELOG.md) ## Steps to test This release has been tested during Autoconsent development. You can check the release notes for more information. 1. Make sure that there's no unexpected failures in CI checks 2. (optional) smoke test some of the sites mentioned in the release notes 3. If there are problems, reach out to a CPM DRI Co-authored-by: muodov <2726132+muodov@users.noreply.github.com> --- DuckDuckGo/Autoconsent/autoconsent-bundle.js | 4 ++-- package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/DuckDuckGo/Autoconsent/autoconsent-bundle.js b/DuckDuckGo/Autoconsent/autoconsent-bundle.js index a30f1e9d51..56995e48b6 100644 --- a/DuckDuckGo/Autoconsent/autoconsent-bundle.js +++ b/DuckDuckGo/Autoconsent/autoconsent-bundle.js @@ -1,4 +1,4 @@ -!function(){"use strict";var e=class e{static setBase(t){e.base=t}static findElement(t,o=null,i=!1){let n=null;return n=null!=o?Array.from(o.querySelectorAll(t.selector)):null!=e.base?Array.from(e.base.querySelectorAll(t.selector)):Array.from(document.querySelectorAll(t.selector)),null!=t.textFilter&&(n=n.filter((e=>{const o=e.textContent.toLowerCase();if(Array.isArray(t.textFilter)){let e=!1;for(const i of t.textFilter)if(-1!==o.indexOf(i.toLowerCase())){e=!0;break}return e}return null!=t.textFilter&&-1!==o.indexOf(t.textFilter.toLowerCase())}))),null!=t.styleFilters&&(n=n.filter((e=>{const o=window.getComputedStyle(e);let i=!0;for(const e of t.styleFilters){const t=o[e.option];i=e.negated?i&&t!==e.value:i&&t===e.value}return i}))),null!=t.displayFilter&&(n=n.filter((e=>t.displayFilter?0!==e.offsetHeight:0===e.offsetHeight))),null!=t.iframeFilter&&(n=n.filter((()=>t.iframeFilter?window.location!==window.parent.location:window.location===window.parent.location))),null!=t.childFilter&&(n=n.filter((o=>{const i=e.base;e.setBase(o);const n=e.find(t.childFilter);return e.setBase(i),null!=n.target}))),i?n:(n.length>1&&console.warn("Multiple possible targets: ",n,t,o),n[0])}static find(t,o=!1){const i=[];if(null!=t.parent){const n=e.findElement(t.parent,null,o);if(null!=n){if(n instanceof Array)return n.forEach((n=>{const s=e.findElement(t.target,n,o);s instanceof Array?s.forEach((e=>{i.push({parent:n,target:e})})):i.push({parent:n,target:s})})),i;{const s=e.findElement(t.target,n,o);s instanceof Array?s.forEach((e=>{i.push({parent:n,target:e})})):i.push({parent:n,target:s})}}}else{const n=e.findElement(t.target,null,o);n instanceof Array?n.forEach((e=>{i.push({parent:null,target:e})})):i.push({parent:null,target:n})}return 0===i.length&&i.push({parent:null,target:null}),o?i:(1!==i.length&&console.warn("Multiple results found, even though multiple false",i),i[0])}};e.base=null;var t=e;function o(e){const o=t.find(e);return"css"===e.type?!!o.target:"checkbox"===e.type?!!o.target&&o.target.checked:void 0}async function i(e,c){switch(e.type){case"click":return async function(e){const o=t.find(e);null!=o.target&&o.target.click();return s(n)}(e);case"list":return async function(e,t){for(const o of e.actions)await i(o,t)}(e,c);case"consent":return async function(e,t){for(const n of e.consents){const e=-1!==t.indexOf(n.type);if(n.matcher&&n.toggleAction){o(n.matcher)!==e&&await i(n.toggleAction)}else e?await i(n.trueAction):await i(n.falseAction)}}(e,c);case"ifcss":return async function(e,o){const n=t.find(e);n.target?e.falseAction&&await i(e.falseAction,o):e.trueAction&&await i(e.trueAction,o)}(e,c);case"waitcss":return async function(e){await new Promise((o=>{let i=e.retries||10;const n=e.waitTime||250,s=()=>{const c=t.find(e);(e.negated&&c.target||!e.negated&&!c.target)&&i>0?(i-=1,setTimeout(s,n)):o()};s()}))}(e);case"foreach":return async function(e,o){const n=t.find(e,!0),s=t.base;for(const s of n)s.target&&(t.setBase(s.target),await i(e.action,o));t.setBase(s)}(e,c);case"hide":return async function(e){const o=t.find(e);o.target&&o.target.classList.add("Autoconsent-Hidden")}(e);case"slide":return async function(e){const o=t.find(e),i=t.find(e.dragTarget);if(o.target){const e=o.target.getBoundingClientRect(),t=i.target.getBoundingClientRect();let n=t.top-e.top,s=t.left-e.left;"y"===this.config.axis.toLowerCase()&&(s=0),"x"===this.config.axis.toLowerCase()&&(n=0);const c=window.screenX+e.left+e.width/2,r=window.screenY+e.top+e.height/2,a=e.left+e.width/2,l=e.top+e.height/2,p=document.createEvent("MouseEvents");p.initMouseEvent("mousedown",!0,!0,window,0,c,r,a,l,!1,!1,!1,!1,0,o.target);const d=document.createEvent("MouseEvents");d.initMouseEvent("mousemove",!0,!0,window,0,c+s,r+n,a+s,l+n,!1,!1,!1,!1,0,o.target);const u=document.createEvent("MouseEvents");u.initMouseEvent("mouseup",!0,!0,window,0,c+s,r+n,a+s,l+n,!1,!1,!1,!1,0,o.target),o.target.dispatchEvent(p),await this.waitTimeout(10),o.target.dispatchEvent(d),await this.waitTimeout(10),o.target.dispatchEvent(u)}}(e);case"close":return async function(){window.close()}();case"wait":return async function(e){await s(e.waitTime)}(e);case"eval":return async function(e){return console.log("eval!",e.code),new Promise((t=>{try{e.async?(window.eval(e.code),setTimeout((()=>{t(window.eval("window.__consentCheckResult"))}),e.timeout||250)):t(window.eval(e.code))}catch(o){console.warn("eval error",o,e.code),t(!1)}}))}(e);default:throw new Error("Unknown action type: "+e.type)}}var n=0;function s(e){return new Promise((t=>{setTimeout((()=>{t()}),e)}))}function c(){return crypto&&void 0!==crypto.randomUUID?crypto.randomUUID():Math.random().toString()}var r=class{constructor(e,t=1e3){this.id=e,this.promise=new Promise(((e,t)=>{this.resolve=e,this.reject=t})),this.timer=window.setTimeout((()=>{this.reject(new Error("timeout"))}),t)}},a={pending:new Map,sendContentMessage:null};var l={EVAL_0:()=>console.log(1),EVAL_CONSENTMANAGER_1:()=>window.__cmp&&"object"==typeof __cmp("getCMPData"),EVAL_CONSENTMANAGER_2:()=>!__cmp("consentStatus").userChoiceExists,EVAL_CONSENTMANAGER_3:()=>__cmp("setConsent",0),EVAL_CONSENTMANAGER_4:()=>__cmp("setConsent",1),EVAL_CONSENTMANAGER_5:()=>__cmp("consentStatus").userChoiceExists,EVAL_COOKIEBOT_1:()=>!!window.Cookiebot,EVAL_COOKIEBOT_2:()=>!window.Cookiebot.hasResponse&&!0===window.Cookiebot.dialog?.visible,EVAL_COOKIEBOT_3:()=>window.Cookiebot.withdraw()||!0,EVAL_COOKIEBOT_4:()=>window.Cookiebot.hide()||!0,EVAL_COOKIEBOT_5:()=>!0===window.Cookiebot.declined,EVAL_KLARO_1:()=>{const e=globalThis.klaroConfig||globalThis.klaro?.getManager&&globalThis.klaro.getManager().config;if(!e)return!0;const t=(e.services||e.apps).filter((e=>!e.required)).map((e=>e.name));if(klaro&&klaro.getManager){const e=klaro.getManager();return t.every((t=>!e.consents[t]))}if(klaroConfig&&"cookie"===klaroConfig.storageMethod){const e=klaroConfig.cookieName||klaroConfig.storageName,o=JSON.parse(decodeURIComponent(document.cookie.split(";").find((t=>t.trim().startsWith(e))).split("=")[1]));return Object.keys(o).filter((e=>t.includes(e))).every((e=>!1===o[e]))}},EVAL_KLARO_OPEN_POPUP:()=>{klaro.show(void 0,!0)},EVAL_KLARO_TRY_API_OPT_OUT:()=>{if(window.klaro&&"function"==typeof klaro.show&&"function"==typeof klaro.getManager)try{return klaro.getManager().changeAll(!1),klaro.getManager().saveAndApplyConsents(),!0}catch(e){return console.warn(e),!1}return!1},EVAL_ONETRUST_1:()=>window.OnetrustActiveGroups.split(",").filter((e=>e.length>0)).length<=1,EVAL_TRUSTARC_TOP:()=>window&&window.truste&&"0"===window.truste.eu.bindMap.prefCookie,EVAL_TRUSTARC_FRAME_TEST:()=>window&&window.QueryString&&"0"===window.QueryString.preferences,EVAL_TRUSTARC_FRAME_GTM:()=>window&&window.QueryString&&"1"===window.QueryString.gtm,EVAL_ABC_TEST:()=>document.cookie.includes("trackingconsent"),EVAL_ADROLL_0:()=>!document.cookie.includes("__adroll_fpc"),EVAL_ALMACMP_0:()=>document.cookie.includes('"name":"Google","consent":false'),EVAL_AFFINITY_SERIF_COM_0:()=>document.cookie.includes("serif_manage_cookies_viewed")&&!document.cookie.includes("serif_allow_analytics"),EVAL_ARBEITSAGENTUR_TEST:()=>document.cookie.includes("cookie_consent=denied"),EVAL_AXEPTIO_0:()=>document.cookie.includes("axeptio_authorized_vendors=%2C%2C"),EVAL_BAHN_TEST:()=>1===utag.gdpr.getSelectedCategories().length,EVAL_BING_0:()=>document.cookie.includes("AD=0"),EVAL_BLOCKSY_0:()=>document.cookie.includes("blocksy_cookies_consent_accepted=no"),EVAL_BORLABS_0:()=>!JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>-1!==e.indexOf("borlabs-cookie"))).split("=",2)[1])).consents.statistics,EVAL_BUNDESREGIERUNG_DE_0:()=>document.cookie.match("cookie-allow-tracking=0"),EVAL_CANVA_0:()=>!document.cookie.includes("gtm_fpc_engagement_event"),EVAL_CC_BANNER2_0:()=>!!document.cookie.match(/sncc=[^;]+D%3Dtrue/),EVAL_CLICKIO_0:()=>document.cookie.includes("__lxG__consent__v2_daisybit="),EVAL_CLINCH_0:()=>document.cookie.includes("ctc_rejected=1"),EVAL_COOKIECONSENT2_TEST:()=>document.cookie.includes("cc_cookie="),EVAL_COOKIECONSENT3_TEST:()=>document.cookie.includes("cc_cookie="),EVAL_COINBASE_0:()=>JSON.parse(decodeURIComponent(document.cookie.match(/cm_(eu|default)_preferences=([0-9a-zA-Z\\{\\}\\[\\]%:]*);?/)[2])).consent.length<=1,EVAL_COMPLIANZ_BANNER_0:()=>document.cookie.includes("cmplz_banner-status=dismissed"),EVAL_COOKIE_LAW_INFO_0:()=>CLI.disableAllCookies()||CLI.reject_close()||!0,EVAL_COOKIE_LAW_INFO_1:()=>-1===document.cookie.indexOf("cookielawinfo-checkbox-non-necessary=yes"),EVAL_COOKIE_LAW_INFO_DETECT:()=>!!window.CLI,EVAL_COOKIE_MANAGER_POPUP_0:()=>!1===JSON.parse(document.cookie.split(";").find((e=>e.trim().startsWith("CookieLevel"))).split("=")[1]).social,EVAL_COOKIEALERT_0:()=>document.querySelector("body").removeAttribute("style")||!0,EVAL_COOKIEALERT_1:()=>document.querySelector("body").removeAttribute("style")||!0,EVAL_COOKIEALERT_2:()=>!0===window.CookieConsent.declined,EVAL_COOKIEFIRST_0:()=>{return!1===(e=JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>-1!==e.indexOf("cookiefirst"))).trim()).split("=")[1])).performance&&!1===e.functional&&!1===e.advertising;var e},EVAL_COOKIEFIRST_1:()=>document.querySelectorAll("button[data-cookiefirst-accent-color=true][role=checkbox]:not([disabled])").forEach((e=>"true"===e.getAttribute("aria-checked")&&e.click()))||!0,EVAL_COOKIEINFORMATION_0:()=>CookieInformation.declineAllCategories()||!0,EVAL_COOKIEINFORMATION_1:()=>CookieInformation.submitAllCategories()||!0,EVAL_COOKIEINFORMATION_2:()=>document.cookie.includes("CookieInformationConsent="),EVAL_COOKIEYES_0:()=>document.cookie.includes("advertisement:no"),EVAL_DAILYMOTION_0:()=>!!document.cookie.match("dm-euconsent-v2"),EVAL_DNDBEYOND_TEST:()=>document.cookie.includes("cookie-consent=denied"),EVAL_DSGVO_0:()=>!document.cookie.includes("sp_dsgvo_cookie_settings"),EVAL_DUNELM_0:()=>document.cookie.includes("cc_functional=0")&&document.cookie.includes("cc_targeting=0"),EVAL_ETSY_0:()=>document.querySelectorAll(".gdpr-overlay-body input").forEach((e=>{e.checked=!1}))||!0,EVAL_ETSY_1:()=>document.querySelector(".gdpr-overlay-view button[data-wt-overlay-close]").click()||!0,EVAL_EU_COOKIE_COMPLIANCE_0:()=>-1===document.cookie.indexOf("cookie-agreed=2"),EVAL_EU_COOKIE_LAW_0:()=>!document.cookie.includes("euCookie"),EVAL_EZOIC_0:()=>ezCMP.handleAcceptAllClick(),EVAL_EZOIC_1:()=>!!document.cookie.match(/ez-consent-tcf/),EVAL_FIDES_DETECT_POPUP:()=>window.Fides?.initialized,EVAL_GOOGLE_0:()=>!!document.cookie.match(/SOCS=CAE/),EVAL_HEMA_TEST_0:()=>document.cookie.includes("cookies_rejected=1"),EVAL_IUBENDA_0:()=>document.querySelectorAll(".purposes-item input[type=checkbox]:not([disabled])").forEach((e=>{e.checked&&e.click()}))||!0,EVAL_IUBENDA_1:()=>!!document.cookie.match(/_iub_cs-\d+=/),EVAL_IWINK_TEST:()=>document.cookie.includes("cookie_permission_granted=no"),EVAL_JQUERY_COOKIEBAR_0:()=>!document.cookie.includes("cookies-state=accepted"),EVAL_KETCH_TEST:()=>document.cookie.includes("_ketch_consent_v1_"),EVAL_MEDIAVINE_0:()=>document.querySelectorAll('[data-name="mediavine-gdpr-cmp"] input[type=checkbox]').forEach((e=>e.checked&&e.click()))||!0,EVAL_MICROSOFT_0:()=>Array.from(document.querySelectorAll("div > button")).filter((e=>e.innerText.match("Reject|Ablehnen")))[0].click()||!0,EVAL_MICROSOFT_1:()=>Array.from(document.querySelectorAll("div > button")).filter((e=>e.innerText.match("Accept|Annehmen")))[0].click()||!0,EVAL_MICROSOFT_2:()=>!!document.cookie.match("MSCC|GHCC"),EVAL_MOOVE_0:()=>document.querySelectorAll("#moove_gdpr_cookie_modal input").forEach((e=>{e.disabled||(e.checked="moove_gdpr_strict_cookies"===e.name||"moove_gdpr_strict_cookies"===e.id)}))||!0,EVAL_ONENINETWO_0:()=>document.cookie.includes("CC_ADVERTISING=NO")&&document.cookie.includes("CC_ANALYTICS=NO"),EVAL_OPENAI_TEST:()=>document.cookie.includes("oai-allow-ne=false"),EVAL_OPERA_0:()=>document.cookie.includes("cookie_consent_essential=true")&&!document.cookie.includes("cookie_consent_marketing=true"),EVAL_PAYPAL_0:()=>!0===document.cookie.includes("cookie_prefs"),EVAL_PRIMEBOX_0:()=>!document.cookie.includes("cb-enabled=accepted"),EVAL_PUBTECH_0:()=>document.cookie.includes("euconsent-v2")&&(document.cookie.match(/.YAAAAAAAAAAA/)||document.cookie.match(/.aAAAAAAAAAAA/)||document.cookie.match(/.YAAACFgAAAAA/)),EVAL_REDDIT_0:()=>document.cookie.includes("eu_cookie={%22opted%22:true%2C%22nonessential%22:false}"),EVAL_ROBLOX_TEST:()=>document.cookie.includes("RBXcb"),EVAL_SIRDATA_UNBLOCK_SCROLL:()=>(document.documentElement.classList.forEach((e=>{e.startsWith("sd-cmp-")&&document.documentElement.classList.remove(e)})),!0),EVAL_SNIGEL_0:()=>!!document.cookie.match("snconsent"),EVAL_STEAMPOWERED_0:()=>2===JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>e.trim().startsWith("cookieSettings"))).split("=")[1])).preference_state,EVAL_SVT_TEST:()=>document.cookie.includes('cookie-consent-1={"optedIn":true,"functionality":false,"statistics":false}'),EVAL_TAKEALOT_0:()=>document.body.classList.remove("freeze")||(document.body.style="")||!0,EVAL_TARTEAUCITRON_0:()=>tarteaucitron.userInterface.respondAll(!1)||!0,EVAL_TARTEAUCITRON_1:()=>tarteaucitron.userInterface.respondAll(!0)||!0,EVAL_TARTEAUCITRON_2:()=>document.cookie.match(/tarteaucitron=[^;]*/)?.[0].includes("false"),EVAL_TAUNTON_TEST:()=>document.cookie.includes("taunton_user_consent_submitted=true"),EVAL_TEALIUM_0:()=>void 0!==window.utag&&"object"==typeof utag.gdpr,EVAL_TEALIUM_1:()=>utag.gdpr.setConsentValue(!1)||!0,EVAL_TEALIUM_DONOTSELL:()=>utag.gdpr.dns?.setDnsState(!1)||!0,EVAL_TEALIUM_2:()=>utag.gdpr.setConsentValue(!0)||!0,EVAL_TEALIUM_3:()=>1!==utag.gdpr.getConsentState(),EVAL_TEALIUM_DONOTSELL_CHECK:()=>1!==utag.gdpr.dns?.getDnsState(),EVAL_TESLA_TEST:()=>document.cookie.includes("tsla-cookie-consent=rejected"),EVAL_TESTCMP_0:()=>"button_clicked"===window.results.results[0],EVAL_TESTCMP_COSMETIC_0:()=>"banner_hidden"===window.results.results[0],EVAL_THEFREEDICTIONARY_0:()=>cmpUi.showPurposes()||cmpUi.rejectAll()||!0,EVAL_THEFREEDICTIONARY_1:()=>cmpUi.allowAll()||!0,EVAL_THEVERGE_0:()=>document.cookie.includes("_duet_gdpr_acknowledged=1"),EVAL_TWCC_TEST:()=>document.cookie.includes("twCookieConsent="),EVAL_UBUNTU_COM_0:()=>document.cookie.includes("_cookies_accepted=essential"),EVAL_UK_COOKIE_CONSENT_0:()=>!document.cookie.includes("catAccCookies"),EVAL_USERCENTRICS_API_0:()=>"object"==typeof UC_UI,EVAL_USERCENTRICS_API_1:()=>!!UC_UI.closeCMP(),EVAL_USERCENTRICS_API_2:()=>!!UC_UI.denyAllConsents(),EVAL_USERCENTRICS_API_3:()=>!!UC_UI.acceptAllConsents(),EVAL_USERCENTRICS_API_4:()=>!!UC_UI.closeCMP(),EVAL_USERCENTRICS_API_5:()=>!0===UC_UI.areAllConsentsAccepted(),EVAL_USERCENTRICS_API_6:()=>!1===UC_UI.areAllConsentsAccepted(),EVAL_USERCENTRICS_BUTTON_0:()=>JSON.parse(localStorage.getItem("usercentrics")).consents.every((e=>e.isEssential||!e.consentStatus)),EVAL_WAITROSE_0:()=>Array.from(document.querySelectorAll("label[id$=cookies-deny-label]")).forEach((e=>e.click()))||!0,EVAL_WAITROSE_1:()=>document.cookie.includes("wtr_cookies_advertising=0")&&document.cookie.includes("wtr_cookies_analytics=0"),EVAL_WP_COOKIE_NOTICE_0:()=>document.cookie.includes("wpl_viewed_cookie=no"),EVAL_XE_TEST:()=>document.cookie.includes("xeConsentState={%22performance%22:false%2C%22marketing%22:false%2C%22compliance%22:false}"),EVAL_XING_0:()=>document.cookie.includes("userConsent=%7B%22marketing%22%3Afalse"),EVAL_YOUTUBE_DESKTOP_0:()=>!!document.cookie.match(/SOCS=CAE/),EVAL_YOUTUBE_MOBILE_0:()=>!!document.cookie.match(/SOCS=CAE/)};var p={main:!0,frame:!1,urlPattern:""},d=class{constructor(e){this.runContext=p,this.autoconsent=e}get hasSelfTest(){throw new Error("Not Implemented")}get isIntermediate(){throw new Error("Not Implemented")}get isCosmetic(){throw new Error("Not Implemented")}mainWorldEval(e){const t=l[e];if(!t)return console.warn("Snippet not found",e),Promise.resolve(!1);const o=this.autoconsent.config.logs;if(this.autoconsent.config.isMainWorld){o.evals&&console.log("inline eval:",e,t);let i=!1;try{i=!!t.call(globalThis)}catch(t){o.evals&&console.error("error evaluating rule",e,t)}return Promise.resolve(i)}const i=`(${t.toString()})()`;return o.evals&&console.log("async eval:",e,i),function(e,t){const o=c();a.sendContentMessage({type:"eval",id:o,code:e,snippetId:t});const i=new r(o);return a.pending.set(i.id,i),i.promise}(i,e).catch((t=>(o.evals&&console.error("error evaluating rule",e,t),!1)))}checkRunContext(){const e={...p,...this.runContext},t=window.top===window;return!(t&&!e.main)&&(!(!t&&!e.frame)&&!(e.urlPattern&&!window.location.href.match(e.urlPattern)))}detectCmp(){throw new Error("Not Implemented")}async detectPopup(){return!1}optOut(){throw new Error("Not Implemented")}optIn(){throw new Error("Not Implemented")}openCmp(){throw new Error("Not Implemented")}async test(){return Promise.resolve(!0)}click(e,t=!1){return this.autoconsent.domActions.click(e,t)}elementExists(e){return this.autoconsent.domActions.elementExists(e)}elementVisible(e,t){return this.autoconsent.domActions.elementVisible(e,t)}waitForElement(e,t){return this.autoconsent.domActions.waitForElement(e,t)}waitForVisible(e,t,o){return this.autoconsent.domActions.waitForVisible(e,t,o)}waitForThenClick(e,t,o){return this.autoconsent.domActions.waitForThenClick(e,t,o)}wait(e){return this.autoconsent.domActions.wait(e)}hide(e,t){return this.autoconsent.domActions.hide(e,t)}prehide(e){return this.autoconsent.domActions.prehide(e)}undoPrehide(){return this.autoconsent.domActions.undoPrehide()}querySingleReplySelector(e,t){return this.autoconsent.domActions.querySingleReplySelector(e,t)}querySelectorChain(e){return this.autoconsent.domActions.querySelectorChain(e)}elementSelector(e){return this.autoconsent.domActions.elementSelector(e)}},u=class extends d{constructor(e,t){super(t),this.rule=e,this.name=e.name,this.runContext=e.runContext||p}get hasSelfTest(){return!!this.rule.test}get isIntermediate(){return!!this.rule.intermediate}get isCosmetic(){return!!this.rule.cosmetic}get prehideSelectors(){return this.rule.prehideSelectors}async detectCmp(){return!!this.rule.detectCmp&&this._runRulesParallel(this.rule.detectCmp)}async detectPopup(){return!!this.rule.detectPopup&&this._runRulesSequentially(this.rule.detectPopup)}async optOut(){const e=this.autoconsent.config.logs;return!!this.rule.optOut&&(e.lifecycle&&console.log("Initiated optOut()",this.rule.optOut),this._runRulesSequentially(this.rule.optOut))}async optIn(){const e=this.autoconsent.config.logs;return!!this.rule.optIn&&(e.lifecycle&&console.log("Initiated optIn()",this.rule.optIn),this._runRulesSequentially(this.rule.optIn))}async openCmp(){return!!this.rule.openCmp&&this._runRulesSequentially(this.rule.openCmp)}async test(){return this.hasSelfTest?this._runRulesSequentially(this.rule.test):super.test()}async evaluateRuleStep(e){const t=[],o=this.autoconsent.config.logs;if(e.exists&&t.push(this.elementExists(e.exists)),e.visible&&t.push(this.elementVisible(e.visible,e.check)),e.eval){const o=this.mainWorldEval(e.eval);t.push(o)}if(e.waitFor&&t.push(this.waitForElement(e.waitFor,e.timeout)),e.waitForVisible&&t.push(this.waitForVisible(e.waitForVisible,e.timeout,e.check)),e.click&&t.push(this.click(e.click,e.all)),e.waitForThenClick&&t.push(this.waitForThenClick(e.waitForThenClick,e.timeout,e.all)),e.wait&&t.push(this.wait(e.wait)),e.hide&&t.push(this.hide(e.hide,e.method)),e.if){if(!e.if.exists&&!e.if.visible)return console.error("invalid conditional rule",e.if),!1;const i=await this.evaluateRuleStep(e.if);o.rulesteps&&console.log("Condition is",i),i?t.push(this._runRulesSequentially(e.then)):e.else?t.push(this._runRulesSequentially(e.else)):t.push(!0)}if(e.any){for(const t of e.any)if(await this.evaluateRuleStep(t))return!0;return!1}if(0===t.length)return o.errors&&console.warn("Unrecognized rule",e),!1;return(await Promise.all(t)).reduce(((e,t)=>e&&t),!0)}async _runRulesParallel(e){const t=e.map((e=>this.evaluateRuleStep(e)));return(await Promise.all(t)).every((e=>!!e))}async _runRulesSequentially(e){const t=this.autoconsent.config.logs;for(const o of e){t.rulesteps&&console.log("Running rule...",o);const e=await this.evaluateRuleStep(o);if(t.rulesteps&&console.log("...rule result",e),!e&&!o.optional)return!1}return!0}},h=class{constructor(e,t){this.name=e,this.config=t,this.methods=new Map,this.runContext=p,this.isCosmetic=!1,t.methods.forEach((e=>{e.action&&this.methods.set(e.name,e.action)})),this.hasSelfTest=!1}get isIntermediate(){return!1}checkRunContext(){return!0}async detectCmp(){return this.config.detectors.map((e=>o(e.presentMatcher))).some((e=>!!e))}async detectPopup(){return this.config.detectors.map((e=>o(e.showingMatcher))).some((e=>!!e))}async executeAction(e,t){return!this.methods.has(e)||i(this.methods.get(e),t)}async optOut(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),await this.executeAction("HIDE_CMP"),await this.executeAction("DO_CONSENT",[]),await this.executeAction("SAVE_CONSENT"),!0}async optIn(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),await this.executeAction("HIDE_CMP"),await this.executeAction("DO_CONSENT",["D","A","B","E","F","X"]),await this.executeAction("SAVE_CONSENT"),!0}async openCmp(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),!0}async test(){return!0}};function m(e="autoconsent-css-rules"){const t=`style#${e}`,o=document.querySelector(t);if(o&&o instanceof HTMLStyleElement)return o;{const t=document.head||document.getElementsByTagName("head")[0]||document.documentElement,o=document.createElement("style");return o.id=e,t.appendChild(o),o}}function A(e){return`${"opacity"===e?"opacity: 0":"display: none"} !important; z-index: -1 !important; pointer-events: none !important;`}function g(e,t,o="display"){const i=`${t} { ${A(o)} } `;return e instanceof HTMLStyleElement&&(e.innerText+=i,t.length>0)}async function f(e,t,o){const i=await e();return!i&&t>0?new Promise((i=>{setTimeout((async()=>{i(f(e,t-1,o))}),o)})):Promise.resolve(i)}function k(e){if(!e)return!1;if(null!==e.offsetParent)return!0;{const t=window.getComputedStyle(e);if("fixed"===t.position&&"none"!==t.display)return!0}return!1}function b(e){const t={enabled:!0,autoAction:"optOut",disabledCmps:[],enablePrehide:!0,enableCosmeticRules:!0,detectRetries:20,isMainWorld:!1,prehideTimeout:2e3,enableFilterList:!1,logs:{lifecycle:!1,rulesteps:!1,evals:!1,errors:!0,messages:!1}},o=(i=t,globalThis.structuredClone?structuredClone(i):JSON.parse(JSON.stringify(i)));var i;for(const i of Object.keys(t))void 0!==e[i]&&(o[i]=e[i]);return o}var y="#truste-show-consent",w="#truste-consent-track",v=[class extends d{constructor(e){super(e),this.name="TrustArc-top",this.prehideSelectors=[".trustarc-banner-container",`.truste_popframe,.truste_overlay,.truste_box_overlay,${w}`],this.runContext={main:!0,frame:!1},this._shortcutButton=null,this._optInDone=!1}get hasSelfTest(){return!0}get isIntermediate(){return!this._optInDone&&!this._shortcutButton}get isCosmetic(){return!1}async detectCmp(){const e=this.elementExists(`${y},${w}`);return e&&(this._shortcutButton=document.querySelector("#truste-consent-required")),e}async detectPopup(){return this.elementVisible(`#truste-consent-content,#trustarc-banner-overlay,${w}`,"any")}openFrame(){this.click(y)}async optOut(){return this._shortcutButton?(this._shortcutButton.click(),!0):(g(m(),`.truste_popframe, .truste_overlay, .truste_box_overlay, ${w}`),this.click(y),setTimeout((()=>{m().remove()}),1e4),!0)}async optIn(){return this._optInDone=!0,this.click("#truste-consent-button")}async openCmp(){return!0}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_TRUSTARC_TOP")}},class extends d{constructor(){super(...arguments),this.name="TrustArc-frame",this.runContext={main:!1,frame:!0,urlPattern:"^https://consent-pref\\.trustarc\\.com/\\?"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return!0}async detectPopup(){return this.elementVisible("#defaultpreferencemanager","any")&&this.elementVisible(".mainContent","any")}async navigateToSettings(){return await f((async()=>this.elementExists(".shp")||this.elementVisible(".advance","any")||this.elementExists(".switch span:first-child")),10,500),this.elementExists(".shp")&&this.click(".shp"),await this.waitForElement(".prefPanel",5e3),this.elementVisible(".advance","any")&&this.click(".advance"),await f((()=>this.elementVisible(".switch span:first-child","any")),5,1e3)}async optOut(){if(await this.mainWorldEval("EVAL_TRUSTARC_FRAME_TEST"))return!0;let e=3e3;return await this.mainWorldEval("EVAL_TRUSTARC_FRAME_GTM")&&(e=1500),await f((()=>"complete"===document.readyState),20,100),await this.waitForElement(".mainContent[aria-hidden=false]",e),!!this.click(".rejectAll")||(this.elementExists(".prefPanel")&&await this.waitForElement('.prefPanel[style="visibility: visible;"]',e),this.click("#catDetails0")?(this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",e),!0):this.click(".required")?(this.waitForThenClick("#gwt-debug-close_id",e),!0):(await this.navigateToSettings(),this.click(".switch span:nth-child(1):not(.active)",!0),this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",10*e),!0))}async optIn(){return this.click(".call")||(await this.navigateToSettings(),this.click(".switch span:nth-child(2)",!0),this.click(".submit"),this.waitForElement("#gwt-debug-close_id",3e5).then((()=>{this.click("#gwt-debug-close_id")}))),!0}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_TRUSTARC_FRAME_TEST")}},class extends d{constructor(){super(...arguments),this.name="Cybotcookiebot",this.prehideSelectors=["#CybotCookiebotDialog,#CybotCookiebotDialogBodyUnderlay,#dtcookie-container,#cookiebanner,#cb-cookieoverlay,.modal--cookie-banner,#cookiebanner_outer,#CookieBanner"]}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return await this.mainWorldEval("EVAL_COOKIEBOT_1")}async detectPopup(){return this.mainWorldEval("EVAL_COOKIEBOT_2")}async optOut(){await this.wait(500);let e=await this.mainWorldEval("EVAL_COOKIEBOT_3");return await this.wait(500),e=e&&await this.mainWorldEval("EVAL_COOKIEBOT_4"),e}async optIn(){return this.elementExists("#dtcookie-container")?this.click(".h-dtcookie-accept"):(this.click(".CybotCookiebotDialogBodyLevelButton:not(:checked):enabled",!0),this.click("#CybotCookiebotDialogBodyLevelButtonAccept"),this.click("#CybotCookiebotDialogBodyButtonAccept"),!0)}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_COOKIEBOT_5")}},class extends d{constructor(){super(...arguments),this.name="Sourcepoint-frame",this.prehideSelectors=["div[id^='sp_message_container_'],.message-overlay","#sp_privacy_manager_container"],this.ccpaNotice=!1,this.ccpaPopup=!1,this.runContext={main:!0,frame:!0}}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){const e=new URL(location.href);return e.searchParams.has("message_id")&&"ccpa-notice.sp-prod.net"===e.hostname?(this.ccpaNotice=!0,!0):"ccpa-pm.sp-prod.net"===e.hostname?(this.ccpaPopup=!0,!0):("/index.html"===e.pathname||"/privacy-manager/index.html"===e.pathname||"/ccpa_pm/index.html"===e.pathname)&&(e.searchParams.has("message_id")||e.searchParams.has("requestUUID")||e.searchParams.has("consentUUID"))}async detectPopup(){return!!this.ccpaNotice||(this.ccpaPopup?await this.waitForElement(".priv-save-btn",2e3):(await this.waitForElement(".sp_choice_type_11,.sp_choice_type_12,.sp_choice_type_13,.sp_choice_type_ACCEPT_ALL,.sp_choice_type_SAVE_AND_EXIT",2e3),!this.elementExists(".sp_choice_type_9")))}async optIn(){return await this.waitForElement(".sp_choice_type_11,.sp_choice_type_ACCEPT_ALL",2e3),!!this.click(".sp_choice_type_11")||!!this.click(".sp_choice_type_ACCEPT_ALL")}isManagerOpen(){return"/privacy-manager/index.html"===location.pathname||"/ccpa_pm/index.html"===location.pathname}async optOut(){const e=this.autoconsent.config.logs;if(this.ccpaPopup){const e=document.querySelectorAll(".priv-purpose-container .sp-switch-arrow-block a.neutral.on .right");for(const t of e)t.click();const t=document.querySelectorAll(".priv-purpose-container .sp-switch-arrow-block a.switch-bg.on");for(const e of t)e.click();return this.click(".priv-save-btn")}if(!this.isManagerOpen()){if(!await this.waitForElement(".sp_choice_type_12,.sp_choice_type_13"))return!1;if(!this.elementExists(".sp_choice_type_12"))return this.click(".sp_choice_type_13");this.click(".sp_choice_type_12"),await f((()=>this.isManagerOpen()),200,100)}await this.waitForElement(".type-modal",2e4),this.waitForThenClick(".ccpa-stack .pm-switch[aria-checked=true] .slider",500,!0);try{const e=".sp_choice_type_REJECT_ALL",t=".reject-toggle",o=await Promise.race([this.waitForElement(e,2e3).then((e=>e?0:-1)),this.waitForElement(t,2e3).then((e=>e?1:-1)),this.waitForElement(".pm-features",2e3).then((e=>e?2:-1))]);if(0===o)return await this.waitForVisible(e),this.click(e);1===o?this.click(t):2===o&&(await this.waitForElement(".pm-features",1e4),this.click(".checked > span",!0),this.click(".chevron"))}catch(t){e.errors&&console.warn(t)}return this.click(".sp_choice_type_SAVE_AND_EXIT")}},class extends d{constructor(){super(...arguments),this.name="consentmanager.net",this.prehideSelectors=["#cmpbox,#cmpbox2"],this.apiAvailable=!1}get hasSelfTest(){return this.apiAvailable}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.apiAvailable=await this.mainWorldEval("EVAL_CONSENTMANAGER_1"),!!this.apiAvailable||this.elementExists("#cmpbox")}async detectPopup(){return this.apiAvailable?(await this.wait(500),await this.mainWorldEval("EVAL_CONSENTMANAGER_2")):this.elementVisible("#cmpbox .cmpmore","any")}async optOut(){return await this.wait(500),this.apiAvailable?await this.mainWorldEval("EVAL_CONSENTMANAGER_3"):!!this.click(".cmpboxbtnno")||(this.elementExists(".cmpwelcomeprpsbtn")?(this.click(".cmpwelcomeprpsbtn > a[aria-checked=true]",!0),this.click(".cmpboxbtnsave"),!0):(this.click(".cmpboxbtncustom"),await this.waitForElement(".cmptblbox",2e3),this.click(".cmptdchoice > a[aria-checked=true]",!0),this.click(".cmpboxbtnyescustomchoices"),this.hide("#cmpwrapper,#cmpbox","display"),!0))}async optIn(){return this.apiAvailable?await this.mainWorldEval("EVAL_CONSENTMANAGER_4"):this.click(".cmpboxbtnyes")}async test(){if(this.apiAvailable)return await this.mainWorldEval("EVAL_CONSENTMANAGER_5")}},class extends d{constructor(){super(...arguments),this.name="Evidon"}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("#_evidon_banner")}async detectPopup(){return this.elementVisible("#_evidon_banner","any")}async optOut(){return this.click("#_evidon-decline-button")||(g(m(),"#evidon-prefdiag-overlay,#evidon-prefdiag-background,#_evidon-background"),await this.waitForThenClick("#_evidon-option-button"),await this.waitForElement("#evidon-prefdiag-overlay",5e3),await this.wait(500),await this.waitForThenClick("#evidon-prefdiag-decline")),!0}async optIn(){return this.click("#_evidon-accept-button")}},class extends d{constructor(){super(...arguments),this.name="Onetrust",this.prehideSelectors=["#onetrust-banner-sdk,#onetrust-consent-sdk,.onetrust-pc-dark-filter,.js-consent-banner"],this.runContext={urlPattern:"^(?!.*https://www\\.nba\\.com/)"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("#onetrust-banner-sdk,#onetrust-pc-sdk")}async detectPopup(){return this.elementVisible("#onetrust-banner-sdk,#onetrust-pc-sdk","any")}async optOut(){return this.elementVisible("#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies","any")?this.click("#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies"):(this.elementExists("#onetrust-pc-btn-handler")?this.click("#onetrust-pc-btn-handler"):this.click(".ot-sdk-show-settings,button.js-cookie-settings"),await this.waitForElement("#onetrust-consent-sdk",2e3),await this.wait(1e3),this.click("#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked",!0),await this.wait(1e3),await this.waitForElement(".save-preference-btn-handler,.js-consent-save",2e3),this.click(".save-preference-btn-handler,.js-consent-save"),await this.waitForVisible("#onetrust-banner-sdk",5e3,"none"),!0)}async optIn(){return this.click("#onetrust-accept-btn-handler,#accept-recommended-btn-handler,.js-accept-cookies")}async test(){return await f((()=>this.mainWorldEval("EVAL_ONETRUST_1")),10,500)}},class extends d{constructor(){super(...arguments),this.name="Klaro",this.prehideSelectors=[".klaro"],this.settingsOpen=!1}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".klaro > .cookie-modal")?(this.settingsOpen=!0,!0):this.elementExists(".klaro > .cookie-notice")}async detectPopup(){return this.elementVisible(".klaro > .cookie-notice,.klaro > .cookie-modal","any")}async optOut(){return!!await this.mainWorldEval("EVAL_KLARO_TRY_API_OPT_OUT")||(!!this.click(".klaro .cn-decline")||(await this.mainWorldEval("EVAL_KLARO_OPEN_POPUP"),!!this.click(".klaro .cn-decline")||(this.click(".cm-purpose:not(.cm-toggle-all) > input:not(.half-checked,.required,.only-required),.cm-purpose:not(.cm-toggle-all) > div > input:not(.half-checked,.required,.only-required)",!0),this.click(".cm-btn-accept,.cm-button"))))}async optIn(){return!!this.click(".klaro .cm-btn-accept-all")||(this.settingsOpen?(this.click(".cm-purpose:not(.cm-toggle-all) > input.half-checked",!0),this.click(".cm-btn-accept")):this.click(".klaro .cookie-notice .cm-btn-success"))}async test(){return await this.mainWorldEval("EVAL_KLARO_1")}},class extends d{constructor(){super(...arguments),this.name="Uniconsent"}get prehideSelectors(){return[".unic",".modal:has(.unic)"]}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".unic .unic-box,.unic .unic-bar,.unic .unic-modal")}async detectPopup(){return this.elementVisible(".unic .unic-box,.unic .unic-bar,.unic .unic-modal","any")}async optOut(){if(await this.waitForElement(".unic button",1e3),document.querySelectorAll(".unic button").forEach((e=>{const t=e.textContent;(t.includes("Manage Options")||t.includes("Optionen verwalten"))&&e.click()})),await this.waitForElement(".unic input[type=checkbox]",1e3)){await this.waitForElement(".unic button",1e3),document.querySelectorAll(".unic input[type=checkbox]").forEach((e=>{e.checked&&e.click()}));for(const e of document.querySelectorAll(".unic button")){const t=e.textContent;for(const o of["Confirm Choices","Save Choices","Auswahl speichern"])if(t.includes(o))return e.click(),await this.wait(500),!0}}return!1}async optIn(){return this.waitForThenClick(".unic #unic-agree")}async test(){await this.wait(1e3);return!this.elementExists(".unic .unic-box,.unic .unic-bar")}},class extends d{constructor(){super(...arguments),this.prehideSelectors=[".cmp-root"],this.name="Conversant"}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".cmp-root .cmp-receptacle")}async detectPopup(){return this.elementVisible(".cmp-root .cmp-receptacle","any")}async optOut(){if(!await this.waitForThenClick(".cmp-main-button:not(.cmp-main-button--primary)"))return!1;if(!await this.waitForElement(".cmp-view-tab-tabs"))return!1;await this.waitForThenClick(".cmp-view-tab-tabs > :first-child"),await this.waitForThenClick(".cmp-view-tab-tabs > .cmp-view-tab--active:first-child");for(const e of Array.from(document.querySelectorAll(".cmp-accordion-item"))){e.querySelector(".cmp-accordion-item-title").click(),await f((()=>!!e.querySelector(".cmp-accordion-item-content.cmp-active")),10,50);const t=e.querySelector(".cmp-accordion-item-content.cmp-active");t.querySelectorAll(".cmp-toggle-actions .cmp-toggle-deny:not(.cmp-toggle-deny--active)").forEach((e=>e.click())),t.querySelectorAll(".cmp-toggle-actions .cmp-toggle-checkbox:not(.cmp-toggle-checkbox--active)").forEach((e=>e.click()))}return await this.click(".cmp-main-button:not(.cmp-main-button--primary)"),!0}async optIn(){return this.waitForThenClick(".cmp-main-button.cmp-main-button--primary")}async test(){return document.cookie.includes("cmp-data=0")}},class extends d{constructor(){super(...arguments),this.name="tiktok.com",this.runContext={urlPattern:"tiktok"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}getShadowRoot(){const e=document.querySelector("tiktok-cookie-banner");return e?e.shadowRoot:null}async detectCmp(){return this.elementExists("tiktok-cookie-banner")}async detectPopup(){return k(this.getShadowRoot().querySelector(".tiktok-cookie-banner"))}async optOut(){const e=this.autoconsent.config.logs,t=this.getShadowRoot().querySelector(".button-wrapper button:first-child");return t?(e.rulesteps&&console.log("[clicking]",t),t.click(),!0):(e.errors&&console.log("no decline button found"),!1)}async optIn(){const e=this.autoconsent.config.logs,t=this.getShadowRoot().querySelector(".button-wrapper button:last-child");return t?(e.rulesteps&&console.log("[clicking]",t),t.click(),!0):(e.errors&&console.log("no accept button found"),!1)}async test(){const e=document.cookie.match(/cookie-consent=([^;]+)/);if(!e)return!1;const t=JSON.parse(decodeURIComponent(e[1]));return Object.values(t).every((e=>"boolean"!=typeof e||!1===e))}},class extends d{constructor(){super(...arguments),this.name="airbnb",this.runContext={urlPattern:"^https://(www\\.)?airbnb\\.[^/]+/"},this.prehideSelectors=["div[data-testid=main-cookies-banner-container]",'div:has(> div:first-child):has(> div:last-child):has(> section [data-testid="strictly-necessary-cookies"])']}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("div[data-testid=main-cookies-banner-container]")}async detectPopup(){return this.elementVisible("div[data-testid=main-cookies-banner-container","any")}async optOut(){let e;for(await this.waitForThenClick("div[data-testid=main-cookies-banner-container] button._snbhip0");e=document.querySelector("[data-testid=modal-container] button[aria-checked=true]:not([disabled])");)e.click();return this.waitForThenClick("button[data-testid=save-btn]")}async optIn(){return this.waitForThenClick("div[data-testid=main-cookies-banner-container] button._148dgdpk")}async test(){return await f((()=>!!document.cookie.match("OptanonAlertBoxClosed")),20,200)}},class extends d{constructor(){super(...arguments),this.name="tumblr-com",this.runContext={urlPattern:"^https://(www\\.)?tumblr\\.com/"}}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}get prehideSelectors(){return["#cmp-app-container"]}async detectCmp(){return this.elementExists("#cmp-app-container")}async detectPopup(){return this.elementVisible("#cmp-app-container","any")}async optOut(){let e=document.querySelector("#cmp-app-container iframe"),t=e.contentDocument?.querySelector(".cmp-components-button.is-secondary");return!!t&&(t.click(),await f((()=>{const e=document.querySelector("#cmp-app-container iframe");return!!e.contentDocument?.querySelector(".cmp__dialog input")}),5,500),e=document.querySelector("#cmp-app-container iframe"),t=e.contentDocument?.querySelector(".cmp-components-button.is-secondary"),!!t&&(t.click(),!0))}async optIn(){const e=document.querySelector("#cmp-app-container iframe").contentDocument.querySelector(".cmp-components-button.is-primary");return!!e&&(e.click(),!0)}},class extends d{constructor(){super(...arguments),this.name="Admiral"}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("div > div[class*=Card] > div[class*=Frame] > div[class*=Pills] > button[class*=Pills__StyledPill]")}async detectPopup(){return this.elementVisible("div > div[class*=Card] > div[class*=Frame] > div[class*=Pills] > button[class*=Pills__StyledPill]","any")}async optOut(){const e="xpath///button[contains(., 'Afvis alle') or contains(., 'Reject all') or contains(., 'Odbaci sve') or contains(., 'Rechazar todo') or contains(., 'Atmesti visus') or contains(., 'Odmítnout vše') or contains(., 'Απόρριψη όλων') or contains(., 'Rejeitar tudo') or contains(., 'Tümünü reddet') or contains(., 'Отклонить все') or contains(., 'Noraidīt visu') or contains(., 'Avvisa alla') or contains(., 'Odrzuć wszystkie') or contains(., 'Alles afwijzen') or contains(., 'Отхвърляне на всички') or contains(., 'Rifiuta tutto') or contains(., 'Zavrni vse') or contains(., 'Az összes elutasítása') or contains(., 'Respingeți tot') or contains(., 'Alles ablehnen') or contains(., 'Tout rejeter') or contains(., 'Odmietnuť všetko') or contains(., 'Lükka kõik tagasi') or contains(., 'Hylkää kaikki')]";if(await this.waitForElement(e,500))return this.click(e);const t="xpath///button[contains(., 'Spara & avsluta') or contains(., 'Save & exit') or contains(., 'Uložit a ukončit') or contains(., 'Enregistrer et quitter') or contains(., 'Speichern & Verlassen') or contains(., 'Tallenna ja poistu') or contains(., 'Išsaugoti ir išeiti') or contains(., 'Opslaan & afsluiten') or contains(., 'Guardar y salir') or contains(., 'Shrani in zapri') or contains(., 'Uložiť a ukončiť') or contains(., 'Kaydet ve çıkış yap') or contains(., 'Сохранить и выйти') or contains(., 'Salvesta ja välju') or contains(., 'Salva ed esci') or contains(., 'Gem & afslut') or contains(., 'Αποθήκευση και έξοδος') or contains(., 'Saglabāt un iziet') or contains(., 'Mentés és kilépés') or contains(., 'Guardar e sair') or contains(., 'Zapisz & zakończ') or contains(., 'Salvare și ieșire') or contains(., 'Spremi i izađi') or contains(., 'Запазване и изход')]";if(await this.waitForThenClick("xpath///button[contains(., 'Zwecke') or contains(., 'Σκοποί') or contains(., 'Purposes') or contains(., 'Цели') or contains(., 'Eesmärgid') or contains(., 'Tikslai') or contains(., 'Svrhe') or contains(., 'Cele') or contains(., 'Účely') or contains(., 'Finalidades') or contains(., 'Mērķi') or contains(., 'Scopuri') or contains(., 'Fines') or contains(., 'Ändamål') or contains(., 'Finalités') or contains(., 'Doeleinden') or contains(., 'Tarkoitukset') or contains(., 'Scopi') or contains(., 'Amaçlar') or contains(., 'Nameni') or contains(., 'Célok') or contains(., 'Formål')]")&&await this.waitForVisible(t)){return this.elementSelector(t)[0].parentElement.parentElement.querySelectorAll("input[type=checkbox]:checked").forEach((e=>e.click())),this.click(t)}return!1}async optIn(){return this.click("xpath///button[contains(., 'Sprejmi vse') or contains(., 'Prihvati sve') or contains(., 'Godkänn alla') or contains(., 'Prijať všetko') or contains(., 'Принять все') or contains(., 'Aceptar todo') or contains(., 'Αποδοχή όλων') or contains(., 'Zaakceptuj wszystkie') or contains(., 'Accetta tutto') or contains(., 'Priimti visus') or contains(., 'Pieņemt visu') or contains(., 'Tümünü kabul et') or contains(., 'Az összes elfogadása') or contains(., 'Accept all') or contains(., 'Приемане на всички') or contains(., 'Accepter alle') or contains(., 'Hyväksy kaikki') or contains(., 'Tout accepter') or contains(., 'Alles accepteren') or contains(., 'Aktsepteeri kõik') or contains(., 'Přijmout vše') or contains(., 'Alles akzeptieren') or contains(., 'Aceitar tudo') or contains(., 'Acceptați tot')]")}}],_=class{constructor(e){this.autoconsentInstance=e}click(e,t=!1){const o=this.elementSelector(e);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[click]",e,t,o),o.length>0&&(t?o.forEach((e=>e.click())):o[0].click()),o.length>0}elementExists(e){return this.elementSelector(e).length>0}elementVisible(e,t){const o=this.elementSelector(e),i=new Array(o.length);return o.forEach(((e,t)=>{i[t]=k(e)})),"none"===t?i.every((e=>!e)):0!==i.length&&("any"===t?i.some((e=>e)):i.every((e=>e)))}waitForElement(e,t=1e4){const o=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForElement]",e),f((()=>this.elementSelector(e).length>0),o,200)}waitForVisible(e,t=1e4,o="any"){const i=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForVisible]",e),f((()=>this.elementVisible(e,o)),i,200)}async waitForThenClick(e,t=1e4,o=!1){return await this.waitForElement(e,t),this.click(e,o)}wait(e){return this.autoconsentInstance.config.logs.rulesteps&&console.log("[wait]",e),new Promise((t=>{setTimeout((()=>{t(!0)}),e)}))}hide(e,t){this.autoconsentInstance.config.logs.rulesteps&&console.log("[hide]",e);return g(m(),e,t)}prehide(e){const t=m("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[prehide]",t,location.href),g(t,e,"opacity")}undoPrehide(){const e=m("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[undoprehide]",e,location.href),e&&e.remove(),!!e}async createOrUpdateStyleSheet(e,t){return t||(t=new CSSStyleSheet),t=await t.replace(e)}removeStyleSheet(e){return!!e&&(e.replace(""),!0)}querySingleReplySelector(e,t=document){if(e.startsWith("aria/"))return[];if(e.startsWith("xpath/")){const o=e.slice(6),i=document.evaluate(o,t,null,XPathResult.ANY_TYPE,null);let n=null;const s=[];for(;n=i.iterateNext();)s.push(n);return s}return e.startsWith("text/")||e.startsWith("pierce/")?[]:t.shadowRoot?Array.from(t.shadowRoot.querySelectorAll(e)):Array.from(t.querySelectorAll(e))}querySelectorChain(e){let t,o=document;for(const i of e){if(t=this.querySingleReplySelector(i,o),0===t.length)return[];o=t[0]}return t}elementSelector(e){return"string"==typeof e?this.querySingleReplySelector(e):this.querySelectorChain(e)}};function C(){return{chars:new Map,code:void 0}}var x=new Uint8Array(0),S=class{constructor(e,t=3e4){this.trie=function(e){const t=C();for(let o=0;o figure.wp-block-image:has(> img[class^="wp-image-"][src^="https://www.sinhasannews.com/"][width="','"]:not([style^="width: 1px; height: 1px; position: absolute; left: -10000px; top: -"])',"acs, document.createElement, %2Fl%5C.parentNode%5C.insertBefore%5C(s%2F","%2Fvisit%2F%22%5D%5Btitle%5E%3D%22https%3A%2F%2F%22%5D, %5Btitle%5D",", OptanonConsent, groups%3DC0001%253A1%252CC0002%253A0%252CC000","rmnt, script, %2Fh%3DdecodeURIComponent%7CpopundersPerIP%2F",'.project-description [href^="/linkout?remoteUrl="][href*="',':not([style^="position: absolute; left: -5000px"])',"href-sanitizer, a%5Bhref%5E%3D%22https%3A%2F%2F","ra, oncontextmenu%7Condragstart%7Conselectstart",", OptanonAlertBoxClosed, %24currentDate%24","acs, document.querySelectorAll, popMagic","acs, addEventListener, google_ad_client","aost, String.prototype.charCodeAt, ai_","aopr, app_vars.force_disable_adblock","acs, document.addEventListener, ","taboola-below-article-thumbnails","acs, document.getElementById, ","no-fetch-if, googlesyndication","aopr, document.dispatchEvent","no-xhr-if, googlesyndication",", document.createElement, ","acs, String.fromCharCode, ","%2522%253Afalse%252C%2522",", document.oncontextmenu","%2522%253Atrue%252C%2522","aeld, DOMContentLoaded, ","nosiif, visibility, 1000","set-local-storage-item, ","%2522%3Afalse%252C%2522","trusted-click-element, ","set, blurred, false","acs, eval, replace","decodeURIComponent",'[target="_blank"]',"%22%3Afalse%2C%22","^script:has-text(",'[href^="https://','[href^="http://','[href="https://','[src^="https://','[data-testid="',"modal-backdrop","rmnt, script, ","BlockDetected","trusted-set-",".prototype.","contextmenu","no-fetch-if","otification",":has-text(","background",'[class*="','[class^="',"body,html","container","Container","decodeURI","div[class",'div[id^="',"div[style","document.","no-xhr-if","placehold",'[href*="',"#wpsafe-","AAAAAAAA","Detector","disclaim","nano-sib","nextFunc","noopFunc","nostif, ","nowebrtc",'.com/"]',"300x250","article","consent","Consent","content","display","keydown","message","Message","overlay","privacy","sidebar","sponsor","wrapper","-child","[data-","accept","Accept","aopr, ","banner","bottom","cookie","Cookie","google","nosiif","notice","nowoif","policy","Policy","script","widget",":has(",":not(","block","Block","click","deskt","disab","fixed","frame","modal","popup","video",".com","2%3A","aeld","body","butt","foot","gdpr","html","icky","ight","show","tion","true"," > ","%3D","%7C","age","box","div","ent","out","rap","set","__",", ",'"]',"%2","%5",'="',"00","ac","ad","Ad","al","an","ar","at","e-","ed","en","er","he","id","in","la","le","lo","od","ol","om","on","op","or","re","s_","s-","se","st","t-","te","ti","un","_","-",";",":",".","(",")","[","]","*","/","#","^","0","1","2","3","4","5","6","7","8","9","b","B","c","C","d","D","e","E","f","F","g","G","h","H","I","j","J","k","l","L","m","M","n","N","O","p","P","q","Q","R","s","S","t","T","u","U","v","V","w","W","x","y","Y","z"],O=["sandbox allow-forms allow-same-origin allow-scripts allow-modals allow-orientation-lock allow-pointer-lock allow-presentation allow-top-navigation","script-src 'self' 'unsafe-inline' 'unsafe-eval' "," *.google.com *.gstatic.com *.googleapis.com",".com *.google.com *.googletagmanager.com *.","script-src 'self' '*' 'unsafe-inline'","default-src 'unsafe-inline' 'self'","script-src 'self' 'unsafe-eval' "," *.google.com *.gstatic.com *.","t-src 'self' 'unsafe-inline' ","script-src * 'unsafe-inline'",".com *.googleapis.com *."," *.googletagmanager.com",".com *.bootstrapcdn.com","default-src 'self' *.","frame-src 'self' *"," *.cloudflare.com","child-src 'none';","worker-src 'none'","'unsafe-inline'"," data: blob:","*.googleapis","connect-src ","unsafe-eval'","child-src *"," *.gstatic","script-src","style-src ","frame-src","facebook","https://"," 'self'"," allow-",".com *.",".net *.","addthis","captcha","gstatic","youtube","defaul","disqus","google","https:","jquery","data:","http:","media","scrip","-src",".com",".net","n.cc"," *.","age","box","str","vic","yti"," '"," *","*.","al","am","an","as","cd","el","es","il","im","in","or","pi","st","ur","wi","wp"," ","-",";",":",".","'","*","/","3","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y"],T=["/homad-global-configs.schneevonmorgen.com/global_config","/videojs-vast-vpaid@2.0.2/bin/videojs_5.vast.vpaid.min","/etc.clientlibs/logitech-common/clientlibs/onetrust.","/pagead/managed/js/adsense/*/show_ads_impl","/pagead/managed/js/gpt/*/pubads_impl","/wrappermessagingwithoutdetection","/pagead/js/adsbygoogle.js","a-z]{8,15}\\.(?:com|net)\\/","/js/sdkloader/ima3.js","/js/sdkloader/ima3_d","/videojs-contrib-ads","/wp-content/plugins/","/wp-content/uploads/","/wp-content/themes/","/detroitchicago/","*/satellitelib-","/appmeasurement","/413gkwmt/init","/cdn-cgi/trace","/^https?:\\/\\/","[a-zA-Z0-9]{","/^https:\\/\\/","notification","\\/[a-z0-9]{","fingerprint","impression","[0-9a-z]{","/plugins/","affiliate","analytics","telemetry","(.+?\\.)?","/assets/","/images/","/pagead/","pageview","template","tracking","/public","300x250","ampaign","captcha","collect","consent","content","counter","default","metrics","privacy","[a-z]{","/embed","728x90","banner","bundle","client","cookie","detect","dn-cgi","google","iframe","module","prebid","script","source","widget",".aspx",".cgi?",".com/",".html","/api/","/beac","/img/","/java","/stat","0x600","block","click","count","event","manag","media","pixel","popup","tegra","theme","track","type=","video","visit",".css",".gif",".jpg",".min",".php",".png","/jqu","/js/","/lib","/log","/web","/wp-","468x","data","gdpr","gi-b","http","ight","mail","play","plug","publ","show","stat","uild","view",".js","/ad","=*&","age","com","ext","jax","key","log","new","sdk","tag","web","ync",":/","*/","*^","/_","/?","/*","/d","/f","/g","/h","/l","/n","/r","/u","/w","ac","ad","al","am","an","ap","ar","as","at","bo","ce","ch","co","de","e/","ec","ed","el","en","er","et","fi","g/","ic","id","im","in","is","it","js","la","le","li","lo","ma","mo","mp","ol","om","on","op","or","ot","re","ro","s_","s-","s?","s/","sp","ss","st","t/","ti","tm","tr","ub","un","ur","us","ut","ve","_","-",",","?",".","}","*","/","\\","&","^","=","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],P=["securepubads.g.doubleclick",".actonservice.com","googlesyndication","imasdk.googleapis",".cloudfront.net","googletagmanag","-1.xx.fbcdn","analytics.","marketing.","tracking.","metrics.","images.",".co.uk","a8clk.","stats.","a8cv.","click","media","track",".com",".net",".xyz","www.",".io",".jp","a8.","app","cdn","new","web",".b",".c",".d",".f",".h",".k",".m",".n",".p",".s",".t","10","24","a-","a1","a2","a4","ab","ac","ad","af","ag","ah","ai","ak","al","am","an","ap","ar","as","at","au","av","aw","ax","ay","az","be","bi","bl","bo","br","bu","ca","ce","ch","ci","ck","cl","cr","ct","cu","de","di","dn","do","dr","ds","du","dy","e-","eb","ec","ed","ef","eg","el","em","en","ep","er","es","et","eu","ev","ew","ex","ey","fe","ff","fi","fo","fr","ft","ge","gh","gi","gn","go","gr","gu","he","ho","ib","ic","id","ie","if","ig","ik","il","im","in","ip","ir","is","it","iv","ix","iz","jo","ks","la","le","li","ll","lo","lu","ly","ma","me","mo","mp","my","no","ok","ol","om","on","oo","op","or","ot","ou","ph","pl","po","pr","pu","qu","re","ri","ro","ru","s-","sc","se","sh","si","sk","sn","so","sp","ss","st","su","sw","sy","t-","ta","te","th","ti","tn","to","tr","ts","tu","ty","ub","ud","ul","um","un","up","ur","us","ut","ve","vi","vo","wa","we","wh","wn","-",".","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],R=["google-analytics.com/analytics.js","googlesyndication_adsbygoogle.js","googletagmanager.com/gtm.js","googletagservices_gpt.js","googletagmanager_gtm.js","fuckadblock.js-3.2.0","amazon_apstag.js","google-analytics","fingerprint2.js","noop-1s.mp4:10","google-ima.js","noop-0.1s.mp3","prebid-ads.js","nobab2.js:10","noopmp3-0.1s","noop-1s.mp4","hd-main.js","noopmp4-1s","32x32.png","noop.html","noopframe","noop.txt","nooptext","1x1.gif","2x2.png","noop.js","noopjs",".com/",".js:5","noop",":10",".js","ads","bea","_a",":5",".0","ar","ch","ic","in","le","ma","on","re","st","_","-",":",".","/","0","1","2","3","4","5","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","r","s","t","u","v","w","x","y","z"],z=[",redirect=google-ima","/js/sdkloader/ima3.j","/wp-content/plugins/",",redirect-rule=noop",".actonservice.com^",".com^$third-party","googlesyndication","imasdk.googleapis",".cloudfront.net^",",redirect-rule=","$script,domain=",",3p,denyallow=",",redirect=noop","xmlhttprequest","^$third-party","||smetrics.","third-party","marketing.","$document","analytics",",domain=","/assets/","metrics.","subdocum","tracking","$script",".co.uk","$ghide","a8clk.","cookie","google","script",".com^",".xyz^","$doma","a8cv.","click","image","media","track",".com",".fr^",".gif",".jp^",".net","/js/","$doc","$xhr","stat","www.",",1p",",3p",".io",".jp",".js","app","cdn","ent","new","web",".b",".c",".d",".f",".h",".m",".n",".p",".s",".t","@@","/*","/p","||","ab","ac","ad","af","ag","ai","ak","al","am","an","ap","ar","as","at","au","av","aw","ax","ay","az","be","bi","bo","br","ca","ce","ch","ck","cl","ct","cu","de","di","do","e-","e^","ec","ed","el","em","en","ep","er","es","et","ev","ew","ex","fe","ff","fi","fo","fr","g^","ge","gi","go","gr","he","hi","ho","hp","ht","ic","id","ig","il","im","in","ip","ir","is","it","ix","js","ke","le","li","lo","lu","ly","me","mo","mp","ne","no","od","ok","ol","om","on","op","or","ot","ow","pl","po","pr","qu","re","ri","ro","ru","s-","s/","sc","se","sh","si","so","sp","ss","st","su","te","th","ti","to","tr","ts","ty","ub","ud","ul","um","un","up","ur","us","ut","ve","vi","_","-",",","?",".","*","/","^","=","|","~","$","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],L=["-webkit-touch-callo",", 1year, , domain, ",", googlesyndication",", SOCS, CAISNQgQEit",":style(overflow: au","##^script:has-text(","9udGVuZHVpc2VydmVyX","GgJmaSADGgYIgOu0sgY","ib3FfaWRlbnRpdHlmcm","position: initial !","set-local-storage-i","set, blurred, false","user-select: text !","zIwMjQwNTE0LjA2X3Aw",'[href^="https://',"rmnt, script, ","ut: default !"," !important)","trusted-set-",", document.",", noopFunc)","##body,html","contextmenu","no-fetch-if","otification",".com##+js(",'="https://',"background","important;"," -webkit-",".*,xhamst","container","AAAAAAAA","nostif, ",",google",":style(","consent","message","nowoif)","privacy","-wrapp",",kayak",".co.uk","[class","##+js(","accept","aopr, ","banner","bottom","cookie","Cookie","google","notice","policy","widget",":has(","##div","block","cript","true)",".co.",".com",".de,",".fr,",".net",".nl,",".pl,",".xyz","#@#.","2%3A","gdpr","html","ight","news","text","to !","wrap","www."," > ",",xh","##.","###","%3D","%7C","ent","lay","web","__","-s",", ",",b",",c",",f",",g",",h",",m",",p",",s",",t",": ",".*",".b",".c",".m",".p",".s",'"]',"##","%2","%5",'="',"00","a-","ab","ac","ad","Ad","af","ag","ak","al","am","an","ap","ar","as","at","au","av","ay","az","bo","ch","ck","cl","ct","de","di","do","e-","ed","el","em","en","er","es","et","ex","fi","fo","he","ic","id","if","ig","il","im","in","is","it","iv","le","lo","mo","ol","om","on","op","or","ot","ov","pl","po","re","ro","s_","s-","se","sh","si","sp","st","t-","th","ti","tr","tv","ub","ul","um","un","up","ur","us","ut","vi"," ","_","-",",",":",".","(",")","[","*","/","^","0","1","2","3","4","5","6","7","8","9","a","b","B","c","C","d","D","e","E","f","F","g","h","i","j","k","l","L","m","M","n","o","p","P","q","r","s","S","t","T","u","v","w","x","y","z"],B=class{constructor(){this.cosmeticSelector=new I(F),this.networkCSP=new I(O),this.networkRedirect=new I(R),this.networkHostname=new I(P),this.networkFilter=new I(T),this.networkRaw=new I(z),this.cosmeticRaw=new I(L)}},U=(()=>{let e=0;const t=new Int32Array(256);for(let o=0;256!==o;o+=1)e=o,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,t[o]=e;return t})();var N=2147483647,V=36,j=1,M=26,D=38,H=700,W=72,q=128,G="-",$=/[^\0-\x7E]/,K=/[\x2E\u3002\uFF0E\uFF61]/g,Q={"invalid-input":"Invalid input","not-basic":"Illegal input >= 0x80 (not a basic code point)",overflow:"Overflow: input needs wider integers to process"},Y=V-j;function X(e){throw new RangeError(Q[e])}function Z(e,t){return e+22+75*(e<26?1:0)-((0!==t?1:0)<<5)}function J(e,t,o){let i=0;for(e=o?Math.floor(e/H):e>>1,e+=Math.floor(e/t);e>Y*M>>1;i+=V)e=Math.floor(e/Y);return Math.floor(i+(Y+1)*e/(e+D))}function ee(e){const t=[],o=e.length;let i=0,n=q,s=W,c=e.lastIndexOf(G);c<0&&(c=0);for(let o=0;o=128&&X("not-basic"),t.push(e.charCodeAt(o));for(let a=c>0?c+1:0;a=o&&X("invalid-input");const c=(r=e.charCodeAt(a++))-48<10?r-22:r-65<26?r-65:r-97<26?r-97:V;(c>=V||c>Math.floor((N-i)/t))&&X("overflow"),i+=c*t;const l=n<=s?j:n>=s+M?M:n-s;if(cMath.floor(N/p)&&X("overflow"),t*=p}const l=t.length+1;s=J(i-c,l,0===c),Math.floor(i/l)>N-n&&X("overflow"),n+=Math.floor(i/l),i%=l,t.splice(i++,0,n)}var r;return String.fromCodePoint.apply(null,t)}function te(e){const t=[],o=function(e){const t=[];let o=0;const i=e.length;for(;o=55296&&n<=56319&&o=n&&iMath.floor((N-s)/i)&&X("overflow"),s+=(e-n)*i,n=e;for(let e=0;eN&&X("overflow"),l===n){let e=s;for(let o=V;;o+=V){const i=o<=c?j:o>=c+M?M:o-c;if(e{const e=new B;return ce=()=>e,e};function re(e){return e<=127?1:5}function ae(e,t){return le(e.length,t)}function le(e,t){return(t?3:0)+e+re(e)}function pe(e){return e.length+re(e.length)}function de(e){const t=te(e).length;return t+re(t)}function ue(e){return e.byteLength+re(e.length)}var he,me=class e{static empty(t){return e.fromUint8Array(ie,t)}static fromUint8Array(t,o){return new e(t,o)}static allocate(t,o){return new e(new Uint8Array(t),o)}constructor(e,{enableCompression:t}){if(!1===se)throw new Error("Adblocker currently does not support Big-endian systems");!0===t&&this.enableCompression(),this.buffer=e,this.pos=0}enableCompression(){this.compression=ce()}checksum(){return function(e,t,o){let i=-1;const n=o-7;let s=t;for(;s>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])];for(;s>>8^U[255&(i^e[s++])];return(-1^i)>>>0}(this.buffer,0,this.pos)}dataAvailable(){return this.pos>>8,this.buffer[this.pos++]=e}getUint16(){return(this.buffer[this.pos++]<<8|this.buffer[this.pos++])>>>0}pushUint32(e){this.buffer[this.pos++]=e>>>24,this.buffer[this.pos++]=e>>>16,this.buffer[this.pos++]=e>>>8,this.buffer[this.pos++]=e}getUint32(){return(this.buffer[this.pos++]<<24>>>0)+(this.buffer[this.pos++]<<16|this.buffer[this.pos++]<<8|this.buffer[this.pos++])>>>0}pushUint32Array(e){this.pushLength(e.length);for(const t of e)this.pushUint32(t)}getUint32Array(){const e=this.getLength(),t=new Uint32Array(e);for(let o=0;othis.buffer.byteLength)throw new Error(`StaticDataView too small: ${this.buffer.byteLength}, but required ${this.pos} bytes`)}pushLength(e){e<=127?this.pushUint8(e):(this.pushUint8(128),this.pushUint32(e))}getLength(){const e=this.getUint8();return 128===e?this.getUint32():e}},Ae=class e{static deserialize(t){return new e({debug:t.getBool(),enableCompression:t.getBool(),enableHtmlFiltering:t.getBool(),enableInMemoryCache:t.getBool(),enableMutationObserver:t.getBool(),enableOptimizations:t.getBool(),enablePushInjectionsOnNavigationEvents:t.getBool(),guessRequestTypeFromUrl:t.getBool(),integrityCheck:t.getBool(),loadCSPFilters:t.getBool(),loadCosmeticFilters:t.getBool(),loadExceptionFilters:t.getBool(),loadExtendedSelectors:t.getBool(),loadGenericCosmeticsFilters:t.getBool(),loadNetworkFilters:t.getBool(),loadPreprocessors:t.getBool()})}constructor({debug:e=!1,enableCompression:t=!1,enableHtmlFiltering:o=!1,enableInMemoryCache:i=!0,enableMutationObserver:n=!0,enableOptimizations:s=!0,enablePushInjectionsOnNavigationEvents:c=!0,guessRequestTypeFromUrl:r=!1,integrityCheck:a=!0,loadCSPFilters:l=!0,loadCosmeticFilters:p=!0,loadExceptionFilters:d=!0,loadExtendedSelectors:u=!1,loadGenericCosmeticsFilters:h=!0,loadNetworkFilters:m=!0,loadPreprocessors:A=!1}={}){this.debug=e,this.enableCompression=t,this.enableHtmlFiltering=o,this.enableInMemoryCache=i,this.enableMutationObserver=n,this.enableOptimizations=s,this.enablePushInjectionsOnNavigationEvents=c,this.guessRequestTypeFromUrl=r,this.integrityCheck=a,this.loadCSPFilters=l,this.loadCosmeticFilters=p,this.loadExceptionFilters=d,this.loadExtendedSelectors=u,this.loadGenericCosmeticsFilters=h,this.loadNetworkFilters=m,this.loadPreprocessors=A}getSerializedSize(){return 16}serialize(e){e.pushBool(this.debug),e.pushBool(this.enableCompression),e.pushBool(this.enableHtmlFiltering),e.pushBool(this.enableInMemoryCache),e.pushBool(this.enableMutationObserver),e.pushBool(this.enableOptimizations),e.pushBool(this.enablePushInjectionsOnNavigationEvents),e.pushBool(this.guessRequestTypeFromUrl),e.pushBool(this.integrityCheck),e.pushBool(this.loadCSPFilters),e.pushBool(this.loadCosmeticFilters),e.pushBool(this.loadExceptionFilters),e.pushBool(this.loadExtendedSelectors),e.pushBool(this.loadGenericCosmeticsFilters),e.pushBool(this.loadNetworkFilters),e.pushBool(this.loadPreprocessors)}},ge="undefined"!=typeof window&&"function"==typeof window.queueMicrotask?e=>window.queueMicrotask(e):e=>(he||(he=Promise.resolve())).then(e).catch((e=>setTimeout((()=>{throw e}),0)));function fe(e,t,o){let i=o.get(e);void 0===i&&(i=[],o.set(e,i)),i.push(t)}function ke(e,t,o){const i=o.get(e);if(void 0!==i){const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}function be(e,t,o){if(0===o.size)return!1;const i=o.get(e);return void 0!==i&&(ge((()=>{for(const e of i)e(...t)})),!0)}var ye=class{constructor(){this.onceListeners=new Map,this.onListeners=new Map}on(e,t){fe(e,t,this.onListeners)}once(e,t){fe(e,t,this.onceListeners)}unsubscribe(e,t){ke(e,t,this.onListeners),ke(e,t,this.onceListeners)}emit(e,...t){be(e,t,this.onListeners),!0===be(e,t,this.onceListeners)&&this.onceListeners.delete(e)}};function we(e,t){return function(e,t){let o=3;const i=()=>e(t).catch((e=>{if(o>0)return o-=1,new Promise(((e,t)=>{setTimeout((()=>{i().then(e).catch(t)}),500)}));throw e}));return i()}(e,t).then((e=>e.text()))}var ve="https://raw.githubusercontent.com/ghostery/adblocker/master/packages/adblocker/assets",_e=[`${ve}/easylist/easylist.txt`,`${ve}/peter-lowe/serverlist.txt`,`${ve}/ublock-origin/badware.txt`,`${ve}/ublock-origin/filters-2020.txt`,`${ve}/ublock-origin/filters-2021.txt`,`${ve}/ublock-origin/filters-2022.txt`,`${ve}/ublock-origin/filters-2023.txt`,`${ve}/ublock-origin/filters-2024.txt`,`${ve}/ublock-origin/filters.txt`,`${ve}/ublock-origin/quick-fixes.txt`,`${ve}/ublock-origin/resource-abuse.txt`,`${ve}/ublock-origin/unbreak.txt`],Ce=[..._e,`${ve}/easylist/easyprivacy.txt`,`${ve}/ublock-origin/privacy.txt`],xe=[...Ce,`${ve}/easylist/easylist-cookie.txt`,`${ve}/ublock-origin/annoyances-others.txt`,`${ve}/ublock-origin/annoyances-cookies.txt`];var Se=new Set(["any","dir","has","host-context","if","if-not","is","matches","not","where"]),Ee={attribute:/\[\s*(?:(?\*|[-\w]*)\|)?(?[-\w\u{0080}-\u{FFFF}]+)\s*(?:(?\W?=)\s*(?.+?)\s*(?[iIsS])?\s*)?\]/gu,id:/#(?(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,class:/\.(?(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,comma:/\s*,\s*/g,combinator:/\s*[\s>+~]\s*/g,"pseudo-element":/::(?[-\w\u{0080}-\u{FFFF}]+)(?:\((?:¶*)\))?/gu,"pseudo-class":/:(?[-\w\u{0080}-\u{FFFF}]+)(?:\((?¶*)\))?/gu,type:/(?:(?\*|[-\w]*)\|)?(?[-\w\u{0080}-\u{FFFF}]+)|\*/gu},Ie=new Set(["pseudo-class","pseudo-element"]),Fe=new Set([...Ie,"attribute"]),Oe=new Set(["combinator","comma"]),Te=Object.assign({},Ee);function Pe(e,t){e.lastIndex=0;const o=e.exec(t);if(null===o)return;const i=o.index-1,n=o[0],s=t.slice(0,i+1),c=t.slice(i+n.length+1);return[s,[n,o.groups||{}],c]}Te["pseudo-element"]=RegExp(Ee["pseudo-element"].source.replace("(?¶*)","(?.*?)"),"gu"),Te["pseudo-class"]=RegExp(Ee["pseudo-class"].source.replace("(?¶*)","(?.*)"),"gu");var Re=[e=>{const t=Pe(Ee.attribute,e);if(void 0===t)return;const[o,[i,{name:n,operator:s,value:c,namespace:r,caseSensitive:a}],l]=t;return void 0!==n?[o,{type:"attribute",content:i,length:i.length,namespace:r,caseSensitive:a,pos:[],name:n,operator:s,value:c},l]:void 0},e=>{const t=Pe(Ee.id,e);if(void 0===t)return;const[o,[i,{name:n}],s]=t;return void 0!==n?[o,{type:"id",content:i,length:i.length,pos:[],name:n},s]:void 0},e=>{const t=Pe(Ee.class,e);if(void 0===t)return;const[o,[i,{name:n}],s]=t;return void 0!==n?[o,{type:"class",content:i,length:i.length,pos:[],name:n},s]:void 0},e=>{const t=Pe(Ee.comma,e);if(void 0===t)return;const[o,[i],n]=t;return[o,{type:"comma",content:i,length:i.length,pos:[]},n]},e=>{const t=Pe(Ee.combinator,e);if(void 0===t)return;const[o,[i],n]=t;return[o,{type:"combinator",content:i,length:i.length,pos:[]},n]},e=>{const t=Pe(Ee["pseudo-element"],e);if(void 0===t)return;const[o,[i,{name:n}],s]=t;return void 0!==n?[o,{type:"pseudo-element",content:i,length:i.length,pos:[],name:n},s]:void 0},e=>{const t=Pe(Ee["pseudo-class"],e);if(void 0===t)return;const[o,[i,{name:n,argument:s}],c]=t;return void 0!==n?[o,{type:"pseudo-class",content:i,length:i.length,pos:[],name:n,argument:s,subtree:void 0},c]:void 0},e=>{const t=Pe(Ee.type,e);if(void 0===t)return;const[o,[i,{name:n,namespace:s}],c]=t;return[o,{type:"type",content:i,length:i.length,namespace:s,pos:[],name:n},c]}];function ze(e,t,o,i){for(const n of t)for(const t of e)if(i.has(t.type)&&t.pos[0]=0&&"\\"===e[t];)o+=1,t-=1;return o%2!=0}function Be(e,t,o){let i=o+1;for(;-1!==(i=e.indexOf(t,i))&&!0===Le(e,i);)i+=1;if(-1!==i)return e.slice(o,i+1)}function Ue(e,t){let o=0;for(let i=t;i0))return;o-=1}if(0===o)return e.slice(t,i+1)}}function Ne(e,t,o,i){const n=[];let s=0;for(;-1!==(s=e.indexOf(o,s));){const o=i(e,s);if(void 0===o)break;n.push({str:o,start:s}),e=`${e.slice(0,s+1)}${t.repeat(o.length-2)}${e.slice(s+o.length-1)}`,s+=o.length}return[n,e]}function Ve(e){if("string"!=typeof e)return[];if(0===(e=e.trim()).length)return[];const[t,o]=Ne(e,"§",'"',((e,t)=>Be(e,'"',t))),[i,n]=Ne(o,"§","'",((e,t)=>Be(e,"'",t))),[s,c]=Ne(n,"¶","(",Ue),r=function(e){if(!e)return[];const t=[e];for(const e of Re)for(let o=0;o0!==e.length)))}}let o=0;for(const e of t)"string"!=typeof e&&(e.pos=[o,o+e.length],Oe.has(e.type)&&(e.content=e.content.trim()||" ")),o+=e.length;return t.every((e=>"string"!=typeof e))?t:[]}(c);return ze(r,s,/\(¶*\)/,Ie),ze(r,t,/"§*"/,Fe),ze(r,i,/'§*'/,Fe),r}function je(e,{list:t=!0}={}){if(!0===t&&e.some((e=>"comma"===e.type))){const t=[],o=[];for(let i=0;i=0;t--){const o=e[t];if("combinator"===o.type){const i=je(e.slice(0,t)),n=je(e.slice(t+1));if(void 0===n)return;if(" "!==o.content&&"~"!==o.content&&"+"!==o.content&&">"!==o.content)return;return{type:"complex",combinator:o.content,left:i,right:n}}}if(0!==e.length)return function(e){return e.every((e=>"comma"!==e.type&&"combinator"!==e.type))}(e)?1===e.length?e[0]:{type:"compound",compound:[...e]}:void 0}function Me(e,t,o,i){if(void 0!==e){if("complex"===e.type)Me(e.left,t,o,e),Me(e.right,t,o,e);else if("compound"===e.type)for(const i of e.compound)Me(i,t,o,e);else"pseudo-class"===e.type&&void 0!==e.subtree&&void 0!==o&&"pseudo-class"===o.type&&void 0!==o.subtree&&Me(e.subtree,t,o,e);t(e,i)}}function De(e,{recursive:t=!0,list:o=!0}={}){const i=Ve(e);if(0===i.length)return;const n=je(i,{list:o});return!0===t&&Me(n,(e=>{"pseudo-class"===e.type&&e.argument&&void 0!==e.name&&Se.has(e.name)&&(e.subtree=De(e.argument,{recursive:!0,list:!0}))})),n}var He,We,qe=new Set(["has","has-text","if"]),Ge=new Set(["active","any","any-link","blank","checked","default","defined","dir","disabled","empty","enabled","first","first-child","first-of-type","focus","focus-visible","focus-within","fullscreen","host","host-context","hover","in-range","indeterminate","invalid","is","lang","last-child","last-of-type","left","link","matches","not","nth-child","nth-last-child","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","placeholder-shown","read-only","read-write","required","right","root","scope","target","valid","visited","where"]),$e=new Set(["after","before","first-letter","first-line"]);function Ke(e){if(-1===e.indexOf(":"))return He.Normal;const t=Ve(e);let o=!1;for(const e of t)if("pseudo-class"===e.type){const{name:t}=e;if(!0===qe.has(t))o=!0;else if(!1===Ge.has(t)&&!1===$e.has(t))return He.Invalid;if(!1===o&&void 0!==e.argument&&!0===Se.has(t)){const t=Ke(e.argument);if(t===He.Invalid)return t;t===He.Extended&&(o=!0)}}return!0===o?He.Extended:He.Normal}(We=He||(He={}))[We.Normal=0]="Normal",We[We.Extended=1]="Extended",We[We.Invalid=2]="Invalid";var Qe=new Set(["htm","html","xhtml"]),Ye=new Set(["eot","otf","sfnt","ttf","woff","woff2"]),Xe=new Set(["apng","bmp","cur","dib","eps","gif","heic","heif","ico","j2k","jfi","jfif","jif","jp2","jpe","jpeg","jpf","jpg","jpm","jpx","mj2","pjp","pjpeg","png","svg","svgz","tif","tiff","webp"]),Ze=new Set(["avi","flv","mp3","mp4","ogg","wav","weba","webm","wmv"]),Je=new Set(["js","ts","jsx","esm"]),et=new Set(["css","scss"]);function tt(e,t){let o=0,i=e.length,n=!1;if(!t){if(e.startsWith("data:"))return null;for(;oo+1&&e.charCodeAt(i-1)<=32;)i-=1;if(47===e.charCodeAt(o)&&47===e.charCodeAt(o+1))o+=2;else{const t=e.indexOf(":/",o);if(-1!==t){const i=t-o,n=e.charCodeAt(o),s=e.charCodeAt(o+1),c=e.charCodeAt(o+2),r=e.charCodeAt(o+3),a=e.charCodeAt(o+4);if(5===i&&104===n&&116===s&&116===c&&112===r&&115===a);else if(4===i&&104===n&&116===s&&116===c&&112===r);else if(3===i&&119===n&&115===s&&115===c);else if(2===i&&119===n&&115===s);else for(let i=o;i=97&&t<=122||t>=48&&t<=57||46===t||45===t||43===t))return null}for(o=t+2;47===e.charCodeAt(o);)o+=1}}let t=-1,s=-1,c=-1;for(let r=o;r=65&&o<=90&&(n=!0)}if(-1!==t&&t>o&&to&&co+1&&46===e.charCodeAt(i-1);)i-=1;const s=0!==o||i!==e.length?e.slice(o,i):e;return n?s.toLowerCase():s}function ot(e){return e>=97&&e<=122||e>=48&&e<=57||e>127}function it(e){if(e.length>255)return!1;if(0===e.length)return!1;if(!ot(e.charCodeAt(0))&&46!==e.charCodeAt(0)&&95!==e.charCodeAt(0))return!1;let t=-1,o=-1;const i=e.length;for(let n=0;n64||46===o||45===o||95===o)return!1;t=n}else if(!ot(i)&&45!==i&&95!==i)return!1;o=i}return i-t-1<=63&&45!==o}var nt=function({allowIcannDomains:e=!0,allowPrivateDomains:t=!1,detectIp:o=!0,extractHostname:i=!0,mixedInputs:n=!0,validHosts:s=null,validateHostname:c=!0}){return{allowIcannDomains:e,allowPrivateDomains:t,detectIp:o,extractHostname:i,mixedInputs:n,validHosts:s,validateHostname:c}}({});function st(e,t,o,i,n){const s=function(e){return void 0===e?nt:function({allowIcannDomains:e=!0,allowPrivateDomains:t=!1,detectIp:o=!0,extractHostname:i=!0,mixedInputs:n=!0,validHosts:s=null,validateHostname:c=!0}){return{allowIcannDomains:e,allowPrivateDomains:t,detectIp:o,extractHostname:i,mixedInputs:n,validHosts:s,validateHostname:c}}(e)}(i);return"string"!=typeof e?n:(s.extractHostname?s.mixedInputs?n.hostname=tt(e,it(e)):n.hostname=tt(e,!1):n.hostname=e,0===t||null===n.hostname||s.detectIp&&(n.isIp=function(e){if(e.length<3)return!1;let t=e.startsWith("[")?1:0,o=e.length;if("]"===e[o-1]&&(o-=1),o-t>39)return!1;let i=!1;for(;t=48&&o<=57||o>=97&&o<=102||o>=65&&o<=90))return!1}return i}(c=n.hostname)||function(e){if(e.length<7)return!1;if(e.length>15)return!1;let t=0;for(let o=0;o57)return!1}return 3===t&&46!==e.charCodeAt(0)&&46!==e.charCodeAt(e.length-1)}(c),n.isIp)?n:s.validateHostname&&s.extractHostname&&!it(n.hostname)?(n.hostname=null,n):(o(n.hostname,s,n),2===t||null===n.publicSuffix?n:(n.domain=function(e,t,o){if(null!==o.validHosts){const e=o.validHosts;for(const o of e)if(function(e,t){return!!e.endsWith(t)&&(e.length===t.length||"."===e[e.length-t.length-1])}(t,o))return o}let i=0;if(t.startsWith("."))for(;i=i)return!1;let n=o,s=i-1;for(;n<=s;){const o=n+s>>>1,i=e[o];if(it))return!0;s=o-1}}return!1}var at=new Uint32Array(20);function lt(e,t,o){if(function(e,t,o){if(!t.allowPrivateDomains&&e.length>3){const t=e.length-1,i=e.charCodeAt(t),n=e.charCodeAt(t-1),s=e.charCodeAt(t-2),c=e.charCodeAt(t-3);if(109===i&&111===n&&99===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="com",!0;if(103===i&&114===n&&111===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="org",!0;if(117===i&&100===n&&101===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="edu",!0;if(118===i&&111===n&&103===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="gov",!0;if(116===i&&101===n&&110===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="net",!0;if(101===i&&100===n&&46===s)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="de",!0}return!1}(e,t,o))return;const{allowIcannDomains:i,allowPrivateDomains:n}=t;let s=-1,c=0,r=0,a=1;const l=function(e,t){let o=5381,i=0;for(let n=e.length-1;n>=0;n-=1){const s=e.charCodeAt(n);if(46===s&&(at[i<<1]=o>>>0,at[1+(i<<1)]=n+1,i+=1,i===t))return i;o=33*o^s}return at[i<<1]=o>>>0,at[1+(i<<1)]=0,i+=1,i}(e,ct[0]);for(let e=0;er;)t.shift();o.publicSuffix=t.join(".")}else o.publicSuffix=e.slice(at[1+(r-2<<1)]);else o.publicSuffix=1===l?e:e.slice(at[1])}function pt(e,t={}){return st(e,5,lt,t,{domain:null,domainWithoutSuffix:null,hostname:null,isIcann:null,isIp:null,isPrivate:null,publicSuffix:null,subdomain:null})}var dt=new class{constructor(e){this.pos=0,this.buffer=new Uint32Array(e)}reset(){this.pos=0}slice(){return this.buffer.slice(0,this.pos)}push(e){this.buffer[this.pos++]=e}empty(){return 0===this.pos}full(){return this.pos===this.buffer.length}remaining(){return this.buffer.length-this.pos}}(1024),ut=37,ht=5011;function mt(e){return 16843009*((e=(858993459&(e-=e>>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135)>>24}function At(e,t){return!!(e&t)}function gt(e,t){return e|t}function ft(e,t){return e&~t}function kt(e,t,o){let i=ht;for(let n=t;n>>0}function bt(e){return"string"!=typeof e||0===e.length?ht:kt(e,0,e.length)}function yt(e){const t=new Uint32Array(e.length);let o=0;for(const i of e)t[o++]=bt(i);return t}function wt(e,t){if(e.length=48&&e<=57}function Ct(e){return e>=97&&e<=122||e>=65&&e<=90}function xt(e){return Ct(e)||_t(e)||37===e||function(e){return e>=192&&e<=450}(e)||function(e){return e>=1024&&e<=1279}(e)}function St(e,t,o,i){const n=Math.min(e.length,2*i.remaining());let s=!1,c=0,r=ht;for(let o=0;o1&&(!1===t||0!==c)&&i.push(r>>>0))}!0===s&&!1===o&&e.length-c>1&&!1===i.full()&&i.push(r>>>0)}function Et(e,t){const o=Math.min(e.length,2*t.remaining());let i=!1,n=0,s=ht;for(let c=0;c1&&t.push(s>>>0))}!0===i&&e.length-n>1&&!1===t.full()&&t.push(s>>>0)}function It(e,t){return-1!==function(e,t){if(0===e.length)return-1;let o=0,i=e.length-1;for(;o<=i;){const n=o+i>>>1,s=e[n];if(st))return n;i=n-1}}return-1}(e,t)}var Ft=/[^\u0000-\u00ff]/;function Ot(e){return Ft.test(e)}var Tt={extractHostname:!0,mixedInputs:!1,validateHostname:!1},Pt={beacon:bt("type:beacon"),cspReport:bt("type:csp"),csp_report:bt("type:csp"),cspviolationreport:bt("type:cspviolationreport"),document:bt("type:document"),eventsource:bt("type:other"),fetch:bt("type:xhr"),font:bt("type:font"),image:bt("type:image"),imageset:bt("type:image"),mainFrame:bt("type:document"),main_frame:bt("type:document"),manifest:bt("type:other"),media:bt("type:media"),object:bt("type:object"),object_subrequest:bt("type:object"),other:bt("type:other"),ping:bt("type:ping"),prefetch:bt("type:other"),preflight:bt("type:preflight"),script:bt("type:script"),signedexchange:bt("type:signedexchange"),speculative:bt("type:other"),stylesheet:bt("type:stylesheet"),subFrame:bt("type:subdocument"),sub_frame:bt("type:subdocument"),texttrack:bt("type:other"),webSocket:bt("type:websocket"),web_manifest:bt("type:other"),websocket:bt("type:websocket"),xhr:bt("type:xhr"),xml_dtd:bt("type:other"),xmlhttprequest:bt("type:xhr"),xslt:bt("type:other")};function Rt(e){let t=ht;for(let o=e.length-1;o>=0;o-=1)t=t*ut^e.charCodeAt(o);return t>>>0}function zt(e,t,o){dt.reset();let i=ht;for(let n=t-1;n>=0;n-=1){const t=e.charCodeAt(n);46===t&&n>>0),i=i*ut^t}return dt.push(i>>>0),dt.slice()}function Lt(e,t){const o=function(e,t){let o=null;const i=t.indexOf(".");if(-1!==i){const n=t.slice(i+1);o=e.slice(0,-n.length-1)}return o}(e,t);return null!==o?zt(o,o.length,o.length):ne}function Bt(e,t){return zt(e,e.length,e.length-t.length)}var Ut=class e{static fromRawDetails({requestId:t="0",tabId:o=0,url:i="",hostname:n,domain:s,sourceUrl:c="",sourceHostname:r,sourceDomain:a,type:l="main_frame",_originalRequestDetails:p}){if(i=i.toLowerCase(),void 0===n||void 0===s){const e=pt(i,Tt);n=n||e.hostname||"",s=s||e.domain||""}if(void 0===r||void 0===a){const e=pt(r||a||c,Tt);r=r||e.hostname||"",a=a||e.domain||r||""}return new e({requestId:t,tabId:o,domain:s,hostname:n,url:i,sourceDomain:a,sourceHostname:r,sourceUrl:c,type:l,_originalRequestDetails:p})}constructor({requestId:e,tabId:t,type:o,domain:i,hostname:n,url:s,sourceDomain:c,sourceHostname:r,_originalRequestDetails:a}){if(this.tokens=void 0,this.hostnameHashes=void 0,this.entityHashes=void 0,this._originalRequestDetails=a,this.id=e,this.tabId=t,this.type=o,this.url=s,this.hostname=n,this.domain=i,this.sourceHostnameHashes=0===r.length?ne:Bt(r,c),this.sourceEntityHashes=0===r.length?ne:Lt(r,c),this.isThirdParty=function(e,t,o,i,n){return"main_frame"!==n&&"mainFrame"!==n&&(0!==t.length&&0!==i.length?t!==i:0!==t.length&&0!==o.length?t!==o:0!==i.length&&0!==e.length&&e!==i)}(n,i,r,c,o),this.isFirstParty=!this.isThirdParty,this.isSupported=!0,"websocket"===this.type||this.url.startsWith("ws:")||this.url.startsWith("wss:"))this.isHttp=!1,this.isHttps=!1,this.type="websocket",this.isSupported=!0;else if(this.url.startsWith("http:"))this.isHttp=!0,this.isHttps=!1;else if(this.url.startsWith("https:"))this.isHttps=!0,this.isHttp=!1;else if(this.url.startsWith("data:")){this.isHttp=!1,this.isHttps=!1;const e=this.url.indexOf(",");-1!==e&&(this.url=this.url.slice(0,e))}else this.isHttp=!1,this.isHttps=!1,this.isSupported=!1}getHostnameHashes(){return void 0===this.hostnameHashes&&(this.hostnameHashes=0===this.hostname.length?ne:Bt(this.hostname,this.domain)),this.hostnameHashes}getEntityHashes(){return void 0===this.entityHashes&&(this.entityHashes=0===this.hostname.length?ne:Lt(this.hostname,this.domain)),this.entityHashes}getTokens(){if(void 0===this.tokens){dt.reset();for(const e of this.sourceHostnameHashes)dt.push(e);dt.push(Pt[this.type]),Et(this.url,dt),this.tokens=dt.slice()}return this.tokens}isMainFrame(){return"main_frame"===this.type||"mainFrame"===this.type}isSubFrame(){return"sub_frame"===this.type||"subFrame"===this.type}guessTypeOfRequest(){const e=this.type;return this.type=function(e){const t=function(e){let t=e.length;const o=e.indexOf("#");-1!==o&&(t=o);const i=e.indexOf("?");-1!==i&&i=0&&(s=e.charCodeAt(n),0!=(s>=65&&s<=90||s>=97&&s<=122||s>=48&&s<=57));n-=1);return 46!==s||n<0||t-n>=10?"":e.slice(n+1,t)}(e);return Xe.has(t)||e.startsWith("data:image/")||e.startsWith("https://frog.wix.com/bt")?"image":Ze.has(t)||e.startsWith("data:audio/")||e.startsWith("data:video/")?"media":et.has(t)||e.startsWith("data:text/css")?"stylesheet":Je.has(t)||e.startsWith("data:")&&(e.startsWith("data:application/ecmascript")||e.startsWith("data:application/javascript")||e.startsWith("data:application/x-ecmascript")||e.startsWith("data:application/x-javascript")||e.startsWith("data:text/ecmascript")||e.startsWith("data:text/javascript")||e.startsWith("data:text/javascript1.0")||e.startsWith("data:text/javascript1.1")||e.startsWith("data:text/javascript1.2")||e.startsWith("data:text/javascript1.3")||e.startsWith("data:text/javascript1.4")||e.startsWith("data:text/javascript1.5")||e.startsWith("data:text/jscript")||e.startsWith("data:text/livescript")||e.startsWith("data:text/x-ecmascript")||e.startsWith("data:text/x-javascript"))||e.startsWith("https://maps.googleapis.com/maps/api/js")||e.startsWith("https://www.googletagmanager.com/gtag/js")?"script":Qe.has(t)||e.startsWith("data:text/html")||e.startsWith("data:application/xhtml")||e.startsWith("https://www.youtube.com/embed/")||e.startsWith("https://www.google.com/gen_204")?"document":Ye.has(t)||e.startsWith("data:font/")?"font":"other"}(this.url),e!==this.type&&(this.tokens=void 0),this.type}},Nt=class e{static parse(t,o=!1){if(0===t.length)return;const i=[],n=[],s=[],c=[];for(let e of t){Ot(e)&&(e=oe(e));const t=126===e.charCodeAt(0),o=42===e.charCodeAt(e.length-1)&&46===e.charCodeAt(e.length-2),r=t?1:0,a=o?e.length-2:e.length,l=Rt(!0===t||!0===o?e.slice(r,a):e);t?o?n.push(l):c.push(l):o?i.push(l):s.push(l)}return new e({entities:0!==i.length?new Uint32Array(i).sort():void 0,hostnames:0!==s.length?new Uint32Array(s).sort():void 0,notEntities:0!==n.length?new Uint32Array(n).sort():void 0,notHostnames:0!==c.length?new Uint32Array(c).sort():void 0,parts:!0===o?t.join(","):void 0})}static deserialize(t){const o=t.getUint8();return new e({entities:1==(1&o)?t.getUint32Array():void 0,hostnames:2==(2&o)?t.getUint32Array():void 0,notEntities:4==(4&o)?t.getUint32Array():void 0,notHostnames:8==(8&o)?t.getUint32Array():void 0,parts:16==(16&o)?t.getUTF8():void 0})}constructor({entities:e,hostnames:t,notEntities:o,notHostnames:i,parts:n}){this.entities=e,this.hostnames=t,this.notEntities=o,this.notHostnames=i,this.parts=n}updateId(e){const{hostnames:t,entities:o,notHostnames:i,notEntities:n}=this;if(void 0!==t)for(const o of t)e=e*ut^o;if(void 0!==o)for(const t of o)e=e*ut^t;if(void 0!==i)for(const t of i)e=e*ut^t;if(void 0!==n)for(const t of n)e=e*ut^t;return e}serialize(e){const t=e.getPos();e.pushUint8(0);let o=0;void 0!==this.entities&&(o|=1,e.pushUint32Array(this.entities)),void 0!==this.hostnames&&(o|=2,e.pushUint32Array(this.hostnames)),void 0!==this.notEntities&&(o|=4,e.pushUint32Array(this.notEntities)),void 0!==this.notHostnames&&(o|=8,e.pushUint32Array(this.notHostnames)),void 0!==this.parts&&(o|=16,e.pushUTF8(this.parts)),e.setByte(t,o)}getSerializedSize(){let e=1;return void 0!==this.entities&&(e+=ue(this.entities)),void 0!==this.hostnames&&(e+=ue(this.hostnames)),void 0!==this.notHostnames&&(e+=ue(this.notHostnames)),void 0!==this.notEntities&&(e+=ue(this.notEntities)),void 0!==this.parts&&(e+=de(this.parts)),e}match(e,t){if(void 0!==this.notHostnames)for(const t of e)if(It(this.notHostnames,t))return!1;if(void 0!==this.notEntities)for(const e of t)if(It(this.notEntities,e))return!1;if(void 0!==this.hostnames||void 0!==this.entities){if(void 0!==this.hostnames)for(const t of e)if(It(this.hostnames,t))return!0;if(void 0!==this.entities)for(const e of t)if(It(this.entities,e))return!0;return!1}return!0}};function Vt(e){if(!1===e.startsWith("^script"))return;const t=":has-text(",o=[];let i=7;for(;e.startsWith(t,i);){i+=10;let t=1;const n=i;let s=-1;for(;i=48&&o<=57||o>=65&&o<=90||o>=97&&o<=122)){if(t{}},t=/^[#.]?[\w-.]+$/;return function(o){if(t.test(o))return!0;try{(t=>{e.matches(t)})(o)}catch(e){return!1}return!0}})();function Yt(e,t){const o=e.getSelector();if(!1===e.isScriptInject())return o;const i=e.parseScript();if(void 0===i)return o;const n=t(i.name);return void 0===n?o:o.replace(i.name,n)}(Kt=$t||($t={}))[Kt.unhide=1]="unhide",Kt[Kt.scriptInject=2]="scriptInject",Kt[Kt.isUnicode=4]="isUnicode",Kt[Kt.isClassSelector=8]="isClassSelector",Kt[Kt.isIdSelector=16]="isIdSelector",Kt[Kt.isHrefSelector=32]="isHrefSelector",Kt[Kt.remove=64]="remove",Kt[Kt.extended=128]="extended";var Xt=class e{static parse(t,o=!1){const i=t;let n,s,c,r=0;const a=t.indexOf("#"),l=a+1;let p=l+1;if(t.length>l&&("@"===t[l]?(r=gt(r,$t.unhide),p+=1):"?"===t[l]&&(p+=1)),p>=t.length)return null;if(a>0&&(s=Nt.parse(t.slice(0,a).split(","),o)),t.endsWith(":remove()"))r=gt(r,$t.remove),r=gt(r,$t.extended),t=t.slice(0,-9);else if(t.length-p>=8&&t.endsWith(")")&&-1!==t.indexOf(":style(",p)){const e=t.indexOf(":style(",p);c=t.slice(e+7,-1),t=t.slice(0,e)}if(94===t.charCodeAt(p)){if(!1===vt(t,"script:has-text(",p+1)||41!==t.charCodeAt(t.length-1))return null;if(n=t.slice(p,t.length),void 0===Vt(n))return null}else if(t.length-p>4&&43===t.charCodeAt(p)&&vt(t,"+js(",p)){if((void 0===s||void 0===s.hostnames&&void 0===s.entities)&&!1===At(r,$t.unhide))return null;if(r=gt(r,$t.scriptInject),n=t.slice(p+4,t.length-1),!1===At(r,$t.unhide)&&0===n.length)return null}else{n=t.slice(p);const e=Ke(n);if(e===He.Extended)r=gt(r,$t.extended);else if(e===He.Invalid||!Qt(n))return null}if(void 0===s&&!0===At(r,$t.extended))return null;if(void 0!==n&&(Ot(n)&&(r=gt(r,$t.isUnicode)),!1===At(r,$t.scriptInject)&&!1===At(r,$t.remove)&&!1===At(r,$t.extended)&&!1===n.startsWith("^"))){const e=n.charCodeAt(0),t=n.charCodeAt(1),o=n.charCodeAt(2);!1===At(r,$t.scriptInject)&&(46===e&&qt(n)?r=gt(r,$t.isClassSelector):35===e&&qt(n)?r=gt(r,$t.isIdSelector):(97===e&&91===t&&104===o&&Gt(n,2)||91===e&&104===t&&Gt(n,1))&&(r=gt(r,$t.isHrefSelector)))}return new e({mask:r,rawLine:!0===o?i:void 0,selector:n,style:c,domains:s})}static deserialize(t){const o=t.getUint8(),i=At(o,$t.isUnicode),n=t.getUint8(),s=i?t.getUTF8():t.getCosmeticSelector();return new e({mask:o,selector:s,domains:1==(1&n)?Nt.deserialize(t):void 0,rawLine:2==(2&n)?t.getRawCosmetic():void 0,style:4==(4&n)?t.getASCII():void 0})}constructor({mask:e,selector:t,domains:o,rawLine:i,style:n}){this.mask=e,this.selector=t,this.domains=o,this.style=n,this.id=void 0,this.rawLine=i,this.scriptletDetails=void 0}isCosmeticFilter(){return!0}isNetworkFilter(){return!1}serialize(e){e.pushUint8(this.mask);const t=e.getPos();e.pushUint8(0),this.isUnicode()?e.pushUTF8(this.selector):e.pushCosmeticSelector(this.selector);let o=0;void 0!==this.domains&&(o|=1,this.domains.serialize(e)),void 0!==this.rawLine&&(o|=2,e.pushRawCosmetic(this.rawLine)),void 0!==this.style&&(o|=4,e.pushASCII(this.style)),e.setByte(t,o)}getSerializedSize(e){let t=2;return this.isUnicode()?t+=de(this.selector):t+=function(e,t){return!0===t?le(ce().cosmeticSelector.getCompressedSize(e),!1):pe(e)}(this.selector,e),void 0!==this.domains&&(t+=this.domains.getSerializedSize()),void 0!==this.rawLine&&(t+=function(e,t){return!0===t?le(ce().cosmeticRaw.getCompressedSize(te(e)),!1):de(e)}(this.rawLine,e)),void 0!==this.style&&(t+=pe(this.style)),t}toString(){if(void 0!==this.rawLine)return this.rawLine;let e="";return void 0!==this.domains&&(void 0!==this.domains.parts?e+=this.domains.parts:e+=""),this.isUnhide()?e+="#@#":e+="##",this.isScriptInject()?(e+="+js(",e+=this.selector,e+=")"):e+=this.selector,e}match(e,t){return!1===this.hasHostnameConstraint()||!(!e&&this.hasHostnameConstraint())&&(void 0===this.domains||this.domains.match(0===e.length?ne:Bt(e,t),0===e.length?ne:Lt(e,t)))}getTokens(){const e=[];if(void 0!==this.domains){const{hostnames:t,entities:o}=this.domains;if(void 0!==t)for(const o of t)e.push(new Uint32Array([o]));if(void 0!==o)for(const t of o)e.push(new Uint32Array([t]))}if(0===e.length&&!1===this.isUnhide())if(this.isIdSelector()||this.isClassSelector()){let t=1;const o=this.selector;for(;t0?n=!0:"'"===p&&e.indexOf("'",o+1)>0?s=!0:"{"===p&&e.indexOf("}",o+1)>0?r+=1:"/"===p&&e.indexOf("/",o+1)>0?c=!0:l=!0)),","===p&&(t.push(e.slice(i+1,o).trim()),i=o,l=!1))),a="\\"===p}if(t.push(e.slice(i+1).trim()),0===t.length)return;const p=t.slice(1).map((e=>e.startsWith("'")&&e.endsWith("'")||e.startsWith('"')&&e.endsWith('"')?e.substring(1,e.length-1):e)).map((e=>e.replace(Dt,",").replace(Ht,"\\").replace(Wt,",")));return this.scriptletDetails={name:t[0],args:p},this.scriptletDetails}getScript(e){const t=this.parseScript();if(void 0===t)return;const{name:o,args:i}=t;let n=e(o);if(void 0!==n){for(let e=0;e>>0}(this.mask,this.selector,this.domains,this.style)),this.id}hasCustomStyle(){return void 0!==this.style}getStyle(e=Mt){return this.style||e}getStyleAttributeHash(){return`s${bt(this.getStyle())}`}getSelector(){return this.selector}getSelectorAST(){return De(this.getSelector())}getExtendedSelector(){return Vt(this.selector)}isExtended(){return At(this.mask,$t.extended)}isRemove(){return At(this.mask,$t.remove)}isUnhide(){return At(this.mask,$t.unhide)}isScriptInject(){return At(this.mask,$t.scriptInject)}isCSS(){return!1===this.isScriptInject()}isIdSelector(){return At(this.mask,$t.isIdSelector)}isClassSelector(){return At(this.mask,$t.isClassSelector)}isHrefSelector(){return At(this.mask,$t.isHrefSelector)}isUnicode(){return At(this.mask,$t.isUnicode)}isHtmlFiltering(){return this.getSelector().startsWith("^")}isGenericHide(){var e,t;return void 0===(null===(e=null==this?void 0:this.domains)||void 0===e?void 0:e.hostnames)&&void 0===(null===(t=null==this?void 0:this.domains)||void 0===t?void 0:t.entities)}},Zt=class{constructor(){this.options=new Set,this.prefix=void 0,this.infix=void 0,this.suffix=void 0,this.redirect=void 0}blockRequestsWithType(e){if(this.options.has(e))throw new Error(`Already blocking type ${e}`);return this.options.add(e),this}images(){return this.blockRequestsWithType("image")}scripts(){return this.blockRequestsWithType("script")}frames(){return this.blockRequestsWithType("frame")}fonts(){return this.blockRequestsWithType("font")}medias(){return this.blockRequestsWithType("media")}styles(){return this.blockRequestsWithType("css")}redirectTo(e){if(void 0!==this.redirect)throw new Error(`Already redirecting: ${this.redirect}`);return this.redirect=`redirect=${e}`,this}urlContains(e){if(void 0!==this.infix)throw new Error(`Already matching pattern: ${this.infix}`);return this.infix=e,this}urlStartsWith(e){if(void 0!==this.prefix)throw new Error(`Already matching prefix: ${this.prefix}`);return this.prefix=`|${e}`,this}urlEndsWith(e){if(void 0!==this.suffix)throw new Error(`Already matching suffix: ${this.suffix}`);return this.suffix=`${e}|`,this}withHostname(e){if(void 0!==this.prefix)throw new Error(`Cannot match hostname if filter already has prefix: ${this.prefix}`);return this.prefix=`||${e}^`,this}toString(){const e=[];void 0!==this.prefix&&e.push(this.prefix),void 0!==this.infix&&e.push(this.infix),void 0!==this.suffix&&e.push(this.suffix);const t=["important"];if(0!==this.options.size)for(const e of this.options)t.push(e);return void 0!==this.redirect&&t.push(this.redirect),`${0===e.length?"*":e.join("*")}$${t.join(",")}`}};function Jt(){return new Zt}var eo,to,oo=bt("http"),io=bt("https");(to=eo||(eo={}))[to.fromDocument=1]="fromDocument",to[to.fromFont=2]="fromFont",to[to.fromHttp=4]="fromHttp",to[to.fromHttps=8]="fromHttps",to[to.fromImage=16]="fromImage",to[to.fromMedia=32]="fromMedia",to[to.fromObject=64]="fromObject",to[to.fromOther=128]="fromOther",to[to.fromPing=256]="fromPing",to[to.fromScript=512]="fromScript",to[to.fromStylesheet=1024]="fromStylesheet",to[to.fromSubdocument=2048]="fromSubdocument",to[to.fromWebsocket=4096]="fromWebsocket",to[to.fromXmlHttpRequest=8192]="fromXmlHttpRequest",to[to.firstParty=16384]="firstParty",to[to.thirdParty=32768]="thirdParty",to[to.isReplace=65536]="isReplace",to[to.isBadFilter=131072]="isBadFilter",to[to.isCSP=262144]="isCSP",to[to.isGenericHide=524288]="isGenericHide",to[to.isImportant=1048576]="isImportant",to[to.isSpecificHide=2097152]="isSpecificHide",to[to.isFullRegex=4194304]="isFullRegex",to[to.isRegex=8388608]="isRegex",to[to.isUnicode=16777216]="isUnicode",to[to.isLeftAnchor=33554432]="isLeftAnchor",to[to.isRightAnchor=67108864]="isRightAnchor",to[to.isException=134217728]="isException",to[to.isHostnameAnchor=268435456]="isHostnameAnchor",to[to.isRedirectRule=536870912]="isRedirectRule",to[to.isRedirect=1073741824]="isRedirect";var no=eo.fromDocument|eo.fromFont|eo.fromImage|eo.fromMedia|eo.fromObject|eo.fromOther|eo.fromPing|eo.fromScript|eo.fromStylesheet|eo.fromSubdocument|eo.fromWebsocket|eo.fromXmlHttpRequest,so={beacon:eo.fromPing,document:eo.fromDocument,cspviolationreport:eo.fromOther,fetch:eo.fromXmlHttpRequest,font:eo.fromFont,image:eo.fromImage,imageset:eo.fromImage,mainFrame:eo.fromDocument,main_frame:eo.fromDocument,media:eo.fromMedia,object:eo.fromObject,object_subrequest:eo.fromObject,ping:eo.fromPing,script:eo.fromScript,stylesheet:eo.fromStylesheet,subFrame:eo.fromSubdocument,sub_frame:eo.fromSubdocument,webSocket:eo.fromWebsocket,websocket:eo.fromWebsocket,xhr:eo.fromXmlHttpRequest,xmlhttprequest:eo.fromXmlHttpRequest,cspReport:eo.fromOther,csp_report:eo.fromOther,eventsource:eo.fromOther,manifest:eo.fromOther,other:eo.fromOther,prefetch:eo.fromOther,preflight:eo.fromOther,signedexchange:eo.fromOther,speculative:eo.fromOther,texttrack:eo.fromOther,web_manifest:eo.fromOther,xml_dtd:eo.fromOther,xslt:eo.fromOther};function co(e){const t=[];return e.fromDocument()&&t.push("document"),e.fromImage()&&t.push("image"),e.fromMedia()&&t.push("media"),e.fromObject()&&t.push("object"),e.fromOther()&&t.push("other"),e.fromPing()&&t.push("ping"),e.fromScript()&&t.push("script"),e.fromStylesheet()&&t.push("stylesheet"),e.fromSubdocument()&&t.push("sub_frame"),e.fromWebsocket()&&t.push("websocket"),e.fromXmlHttpRequest()&&t.push("xhr"),e.fromFont()&&t.push("font"),t}function ro(e,t,o,i,n,s){let c=ht*ut^e;if(void 0!==i&&(c=i.updateId(c)),void 0!==n&&(c=n.updateId(c)),void 0!==t)for(let e=0;e>>0}function ao(e,t,o,i){return!0===i?new RegExp(e.slice(1,e.length-1),"i"):(e=(e=(e=e.replace(/([|.$+?{}()[\]\\])/g,"\\$1")).replace(/\*/g,".*")).replace(/\^/g,"(?:[^\\w\\d_.%-]|$)"),o&&(e=`${e}$`),t&&(e=`^${e}`),new RegExp(e))}function lo(e,t,o){const i=t;for(;t=48&&e<=57||e<=65&&e<=70||e>=97&&e<=102}function mo(e,t,o){const i=e.charCodeAt(t+1);return 44===i||47===i?[t+1,!1]:function(e,t,o){const i=e.charCodeAt(t+1);if(44===i||uo.has(i))return[t+1,!0];if(99===i){const o=e.charCodeAt(t+2);if(o>=65&&o<=90||o>=97&&o<=122)return[t+2,!0]}if(120===i&&ho(e.charCodeAt(t+2))&&ho(e.charCodeAt(t+3)))return[t+3,!0];if(117===i)if(123===e.charCodeAt(t+2)){const o=e.indexOf("}",t+3),i=o-t+3;if(i>=1&&i<=6)return[o,!0]}else if(ho(e.charCodeAt(t+2))&&ho(e.charCodeAt(t+3))&&ho(e.charCodeAt(t+4))&&ho(e.charCodeAt(t+5)))return[t+5,!0];return[t+1,!1]}(e,t)}function Ao(e,t,o){if(47!==e.charCodeAt(t++))return[o,void 0];const i=["","",""];let n=t,s=0;for(;t0&&92===e.charCodeAt(o-1);)o=e.lastIndexOf(t,o-1);return o}(t,"$");if(-1!==u&&47!==t.charCodeAt(u+1)){d=u;for(const e of function(e,t,o){const i=[];let n,s;for(;t0&&(c=p);break;case"ehide":case"elemhide":if(t)return null;r=gt(r,eo.isGenericHide),r=gt(r,eo.isSpecificHide);break;case"shide":case"specifichide":if(t)return null;r=gt(r,eo.isSpecificHide);break;case"ghide":case"generichide":if(t)return null;r=gt(r,eo.isGenericHide);break;case"inline-script":if(t)return null;r=gt(r,eo.isCSP),c="script-src 'self' 'unsafe-eval' http: https: data: blob: mediastream: filesystem:";break;case"inline-font":if(t)return null;r=gt(r,eo.isCSP),c="font-src 'self' 'unsafe-eval' http: https: data: blob: mediastream: filesystem:";break;case"replace":case"content":if(t||(0===p.length?!1===At(r,eo.isException):null===go(p)))return null;r=gt(r,eo.isReplace),c=p;break;default:{let e=0;switch(i){case"all":if(t)return null;break;case"image":e=eo.fromImage;break;case"media":e=eo.fromMedia;break;case"object":case"object-subrequest":e=eo.fromObject;break;case"other":e=eo.fromOther;break;case"ping":case"beacon":e=eo.fromPing;break;case"script":e=eo.fromScript;break;case"css":case"stylesheet":e=eo.fromStylesheet;break;case"frame":case"subdocument":e=eo.fromSubdocument;break;case"xhr":case"xmlhttprequest":e=eo.fromXmlHttpRequest;break;case"websocket":e=eo.fromWebsocket;break;case"font":e=eo.fromFont;break;case"doc":case"document":e=eo.fromDocument;break;default:return null}t?l=ft(l,e):a=gt(a,e);break}}}}let h;if(r|=0===a?l:l===no?a:a&l,d-p>=2&&47===t.charCodeAt(p)&&47===t.charCodeAt(d-1)){h=t.slice(p,d);try{ao(h,!1,!1,!0)}catch(e){return null}r=gt(r,eo.isFullRegex)}else{if(d>0&&124===t.charCodeAt(d-1)&&(r=gt(r,eo.isRightAnchor),d-=1),p0&&42===t.charCodeAt(d-1)&&(d-=1),!1===At(r,eo.isHostnameAnchor)&&d-p>0&&42===t.charCodeAt(p)&&(r=ft(r,eo.isLeftAnchor),p+=1),At(r,eo.isLeftAnchor)&&(d-p==5&&vt(t,"ws://",p)?(r=gt(r,eo.fromWebsocket),r=ft(r,eo.isLeftAnchor),r=ft(r,eo.fromHttp),r=ft(r,eo.fromHttps),p=d):d-p==7&&vt(t,"http://",p)?(r=gt(r,eo.fromHttp),r=ft(r,eo.fromHttps),r=ft(r,eo.isLeftAnchor),p=d):d-p==8&&vt(t,"https://",p)?(r=gt(r,eo.fromHttps),r=ft(r,eo.fromHttp),r=ft(r,eo.isLeftAnchor),p=d):d-p==8&&vt(t,"http*://",p)&&(r=gt(r,eo.fromHttps),r=gt(r,eo.fromHttp),r=ft(r,eo.isLeftAnchor),p=d)),d-p>0&&(h=t.slice(p,d).toLowerCase(),r=bo(r,eo.isUnicode,Ot(h)),!1===At(r,eo.isRegex)&&(r=bo(r,eo.isRegex,function(e,t,o){const i=e.indexOf("^",t);if(-1!==i&&it.length)return!1;if(e.length===t.length)return e===t;const i=t.indexOf(e);if(-1===i)return!1;if(0===i)return!0===o||46===t.charCodeAt(e.length)||46===e.charCodeAt(e.length-1);if(t.length===i+e.length)return 46===t.charCodeAt(i-1)||46===e.charCodeAt(0);return!(!0!==o&&46!==t.charCodeAt(e.length)&&46!==e.charCodeAt(e.length-1)||46!==t.charCodeAt(i-1)&&46!==e.charCodeAt(0))}(i,t.hostname,void 0!==e.filter&&42===e.filter.charCodeAt(0)))return!1;if(e.isRegex())return e.getRegex().test(t.url.slice(t.url.indexOf(i)+i.length));if(e.isRightAnchor()&&e.isLeftAnchor()){return o===t.url.slice(t.url.indexOf(i)+i.length)}if(e.isRightAnchor()){const n=t.hostname;return!1===e.hasFilter()?i.length===n.length||n.endsWith(i):t.url.endsWith(o)}return e.isLeftAnchor()?vt(t.url,o,t.url.indexOf(i)+i.length):!1===e.hasFilter()||-1!==t.url.indexOf(o,t.url.indexOf(i)+i.length)}if(e.isRegex())return e.getRegex().test(t.url);if(e.isLeftAnchor()&&e.isRightAnchor())return t.url===o;if(e.isLeftAnchor())return wt(t.url,o);if(e.isRightAnchor())return t.url.endsWith(o);if(!1===e.hasFilter())return!0;return-1!==t.url.indexOf(o)}(this,e)}serialize(e){e.pushUint32(this.mask);const t=e.getPos();e.pushUint8(0);let o=0;void 0!==this.filter&&(o|=1,this.isUnicode()?e.pushUTF8(this.filter):e.pushNetworkFilter(this.filter)),void 0!==this.hostname&&(o|=2,e.pushNetworkHostname(this.hostname)),void 0!==this.domains&&(o|=4,this.domains.serialize(e)),void 0!==this.rawLine&&(o|=8,e.pushRawNetwork(this.rawLine)),void 0!==this.denyallow&&(o|=16,this.denyallow.serialize(e)),void 0!==this.optionValue&&(o|=32,this.isCSP()?e.pushNetworkCSP(this.optionValue):this.isRedirect()?e.pushNetworkRedirect(this.optionValue):e.pushUTF8(this.optionValue)),e.setByte(t,o)}getSerializedSize(e){let t=5;return void 0!==this.filter&&(!0===this.isUnicode()?t+=de(this.filter):t+=function(e,t){return!0===t?le(ce().networkFilter.getCompressedSize(e),!1):pe(e)}(this.filter,e)),void 0!==this.hostname&&(t+=function(e,t){return!0===t?le(ce().networkHostname.getCompressedSize(e),!1):pe(e)}(this.hostname,e)),void 0!==this.domains&&(t+=this.domains.getSerializedSize()),void 0!==this.rawLine&&(t+=function(e,t){return!0===t?le(ce().networkRaw.getCompressedSize(te(e)),!1):de(e)}(this.rawLine,e)),void 0!==this.denyallow&&(t+=this.denyallow.getSerializedSize()),void 0!==this.optionValue&&(this.isCSP()?t+=function(e,t){return!0===t?le(ce().networkCSP.getCompressedSize(e),!1):pe(e)}(this.optionValue,e):this.isRedirect()?t+=function(e,t){return!0===t?le(ce().networkRedirect.getCompressedSize(e),!1):pe(e)}(this.optionValue,e):t+=de(this.optionValue)),t}toString(e){if(void 0!==this.rawLine)return this.rawLine;let t="";this.isException()&&(t+="@@"),this.isHostnameAnchor()?t+="||":this.fromHttp()!==this.fromHttps()?this.fromHttp()?t+="|http://":t+="|https://":this.isLeftAnchor()&&(t+="|"),this.hasHostname()&&(t+=this.getHostname(),t+="^"),this.isFullRegex()?t+=`/${this.getRegex().source}/`:this.isRegex()?t+=this.getRegex().source:t+=this.getFilter(),this.isRightAnchor()&&"^"!==t[t.length-1]&&(t+="|");const o=[];if(!1===this.fromAny()){const e=mt(this.getCptMask());if(mt(no)-e")),void 0!==this.denyallow&&(void 0!==this.denyallow.parts?o.push(`denyallow=${this.denyallow.parts}`):o.push("denyallow=")),this.isBadFilter()&&o.push("badfilter"),o.length>0&&(t+="function"==typeof e?`$${o.map(e).join(",")}`:`$${o.join(",")}`),t}getIdWithoutBadFilter(){return ro(this.mask&~eo.isBadFilter,this.filter,this.hostname,this.domains,this.denyallow,this.optionValue)}getId(){return void 0===this.id&&(this.id=ro(this.mask,this.filter,this.hostname,this.domains,this.denyallow,this.optionValue)),this.id}hasFilter(){return void 0!==this.filter}hasDomains(){return void 0!==this.domains}getMask(){return this.mask}getCptMask(){return this.getMask()&no}isRedirect(){return At(this.getMask(),eo.isRedirect)}isRedirectRule(){return At(this.mask,eo.isRedirectRule)}getRedirect(){var e;return null!==(e=this.optionValue)&&void 0!==e?e:""}isReplace(){return At(this.getMask(),eo.isReplace)}getHtmlModifier(){var e;return 0===(null===(e=this.optionValue)||void 0===e?void 0:e.length)?null:go(this.optionValue)}isHtmlFilteringRule(){return this.isReplace()}getRedirectResource(){const e=this.getRedirect(),t=e.lastIndexOf(":");return-1===t?e:e.slice(0,t)}getRedirectPriority(){const e=this.getRedirect(),t=e.lastIndexOf(":");return-1===t?0:Number(e.slice(t+1))}hasHostname(){return void 0!==this.hostname}getHostname(){return this.hostname||""}getFilter(){return this.filter||""}getRegex(){return void 0===this.regex&&(this.regex=void 0!==this.filter&&this.isRegex()?ao(this.filter,this.isLeftAnchor(),this.isRightAnchor(),this.isFullRegex()):fo),this.regex}getTokens(){if(dt.reset(),void 0!==this.domains&&void 0!==this.domains.hostnames&&void 0===this.domains.entities&&void 0===this.domains.notHostnames&&void 0===this.domains.notEntities&&1===this.domains.hostnames.length&&dt.push(this.domains.hostnames[0]),!1===this.isFullRegex()){if(void 0!==this.filter){const e=!this.isRightAnchor(),t=!this.isLeftAnchor();!function(e,t,o,i){const n=Math.min(e.length,2*i.remaining());let s=!1,c=0,r=0,a=ht;for(let o=0;o1&&42!==n&&42!==c&&(!1===t||0!==r)&&i.push(a>>>0)),c=n)}!1===o&&!0===s&&42!==c&&e.length-r>1&&!1===i.full()&&i.push(a>>>0)}(this.filter,t,e,dt)}void 0!==this.hostname&&St(this.hostname,!1,void 0!==this.filter&&42===this.filter.charCodeAt(0),dt)}else void 0!==this.filter&&function(e,t){let o=e.length-1,i=1,n=0;for(;i=i;o-=1){const t=e.charCodeAt(o);if(124===t)return;if(41===t||42===t||43===t||63===t||93===t||125===t||46===t&&92!==e.charCodeAt(o-1)||92===t&&Ct(n))break;n=t}if(o1&&St(e.slice(1,i),94!==e.charCodeAt(1),!0,t),oObject.prototype.hasOwnProperty.call(Io,e),Oo=(e,t)=>"true"===e&&!t.has("true")||!("false"===e&&!t.has("false"))&&!!t.get(e),To=(e,t)=>{if(0===e.length)return!1;if((e=>Eo.test(e))(e))return"!"===e[0]?!Oo(e.slice(1),t):Oo(e,t);const o=(e=>e.match(So))(e);if(!o||0===o.length)return!1;if(e.length!==o.reduce(((e,t)=>e+t.length),0))return!1;const i=[],n=[];for(const e of o)if("("===e)n.push(e);else if(")"===e){for(;0!==n.length&&"("!==n[n.length-1];)i.push(n.pop());if(0===n.length)return!1;n.pop()}else if(Fo(e)){for(;n.length&&Fo(n[n.length-1])&&Io[e]<=Io[n[n.length-1]];)i.push(n.pop());n.push(e)}else i.push(Oo(e,t));if("("===n[0]||")"===n[0])return!1;for(;0!==n.length;)i.push(n.pop());for(const e of i)if(!0===e||!1===e)n.push(e);else if("!"===e)n.push(!n.pop());else if(Fo(e)){const t=n.pop(),o=n.pop();"&&"===e?n.push(o&&t):n.push(o||t)}return!0===n[0]},Po=class e{static getCondition(e){return e.slice(5).replace(/\s/g,"")}static parse(t,o){return new this({condition:e.getCondition(t),filterIDs:o})}static deserialize(e){const t=e.getUTF8(),o=new Set;for(let t=0,i=e.getUint32();t2)for(;e4&&32===t.charCodeAt(0)&&32===t.charCodeAt(1)&&32===t.charCodeAt(2)&&32===t.charCodeAt(3)&&32!==t.charCodeAt(4)))break;a+=t.slice(4),e+=1}0!==a.length&&a.charCodeAt(a.length-1)<=32&&(a=a.trim());const l=Ro(a,{extendedNonSupportedTypes:!0});if(l===Co.NETWORK&&!0===t.loadNetworkFilters){const i=ko.parse(a,t.debug);null!==i?(o.push(i),r.length>0&&r[r.length-1].filterIDs.add(i.getId())):n.push({lineNumber:e,filter:a,filterType:l})}else if(l===Co.COSMETIC&&!0===t.loadCosmeticFilters){const o=Xt.parse(a,t.debug);null!==o?!0!==t.loadGenericCosmeticsFilters&&!1!==o.isGenericHide()||(i.push(o),r.length>0&&r[r.length-1].filterIDs.add(o.getId())):n.push({lineNumber:e,filter:a,filterType:Co.COSMETIC})}else if(t.loadPreprocessors){const t=_o(a);if(t===yo.BEGIF)r.length>0?r.push(new Po({condition:`(${r[r.length-1].condition})&&(${Po.getCondition(a)})`})):r.push(Po.parse(a));else if((t===yo.ENDIF||t===yo.ELSE)&&r.length>0){const e=r.pop();c.push(e),t===yo.ELSE&&r.push(new Po({condition:`!(${e.condition})`}))}else l===Co.NOT_SUPPORTED_ADGUARD&&n.push({lineNumber:e,filter:a,filterType:l})}else l===Co.NOT_SUPPORTED_ADGUARD&&n.push({lineNumber:e,filter:a,filterType:l})}return{networkFilters:o,cosmeticFilters:i,preprocessors:c.filter((e=>e.filterIDs.size>0)),notSupportedFilters:n}}(xo=Co||(Co={}))[xo.NOT_SUPPORTED=0]="NOT_SUPPORTED",xo[xo.NETWORK=1]="NETWORK",xo[xo.COSMETIC=2]="COSMETIC",xo[xo.NOT_SUPPORTED_EMPTY=100]="NOT_SUPPORTED_EMPTY",xo[xo.NOT_SUPPORTED_COMMENT=101]="NOT_SUPPORTED_COMMENT",xo[xo.NOT_SUPPORTED_ADGUARD=102]="NOT_SUPPORTED_ADGUARD";var Lo="video/flv",Bo={contentType:`${Lo};base64`,aliases:[Lo,".flv","flv"],body:"RkxWAQEAAAAJAAAAABIAALgAAAAAAAAAAgAKb25NZXRhRGF0YQgAAAAIAAhkdXJhdGlvbgAAAAAAAAAAAAAFd2lkdGgAP/AAAAAAAAAABmhlaWdodAA/8AAAAAAAAAANdmlkZW9kYXRhcmF0ZQBAaGoAAAAAAAAJZnJhbWVyYXRlAEBZAAAAAAAAAAx2aWRlb2NvZGVjaWQAQAAAAAAAAAAAB2VuY29kZXICAA1MYXZmNTcuNDEuMTAwAAhmaWxlc2l6ZQBAaoAAAAAAAAAACQAAAMM="},Uo="image/gif",No={contentType:`${Uo};base64`,aliases:[Uo,".gif","gif"],body:"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"},Vo="text/html",jo={contentType:Vo,aliases:[Vo,".html","html",".htm","htm","noopframe","noop.html"],body:""},Mo="image/vnd.microsoft.icon",Do={contentType:`${Mo};base64`,aliases:[Mo,".ico","ico"],body:"AAABAAEAAQEAAAEAGAAwAAAAFgAAACgAAAABAAAAAgAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA=="},Ho="image/jpeg",Wo={contentType:`${Ho};base64`,aliases:[Ho,".jpg","jpg",".jpeg","jpeg"],body:"/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k="},qo="application/javascript",Go={contentType:qo,aliases:[qo,".js","js","javascript",".jsx","jsx","typescript",".ts","ts","noop.js","noopjs"],body:""},$o="application/json",Ko={contentType:$o,aliases:[$o,".json","json"],body:"0"},Qo="audio/mpeg",Yo={contentType:`${Qo};base64`,aliases:[Qo,".mp3","mp3","noop-0.1s.mp3","noopmp3-0.1s"],body:"/+MYxAAAAANIAAAAAExBTUUzLjk4LjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},Xo="video/mp4",Zo={contentType:`${Xo};base64`,aliases:[Xo,".mp4","mp4",".m4a","m4a",".m4p","m4p",".m4b","m4b",".m4r","m4r",".m4v","m4v","noop-1s.mp4","noopmp4-1s"],body:"AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAC721kYXQhEAUgpBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3pwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcCEQBSCkG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADengAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAsJtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAALwABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAB7HRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAIAAAAAAAAALwAAAAAAAAAAAAAAAQEAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAC8AAAAAAAEAAAAAAWRtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAAKxEAAAIAFXEAAAAAAAtaGRscgAAAAAAAAAAc291bgAAAAAAAAAAAAAAAFNvdW5kSGFuZGxlcgAAAAEPbWluZgAAABBzbWhkAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAADTc3RibAAAAGdzdHNkAAAAAAAAAAEAAABXbXA0YQAAAAAAAAABAAAAAAAAAAAAAgAQAAAAAKxEAAAAAAAzZXNkcwAAAAADgICAIgACAASAgIAUQBUAAAAAAfQAAAHz+QWAgIACEhAGgICAAQIAAAAYc3R0cwAAAAAAAAABAAAAAgAABAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAIAAAABAAAAHHN0c3oAAAAAAAAAAAAAAAIAAAFzAAABdAAAABRzdGNvAAAAAAAAAAEAAAAsAAAAYnVkdGEAAABabWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcmFwcGwAAAAAAAAAAAAAAAAtaWxzdAAAACWpdG9vAAAAHWRhdGEAAAABAAAAAExhdmY1Ni40MC4xMDE="},Jo="application/pdf",ei={contentType:`${Jo};base64`,aliases:[Jo,".pdf","pdf"],body:"JVBERi0xLgoxIDAgb2JqPDwvUGFnZXMgMiAwIFI+PmVuZG9iagoyIDAgb2JqPDwvS2lkc1szIDAgUl0vQ291bnQgMT4+ZW5kb2JqCjMgMCBvYmo8PC9QYXJlbnQgMiAwIFI+PmVuZG9iagp0cmFpbGVyIDw8L1Jvb3QgMSAwIFI+Pg=="},ti="image/png",oi={contentType:`${ti};base64`,aliases:[ti,".png","png"],body:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg=="},ii="image/svg+xml",ni={contentType:ii,aliases:[ii,".svg","svg"],body:"https://raw.githubusercontent.com/mathiasbynens/small/master/svg.svg"},si="text/plain",ci={contentType:si,aliases:[si,".txt","txt","text","nooptext","noop.txt"],body:""},ri="audio/wav",ai={contentType:`${ri};base64`,aliases:[ri,".wav","wav"],body:"UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA="},li="video/webm",pi={contentType:`${li};base64`,aliases:[li,".webm","webm"],body:"GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA="},di="image/webp",ui={contentType:`${di};base64`,aliases:[di,".webp","webp"],body:"UklGRhIAAABXRUJQVlA4TAYAAAAvQWxvAGs="},hi="video/wmv",mi={contentType:`${hi};base64`,aliases:[hi,".wmv","wmv"],body:"MCaydY5mzxGm2QCqAGLObOUBAAAAAAAABQAAAAECodyrjEepzxGO5ADADCBTZWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcCAAAAAAAAAIA+1d6xnQEAAAAAAAAAAMAF2QEAAAAAAAAAAAAAAAAcDAAAAAAAAAIAAACADAAAgAwAAEANAwC1A79fLqnPEY7jAMAMIFNlLgAAAAAAAAAR0tOruqnPEY7mAMAMIFNlBgAAAAAAQKTQ0gfj0hGX8ACgyV6oUGQAAAAAAAAAAQAoAFcATQAvAEUAbgBjAG8AZABpAG4AZwBTAGUAdAB0AGkAbgBnAHMAAAAAABwATABhAHYAZgA1ADcALgA0ADEALgAxADAAMAAAAJEH3Le3qc8RjuYAwAwgU2WBAAAAAAAAAMDvGbxNW88RqP0AgF9cRCsAV/sgVVvPEaj9AIBfXEQrAAAAAAAAAAAzAAAAAAAAAAEAAAAAAAEAAAABAAAAAigAKAAAAAEAAAABAAAAAQAYAE1QNDMDAAAAAAAAAAAAAAAAAAAAAAAAAEBS0YYdMdARo6QAoMkDSPZMAAAAAAAAAEFS0YYdMdARo6QAoMkDSPYBAAAAAQAKAG0AcwBtAHAAZQBnADQAdgAzAAAAAAAEAE1QNDM2JrJ1jmbPEabZAKoAYs5sMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQ=="},Ai=(()=>{const e={};for(const t of[Bo,No,jo,Do,Wo,Go,Ko,Yo,Zo,ei,oi,ni,ci,ai,pi,ui,mi])for(const o of t.aliases)e[o]=t;return e})();function gi(e){return Ai[e]||ci}function fi(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{name:t,aliases:o,body:i,contentType:n}=e;return"string"==typeof t&&(!(!Array.isArray(o)||!o.every((e=>"string"==typeof e)))&&("string"==typeof i&&"string"==typeof n))}function ki(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{name:t,aliases:o,body:i,dependencies:n,executionWorld:s,requiresTrust:c}=e;return"string"==typeof t&&(!(!Array.isArray(o)||!o.every((e=>"string"==typeof e)))&&("string"==typeof i&&(!(!Array.isArray(n)||!n.every((e=>"string"==typeof e)))&&((void 0===s||"MAIN"===s||"ISOLATED"===s)&&(void 0===c||"boolean"==typeof c)))))}var bi=class e{static deserialize(t){const o=t.getASCII(),i=[],n=[];for(let e=0,o=t.getUint16();e["if (typeof scriptletGlobals === 'undefined') { var scriptletGlobals = {}; }",...t,`(${e})(...['{{1}}','{{2}}','{{3}}','{{4}}','{{5}}','{{6}}','{{7}}','{{8}}','{{9}}','{{10}}'].filter((a,i) => a !== '{{'+(i+1)+'}}').map((a) => decodeURIComponent(a)))`].join(";"))(t.body,i),this.scriptletsCache.set(t.name,o),o}getSurrogate(e){const t=this.resourcesByName.get(e.endsWith(".js")?e:`${e}.js`);if(void 0!==t&&"application/javascript"===t.contentType)return t.body}getScriptletCanonicalName(e){var t;return null===(t=this.getRawScriptlet(e))||void 0===t?void 0:t.name}getRawScriptlet(e){if(!e.endsWith(".fn"))return this.scriptletsByName.get(e.endsWith(".js")?e:`${e}.js`)}getScriptletDependencies(e){const t=new Map,o=[...e.dependencies];for(;o.length>0;){const e=o.pop();if(t.has(e))continue;const i=this.scriptletsByName.get(e);t.set(e,i.body),o.push(...i.dependencies)}return Array.from(t.values())}getSerializedSize(){let e=pe(this.checksum);e+=2;for(const{name:t,aliases:o,body:i,contentType:n}of this.resources)e+=pe(t),e+=o.reduce(((e,t)=>e+pe(t)),2),e+=de(i),e+=pe(n);e+=2;for(const{name:t,aliases:o,body:i,dependencies:n}of this.scriptlets)e+=pe(t),e+=o.reduce(((e,t)=>e+pe(t)),2),e+=de(i),e+=1,e+=1,e+=1,e+=1,e+=n.reduce(((e,t)=>e+pe(t)),2);return e}serialize(e){e.pushASCII(this.checksum),e.pushUint16(this.resources.length);for(const{name:t,aliases:o,body:i,contentType:n}of this.resources){e.pushASCII(t),e.pushUint16(o.length);for(const t of o)e.pushASCII(t);e.pushUTF8(i),e.pushASCII(n)}e.pushUint16(this.scriptlets.length);for(const{name:t,aliases:o,body:i,dependencies:n,executionWorld:s,requiresTrust:c}of this.scriptlets){e.pushASCII(t),e.pushUint16(o.length);for(const t of o)e.pushASCII(t);e.pushUTF8(i),e.pushBool(void 0!==s),e.pushBool("ISOLATED"===s),e.pushBool(void 0!==c),e.pushBool(!0===c),e.pushUint16(n.length),n.forEach((t=>e.pushASCII(t)))}}};var yi=new Uint32Array(0);function wi(e){return`(?:${e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")})`}function vi(e,t,o){let i=e.get(t);void 0===i&&(i=[],e.set(t,i)),i.push(o)}function _i(e,t){const o=new Map;for(const i of e)vi(o,t(i),i);return Array.from(o.values())}function Ci(e,t){const o=[],i=[];for(const n of e)t(n)?o.push(n):i.push(n);return{negative:i,positive:o}}var xi=[{description:"Remove duplicated filters by ID",fusion:e=>e[0],groupByCriteria:e=>""+e.getId(),select:()=>!0},{description:"Group idential filter with same mask but different domains in single filters",fusion:e=>{const t=[],o=new Set,i=new Set,n=new Set,s=new Set;for(const{domains:c}of e)if(void 0!==c){if(void 0!==c.parts&&t.push(c.parts),void 0!==c.hostnames)for(const e of c.hostnames)o.add(e);if(void 0!==c.entities)for(const e of c.entities)n.add(e);if(void 0!==c.notHostnames)for(const e of c.notHostnames)i.add(e);if(void 0!==c.notEntities)for(const e of c.notEntities)s.add(e)}return new ko(Object.assign({},e[0],{domains:new Nt({hostnames:0!==o.size?new Uint32Array(o).sort():void 0,entities:0!==n.size?new Uint32Array(n).sort():void 0,notHostnames:0!==i.size?new Uint32Array(i).sort():void 0,notEntities:0!==s.size?new Uint32Array(s).sort():void 0,parts:0!==t.length?t.join(","):void 0}),rawLine:void 0!==e[0].rawLine?e.map((({rawLine:e})=>e)).join(" <+> "):void 0}))},groupByCriteria:e=>{var t;return e.getHostname()+e.getFilter()+e.getMask()+(null!==(t=e.optionValue)&&void 0!==t?t:"")},select:e=>!e.isCSP()&&void 0===e.denyallow&&void 0!==e.domains},{description:"Group simple patterns, into a single filter",fusion:e=>{const t=[];for(const o of e)o.isRegex()?t.push(`(?:${o.getRegex().source})`):o.isRightAnchor()?t.push(`${wi(o.getFilter())}$`):o.isLeftAnchor()?t.push(`^${wi(o.getFilter())}`):t.push(wi(o.getFilter()));return new ko(Object.assign({},e[0],{mask:gt(e[0].mask,eo.isRegex),rawLine:void 0!==e[0].rawLine?e.map((({rawLine:e})=>e)).join(" <+> "):void 0,regex:new RegExp(t.join("|"))}))},groupByCriteria:e=>""+(e.getMask()&~eo.isRegex&~eo.isFullRegex),select:e=>void 0===e.domains&&void 0===e.denyallow&&!e.isHostnameAnchor()&&!e.isRedirect()&&!e.isCSP()}];function Si(e){return e}function Ei(e){return e}function Ii(e){const t=[];let o=e;for(const{select:e,fusion:i,groupByCriteria:n}of xi){const{positive:s,negative:c}=Ci(o,e);o=c;const r=_i(s,n);for(const e of r)e.length>1?t.push(i(e)):o.push(e[0])}for(const e of o)t.push(e);return t}function Fi(e){return e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,e|=e>>16,++e}var Oi=1;var Ti=Number.MAX_SAFE_INTEGER>>>0,Pi=class e{static deserialize(t,o,i,n){const s=t.getUint32(),c=t.getUint32(),r=t.getUint32(),a=me.fromUint8Array(t.getBytes(!0),n),l=a.getUint32ArrayView(s),p=a.getUint32ArrayView(c),d=a.pos;return a.seekZero(),new e({config:n,deserialize:o,filters:[],optimize:i}).updateInternals({bucketsIndex:p,filtersIndexStart:d,numberOfFilters:r,tokensLookupIndex:l,view:a})}constructor({deserialize:e,filters:t,optimize:o,config:i}){this.bucketsIndex=ne,this.filtersIndexStart=0,this.numberOfFilters=0,this.tokensLookupIndex=ne,this.cache=new Map,this.view=me.empty(i),this.deserializeFilter=e,this.optimize=o,this.config=i,0!==t.length&&this.update(t,void 0)}getFilters(){const e=[];if(0===this.numberOfFilters)return e;this.view.setPos(this.filtersIndexStart);for(let t=0;t!t.has(e.getId())||(r-=e.getSerializedSize(o),!1))));for(const t of e)r+=t.getSerializedSize(o),a.push(t)}else{a=e;for(const t of e)r+=t.getSerializedSize(o)}if(0===a.length)return void this.updateInternals({bucketsIndex:ne,filtersIndexStart:0,numberOfFilters:0,tokensLookupIndex:ne,view:me.empty(this.config)});!0===this.config.debug&&a.sort(((e,t)=>e.getId()-t.getId()));const l=new Uint32Array(Math.max(Fi(2*a.length),256));for(const e of a){const t=e.getTokens();s.push(t),c+=2*t.length,n+=t.length;for(const e of t){i+=e.length;for(const t of e)l[t%l.length]+=1}}r+=4*c;const p=Math.max(2,Fi(n)),d=p-1,u=[];for(let e=0;e1?this.optimize(c):c,lastRequestSeen:-1},!0===this.config.enableInMemoryCache&&this.cache.set(e,i)}if(i.lastRequestSeen!==t){i.lastRequestSeen=t;const e=i.filters;for(let t=0;t0){const o=e[t];e[t]=e[t-1],e[t-1]=o}return!1}}return!0}},Ri=new Uint8Array(4),zi=class e{static deserialize(t,o,i){const n=new e({deserialize:o,config:i,filters:[]});return n.filters=t.getBytes(),n}constructor({config:e,deserialize:t,filters:o}){this.deserialize=t,this.filters=Ri,this.config=e,0!==o.length&&this.update(o,void 0)}update(e,t){let o=this.filters.byteLength,i=[];const n=this.config.enableCompression,s=this.getFilters();if(0!==s.length)if(void 0===t||0===t.size)i=s;else for(const e of s)!1===t.has(e.getId())?i.push(e):o-=e.getSerializedSize(n);const c=i.length!==s.length,r=i.length;for(const t of e)o+=t.getSerializedSize(n),i.push(t);const a=i.length>r;if(0===i.length)this.filters=Ri;else if(!0===a||!0===c){const e=me.allocate(o,this.config);e.pushUint32(i.length),!0===this.config.debug&&i.sort(((e,t)=>e.getId()-t.getId()));for(const t of i)t.serialize(e);this.filters=e.buffer}}getSerializedSize(){return ae(this.filters,!1)}serialize(e){e.pushBytes(this.filters)}getFilters(){if(this.filters.byteLength<=4)return[];const e=[],t=me.fromUint8Array(this.filters,this.config),o=t.getUint32();for(let i=0;i(!0!==c&&!0!==o.isScriptInject()||!o.match(t,e)||(null==p?void 0:p(o))||u.push(o),!0))),!0===s&&!0===a){const o=this.getGenericRules(l);for(const i of o)!0!==i.match(t,e)||(null==p?void 0:p(i))||u.push(i)}!0===s&&!0===r&&0!==o.length&&this.classesIndex.iterMatchingFilters(yt(o),(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&u.push(o),!0))),!0===s&&!0===r&&0!==n.length&&this.idsIndex.iterMatchingFilters(yt(n),(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&u.push(o),!0))),!0===s&&!0===r&&0!==i.length&&this.hrefsIndex.iterMatchingFilters(function(e){const t=e.sort();let o=1;for(let e=1;e{return t=e,dt.reset(),Et(t,dt),dt.slice();var t})))),(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&u.push(o),!0)));const h=[];return 0!==u.length&&this.unhideIndex.iterMatchingFilters(d,(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&h.push(o),!0))),{filters:u,unhides:h}}getStylesheetsFromFilters({filters:e,extendedFilters:t},{getBaseRules:o,allowGenericHides:i,hidingStyle:n=Mt}){let s=!1===o||!1===i?"":this.getBaseStylesheet(n);0!==e.length&&(0!==s.length&&(s+="\n\n"),s+=Ui(e,n));const c=[];if(0!==t.length){const e=new Map;for(const o of t){const t=o.getSelectorAST();if(void 0!==t){const i=o.isRemove()?void 0:o.getStyleAttributeHash();void 0!==i&&e.set(o.getStyle(n),i),c.push({ast:t,remove:o.isRemove(),attribute:i})}}0!==e.size&&(0!==s.length&&(s+="\n\n"),s+=[...e.entries()].map((([e,t])=>`[${t}] { ${e} }`)).join("\n\n"))}return{stylesheet:s,extended:c}}getGenericRules(e){return null===this.extraGenericRules?this.lazyPopulateGenericRulesCache(e).genericRules:this.extraGenericRules}getBaseStylesheet(e){return null===this.baseStylesheet?this.lazyPopulateGenericRulesCache(e).baseStylesheet:this.baseStylesheet}lazyPopulateGenericRulesCache(e){if(null===this.baseStylesheet||null===this.extraGenericRules){const t=this.unhideIndex.getFilters(),o=new Set;for(const e of t)o.add(e.getSelector());const i=this.genericRules.getFilters(),n=[],s=[];for(const e of i)e.hasCustomStyle()||e.isScriptInject()||e.hasHostnameConstraint()||o.has(e.getSelector())?s.push(e):n.push(e);this.baseStylesheet=Ui(n,e),this.extraGenericRules=s}return{baseStylesheet:this.baseStylesheet,genericRules:this.extraGenericRules}}},ji=class e{static deserialize(t,o){const i=new e({config:o});return i.index=Pi.deserialize(t,ko.deserialize,o.enableOptimizations?Ii:Si,o),i.badFilters=zi.deserialize(t,ko.deserialize,o),i}constructor({filters:e=[],config:t}){this.index=new Pi({config:t,deserialize:ko.deserialize,filters:[],optimize:t.enableOptimizations?Ii:Si}),this.badFiltersIds=null,this.badFilters=new zi({config:t,deserialize:ko.deserialize,filters:[]}),0!==e.length&&this.update(e,void 0)}getFilters(){return[].concat(this.badFilters.getFilters(),this.index.getFilters())}update(e,t){const o=[],i=[];for(const t of e)t.isBadFilter()?o.push(t):i.push(t);this.badFilters.update(o,t),this.index.update(i,t),this.badFiltersIds=null}getSerializedSize(){return this.badFilters.getSerializedSize()+this.index.getSerializedSize()}serialize(e){this.index.serialize(e),this.badFilters.serialize(e)}matchAll(e,t){const o=[];return this.index.iterMatchingFilters(e.getTokens(),(i=>(i.match(e)&&!1===this.isFilterDisabled(i)&&!(null==t?void 0:t(i))&&o.push(i),!0))),o}match(e,t){let o;return this.index.iterMatchingFilters(e.getTokens(),(i=>!(i.match(e)&&!1===this.isFilterDisabled(i)&&!(null==t?void 0:t(i)))||(o=i,!1))),o}isFilterDisabled(e){if(null===this.badFiltersIds){const e=this.badFilters.getFilters();if(0===e.length)return!1;const t=new Set;for(const o of e)t.add(o.getIdWithoutBadFilter());this.badFiltersIds=t}return this.badFiltersIds.has(e.getId())}},Mi=class e{static deserialize(t,o){const i=new e({config:o});return i.networkIndex=Pi.deserialize(t,ko.deserialize,o.enableOptimizations?Ii:Si,o),i.exceptionsIndex=Pi.deserialize(t,ko.deserialize,o.enableOptimizations?Ii:Si,o),i.cosmeticIndex=Pi.deserialize(t,Xt.deserialize,Ei,o),i.unhideIndex=Pi.deserialize(t,Xt.deserialize,Ei,o),i}constructor({filters:e=[],config:t}){this.config=t,this.networkIndex=new Pi({config:t,deserialize:ko.deserialize,filters:[],optimize:t.enableOptimizations?Ii:Si}),this.exceptionsIndex=new Pi({config:t,deserialize:ko.deserialize,filters:[],optimize:t.enableOptimizations?Ii:Si}),this.cosmeticIndex=new Pi({config:t,deserialize:Xt.deserialize,filters:[],optimize:Ei}),this.unhideIndex=new Pi({config:t,deserialize:Xt.deserialize,filters:[],optimize:Ei}),0!==e.length&&this.update(e,void 0)}update(e,t){const o=[],i=[],n=[],s=[];for(const t of e)t.isNetworkFilter()?t.isException()?i.push(t):o.push(t):t.isCosmeticFilter()&&(t.isUnhide()?s.push(t):n.push(t));this.networkIndex.update(o,t),this.exceptionsIndex.update(i,t),this.cosmeticIndex.update(n,t),this.unhideIndex.update(s,t)}serialize(e){this.networkIndex.serialize(e),this.exceptionsIndex.serialize(e),this.cosmeticIndex.serialize(e),this.unhideIndex.serialize(e)}getSerializedSize(){return this.networkIndex.getSerializedSize()+this.exceptionsIndex.getSerializedSize()+this.cosmeticIndex.getSerializedSize()+this.unhideIndex.getSerializedSize()}getHTMLFilters(e,t){const o=[],i=[],n=[],s=[];if(!0===this.config.loadNetworkFilters&&this.networkIndex.iterMatchingFilters(e.getTokens(),(i=>(i.match(e)&&!(null==t?void 0:t(i))&&o.push(i),!0))),0!==o.length&&this.exceptionsIndex.iterMatchingFilters(e.getTokens(),(o=>(o.match(e)&&!(null==t?void 0:t(o))&&n.push(o),!0))),!0===this.config.loadCosmeticFilters&&e.isMainFrame()){const{hostname:o,domain:n=""}=e,c=Ni(o,n);this.cosmeticIndex.iterMatchingFilters(c,(e=>(e.match(o,n)&&!(null==t?void 0:t(e))&&i.push(e),!0))),0!==i.length&&this.unhideIndex.iterMatchingFilters(c,(e=>(e.match(o,n)&&!(null==t?void 0:t(e))&&s.push(e),!0)))}return{networkFilters:o,cosmeticFilters:i,unhides:s,exceptions:n}}getFilters(){return[].concat(this.networkIndex.getFilters(),this.exceptionsIndex.getFilters(),this.cosmeticIndex.getFilters(),this.unhideIndex.getFilters())}},Di=Number.MAX_SAFE_INTEGER>>>0,Hi=class e{static deserialize(t,o){const i=t.getUint32(),n=t.getUint32(),s=t.getUint32(),c=me.fromUint8Array(t.getBytes(!0),{enableCompression:!1}),r=c.getUint32ArrayView(i),a=c.getUint32ArrayView(n),l=c.pos;return c.seekZero(),new e({deserialize:o,values:[],getKeys:()=>[],getSerializedSize:()=>0,serialize:()=>{}}).updateInternals({bucketsIndex:a,valuesIndexStart:l,numberOfValues:s,tokensLookupIndex:r,view:c})}constructor({serialize:e,deserialize:t,getKeys:o,getSerializedSize:i,values:n}){if(this.cache=new Map,this.bucketsIndex=ne,this.tokensLookupIndex=ne,this.valuesIndexStart=0,this.numberOfValues=0,this.view=me.empty({enableCompression:!1}),this.deserializeValue=t,0!==n.length){const t=[];let s=0,c=0;for(const e of n)c+=i(e);if(0===n.length)return void this.updateInternals({bucketsIndex:ne,valuesIndexStart:0,numberOfValues:0,tokensLookupIndex:ne,view:me.empty({enableCompression:!1})});for(const e of n){const i=o(e);t.push(i),s+=2*i.length}c+=4*s;const r=Math.max(2,Fi(n.length)),a=r-1,l=[];for(let e=0;e[qi(e)],serialize:$i,deserialize:Ki,values:e})}function Yi(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{key:t,name:o,description:i,country:n,website_url:s,privacy_policy_url:c,privacy_contact:r,ghostery_id:a}=e;return"string"==typeof t&&("string"==typeof o&&((null===i||"string"==typeof i)&&((null===n||"string"==typeof n)&&((null===s||"string"==typeof s)&&((null===c||"string"==typeof c)&&((null===r||"string"==typeof r)&&(null===a||"string"==typeof a)))))))}function Xi(e){return bt(e.key)}function Zi(e){return de(e.key)+de(e.name)+de(e.description||"")+de(e.website_url||"")+de(e.country||"")+de(e.privacy_policy_url||"")+de(e.privacy_contact||"")+de(e.ghostery_id||"")}function Ji(e,t){t.pushUTF8(e.key),t.pushUTF8(e.name),t.pushUTF8(e.description||""),t.pushUTF8(e.website_url||""),t.pushUTF8(e.country||""),t.pushUTF8(e.privacy_policy_url||""),t.pushUTF8(e.privacy_contact||""),t.pushUTF8(e.ghostery_id||"")}function en(e){return{key:e.getUTF8(),name:e.getUTF8(),description:e.getUTF8()||null,website_url:e.getUTF8()||null,country:e.getUTF8()||null,privacy_policy_url:e.getUTF8()||null,privacy_contact:e.getUTF8()||null,ghostery_id:e.getUTF8()||null}}function tn(e){return new Hi({getSerializedSize:Zi,getKeys:e=>[Xi(e)],serialize:Ji,deserialize:en,values:e})}function on(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{key:t,name:o,category:i,organization:n,alias:s,website_url:c,domains:r,filters:a}=e;return"string"==typeof t&&("string"==typeof o&&("string"==typeof i&&((null===n||"string"==typeof n)&&(("string"==typeof s||null===s)&&((null===c||"string"==typeof c)&&(!(!Array.isArray(r)||!r.every((e=>"string"==typeof e)))&&!(!Array.isArray(a)||!a.every((e=>"string"==typeof e)))))))))}function nn(e){const t=[];for(const o of e.filters){const e=ko.parse(o);null!==e&&t.push(e.getId())}for(const o of e.domains){const e=ko.parse(`||${o}^`);null!==e&&t.push(e.getId())}return[...new Set(t)]}function sn(e){let t=re(e.domains.length);for(const o of e.domains)t+=de(o);let o=re(e.filters.length);for(const t of e.filters)o+=de(t);return de(e.key)+de(e.name)+de(e.category)+de(e.organization||"")+de(e.alias||"")+de(e.website_url||"")+de(e.ghostery_id||"")+t+o}function cn(e,t){t.pushUTF8(e.key),t.pushUTF8(e.name),t.pushUTF8(e.category),t.pushUTF8(e.organization||""),t.pushUTF8(e.alias||""),t.pushUTF8(e.website_url||""),t.pushUTF8(e.ghostery_id||""),t.pushLength(e.domains.length);for(const o of e.domains)t.pushUTF8(o);t.pushLength(e.filters.length);for(const o of e.filters)t.pushUTF8(o)}function rn(e){const t=e.getUTF8(),o=e.getUTF8(),i=e.getUTF8(),n=e.getUTF8()||null,s=e.getUTF8()||null,c=e.getUTF8()||null,r=e.getUTF8()||null,a=e.getLength(),l=[];for(let t=0;t=2;t.shift()){const e=t.join("."),o=ko.parse(`||${e}^`);if(null===o)continue;const i=this.fromId(o.getId());if(i.length>0)return i}return[]}fromId(e){var t,o;const i=[];for(const n of this.patterns.get(e))i.push({pattern:n,category:null===(t=this.categories.get(qi({key:n.category})))||void 0===t?void 0:t[0],organization:null!==n.organization?null===(o=this.organizations.get(Xi({key:n.organization})))||void 0===o?void 0:o[0]:null});return i}},pn=class{static deserialize(e){const t=new Set;for(let o=0,i=e.getUint32();ot.condition===e.condition));if(t)for(const o of e.filterIDs)t.filterIDs.delete(o)}if(e)for(const t of e){const e=this.preprocessors.find((e=>e.condition===t.condition));if(e)for(const o of t.filterIDs)e.filterIDs.add(o);else this.preprocessors.push(t)}(t&&0!==t.length||e&&0!==e.length)&&this.updateEnv(o)}serialize(e){e.pushUint32(this.excluded.size);for(const t of this.excluded)e.pushUint32(t);e.pushUint32(this.preprocessors.length);for(const t of this.preprocessors)t.serialize(e)}getSerializedSize(){let e=4*(1+this.excluded.size);e+=4;for(const t of this.preprocessors)e+=t.getSerializedSize();return e}};function dn(e){if(0===e.length)return!1;let t,o=0;for(const i of e){const e=(i.isImportant()?4:0)|(i.isException()?1:2);e>=o&&(o=e,t=i)}return void 0!==t&&t.isException()}var un=class extends ye{static fromCached(e,t){if(void 0===t)return e();const{path:o,read:i,write:n}=t;return i(o).then((e=>this.deserialize(e))).catch((()=>e().then((e=>n(o,e.serialize()).then((()=>e))))))}static empty(e={}){return new this({config:e})}static fromLists(e,t,o={},i){return this.fromCached((()=>{const i=function(e,t){return Promise.all(t.map((t=>we(e,t))))}(e,t),n=function(e){return we(e,`${ve}/ublock-origin/resources.json`)}(e);return Promise.all([i,n]).then((([e,t])=>{const i=this.parse(e.join("\n"),o);return void 0!==t&&i.updateResources(t,""+t.length),i}))}),i)}static fromPrebuiltAdsOnly(e=fetch,t){return this.fromLists(e,_e,{},t)}static fromPrebuiltAdsAndTracking(e=fetch,t){return this.fromLists(e,Ce,{},t)}static fromPrebuiltFull(e=fetch,t){return this.fromLists(e,xe,{},t)}static fromTrackerDB(e,t={}){const o=new Ae(t),i=new ln(e),n=[];for(const e of i.getPatterns())n.push(...e.filters);const s=this.parse(n.join("\n"),o);return s.metadata=i,s}static merge(e,{skipResources:t=!1}={}){if(!e||e.length<2)throw new Error("merging engines requires at least two engines");const o=e[0].config,i=new Map,n=new Map,s=new Map,c=[],r={organizations:{},categories:{},patterns:{}},a=[],l=Object.keys(o).filter((function(e){return"boolean"==typeof o[e]&&!a.includes(e)}));for(const t of e){for(const e of l)if(o[e]!==t.config[e])throw new Error(`config "${e}" of all merged engines must be the same`);const e=t.getFilters();for(const t of e.networkFilters)n.set(t.getId(),t);for(const t of e.cosmeticFilters)s.set(t.getId(),t);for(const e of t.preprocessors.preprocessors)c.push(e);for(const[e,o]of t.lists)i.has(e)||i.set(e,o);if(void 0!==t.metadata){for(const e of t.metadata.organizations.getValues())void 0===r.organizations[e.key]&&(r.organizations[e.key]=e);for(const e of t.metadata.categories.getValues())void 0===r.categories[e.key]&&(r.categories[e.key]=e);for(const e of t.metadata.patterns.getValues())void 0===r.patterns[e.key]&&(r.patterns[e.key]=e)}}const p=new this({networkFilters:Array.from(n.values()),cosmeticFilters:Array.from(s.values()),preprocessors:c,lists:i,config:o});if(Object.keys(r.categories).length+Object.keys(r.organizations).length+Object.keys(r.patterns).length!==0&&(p.metadata=new ln(r)),!0!==t){for(const t of e.slice(1))if(t.resources.checksum!==e[0].resources.checksum)throw new Error(`resource checksum of all merged engines must match with the first one: "${e[0].resources.checksum}" but got: "${t.resources.checksum}"`);p.resources=bi.copy(e[0].resources)}return p}static parse(e,t={}){const o=new Ae(t);return new this({...zo(e,o),config:o})}static deserialize(e){const t=me.fromUint8Array(e,{enableCompression:!1}),o=t.getUint16();if(699!==o)throw new Error(`serialized engine version mismatch, expected 699 but got ${o}`);const i=Ae.deserialize(t);if(i.enableCompression&&t.enableCompression(),i.integrityCheck){const o=t.pos;t.pos=e.length-4;const i=t.checksum(),n=t.getUint32();if(i!==n)throw new Error(`serialized engine checksum mismatch, expected ${n} but got ${i}`);t.pos=o}const n=new this({config:i});n.resources=bi.deserialize(t);const s=new Map,c=t.getUint16();for(let e=0;ee.getId()))).concat(o.map((e=>e.getId()))));l.push(new Po({condition:e,filterIDs:n}))}if(void 0!==t.added&&0!==t.added.length){const{networkFilters:o,cosmeticFilters:i}=zo(t.added.join("\n"),this.config),n=new Set([].concat(i.map((e=>e.getId()))).concat(o.map((e=>e.getId()))));c.push(new Po({condition:e,filterIDs:n}))}}return this.update({newCosmeticFilters:n,newNetworkFilters:s,newPreprocessors:c,removedCosmeticFilters:r.map((e=>e.getId())),removedNetworkFilters:a.map((e=>e.getId())),removedPreprocessors:l},i)}getHtmlFilters(e){const t=[];if(!1===this.config.enableHtmlFiltering)return t;const{networkFilters:o,exceptions:i,cosmeticFilters:n,unhides:s}=this.htmlFilters.getHTMLFilters(e,this.isFilterExcluded.bind(this));if(0!==n.length){const o=new Map(s.map((e=>[e.getSelector(),e])));for(const i of n){const n=i.getExtendedSelector();if(void 0===n)continue;const s=o.get(i.getSelector());void 0===s&&t.push(n),this.emit("filter-matched",{filter:i,exception:s},{request:e,filterType:Co.COSMETIC})}}if(0!==o.length){const n=new Map;let s;for(const e of i){const t=e.optionValue;if(""===t){s=e;break}n.set(t,e)}for(const i of o){const o=i.getHtmlModifier();if(null===o)continue;const c=s||n.get(i.optionValue);this.emit("filter-matched",{filter:i,exception:c},{request:e,filterType:Co.NETWORK}),void 0===c&&t.push(["replace",o])}}return 0!==t.length&&this.emit("html-filtered",t,e.url),t}getCosmeticsFilters({url:e,hostname:t,domain:o,classes:i,hrefs:n,ids:s,getBaseRules:c=!0,getInjectionRules:r=!0,getExtendedRules:a=!0,getRulesFromDOM:l=!0,getRulesFromHostname:p=!0,hidingStyle:d,callerContext:u}){if(!1===this.config.loadCosmeticFilters)return{active:!1,extended:[],scripts:[],styles:""};o||(o="");let h=!0,m=!0;const A=this.hideExceptions.matchAll(Ut.fromRawDetails({domain:o,hostname:t,url:e,sourceDomain:"",sourceHostname:"",sourceUrl:""}),this.isFilterExcluded.bind(this)),g=[],f=[];for(const e of A){if(e.isElemHide()){h=!1,m=!1;break}e.isSpecificHide()?f.push(e):e.isGenericHide()&&g.push(e)}!0===h&&(h=!1===dn(g)),!0===m&&(m=!1===dn(f));const{filters:k,unhides:b}=this.cosmetics.getCosmeticsFilters({domain:o,hostname:t,classes:i,hrefs:n,ids:s,allowGenericHides:h,allowSpecificHides:m,getRulesFromDOM:l,getRulesFromHostname:p,hidingStyle:d,isFilterExcluded:this.isFilterExcluded.bind(this)});let y=!1;const w=new Map;for(const e of b)!0===e.isScriptInject()&&!0===e.isUnhide()&&0===e.getSelector().length&&(y=!0),w.set(Yt(e,this.resources.getScriptletCanonicalName.bind(this.resources)),e);const v=[],_=[],C=[];if(0!==k.length)for(const t of k){const o=w.get(Yt(t,this.resources.getScriptletCanonicalName.bind(this.resources)));if(void 0!==o)continue;let i=!1;!0===t.isScriptInject()?!0===r&&!1===y&&(v.push(t),i=!0):t.isExtended()?!0===a&&(C.push(t),i=!0):(_.push(t),i=!0),i&&this.emit("filter-matched",{filter:t,exception:o},{url:e,callerContext:u,filterType:Co.COSMETIC})}const x=[];for(const t of v){const o=t.getScript(this.resources.getScriptlet.bind(this.resources));void 0!==o&&(this.emit("script-injected",o,e),x.push(o))}const{stylesheet:S,extended:E}=this.cosmetics.getStylesheetsFromFilters({filters:_,extendedFilters:C},{getBaseRules:c,allowGenericHides:h,hidingStyle:d});return 0!==S.length&&this.emit("style-injected",S,e),{active:!0,extended:E,scripts:x,styles:S}}matchAll(e){const t=[];return e.isSupported&&(Array.prototype.push.apply(t,this.importants.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.filters.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.exceptions.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.csp.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.hideExceptions.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.redirects.matchAll(e,this.isFilterExcluded.bind(this)))),new Set(t)}getCSPDirectives(e){if(!this.config.loadNetworkFilters)return;if(!0!==e.isSupported||!1===e.isMainFrame())return;const t=this.csp.matchAll(e,this.isFilterExcluded.bind(this));if(0===t.length)return;const o=new Map,i=[];for(const n of t)if(n.isException()){if(void 0===n.csp)return void this.emit("filter-matched",{exception:n},{request:e,filterType:Co.NETWORK});o.set(n.csp,n)}else i.push(n);if(0===i.length)return;const n=new Set;for(const t of i.values()){const i=o.get(t.csp);void 0===i&&n.add(t.csp),this.emit("filter-matched",{filter:t,exception:i},{request:e,filterType:Co.NETWORK})}const s=Array.from(n).join("; ");return s.length>0&&this.emit("csp-injected",e,s),s}match(e,t=!1){const o={exception:void 0,filter:void 0,match:!1,redirect:void 0,metadata:void 0};if(!this.config.loadNetworkFilters)return o;if(e.isSupported){let t,i;if(o.filter=this.importants.match(e,this.isFilterExcluded.bind(this)),void 0===o.filter){const n=this.redirects.matchAll(e,this.isFilterExcluded.bind(this)).sort(((e,t)=>t.getRedirectPriority()-e.getRedirectPriority()));if(0!==n.length)for(const e of n)"none"===e.getRedirectResource()?t=e:e.isRedirectRule()?void 0===i&&(i=e):void 0===o.filter&&(o.filter=e);void 0===o.filter&&(o.filter=this.filters.match(e,this.isFilterExcluded.bind(this)),void 0!==i&&void 0!==o.filter&&(o.filter=i)),void 0!==o.filter&&(o.exception=this.exceptions.match(e,this.isFilterExcluded.bind(this)))}void 0!==o.filter&&void 0===o.exception&&o.filter.isRedirect()&&(void 0!==t?o.exception=t:o.redirect=this.resources.getResource(o.filter.getRedirectResource()))}return o.match=void 0===o.exception&&void 0!==o.filter,o.filter&&this.emit("filter-matched",{filter:o.filter,exception:o.exception},{request:e,filterType:Co.NETWORK}),void 0!==o.exception?this.emit("request-whitelisted",e,o):void 0!==o.redirect?this.emit("request-redirected",e,o):void 0!==o.filter?this.emit("request-blocked",e,o):this.emit("request-allowed",e,o),!0===t&&void 0!==o.filter&&this.metadata&&(o.metadata=this.metadata.fromFilter(o.filter)),o}getPatternMetadata(e,{getDomainMetadata:t=!1}={}){if(void 0===this.metadata)return[];const o=new Set,i=[];for(const t of this.matchAll(e))for(const e of this.metadata.fromFilter(t))o.has(e.pattern.key)||(o.add(e.pattern.key),i.push(e));if(t)for(const t of this.metadata.fromDomain(e.hostname))o.has(t.pattern.key)||(o.add(t.pattern.key),i.push(t));return i}blockScripts(){return this.updateFromDiff({added:[Jt().scripts().redirectTo("javascript").toString()]}),this}blockImages(){return this.updateFromDiff({added:[Jt().images().redirectTo("png").toString()]}),this}blockMedias(){return this.updateFromDiff({added:[Jt().medias().redirectTo("mp4").toString()]}),this}blockFrames(){return this.updateFromDiff({added:[Jt().frames().redirectTo("html").toString()]}),this}blockFonts(){return this.updateFromDiff({added:[Jt().fonts().toString()]}),this}blockStyles(){return this.updateFromDiff({added:[Jt().styles().toString()]}),this}};function hn(e){const t=new Set(["br","head","link","meta","script","style","s"]),o=new Set,i=new Set,n=new Set,s=new Set;for(const c of e)for(const e of[c,...c.querySelectorAll("[id]:not(html):not(body),[class]:not(html):not(body),[href]:not(html):not(body)")]){if(s.has(e))continue;if(s.add(e),t.has(e.nodeName.toLowerCase()))continue;const c=e.getAttribute("id");"string"==typeof c&&n.add(c);const r=e.classList;for(const e of r)o.add(e);const a=e.getAttribute("href");"string"==typeof a&&i.add(a)}return{classes:Array.from(o),hrefs:Array.from(i),ids:Array.from(n)}}function mn(e){try{const t=pt(location.href),o=t.hostname||"",i=t.domain||"";return e.getCosmeticsFilters({url:location.href,hostname:o,domain:i,...hn([document.documentElement]),getBaseRules:!0,getInjectionRules:!1,getExtendedRules:!0,getRulesFromDOM:!0,getRulesFromHostname:!0,hidingStyle:A("opacity")}).styles}catch(e){return console.error("Error getting cosmetic rules",e),""}}var An=new Uint8Array([]);var gn=[{name:"192.com",detectCmp:[{exists:".ont-cookies"}],detectPopup:[{visible:".ont-cookies"}],optIn:[{click:".ont-btn-main.ont-cookies-btn.js-ont-btn-ok2"}],optOut:[{click:".ont-cookes-btn-manage"},{click:".ont-btn-main.ont-cookies-btn.js-ont-btn-choose"}],test:[{eval:"EVAL_ONENINETWO_0"}]},{name:"1password-com",cosmetic:!0,prehideSelectors:['footer #footer-root [aria-label="Cookie Consent"]'],detectCmp:[{exists:'footer #footer-root [aria-label="Cookie Consent"]'}],detectPopup:[{visible:'footer #footer-root [aria-label="Cookie Consent"]'}],optIn:[{click:'footer #footer-root [aria-label="Cookie Consent"] button'}],optOut:[{hide:'footer #footer-root [aria-label="Cookie Consent"]'}]},{name:"aa",vendorUrl:"https://aa.com",prehideSelectors:[],cosmetic:!0,detectCmp:[{exists:"#aa_optoutmulti-Modal,#cookieBannerMessage"}],detectPopup:[{visible:"#aa_optoutmulti-Modal,#cookieBannerMessage"}],optIn:[{hide:"#aa_optoutmulti-Modal,#cookieBannerMessage"},{waitForThenClick:"#aa_optoutmulti_checkBox"},{waitForThenClick:"#aa_optoutmulti-Modal button.optoutmulti_button"}],optOut:[{hide:"#aa_optoutmulti-Modal,#cookieBannerMessage"}]},{name:"abc",vendorUrl:"https://abc.net.au",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?abc\\.net\\.au/"},prehideSelectors:[],detectCmp:[{exists:"[data-component=CookieBanner]"}],detectPopup:[{visible:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptAll]"}],optIn:[{waitForThenClick:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptAll]"}],optOut:[{waitForThenClick:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptABCRequired]"}],test:[{eval:"EVAL_ABC_TEST"}]},{name:"abconcerts.be",vendorUrl:"https://unknown",intermediate:!1,prehideSelectors:["dialog.cookie-consent"],detectCmp:[{exists:"dialog.cookie-consent form.cookie-consent__form"}],detectPopup:[{visible:"dialog.cookie-consent form.cookie-consent__form"}],optIn:[{waitForThenClick:"dialog.cookie-consent form.cookie-consent__form button[value=yes]"}],optOut:[{if:{exists:"dialog.cookie-consent form.cookie-consent__form button[value=no]"},then:[{click:"dialog.cookie-consent form.cookie-consent__form button[value=no]"}],else:[{click:"dialog.cookie-consent form.cookie-consent__form button.cookie-consent__options-toggle"},{waitForThenClick:'dialog.cookie-consent form.cookie-consent__form button[value="save_options"]'}]}]},{name:"acris",prehideSelectors:["div.acris-cookie-consent"],detectCmp:[{exists:"[data-acris-cookie-consent]"}],detectPopup:[{visible:".acris-cookie-consent.is--modal"}],optIn:[{waitForVisible:"#ccConsentAcceptAllButton",check:"any"},{wait:500},{waitForThenClick:"#ccConsentAcceptAllButton"}],optOut:[{waitForVisible:"#ccAcceptOnlyFunctional",check:"any"},{wait:500},{waitForThenClick:"#ccAcceptOnlyFunctional"}]},{name:"activobank.pt",runContext:{urlPattern:"^https://(www\\.)?activobank\\.pt"},prehideSelectors:["aside#cookies,.overlay-cookies"],detectCmp:[{exists:"#cookies .cookies-btn"}],detectPopup:[{visible:"#cookies #submitCookies"}],optIn:[{waitForThenClick:"#cookies #submitCookies"}],optOut:[{waitForThenClick:"#cookies #rejectCookies"}]},{name:"Adroll",prehideSelectors:["#adroll_consent_container"],detectCmp:[{exists:"#adroll_consent_container"}],detectPopup:[{visible:"#adroll_consent_container"}],optIn:[{waitForThenClick:"#adroll_consent_accept"}],optOut:[{waitForThenClick:"#adroll_consent_reject"}],test:[{eval:"EVAL_ADROLL_0"}]},{name:"affinity.serif.com",detectCmp:[{exists:".c-cookie-banner button[data-qa='allow-all-cookies']"}],detectPopup:[{visible:".c-cookie-banner"}],optIn:[{click:'button[data-qa="allow-all-cookies"]'}],optOut:[{click:'button[data-qa="manage-cookies"]'},{waitFor:'.c-cookie-banner ~ [role="dialog"]'},{waitForThenClick:'.c-cookie-banner ~ [role="dialog"] input[type="checkbox"][value="true"]',all:!0},{click:'.c-cookie-banner ~ [role="dialog"] .c-modal__action button'}],test:[{wait:500},{eval:"EVAL_AFFINITY_SERIF_COM_0"}]},{name:"agolde.com",cosmetic:!0,prehideSelectors:["#modal-1 div[data-micromodal-close]"],detectCmp:[{exists:"#modal-1 div[aria-labelledby=modal-1-title]"}],detectPopup:[{exists:"#modal-1 div[data-micromodal-close]"}],optIn:[{click:'button[aria-label="Close modal"]'}],optOut:[{hide:"#modal-1 div[data-micromodal-close]"}]},{name:"aliexpress",vendorUrl:"https://aliexpress.com/",runContext:{urlPattern:"^https://.*\\.aliexpress\\.com/"},prehideSelectors:["#gdpr-new-container"],detectCmp:[{exists:"#gdpr-new-container,#voyager-gdpr > div"}],detectPopup:[{visible:"#gdpr-new-container,#voyager-gdpr > div"}],optIn:[{waitForThenClick:"#gdpr-new-container .btn-accept,#voyager-gdpr > div > div > button:nth-child(1)"}],optOut:[{if:{exists:"#voyager-gdpr > div"},then:[{waitForThenClick:"#voyager-gdpr > div > div > button:nth-child(2)"}],else:[{waitForThenClick:"#gdpr-new-container .btn-more"},{waitFor:"#gdpr-new-container .gdpr-dialog-switcher"},{click:"#gdpr-new-container .switcher-on",all:!0,optional:!0},{click:"#gdpr-new-container .btn-save"}]}]},{name:"almacmp",prehideSelectors:["#alma-cmpv2-container"],detectCmp:[{exists:"#alma-cmpv2-container"}],detectPopup:[{visible:"#alma-cmpv2-container #almacmp-modal-layer1"}],optIn:[{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer1 #almacmp-modalConfirmBtn"}],optOut:[{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer1 #almacmp-modalSettingBtn"},{waitFor:"#alma-cmpv2-container #almacmp-modal-layer2"},{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer2 #almacmp-reject-all-layer2"}],test:[{eval:"EVAL_ALMACMP_0"}]},{name:"altium.com",cosmetic:!0,prehideSelectors:[".altium-privacy-bar"],detectCmp:[{exists:".altium-privacy-bar"}],detectPopup:[{exists:".altium-privacy-bar"}],optIn:[{click:"a.altium-privacy-bar__btn"}],optOut:[{hide:".altium-privacy-bar"}]},{name:"amazon.com",prehideSelectors:['span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'],detectCmp:[{exists:'span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'}],detectPopup:[{visible:'span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'}],optIn:[{waitForVisible:"#sp-cc-accept"},{wait:500},{click:"#sp-cc-accept"}],optOut:[{waitForVisible:"#sp-cc-rejectall-link"},{wait:500},{click:"#sp-cc-rejectall-link"}]},{name:"amex",vendorUrl:"https://www.americanexpress.com/",cosmetic:!1,prehideSelectors:["#user-consent-management-granular-banner-overlay"],detectCmp:[{exists:"#user-consent-management-granular-banner-overlay"}],detectPopup:[{visible:"#user-consent-management-granular-banner-overlay"}],optIn:[{waitForThenClick:"[data-testid=granular-banner-button-accept-all]"}],optOut:[{waitForThenClick:"[data-testid=granular-banner-button-decline-all]"}]},{name:"aquasana.com",prehideSelectors:["#consent-tracking"],detectCmp:[{exists:"#consent-tracking"}],detectPopup:[{exists:"#consent-tracking"}],optIn:[{waitForThenClick:"#consent-tracking .affirm.btn"}],optOut:[{if:{exists:"#consent-tracking .decline.btn"},then:[{click:"#consent-tracking .decline.btn"}],else:[{hide:"#consent-tracking"}]}]},{name:"arbeitsagentur",vendorUrl:"https://www.arbeitsagentur.de/",prehideSelectors:[".modal-open bahf-cookie-disclaimer-dpl3"],detectCmp:[{exists:"bahf-cookie-disclaimer-dpl3"}],detectPopup:[{visible:"bahf-cookie-disclaimer-dpl3"}],optIn:[{waitForThenClick:["bahf-cookie-disclaimer-dpl3","#bahf-cookie-disclaimer-modal .ba-btn-primary"]}],optOut:[{waitForThenClick:["bahf-cookie-disclaimer-dpl3","#bahf-cookie-disclaimer-modal .ba-btn-contrast"]}],test:[{eval:"EVAL_ARBEITSAGENTUR_TEST"}]},{name:"asus",vendorUrl:"https://www.asus.com/",runContext:{urlPattern:"^https://www\\.asus\\.com/"},prehideSelectors:["#cookie-policy-info,#cookie-policy-info-bg"],detectCmp:[{exists:"#cookie-policy-info"}],detectPopup:[{visible:"#cookie-policy-info"}],optIn:[{waitForThenClick:'#cookie-policy-info [data-agree="Accept Cookies"]'}],optOut:[{if:{exists:"#cookie-policy-info .btn-reject"},then:[{waitForThenClick:"#cookie-policy-info .btn-reject"}],else:[{waitForThenClick:"#cookie-policy-info .btn-setting"},{waitForThenClick:'#cookie-policy-lightbox-wrapper [data-agree="Save Settings"]'}]}]},{name:"athlinks-com",runContext:{urlPattern:"^https://(www\\.)?athlinks\\.com/"},cosmetic:!0,prehideSelectors:["#footer-container ~ div"],detectCmp:[{exists:"#footer-container ~ div"}],detectPopup:[{visible:"#footer-container > div"}],optIn:[{click:"#footer-container ~ div button"}],optOut:[{hide:"#footer-container ~ div"}]},{name:"ausopen.com",cosmetic:!0,detectCmp:[{exists:".gdpr-popup__message"}],detectPopup:[{visible:".gdpr-popup__message"}],optOut:[{hide:".gdpr-popup__message"}],optIn:[{click:".gdpr-popup__message button"}]},{name:"automattic-cmp-optout",prehideSelectors:['form[class*="cookie-banner"][method="post"]'],detectCmp:[{exists:'form[class*="cookie-banner"][method="post"]'}],detectPopup:[{visible:'form[class*="cookie-banner"][method="post"]'}],optIn:[{click:'a[class*="accept-all-button"]'}],optOut:[{click:'form[class*="cookie-banner"] div[class*="simple-options"] a[class*="customize-button"]'},{waitForThenClick:"input[type=checkbox][checked]:not([disabled])",all:!0},{click:'a[class*="accept-selection-button"]'}]},{name:"aws.amazon.com",prehideSelectors:["#awsccc-cb-content","#awsccc-cs-container","#awsccc-cs-modalOverlay","#awsccc-cs-container-inner"],detectCmp:[{exists:"#awsccc-cb-content"}],detectPopup:[{visible:"#awsccc-cb-content"}],optIn:[{click:"button[data-id=awsccc-cb-btn-accept"}],optOut:[{click:"button[data-id=awsccc-cb-btn-customize]"},{waitFor:"input[aria-checked]"},{click:"input[aria-checked=true]",all:!0,optional:!0},{click:"button[data-id=awsccc-cs-btn-save]"}]},{name:"axeptio",prehideSelectors:[".axeptio_widget"],detectCmp:[{exists:".axeptio_widget"}],detectPopup:[{visible:".axeptio_widget"}],optIn:[{waitFor:".axeptio-widget--open"},{click:"button#axeptio_btn_acceptAll"}],optOut:[{waitFor:".axeptio-widget--open"},{click:"button#axeptio_btn_dismiss"}],test:[{eval:"EVAL_AXEPTIO_0"}]},{name:"baden-wuerttemberg.de",prehideSelectors:[".cookie-alert.t-dark"],cosmetic:!0,detectCmp:[{exists:".cookie-alert.t-dark"}],detectPopup:[{visible:".cookie-alert.t-dark"}],optIn:[{click:".cookie-alert__form input:not([disabled]):not([checked])"},{click:".cookie-alert__button button"}],optOut:[{hide:".cookie-alert.t-dark"}]},{name:"bahn-de",vendorUrl:"https://www.bahn.de/",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?bahn\\.de/"},intermediate:!1,prehideSelectors:[],detectCmp:[{exists:["body > div:first-child","#consent-layer"]}],detectPopup:[{visible:["body > div:first-child","#consent-layer"]}],optIn:[{waitForThenClick:["body > div:first-child","#consent-layer .js-accept-all-cookies"]}],optOut:[{waitForThenClick:["body > div:first-child","#consent-layer .js-accept-essential-cookies"]}],test:[{eval:"EVAL_BAHN_TEST"}]},{name:"bbb.org",runContext:{urlPattern:"^https://www\\.bbb\\.org/"},cosmetic:!0,prehideSelectors:['div[aria-label="use of cookies on bbb.org"]'],detectCmp:[{exists:'div[aria-label="use of cookies on bbb.org"]'}],detectPopup:[{visible:'div[aria-label="use of cookies on bbb.org"]'}],optIn:[{click:'div[aria-label="use of cookies on bbb.org"] button.bds-button-unstyled span.visually-hidden'}],optOut:[{hide:'div[aria-label="use of cookies on bbb.org"]'}]},{name:"bing.com",prehideSelectors:["#bnp_container"],detectCmp:[{exists:"#bnp_cookie_banner"}],detectPopup:[{visible:"#bnp_cookie_banner"},{visible:"#bnp_btn_accept,#bnp_btn_reject"}],optIn:[{waitForThenClick:"#bnp_btn_accept"}],optOut:[{wait:500},{waitForThenClick:"#bnp_btn_reject"}],test:[{eval:"EVAL_BING_0"}]},{name:"blocksy",vendorUrl:"https://creativethemes.com/blocksy/docs/extensions/cookies-consent/",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,prehideSelectors:[".cookie-notification"],detectCmp:[{exists:"#blocksy-ext-cookies-consent-styles-css"}],detectPopup:[{visible:".cookie-notification"}],optIn:[{click:".cookie-notification .ct-cookies-decline-button"}],optOut:[{waitForThenClick:".cookie-notification .ct-cookies-decline-button"}],test:[{eval:"EVAL_BLOCKSY_0"}]},{name:"borlabs",detectCmp:[{exists:"._brlbs-block-content"}],detectPopup:[{visible:"._brlbs-bar-wrap,._brlbs-box-wrap"}],optIn:[{click:"a[data-cookie-accept-all]"}],optOut:[{click:"a[data-cookie-individual]"},{waitForVisible:".cookie-preference"},{click:"input[data-borlabs-cookie-checkbox]:checked",all:!0,optional:!0},{click:"#CookiePrefSave"},{wait:500}],prehideSelectors:["#BorlabsCookieBox"],test:[{eval:"EVAL_BORLABS_0"}]},{name:"bundesregierung.de",prehideSelectors:[".bpa-cookie-banner"],detectCmp:[{exists:".bpa-cookie-banner"}],detectPopup:[{visible:".bpa-cookie-banner .bpa-module-full-hero"}],optIn:[{click:".bpa-accept-all-button"}],optOut:[{wait:500,comment:"click is not immediately recognized"},{waitForThenClick:".bpa-close-button"}],test:[{eval:"EVAL_BUNDESREGIERUNG_DE_0"}]},{name:"burpee.com",cosmetic:!0,prehideSelectors:["#notice-cookie-block"],detectCmp:[{exists:"#notice-cookie-block"}],detectPopup:[{exists:"#html-body #notice-cookie-block"}],optIn:[{click:"#btn-cookie-allow"}],optOut:[{hide:"#html-body #notice-cookie-block, #notice-cookie"}]},{name:"canva.com",prehideSelectors:['div[role="dialog"] a[data-anchor-id="cookie-policy"]'],detectCmp:[{exists:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'}],detectPopup:[{exists:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'}],optIn:[{click:'div[role="dialog"] button:nth-child(1)'}],optOut:[{if:{exists:'div[role="dialog"] button:nth-child(3)'},then:[{click:'div[role="dialog"] button:nth-child(2)'}],else:[{click:'div[role="dialog"] button:nth-child(2)'},{waitFor:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'},{waitFor:'div[role="dialog"] button[role=switch]'},{click:'div[role="dialog"] button:nth-child(2):not([role])'},{click:'div[role="dialog"] div:last-child button:only-child'}]}],test:[{eval:"EVAL_CANVA_0"}]},{name:"canyon.com",runContext:{urlPattern:"^https://www\\.canyon\\.com/"},prehideSelectors:["div.modal.cookiesModal.is-open"],detectCmp:[{exists:"div.modal.cookiesModal.is-open"}],detectPopup:[{visible:"div.modal.cookiesModal.is-open"}],optIn:[{click:'div.cookiesModal__buttonWrapper > button[data-closecause="close-by-submit"]'}],optOut:[{click:'div.cookiesModal__buttonWrapper > button[data-closecause="close-by-manage-cookies"]'},{waitForThenClick:"button#js-manage-data-privacy-save-button"}]},{name:"cc-banner-springer",prehideSelectors:[".cc-banner[data-cc-banner]"],detectCmp:[{exists:".cc-banner[data-cc-banner]"}],detectPopup:[{visible:".cc-banner[data-cc-banner]"}],optIn:[{waitForThenClick:".cc-banner[data-cc-banner] button[data-cc-action=accept]"}],optOut:[{if:{exists:".cc-banner[data-cc-banner] button[data-cc-action=reject]"},then:[{click:".cc-banner[data-cc-banner] button[data-cc-action=reject]"}],else:[{waitForThenClick:".cc-banner[data-cc-banner] button[data-cc-action=preferences]"},{waitFor:".cc-preferences[data-cc-preferences]"},{click:".cc-preferences[data-cc-preferences] input[type=radio][data-cc-action=toggle-category][value=off]",all:!0,optional:!0},{if:{exists:".cc-preferences[data-cc-preferences] button[data-cc-action=reject]"},then:[{click:".cc-preferences[data-cc-preferences] button[data-cc-action=reject]"}],else:[{click:".cc-preferences[data-cc-preferences] button[data-cc-action=save]"}]}]}],test:[{eval:"EVAL_CC_BANNER2_0"}]},{name:"cc_banner",cosmetic:!0,prehideSelectors:[".cc_banner-wrapper"],detectCmp:[{exists:".cc_banner-wrapper"}],detectPopup:[{visible:".cc_banner"}],optIn:[{click:".cc_btn_accept_all"}],optOut:[{hide:".cc_banner-wrapper"}]},{name:"check24-partnerprogramm-de",prehideSelectors:["[data-modal-content]:has([data-toggle-target^='cookie'])"],detectCmp:[{exists:"[data-toggle-target^='cookie']"}],detectPopup:[{visible:"[data-toggle-target^='cookie']",check:"any"}],optIn:[{waitForThenClick:"[data-cookie-accept-all]"}],optOut:[{waitForThenClick:"[data-cookie-dismiss-all]"}]},{name:"ciaopeople.it",prehideSelectors:["#cp-gdpr-choices"],detectCmp:[{exists:"#cp-gdpr-choices"}],detectPopup:[{visible:"#cp-gdpr-choices"}],optIn:[{waitForThenClick:".gdpr-btm__right > button:nth-child(2)"}],optOut:[{waitForThenClick:".gdpr-top-content > button"},{waitFor:".gdpr-top-back"},{waitForThenClick:".gdpr-btm__right > button:nth-child(1)"}],test:[{visible:"#cp-gdpr-choices",check:"none"}]},{vendorUrl:"https://www.civicuk.com/cookie-control/",name:"civic-cookie-control",prehideSelectors:["#ccc-module,#ccc-overlay"],detectCmp:[{exists:"#ccc-module"}],detectPopup:[{visible:"#ccc"},{visible:"#ccc-module"}],optOut:[{click:"#ccc-reject-settings"}],optIn:[{click:"#ccc-recommended-settings"}]},{name:"click.io",prehideSelectors:["#cl-consent"],detectCmp:[{exists:"#cl-consent"}],detectPopup:[{visible:"#cl-consent"}],optIn:[{waitForThenClick:'#cl-consent [data-role="b_agree"]'}],optOut:[{waitFor:'#cl-consent [data-role="b_options"]'},{wait:500},{click:'#cl-consent [data-role="b_options"]'},{waitFor:'.cl-consent-popup.cl-consent-visible [data-role="alloff"]'},{click:'.cl-consent-popup.cl-consent-visible [data-role="alloff"]',all:!0},{click:'[data-role="b_save"]'}],test:[{eval:"EVAL_CLICKIO_0",comment:"TODO: this only checks if we interacted at all"}]},{name:"clinch",intermediate:!1,runContext:{frame:!1,main:!0},prehideSelectors:[".consent-modal[role=dialog]"],detectCmp:[{exists:".consent-modal[role=dialog]"}],detectPopup:[{visible:".consent-modal[role=dialog]"}],optIn:[{click:"#consent_agree"}],optOut:[{if:{exists:"#consent_reject"},then:[{click:"#consent_reject"}],else:[{click:"#manage_cookie_preferences"},{click:"#cookie_consent_preferences input:checked",all:!0,optional:!0},{click:"#consent_save"}]}],test:[{eval:"EVAL_CLINCH_0"}]},{name:"clustrmaps.com",runContext:{urlPattern:"^https://(www\\.)?clustrmaps\\.com/"},cosmetic:!0,prehideSelectors:["#gdpr-cookie-message"],detectCmp:[{exists:"#gdpr-cookie-message"}],detectPopup:[{visible:"#gdpr-cookie-message"}],optIn:[{click:"button#gdpr-cookie-accept"}],optOut:[{hide:"#gdpr-cookie-message"}]},{name:"coinbase",intermediate:!1,runContext:{frame:!0,main:!0,urlPattern:"^https://(www|help)\\.coinbase\\.com"},prehideSelectors:[],detectCmp:[{exists:"div[class^=CookieBannerContent__Container]"}],detectPopup:[{visible:"div[class^=CookieBannerContent__Container]"}],optIn:[{click:"div[class^=CookieBannerContent__CTA] :nth-last-child(1)"}],optOut:[{click:"button[class^=CookieBannerContent__Settings]"},{click:"div[class^=CookiePreferencesModal__CategoryContainer] input:checked",all:!0,optional:!0},{click:"div[class^=CookiePreferencesModal__ButtonContainer] > button"}],test:[{eval:"EVAL_COINBASE_0"}]},{name:"Complianz banner",prehideSelectors:["#cmplz-cookiebanner-container"],detectCmp:[{exists:"#cmplz-cookiebanner-container .cmplz-cookiebanner"}],detectPopup:[{visible:"#cmplz-cookiebanner-container .cmplz-cookiebanner",check:"any"}],optIn:[{waitForThenClick:".cmplz-cookiebanner .cmplz-accept"}],optOut:[{waitForThenClick:".cmplz-cookiebanner .cmplz-deny"}],test:[{eval:"EVAL_COMPLIANZ_BANNER_0"}]},{name:"Complianz categories",prehideSelectors:['.cc-type-categories[aria-describedby="cookieconsent:desc"]'],detectCmp:[{exists:'.cc-type-categories[aria-describedby="cookieconsent:desc"]'}],detectPopup:[{visible:'.cc-type-categories[aria-describedby="cookieconsent:desc"]'}],optIn:[{any:[{click:".cc-accept-all"},{click:".cc-allow-all"},{click:".cc-allow"},{click:".cc-dismiss"}]}],optOut:[{if:{exists:'.cc-type-categories[aria-describedby="cookieconsent:desc"] .cc-dismiss'},then:[{click:".cc-dismiss"}],else:[{click:".cc-type-categories input[type=checkbox]:not([disabled]):checked",all:!0,optional:!0},{click:".cc-save"}]}]},{name:"Complianz notice",prehideSelectors:['.cc-type-info[aria-describedby="cookieconsent:desc"]'],cosmetic:!0,detectCmp:[{exists:'.cc-type-info[aria-describedby="cookieconsent:desc"] .cc-compliance .cc-btn'}],detectPopup:[{visible:'.cc-type-info[aria-describedby="cookieconsent:desc"] .cc-compliance .cc-btn'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{if:{exists:".cc-deny"},then:[{click:".cc-deny"}],else:[{hide:'[aria-describedby="cookieconsent:desc"]'}]}]},{name:"Complianz opt-both",prehideSelectors:['[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'],detectCmp:[{exists:'[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'}],detectPopup:[{visible:'[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{waitForThenClick:".cc-deny"}]},{name:"Complianz opt-out",prehideSelectors:['[aria-describedby="cookieconsent:desc"].cc-type-opt-out'],detectCmp:[{exists:'[aria-describedby="cookieconsent:desc"].cc-type-opt-out'}],detectPopup:[{visible:'[aria-describedby="cookieconsent:desc"].cc-type-opt-out'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{if:{exists:".cc-deny"},then:[{click:".cc-deny"}],else:[{if:{exists:".cmp-pref-link"},then:[{click:".cmp-pref-link"},{waitForThenClick:".cmp-body [id*=rejectAll]"},{waitForThenClick:".cmp-body .cmp-save-btn"}]}]}]},{name:"Complianz optin",prehideSelectors:['.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'],detectCmp:[{exists:'.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'}],detectPopup:[{visible:'.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'}],optIn:[{any:[{click:".cc-accept-all"},{click:".cc-allow"},{click:".cc-dismiss"}]}],optOut:[{if:{visible:".cc-deny"},then:[{click:".cc-deny"}],else:[{if:{visible:".cc-settings"},then:[{waitForThenClick:".cc-settings"},{waitForVisible:".cc-settings-view"},{click:".cc-settings-view input[type=checkbox]:not([disabled]):checked",all:!0,optional:!0},{click:".cc-settings-view .cc-btn-accept-selected"}],else:[{click:".cc-dismiss"}]}]}]},{name:"cookie-law-info",prehideSelectors:["#cookie-law-info-bar"],detectCmp:[{exists:"#cookie-law-info-bar"},{eval:"EVAL_COOKIE_LAW_INFO_DETECT"}],detectPopup:[{visible:"#cookie-law-info-bar"}],optIn:[{click:'[data-cli_action="accept_all"]'}],optOut:[{hide:"#cookie-law-info-bar"},{eval:"EVAL_COOKIE_LAW_INFO_0"}],test:[{eval:"EVAL_COOKIE_LAW_INFO_1"}]},{name:"cookie-manager-popup",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,detectCmp:[{exists:"#notice-cookie-block #allow-functional-cookies, #notice-cookie-block #btn-cookie-settings"}],detectPopup:[{visible:"#notice-cookie-block"}],optIn:[{click:"#btn-cookie-allow"}],optOut:[{if:{exists:"#allow-functional-cookies"},then:[{click:"#allow-functional-cookies"}],else:[{waitForThenClick:"#btn-cookie-settings"},{waitForVisible:".modal-body"},{click:'.modal-body input:checked, .switch[data-switch="on"]',all:!0,optional:!0},{click:'[role="dialog"] .modal-footer button'}]}],prehideSelectors:["#btn-cookie-settings"],test:[{eval:"EVAL_COOKIE_MANAGER_POPUP_0"}]},{name:"cookie-notice",prehideSelectors:["#cookie-notice"],cosmetic:!0,detectCmp:[{visible:"#cookie-notice .cookie-notice-container"}],detectPopup:[{visible:"#cookie-notice"}],optIn:[{click:"#cn-accept-cookie"}],optOut:[{hide:"#cookie-notice"}]},{name:"cookie-script",vendorUrl:"https://cookie-script.com/",prehideSelectors:["#cookiescript_injected"],detectCmp:[{exists:"#cookiescript_injected"}],detectPopup:[{visible:"#cookiescript_injected"}],optOut:[{if:{exists:"#cookiescript_reject"},then:[{wait:100},{click:"#cookiescript_reject"}],else:[{click:"#cookiescript_manage"},{waitForVisible:".cookiescript_fsd_main"},{waitForThenClick:"#cookiescript_reject"}]}],optIn:[{click:"#cookiescript_accept"}]},{name:"cookieacceptbar",vendorUrl:"https://unknown",cosmetic:!0,prehideSelectors:["#cookieAcceptBar.cookieAcceptBar"],detectCmp:[{exists:"#cookieAcceptBar.cookieAcceptBar"}],detectPopup:[{visible:"#cookieAcceptBar.cookieAcceptBar"}],optIn:[{waitForThenClick:"#cookieAcceptBarConfirm"}],optOut:[{hide:"#cookieAcceptBar.cookieAcceptBar"}]},{name:"cookiealert",intermediate:!1,prehideSelectors:[],runContext:{frame:!0,main:!0},detectCmp:[{exists:".cookie-alert-extended"}],detectPopup:[{visible:".cookie-alert-extended-modal"}],optIn:[{click:"button[data-controller='cookie-alert/extended/button/accept']"},{eval:"EVAL_COOKIEALERT_0"}],optOut:[{click:"a[data-controller='cookie-alert/extended/detail-link']"},{click:".cookie-alert-configuration-input:checked",all:!0,optional:!0},{click:"button[data-controller='cookie-alert/extended/button/configuration']"},{eval:"EVAL_COOKIEALERT_0"}],test:[{eval:"EVAL_COOKIEALERT_2"}]},{name:"cookieconsent2",vendorUrl:"https://www.github.com/orestbida/cookieconsent",comment:"supports v2.x.x of the library",prehideSelectors:["#cc--main"],detectCmp:[{exists:"#cc--main"}],detectPopup:[{visible:"#cm"},{exists:"#s-all-bn"}],optIn:[{waitForThenClick:"#s-all-bn"}],optOut:[{waitForThenClick:"#s-rall-bn"}],test:[{eval:"EVAL_COOKIECONSENT2_TEST"}]},{name:"cookieconsent3",vendorUrl:"https://www.github.com/orestbida/cookieconsent",comment:"supports v3.x.x of the library",prehideSelectors:["#cc-main"],detectCmp:[{exists:"#cc-main"}],detectPopup:[{visible:"#cc-main .cm-wrapper"}],optIn:[{waitForThenClick:".cm__btn[data-role=all]"}],optOut:[{waitForThenClick:".cm__btn[data-role=necessary]"}],test:[{eval:"EVAL_COOKIECONSENT3_TEST"}]},{name:"cookiecuttr",vendorUrl:"https://github.com/cdwharton/cookieCuttr",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:""},prehideSelectors:[".cc-cookies"],detectCmp:[{exists:".cc-cookies .cc-cookie-accept"}],detectPopup:[{visible:".cc-cookies .cc-cookie-accept"}],optIn:[{waitForThenClick:".cc-cookies .cc-cookie-accept"}],optOut:[{if:{exists:".cc-cookies .cc-cookie-decline"},then:[{click:".cc-cookies .cc-cookie-decline"}],else:[{hide:".cc-cookies"}]}]},{name:"cookiefirst.com",prehideSelectors:["#cookiefirst-root,.cookiefirst-root,[aria-labelledby=cookie-preference-panel-title]"],detectCmp:[{exists:"#cookiefirst-root,.cookiefirst-root"}],detectPopup:[{visible:"#cookiefirst-root,.cookiefirst-root"}],optIn:[{click:"button[data-cookiefirst-action=accept]"}],optOut:[{if:{exists:"button[data-cookiefirst-action=adjust]"},then:[{click:"button[data-cookiefirst-action=adjust]"},{waitForVisible:"[data-cookiefirst-widget=modal]",timeout:1e3},{eval:"EVAL_COOKIEFIRST_1"},{wait:1e3},{click:"button[data-cookiefirst-action=save]"}],else:[{click:"button[data-cookiefirst-action=reject]"}]}],test:[{eval:"EVAL_COOKIEFIRST_0"}]},{name:"Cookie Information Banner",prehideSelectors:["#cookie-information-template-wrapper"],detectCmp:[{exists:"#cookie-information-template-wrapper"}],detectPopup:[{visible:"#cookie-information-template-wrapper"}],optIn:[{eval:"EVAL_COOKIEINFORMATION_1"}],optOut:[{hide:"#cookie-information-template-wrapper",comment:"some templates don't hide the banner automatically"},{eval:"EVAL_COOKIEINFORMATION_0"}],test:[{eval:"EVAL_COOKIEINFORMATION_2"}]},{name:"cookieyes",prehideSelectors:[".cky-overlay,.cky-consent-container"],detectCmp:[{exists:".cky-consent-container"}],detectPopup:[{visible:".cky-consent-container"}],optIn:[{waitForThenClick:".cky-consent-container [data-cky-tag=accept-button]"}],optOut:[{if:{exists:".cky-consent-container [data-cky-tag=reject-button]"},then:[{waitForThenClick:".cky-consent-container [data-cky-tag=reject-button]"}],else:[{if:{exists:".cky-consent-container [data-cky-tag=settings-button]"},then:[{click:".cky-consent-container [data-cky-tag=settings-button]"},{waitFor:".cky-modal-open input[type=checkbox]"},{click:".cky-modal-open input[type=checkbox]:checked",all:!0,optional:!0},{waitForThenClick:".cky-modal [data-cky-tag=detail-save-button]"}],else:[{hide:".cky-consent-container,.cky-overlay"}]}]}],test:[{eval:"EVAL_COOKIEYES_0"}]},{name:"corona-in-zahlen.de",prehideSelectors:[".cookiealert"],detectCmp:[{exists:".cookiealert"}],detectPopup:[{visible:".cookiealert"}],optOut:[{click:".configurecookies"},{click:".confirmcookies"}],optIn:[{click:".acceptcookies"}]},{name:"crossfit-com",cosmetic:!0,prehideSelectors:['body #modal > div > div[class^="_wrapper_"]'],detectCmp:[{exists:'body #modal > div > div[class^="_wrapper_"]'}],detectPopup:[{visible:'body #modal > div > div[class^="_wrapper_"]'}],optIn:[{click:'button[aria-label="accept cookie policy"]'}],optOut:[{hide:'body #modal > div > div[class^="_wrapper_"]'}]},{name:"csu-landtag-de",runContext:{urlPattern:"^https://(www\\.|)?csu-landtag\\.de"},prehideSelectors:["#cookie-disclaimer"],detectCmp:[{exists:"#cookie-disclaimer"}],detectPopup:[{visible:"#cookie-disclaimer"}],optIn:[{click:"#cookieall"}],optOut:[{click:"#cookiesel"}]},{name:"dailymotion-us",cosmetic:!0,prehideSelectors:['div[class*="CookiePopup__desktopContainer"]:has(div[class*="CookiePopup"])'],detectCmp:[{exists:'div[class*="CookiePopup__desktopContainer"]'}],detectPopup:[{visible:'div[class*="CookiePopup__desktopContainer"]'}],optIn:[{click:'div[class*="CookiePopup__desktopContainer"] > button > span'}],optOut:[{hide:'div[class*="CookiePopup__desktopContainer"]'}]},{name:"dailymotion.com",runContext:{urlPattern:"^https://(www\\.)?dailymotion\\.com/"},prehideSelectors:['div[class*="Overlay__container"]:has(div[class*="TCF2Popup"])'],detectCmp:[{exists:'div[class*="TCF2Popup"]'}],detectPopup:[{visible:'[class*="TCF2Popup"] a[href^="https://www.dailymotion.com/legal/cookiemanagement"]'}],optIn:[{waitForThenClick:'button[class*="TCF2Popup__button"]:not([class*="TCF2Popup__personalize"])'}],optOut:[{waitForThenClick:'button[class*="TCF2ContinueWithoutAcceptingButton"]'}],test:[{eval:"EVAL_DAILYMOTION_0"}]},{name:"dan-com",vendorUrl:"https://unknown",runContext:{main:!0,frame:!1},prehideSelectors:[],detectCmp:[{exists:".cookie-banner.show .cookie-banner__content-all-btn"}],detectPopup:[{visible:".cookie-banner.show .cookie-banner__content-all-btn"}],optIn:[{waitForThenClick:".cookie-banner__content-all-btn"}],optOut:[{waitForThenClick:".cookie-banner__content-essential-btn"}]},{name:"deepl.com",prehideSelectors:[".dl_cookieBanner_container"],detectCmp:[{exists:".dl_cookieBanner_container"}],detectPopup:[{visible:".dl_cookieBanner_container"}],optOut:[{click:".dl_cookieBanner--buttonSelected"}],optIn:[{click:".dl_cookieBanner--buttonAll"}]},{name:"delta.com",runContext:{urlPattern:"^https://www\\.delta\\.com/"},cosmetic:!0,prehideSelectors:["ngc-cookie-banner"],detectCmp:[{exists:"div.cookie-footer-container"}],detectPopup:[{visible:"div.cookie-footer-container"}],optIn:[{click:" button.cookie-close-icon"}],optOut:[{hide:"div.cookie-footer-container"}]},{name:"dmgmedia-us",prehideSelectors:["#mol-ads-cmp-iframe, div.mol-ads-cmp > form > div"],detectCmp:[{exists:"div.mol-ads-cmp > form > div"}],detectPopup:[{waitForVisible:"div.mol-ads-cmp > form > div"}],optIn:[{waitForThenClick:"button.mol-ads-cmp--btn-primary"}],optOut:[{waitForThenClick:"div.mol-ads-ccpa--message > u > a"},{waitForVisible:".mol-ads-cmp--modal-dialog"},{waitForThenClick:"a.mol-ads-cmp-footer-privacy"},{waitForThenClick:"button.mol-ads-cmp--btn-secondary"}]},{name:"dmgmedia",prehideSelectors:['[data-project="mol-fe-cmp"]'],detectCmp:[{exists:'[data-project="mol-fe-cmp"] [class*=footer]'}],detectPopup:[{visible:'[data-project="mol-fe-cmp"] [class*=footer]'}],optIn:[{waitForThenClick:'[data-project="mol-fe-cmp"] button[class*=primary]'}],optOut:[{waitForThenClick:'[data-project="mol-fe-cmp"] button[class*=basic]'},{waitForVisible:'[data-project="mol-fe-cmp"] div[class*="tabContent"]'},{waitForThenClick:'[data-project="mol-fe-cmp"] div[class*="toggle"][class*="enabled"]',all:!0},{waitForThenClick:['[data-project="mol-fe-cmp"] [class*=footer]',"xpath///button[contains(., 'Save & Exit')]"]}]},{name:"dndbeyond",vendorUrl:"https://www.dndbeyond.com/",runContext:{urlPattern:"^https://(www\\.)?dndbeyond\\.com/"},prehideSelectors:["[id^=cookie-consent-banner]"],detectCmp:[{exists:"[id^=cookie-consent-banner]"}],detectPopup:[{visible:"[id^=cookie-consent-banner]"}],optIn:[{waitForThenClick:"#cookie-consent-granted"}],optOut:[{waitForThenClick:"#cookie-consent-denied"}],test:[{eval:"EVAL_DNDBEYOND_TEST"}]},{name:"dpgmedia-nl",prehideSelectors:["#pg-shadow-root-host"],detectCmp:[{exists:"#pg-shadow-root-host"}],detectPopup:[{visible:["#pg-shadow-root-host","#pg-modal"]}],optIn:[{waitForThenClick:["#pg-shadow-root-host","#pg-accept-btn"]}],optOut:[{waitForThenClick:["#pg-shadow-root-host","#pg-configure-btn"]},{waitForThenClick:["#pg-shadow-root-host","#pg-reject-btn"]}]},{name:"Drupal",detectCmp:[{exists:"#drupalorg-crosssite-gdpr"}],detectPopup:[{visible:"#drupalorg-crosssite-gdpr"}],optOut:[{click:".no"}],optIn:[{click:".yes"}]},{name:"WP DSGVO Tools",link:"https://wordpress.org/plugins/shapepress-dsgvo/",prehideSelectors:[".sp-dsgvo"],cosmetic:!0,detectCmp:[{exists:".sp-dsgvo.sp-dsgvo-popup-overlay"}],detectPopup:[{visible:".sp-dsgvo.sp-dsgvo-popup-overlay",check:"any"}],optIn:[{click:".sp-dsgvo-privacy-btn-accept-all",all:!0}],optOut:[{hide:".sp-dsgvo.sp-dsgvo-popup-overlay"}],test:[{eval:"EVAL_DSGVO_0"}]},{name:"dunelm.com",prehideSelectors:["div[data-testid=cookie-consent-modal-backdrop]"],detectCmp:[{exists:"div[data-testid=cookie-consent-message-contents]"}],detectPopup:[{visible:"div[data-testid=cookie-consent-message-contents]"}],optIn:[{click:'[data-testid="cookie-consent-allow-all"]'}],optOut:[{click:"button[data-testid=cookie-consent-adjust-settings]"},{click:"button[data-testid=cookie-consent-preferences-save]"}],test:[{eval:"EVAL_DUNELM_0"}]},{name:"ebay",vendorUrl:"https://ebay.com",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?ebay\\.([.a-z]+)/"},prehideSelectors:["#gdpr-banner"],detectCmp:[{exists:"#gdpr-banner"}],detectPopup:[{visible:"#gdpr-banner"}],optIn:[{waitForThenClick:"#gdpr-banner-accept"}],optOut:[{waitForThenClick:"#gdpr-banner-decline"}]},{name:"ecosia",vendorUrl:"https://www.ecosia.org/",runContext:{urlPattern:"^https://www\\.ecosia\\.org/"},prehideSelectors:[".cookie-wrapper"],detectCmp:[{exists:".cookie-wrapper > .cookie-notice"}],detectPopup:[{visible:".cookie-wrapper > .cookie-notice"}],optIn:[{waitForThenClick:"[data-test-id=cookie-notice-accept]"}],optOut:[{waitForThenClick:"[data-test-id=cookie-notice-reject]"}]},{name:"Ensighten ensModal",prehideSelectors:[".ensModal"],detectCmp:[{exists:".ensModal"}],detectPopup:[{visible:"#ensModalWrapper[style*=block]"}],optIn:[{waitForThenClick:"#modalAcceptButton"}],optOut:[{wait:500},{visible:"#ensModalWrapper[style*=block]"},{waitForThenClick:".ensCheckbox:checked",all:!0},{waitForThenClick:"#ensSave"}]},{name:"Ensighten ensNotifyBanner",prehideSelectors:["#ensNotifyBanner"],detectCmp:[{exists:"#ensNotifyBanner"}],detectPopup:[{visible:"#ensNotifyBanner[style*=block]"}],optIn:[{waitForThenClick:"#ensCloseBanner"}],optOut:[{wait:500},{visible:"#ensNotifyBanner[style*=block]"},{waitForThenClick:"#ensRejectAll,#rejectAll,#ensRejectBanner,.rejectAll,#ensCloseBanner",timeout:2e3}]},{name:"espace-personnel.agirc-arrco.fr",runContext:{urlPattern:"^https://espace-personnel\\.agirc-arrco\\.fr/"},prehideSelectors:[".cdk-overlay-container"],detectCmp:[{exists:".cdk-overlay-container app-esaa-cookie-component"}],detectPopup:[{visible:".cdk-overlay-container app-esaa-cookie-component"}],optIn:[{waitForThenClick:".btn-cookie-accepter"}],optOut:[{waitForThenClick:".btn-cookie-refuser"}]},{name:"etsy",prehideSelectors:["#gdpr-single-choice-overlay","#gdpr-privacy-settings"],detectCmp:[{exists:"#gdpr-single-choice-overlay"}],detectPopup:[{visible:"#gdpr-single-choice-overlay"}],optOut:[{click:"button[data-gdpr-open-full-settings]"},{waitForVisible:".gdpr-overlay-body input",timeout:3e3},{wait:1e3},{eval:"EVAL_ETSY_0"},{eval:"EVAL_ETSY_1"}],optIn:[{click:"button[data-gdpr-single-choice-accept]"}]},{name:"eu-cookie-compliance-banner",detectCmp:[{exists:"body.eu-cookie-compliance-popup-open"}],detectPopup:[{exists:"body.eu-cookie-compliance-popup-open"}],optIn:[{click:".agree-button"}],optOut:[{if:{visible:".decline-button,.eu-cookie-compliance-save-preferences-button"},then:[{click:".decline-button,.eu-cookie-compliance-save-preferences-button"}]},{hide:".eu-cookie-compliance-banner-info, #sliding-popup"}],test:[{eval:"EVAL_EU_COOKIE_COMPLIANCE_0"}]},{name:"EU Cookie Law",prehideSelectors:[".pea_cook_wrapper,.pea_cook_more_info_popover"],cosmetic:!0,detectCmp:[{exists:".pea_cook_wrapper"}],detectPopup:[{wait:500},{visible:".pea_cook_wrapper"}],optIn:[{click:"#pea_cook_btn"}],optOut:[{hide:".pea_cook_wrapper"}],test:[{eval:"EVAL_EU_COOKIE_LAW_0"}]},{name:"europa-eu",vendorUrl:"https://ec.europa.eu/",runContext:{urlPattern:"^https://[^/]*europa\\.eu/"},prehideSelectors:["#cookie-consent-banner"],detectCmp:[{exists:".cck-container"}],detectPopup:[{visible:".cck-container"}],optIn:[{waitForThenClick:'.cck-actions-button[href="#accept"]'}],optOut:[{waitForThenClick:'.cck-actions-button[href="#refuse"]',hide:".cck-container"}]},{name:"EZoic",prehideSelectors:["#ez-cookie-dialog-wrapper"],detectCmp:[{exists:"#ez-cookie-dialog-wrapper"}],detectPopup:[{visible:"#ez-cookie-dialog-wrapper"}],optIn:[{click:"#ez-accept-all",optional:!0},{eval:"EVAL_EZOIC_0",optional:!0}],optOut:[{wait:500},{click:"#ez-manage-settings"},{waitFor:"#ez-cookie-dialog input[type=checkbox]"},{click:"#ez-cookie-dialog input[type=checkbox]:checked",all:!0},{click:"#ez-save-settings"}],test:[{eval:"EVAL_EZOIC_1"}]},{name:"facebook",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?facebook\\.com/"},prehideSelectors:['div[data-testid="cookie-policy-manage-dialog"]'],detectCmp:[{exists:'div[data-testid="cookie-policy-manage-dialog"]'}],detectPopup:[{visible:'div[data-testid="cookie-policy-manage-dialog"]'}],optIn:[{waitForThenClick:'button[data-cookiebanner="accept_button"]'},{waitForVisible:'div[data-testid="cookie-policy-manage-dialog"]',check:"none"}],optOut:[{waitForThenClick:'button[data-cookiebanner="accept_only_essential_button"]'},{waitForVisible:'div[data-testid="cookie-policy-manage-dialog"]',check:"none"}]},{name:"fides",vendorUrl:"https://github.com/ethyca/fides",prehideSelectors:["#fides-overlay"],detectCmp:[{exists:"#fides-overlay #fides-banner"}],detectPopup:[{visible:"#fides-overlay #fides-banner"},{eval:"EVAL_FIDES_DETECT_POPUP"}],optIn:[{waitForThenClick:"#fides-banner .fides-accept-all-button"}],optOut:[{waitForThenClick:"#fides-banner .fides-reject-all-button"}]},{name:"funding-choices",prehideSelectors:[".fc-consent-root,.fc-dialog-container,.fc-dialog-overlay,.fc-dialog-content"],detectCmp:[{exists:".fc-consent-root"}],detectPopup:[{exists:".fc-dialog-container"}],optOut:[{click:".fc-cta-do-not-consent,.fc-cta-manage-options"},{click:".fc-preference-consent:checked,.fc-preference-legitimate-interest:checked",all:!0,optional:!0},{click:".fc-confirm-choices",optional:!0}],optIn:[{click:".fc-cta-consent"}]},{name:"geeks-for-geeks",runContext:{urlPattern:"^https://www\\.geeksforgeeks\\.org/"},cosmetic:!0,prehideSelectors:[".cookie-consent"],detectCmp:[{exists:".cookie-consent"}],detectPopup:[{visible:".cookie-consent"}],optIn:[{click:".cookie-consent button.consent-btn"}],optOut:[{hide:".cookie-consent"}]},{name:"google-consent-standalone",prehideSelectors:[],detectCmp:[{exists:'a[href^="https://policies.google.com/technologies/cookies"'},{exists:'form[action^="https://consent.google."][action$="/save"]'}],detectPopup:[{visible:'a[href^="https://policies.google.com/technologies/cookies"'}],optIn:[{waitForThenClick:'form[action^="https://consent.google."][action$="/save"]:has(input[name=set_eom][value=false]) button'}],optOut:[{waitForThenClick:'form[action^="https://consent.google."][action$="/save"]:has(input[name=set_eom][value=true]) button'}]},{name:"google-cookiebar",vendorUrl:"https://www.android.com/better-together/quick-share-app/",cosmetic:!1,prehideSelectors:[".glue-cookie-notification-bar"],detectCmp:[{exists:".glue-cookie-notification-bar"}],detectPopup:[{visible:".glue-cookie-notification-bar"}],optIn:[{waitForThenClick:".glue-cookie-notification-bar__accept"}],optOut:[{if:{exists:".glue-cookie-notification-bar__reject"},then:[{click:".glue-cookie-notification-bar__reject"}],else:[{hide:".glue-cookie-notification-bar"}]}],test:[]},{name:"google.com",prehideSelectors:[".HTjtHe#xe7COe"],detectCmp:[{exists:".HTjtHe#xe7COe"},{exists:'.HTjtHe#xe7COe a[href^="https://policies.google.com/technologies/cookies"]'}],detectPopup:[{visible:".HTjtHe#xe7COe button#W0wltc"}],optIn:[{waitForThenClick:".HTjtHe#xe7COe button#L2AGLb"}],optOut:[{waitForThenClick:".HTjtHe#xe7COe button#W0wltc"}],test:[{eval:"EVAL_GOOGLE_0"}]},{name:"gov.uk",detectCmp:[{exists:"#global-cookie-message"}],detectPopup:[{exists:"#global-cookie-message"}],optIn:[{click:"button[data-accept-cookies=true]"}],optOut:[{click:"button[data-reject-cookies=true],#reject-cookies"},{click:"button[data-hide-cookie-banner=true],#hide-cookie-decision"}]},{name:"hashicorp",vendorUrl:"https://hashicorp.com/",runContext:{urlPattern:"^https://[^.]*\\.hashicorp\\.com/"},prehideSelectors:["[data-testid=consent-banner]"],detectCmp:[{exists:"[data-testid=consent-banner]"}],detectPopup:[{visible:"[data-testid=consent-banner]"}],optIn:[{waitForThenClick:"[data-testid=accept]"}],optOut:[{waitForThenClick:"[data-testid=manage-preferences]"},{waitForThenClick:"[data-testid=consent-mgr-dialog] [data-ga-button=save-preferences]"}]},{name:"healthline-media",prehideSelectors:["#modal-host > div.no-hash > div.window-wrapper"],detectCmp:[{exists:"#modal-host > div.no-hash > div.window-wrapper, div[data-testid=qualtrics-container]"}],detectPopup:[{exists:"#modal-host > div.no-hash > div.window-wrapper, div[data-testid=qualtrics-container]"}],optIn:[{click:"#modal-host > div.no-hash > div.window-wrapper > div:last-child button"}],optOut:[{if:{exists:'#modal-host > div.no-hash > div.window-wrapper > div:last-child a[href="/privacy-settings"]'},then:[{click:'#modal-host > div.no-hash > div.window-wrapper > div:last-child a[href="/privacy-settings"]'}],else:[{waitForVisible:"div#__next"},{click:"#__next div:nth-child(1) > button:first-child"}]}]},{name:"hema",prehideSelectors:[".cookie-modal"],detectCmp:[{visible:".cookie-modal .cookie-accept-btn"}],detectPopup:[{visible:".cookie-modal .cookie-accept-btn"}],optIn:[{waitForThenClick:".cookie-modal .cookie-accept-btn"}],optOut:[{waitForThenClick:".cookie-modal .js-cookie-reject-btn"}],test:[{eval:"EVAL_HEMA_TEST_0"}]},{name:"hetzner.com",runContext:{urlPattern:"^https://www\\.hetzner\\.com/"},prehideSelectors:["#CookieConsent"],detectCmp:[{exists:"#CookieConsent"}],detectPopup:[{visible:"#CookieConsent"}],optIn:[{click:"#CookieConsentGiven"}],optOut:[{click:"#CookieConsentDeclined"}]},{name:"hl.co.uk",prehideSelectors:[".cookieModalContent","#cookie-banner-overlay"],detectCmp:[{exists:"#cookie-banner-overlay"}],detectPopup:[{exists:"#cookie-banner-overlay"}],optIn:[{click:"#acceptCookieButton"}],optOut:[{click:"#manageCookie"},{hide:".cookieSettingsModal"},{waitFor:"#AOCookieToggle"},{click:"#AOCookieToggle[aria-pressed=true]",optional:!0},{waitFor:"#TPCookieToggle"},{click:"#TPCookieToggle[aria-pressed=true]",optional:!0},{click:"#updateCookieButton"}]},{name:"holidaymedia",vendorUrl:"https://holidaymedia.nl/",prehideSelectors:["dialog[data-cookie-consent]"],detectCmp:[{exists:"dialog[data-cookie-consent]"}],detectPopup:[{visible:"dialog[data-cookie-consent]"}],optIn:[{waitForThenClick:"button.cookie-consent__button--accept-all"}],optOut:[{waitForThenClick:'a[data-cookie-accept="functional"]',timeout:2e3}]},{name:"hu-manity",vendorUrl:"https://hu-manity.co/",prehideSelectors:["#hu.hu-wrapper"],detectCmp:[{exists:"#hu.hu-visible"}],detectPopup:[{visible:"#hu.hu-visible"}],optIn:[{waitForThenClick:"[data-hu-action=cookies-notice-consent-choices-3]"},{waitForThenClick:"#hu-cookies-save"}],optOut:[{waitForThenClick:"#hu-cookies-save"}]},{name:"hubspot",detectCmp:[{exists:"#hs-eu-cookie-confirmation"}],detectPopup:[{visible:"#hs-eu-cookie-confirmation"}],optIn:[{click:"#hs-eu-confirmation-button"}],optOut:[{click:"#hs-eu-decline-button"}]},{name:"indeed.com",cosmetic:!0,prehideSelectors:["#CookiePrivacyNotice"],detectCmp:[{exists:"#CookiePrivacyNotice"}],detectPopup:[{visible:"#CookiePrivacyNotice"}],optIn:[{click:"#CookiePrivacyNotice button[data-gnav-element-name=CookiePrivacyNoticeOk]"}],optOut:[{hide:"#CookiePrivacyNotice"}]},{name:"ing.de",runContext:{urlPattern:"^https://www\\.ing\\.de/"},cosmetic:!0,prehideSelectors:['div[slot="backdrop"]'],detectCmp:[{exists:'[data-tag-name="ing-cc-dialog-frame"]'}],detectPopup:[{visible:'[data-tag-name="ing-cc-dialog-frame"]'}],optIn:[{click:['[data-tag-name="ing-cc-dialog-level0"]','[data-tag-name="ing-cc-button"][class*="accept"]']}],optOut:[{click:['[data-tag-name="ing-cc-dialog-level0"]','[data-tag-name="ing-cc-button"][class*="more"]']}]},{name:"instagram",vendorUrl:"https://instagram.com",runContext:{urlPattern:"^https://www\\.instagram\\.com/"},prehideSelectors:[],detectCmp:[{exists:'xpath///span[contains(., "Vill du tillåta användningen av cookies från Instagram i den här webbläsaren?") or contains(., "Allow the use of cookies from Instagram on this browser?") or contains(., "Povolit v prohlížeči použití souborů cookie z Instagramu?") or contains(., "Dopustiti upotrebu kolačića s Instagrama na ovom pregledniku?") or contains(., "Разрешить использование файлов cookie от Instagram в этом браузере?") or contains(., "Vuoi consentire l\'uso dei cookie di Instagram su questo browser?") or contains(., "Povoliť používanie cookies zo služby Instagram v tomto prehliadači?") or contains(., "Die Verwendung von Cookies durch Instagram in diesem Browser erlauben?") or contains(., "Sallitaanko Instagramin evästeiden käyttö tällä selaimella?") or contains(., "Engedélyezed az Instagram cookie-jainak használatát ebben a böngészőben?") or contains(., "Het gebruik van cookies van Instagram toestaan in deze browser?") or contains(., "Bu tarayıcıda Instagram\'dan çerez kullanımına izin verilsin mi?") or contains(., "Permitir o uso de cookies do Instagram neste navegador?") or contains(., "Permiţi folosirea modulelor cookie de la Instagram în acest browser?") or contains(., "Autoriser l’utilisation des cookies d’Instagram sur ce navigateur ?") or contains(., "¿Permitir el uso de cookies de Instagram en este navegador?") or contains(., "Zezwolić na użycie plików cookie z Instagramu w tej przeglądarce?") or contains(., "Να επιτρέπεται η χρήση cookies από τo Instagram σε αυτό το πρόγραμμα περιήγησης;") or contains(., "Разрешавате ли използването на бисквитки от Instagram на този браузър?") or contains(., "Vil du tillade brugen af cookies fra Instagram i denne browser?") or contains(., "Vil du tillate bruk av informasjonskapsler fra Instagram i denne nettleseren?")]'}],detectPopup:[{visible:'xpath///span[contains(., "Vill du tillåta användningen av cookies från Instagram i den här webbläsaren?") or contains(., "Allow the use of cookies from Instagram on this browser?") or contains(., "Povolit v prohlížeči použití souborů cookie z Instagramu?") or contains(., "Dopustiti upotrebu kolačića s Instagrama na ovom pregledniku?") or contains(., "Разрешить использование файлов cookie от Instagram в этом браузере?") or contains(., "Vuoi consentire l\'uso dei cookie di Instagram su questo browser?") or contains(., "Povoliť používanie cookies zo služby Instagram v tomto prehliadači?") or contains(., "Die Verwendung von Cookies durch Instagram in diesem Browser erlauben?") or contains(., "Sallitaanko Instagramin evästeiden käyttö tällä selaimella?") or contains(., "Engedélyezed az Instagram cookie-jainak használatát ebben a böngészőben?") or contains(., "Het gebruik van cookies van Instagram toestaan in deze browser?") or contains(., "Bu tarayıcıda Instagram\'dan çerez kullanımına izin verilsin mi?") or contains(., "Permitir o uso de cookies do Instagram neste navegador?") or contains(., "Permiţi folosirea modulelor cookie de la Instagram în acest browser?") or contains(., "Autoriser l’utilisation des cookies d’Instagram sur ce navigateur ?") or contains(., "¿Permitir el uso de cookies de Instagram en este navegador?") or contains(., "Zezwolić na użycie plików cookie z Instagramu w tej przeglądarce?") or contains(., "Να επιτρέπεται η χρήση cookies από τo Instagram σε αυτό το πρόγραμμα περιήγησης;") or contains(., "Разрешавате ли използването на бисквитки от Instagram на този браузър?") or contains(., "Vil du tillade brugen af cookies fra Instagram i denne browser?") or contains(., "Vil du tillate bruk av informasjonskapsler fra Instagram i denne nettleseren?")]'}],optIn:[{waitForThenClick:"xpath///button[contains(., 'Tillad alle cookies') or contains(., 'Alle Cookies erlauben') or contains(., 'Allow all cookies') or contains(., 'Разрешаване на всички бисквитки') or contains(., 'Tillåt alla cookies') or contains(., 'Povolit všechny soubory cookie') or contains(., 'Tüm çerezlere izin ver') or contains(., 'Permite toate modulele cookie') or contains(., 'Να επιτρέπονται όλα τα cookies') or contains(., 'Tillat alle informasjonskapsler') or contains(., 'Povoliť všetky cookies') or contains(., 'Permitir todas las cookies') or contains(., 'Permitir todos os cookies') or contains(., 'Alle cookies toestaan') or contains(., 'Salli kaikki evästeet') or contains(., 'Consenti tutti i cookie') or contains(., 'Az összes cookie engedélyezése') or contains(., 'Autoriser tous les cookies') or contains(., 'Zezwól na wszystkie pliki cookie') or contains(., 'Разрешить все cookie') or contains(., 'Dopusti sve kolačiće')]"}],optOut:[{waitForThenClick:"xpath///button[contains(., 'Отклонить необязательные файлы cookie') or contains(., 'Decline optional cookies') or contains(., 'Refuser les cookies optionnels') or contains(., 'Hylkää valinnaiset evästeet') or contains(., 'Afvis valgfrie cookies') or contains(., 'Odmietnuť nepovinné cookies') or contains(., 'Απόρριψη προαιρετικών cookies') or contains(., 'Neka valfria cookies') or contains(., 'Optionale Cookies ablehnen') or contains(., 'Rifiuta cookie facoltativi') or contains(., 'Odbij neobavezne kolačiće') or contains(., 'Avvis valgfrie informasjonskapsler') or contains(., 'İsteğe bağlı çerezleri reddet') or contains(., 'Recusar cookies opcionais') or contains(., 'Optionele cookies afwijzen') or contains(., 'Rechazar cookies opcionales') or contains(., 'Odrzuć opcjonalne pliki cookie') or contains(., 'Отхвърляне на бисквитките по избор') or contains(., 'Odmítnout volitelné soubory cookie') or contains(., 'Refuză modulele cookie opţionale') or contains(., 'A nem kötelező cookie-k elutasítása')]"},{wait:2e3}]},{name:"ionos.de",prehideSelectors:[".privacy-consent--backdrop",".privacy-consent--modal"],detectCmp:[{exists:".privacy-consent--modal"}],detectPopup:[{visible:".privacy-consent--modal"}],optIn:[{click:"#selectAll"}],optOut:[{click:".footer-config-link"},{click:"#confirmSelection"}]},{name:"itopvpn.com",cosmetic:!0,prehideSelectors:[".pop-cookie"],detectCmp:[{exists:".pop-cookie"}],detectPopup:[{exists:".pop-cookie"}],optIn:[{click:"#_pcookie"}],optOut:[{hide:".pop-cookie"}]},{name:"iubenda",prehideSelectors:["#iubenda-cs-banner"],detectCmp:[{exists:"#iubenda-cs-banner"}],detectPopup:[{visible:".iubenda-cs-accept-btn"}],optIn:[{waitForThenClick:".iubenda-cs-accept-btn"}],optOut:[{waitForThenClick:".iubenda-cs-customize-btn"},{eval:"EVAL_IUBENDA_0"},{waitForThenClick:"#iubFooterBtn"}],test:[{eval:"EVAL_IUBENDA_1"}]},{name:"iWink",prehideSelectors:["body.cookies-request #cookie-bar"],detectCmp:[{exists:"body.cookies-request #cookie-bar"}],detectPopup:[{visible:"body.cookies-request #cookie-bar"}],optIn:[{waitForThenClick:"body.cookies-request #cookie-bar .allow-cookies"}],optOut:[{waitForThenClick:"body.cookies-request #cookie-bar .disallow-cookies"}],test:[{eval:"EVAL_IWINK_TEST"}]},{name:"jdsports",vendorUrl:"https://www.jdsports.co.uk/",runContext:{urlPattern:"^https://(www|m)\\.jdsports\\."},prehideSelectors:[".miniConsent,#PrivacyPolicyBanner"],detectCmp:[{exists:".miniConsent,#PrivacyPolicyBanner"}],detectPopup:[{visible:".miniConsent,#PrivacyPolicyBanner"}],optIn:[{waitForThenClick:".miniConsent .accept-all-cookies"}],optOut:[{if:{exists:"#PrivacyPolicyBanner"},then:[{hide:"#PrivacyPolicyBanner"}],else:[{waitForThenClick:"#cookie-settings"},{waitForThenClick:"#reject-all-cookies"}]}]},{name:"johnlewis.com",prehideSelectors:["div[class^=pecr-cookie-banner-]"],detectCmp:[{exists:"div[class^=pecr-cookie-banner-]"}],detectPopup:[{exists:"div[class^=pecr-cookie-banner-]"}],optOut:[{click:"button[data-test^=manage-cookies]"},{wait:"500"},{click:"label[data-test^=toggle][class*=checked]:not([class*=disabled])",all:!0,optional:!0},{click:"button[data-test=save-preferences]"}],optIn:[{click:"button[data-test=allow-all]"}]},{name:"jquery.cookieBar",vendorUrl:"https://github.com/kovarp/jquery.cookieBar",prehideSelectors:[".cookie-bar"],cosmetic:!0,detectCmp:[{exists:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons"}],detectPopup:[{visible:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons",check:"any"}],optIn:[{click:".cookie-bar .cookie-bar__btn"}],optOut:[{hide:".cookie-bar"}],test:[{visible:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons",check:"none"},{eval:"EVAL_JQUERY_COOKIEBAR_0"}]},{name:"justwatch.com",prehideSelectors:[".consent-banner"],detectCmp:[{exists:".consent-banner .consent-banner__actions"}],detectPopup:[{visible:".consent-banner .consent-banner__actions"}],optIn:[{click:".consent-banner__actions button.basic-button.primary"}],optOut:[{click:".consent-banner__actions button.basic-button.secondary"},{waitForThenClick:".consent-modal__footer button.basic-button.secondary"},{waitForThenClick:".consent-modal ion-content > div > a:nth-child(9)"},{click:"label.consent-switch input[type=checkbox]:checked",all:!0,optional:!0},{waitForVisible:".consent-modal__footer button.basic-button.primary"},{click:".consent-modal__footer button.basic-button.primary"}]},{name:"ketch",vendorUrl:"https://www.ketch.com",runContext:{frame:!1,main:!0},intermediate:!1,prehideSelectors:["#lanyard_root div[role='dialog']"],detectCmp:[{exists:"#lanyard_root div[role='dialog']"}],detectPopup:[{visible:"#lanyard_root div[role='dialog']"}],optIn:[{if:{exists:"#lanyard_root button[class='confirmButton']"},then:[{waitForThenClick:"#lanyard_root div[class*=buttons] > :nth-child(2)"},{click:"#lanyard_root button[class='confirmButton']"}],else:[{waitForThenClick:"#lanyard_root div[class*=buttons] > :nth-child(2)"}]}],optOut:[{if:{exists:"#lanyard_root [aria-describedby=banner-description]"},then:[{waitForThenClick:"#lanyard_root div[class*=buttons] > button[class*=secondaryButton], #lanyard_root button[class*=buttons-secondary]",comment:"can be either settings or reject button"}]},{waitFor:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description], #ketch-preferences",timeout:1e3,optional:!0},{if:{exists:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description], #ketch-preferences"},then:[{waitForThenClick:"#lanyard_root button[class*=rejectButton], #lanyard_root button[class*=rejectAllButton]"},{click:"#lanyard_root button[class*=confirmButton],#lanyard_root div[class*=actions_] > button:nth-child(1), #lanyard_root button[class*=actionButton]"}]}],test:[{eval:"EVAL_KETCH_TEST"}]},{name:"kleinanzeigen-de",runContext:{urlPattern:"^https?://(www\\.)?kleinanzeigen\\.de"},prehideSelectors:["#gdpr-banner-container"],detectCmp:[{any:[{exists:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"},{exists:"#ConsentManagementPage"}]}],detectPopup:[{any:[{visible:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"},{visible:"#ConsentManagementPage"}]}],optIn:[{if:{exists:"#gdpr-banner-container #gdpr-banner"},then:[{click:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-accept]"}],else:[{click:"#ConsentManagementPage .Button-primary"}]}],optOut:[{if:{exists:"#gdpr-banner-container #gdpr-banner"},then:[{click:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"}],else:[{click:"#ConsentManagementPage .Button-secondary"}]}]},{name:"lightbox",prehideSelectors:[".darken-layer.open,.lightbox.lightbox--cookie-consent"],detectCmp:[{exists:"body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"}],detectPopup:[{visible:"body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"}],optOut:[{click:".cookie-consent__footer > button[type='submit']:not([data-button='selectAll'])"}],optIn:[{click:".cookie-consent__footer > button[type='submit'][data-button='selectAll']"}]},{name:"lineagrafica",vendorUrl:"https://addons.prestashop.com/en/legal/8734-eu-cookie-law-gdpr-banner-blocker.html",cosmetic:!0,prehideSelectors:["#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"],detectCmp:[{exists:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}],detectPopup:[{exists:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}],optIn:[{waitForThenClick:"#lgcookieslaw_accept"}],optOut:[{hide:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}]},{name:"linkedin.com",prehideSelectors:[".artdeco-global-alert[type=COOKIE_CONSENT]"],detectCmp:[{exists:".artdeco-global-alert[type=COOKIE_CONSENT]"}],detectPopup:[{visible:".artdeco-global-alert[type=COOKIE_CONSENT]"}],optIn:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=ACCEPT]"},{wait:500},{waitForThenClick:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=ACCEPT]"}],optOut:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=DENY]"},{wait:500},{waitForThenClick:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=DENY]"}],test:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT]",check:"none"}]},{name:"livejasmin",vendorUrl:"https://www.livejasmin.com/",runContext:{urlPattern:"^https://(m|www)\\.livejasmin\\.com/"},prehideSelectors:["#consent_modal"],detectCmp:[{exists:"#consent_modal"}],detectPopup:[{visible:"#consent_modal"}],optIn:[{waitForThenClick:"#consent_modal button[data-testid=ButtonStyledButton]:first-of-type"}],optOut:[{waitForThenClick:"#consent_modal button[data-testid=ButtonStyledButton]:nth-of-type(2)"},{waitForVisible:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent]"},{click:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent] input[data-testid=PrivacyPreferenceCenterWithConsentCookieSwitch]:checked",optional:!0,all:!0},{waitForThenClick:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent] button[data-testid=ButtonStyledButton]:last-child"}]},{name:"macpaw.com",cosmetic:!0,prehideSelectors:['div[data-banner="cookies"]'],detectCmp:[{exists:'div[data-banner="cookies"]'}],detectPopup:[{exists:'div[data-banner="cookies"]'}],optIn:[{click:'button[data-banner-close="cookies"]'}],optOut:[{hide:'div[data-banner="cookies"]'}]},{name:"marksandspencer.com",cosmetic:!0,detectCmp:[{exists:".navigation-cookiebbanner"}],detectPopup:[{visible:".navigation-cookiebbanner"}],optOut:[{hide:".navigation-cookiebbanner"}],optIn:[{click:".navigation-cookiebbanner__submit"}]},{name:"mediamarkt.de",prehideSelectors:["div[aria-labelledby=pwa-consent-layer-title]","div[class^=StyledConsentLayerWrapper-]"],detectCmp:[{exists:"div[aria-labelledby^=pwa-consent-layer-title]"}],detectPopup:[{exists:"div[aria-labelledby^=pwa-consent-layer-title]"}],optOut:[{click:"button[data-test^=pwa-consent-layer-deny-all]"}],optIn:[{click:"button[data-test^=pwa-consent-layer-accept-all"}]},{name:"Mediavine",prehideSelectors:['[data-name="mediavine-gdpr-cmp"]'],detectCmp:[{exists:'[data-name="mediavine-gdpr-cmp"]'}],detectPopup:[{wait:500},{visible:'[data-name="mediavine-gdpr-cmp"]'}],optIn:[{waitForThenClick:'[data-name="mediavine-gdpr-cmp"] [format="primary"]'}],optOut:[{waitForThenClick:'[data-name="mediavine-gdpr-cmp"] [data-view="manageSettings"]'},{waitFor:'[data-name="mediavine-gdpr-cmp"] input[type=checkbox]'},{eval:"EVAL_MEDIAVINE_0",optional:!0},{click:'[data-name="mediavine-gdpr-cmp"] [format="secondary"]'}]},{name:"medium",vendorUrl:"https://medium.com",cosmetic:!0,runContext:{main:!0,frame:!1,urlPattern:"^https://([a-z0-9-]+\\.)?medium\\.com/"},prehideSelectors:[],detectCmp:[{exists:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}],detectPopup:[{visible:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}],optIn:[{waitForThenClick:"[data-testid=close-button]"}],optOut:[{hide:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}]},{name:"microsoft.com",prehideSelectors:["#wcpConsentBannerCtrl"],detectCmp:[{exists:"#wcpConsentBannerCtrl"}],detectPopup:[{exists:"#wcpConsentBannerCtrl"}],optOut:[{eval:"EVAL_MICROSOFT_0"}],optIn:[{eval:"EVAL_MICROSOFT_1"}],test:[{eval:"EVAL_MICROSOFT_2"}]},{name:"midway-usa",runContext:{urlPattern:"^https://www\\.midwayusa\\.com/"},cosmetic:!0,prehideSelectors:["#cookie-container"],detectCmp:[{exists:['div[aria-label="Cookie Policy Banner"]']}],detectPopup:[{visible:"#cookie-container"}],optIn:[{click:"button#cookie-btn"}],optOut:[{hide:'div[aria-label="Cookie Policy Banner"]'}]},{name:"moneysavingexpert.com",detectCmp:[{exists:"dialog[data-testid=accept-our-cookies-dialog]"}],detectPopup:[{visible:"dialog[data-testid=accept-our-cookies-dialog]"}],optIn:[{click:"#banner-accept"}],optOut:[{click:"#banner-manage"},{click:"#pc-confirm"}]},{name:"monzo.com",prehideSelectors:[".cookie-alert, cookie-alert__content"],detectCmp:[{exists:'div.cookie-alert[role="dialog"]'},{exists:'a[href*="monzo"]'}],detectPopup:[{visible:".cookie-alert__content"}],optIn:[{click:".js-accept-cookie-policy"}],optOut:[{click:".js-decline-cookie-policy"}]},{name:"Moove",prehideSelectors:["#moove_gdpr_cookie_info_bar"],detectCmp:[{exists:"#moove_gdpr_cookie_info_bar"}],detectPopup:[{visible:"#moove_gdpr_cookie_info_bar:not(.moove-gdpr-info-bar-hidden)"}],optIn:[{waitForThenClick:".moove-gdpr-infobar-allow-all"}],optOut:[{if:{exists:"#moove_gdpr_cookie_info_bar .change-settings-button"},then:[{click:"#moove_gdpr_cookie_info_bar .change-settings-button"},{waitForVisible:"#moove_gdpr_cookie_modal"},{eval:"EVAL_MOOVE_0"},{click:".moove-gdpr-modal-save-settings"}],else:[{hide:"#moove_gdpr_cookie_info_bar"}]}],test:[{visible:"#moove_gdpr_cookie_info_bar",check:"none"}]},{name:"national-lottery.co.uk",detectCmp:[{exists:".cuk_cookie_consent"}],detectPopup:[{visible:".cuk_cookie_consent",check:"any"}],optOut:[{click:".cuk_cookie_consent_manage_pref"},{click:".cuk_cookie_consent_save_pref"},{click:".cuk_cookie_consent_close"}],optIn:[{click:".cuk_cookie_consent_accept_all"}]},{name:"nba.com",runContext:{urlPattern:"^https://(www\\.)?nba.com/"},cosmetic:!0,prehideSelectors:["#onetrust-banner-sdk"],detectCmp:[{exists:"#onetrust-banner-sdk"}],detectPopup:[{visible:"#onetrust-banner-sdk"}],optIn:[{click:"#onetrust-accept-btn-handler"}],optOut:[{hide:"#onetrust-banner-sdk"}]},{name:"netbeat.de",runContext:{urlPattern:"^https://(www\\.)?netbeat\\.de/"},prehideSelectors:["div#cookieWarning"],detectCmp:[{exists:"div#cookieWarning"}],detectPopup:[{visible:"div#cookieWarning"}],optIn:[{waitForThenClick:"a#btnCookiesAcceptAll"}],optOut:[{waitForThenClick:"a#btnCookiesDenyAll"}]},{name:"netflix.de",detectCmp:[{exists:"#cookie-disclosure"}],detectPopup:[{visible:".cookie-disclosure-message",check:"any"}],optIn:[{click:".btn-accept"}],optOut:[{hide:"#cookie-disclosure"},{click:".btn-reject"}]},{name:"nhs.uk",prehideSelectors:["#nhsuk-cookie-banner"],detectCmp:[{exists:"#nhsuk-cookie-banner"}],detectPopup:[{exists:"#nhsuk-cookie-banner"}],optOut:[{click:"#nhsuk-cookie-banner__link_accept"}],optIn:[{click:"#nhsuk-cookie-banner__link_accept_analytics"}]},{name:"nike",vendorUrl:"https://nike.com",runContext:{urlPattern:"^https://(www\\.)?nike\\.com/"},prehideSelectors:[],detectCmp:[{exists:"[data-testid=cookie-dialog-root]"}],detectPopup:[{visible:"[data-testid=cookie-dialog-root]"}],optIn:[{waitForThenClick:"[data-testid=dialog-accept-button]"}],optOut:[{waitForThenClick:"input[type=radio][id$=-declineLabel]",all:!0},{waitForThenClick:"[data-testid=confirm-choice-button]"}]},{name:"notice-cookie",prehideSelectors:[".button--notice"],cosmetic:!0,detectCmp:[{exists:".notice--cookie"}],detectPopup:[{visible:".notice--cookie"}],optIn:[{click:".button--notice"}],optOut:[{hide:".notice--cookie"}]},{name:"nrk.no",cosmetic:!0,prehideSelectors:[".nrk-masthead__info-banner--cookie"],detectCmp:[{exists:".nrk-masthead__info-banner--cookie"}],detectPopup:[{exists:".nrk-masthead__info-banner--cookie"}],optIn:[{click:"div.nrk-masthead__info-banner--cookie button > span:has(+ svg.nrk-close)"}],optOut:[{hide:".nrk-masthead__info-banner--cookie"}]},{name:"obi.de",prehideSelectors:[".disc-cp--active"],detectCmp:[{exists:".disc-cp-modal__modal"}],detectPopup:[{visible:".disc-cp-modal__modal"}],optIn:[{click:".js-disc-cp-accept-all"}],optOut:[{click:".js-disc-cp-deny-all"}]},{name:"om",vendorUrl:"https://olli-machts.de/en/extension/cookie-manager",prehideSelectors:[".tx-om-cookie-consent"],detectCmp:[{exists:".tx-om-cookie-consent .active[data-omcookie-panel]"}],detectPopup:[{exists:".tx-om-cookie-consent .active[data-omcookie-panel]"}],optIn:[{waitForThenClick:"[data-omcookie-panel-save=all]"}],optOut:[{if:{exists:"[data-omcookie-panel-save=min]"},then:[{waitForThenClick:"[data-omcookie-panel-save=min]"}],else:[{click:"input[data-omcookie-panel-grp]:checked:not(:disabled)",all:!0,optional:!0},{waitForThenClick:"[data-omcookie-panel-save=save]"}]}]},{name:"onlyFans.com",runContext:{urlPattern:"^https://onlyfans\\.com/"},prehideSelectors:["div.b-cookies-informer"],detectCmp:[{exists:"div.b-cookies-informer"}],detectPopup:[{exists:"div.b-cookies-informer"}],optIn:[{click:"div.b-cookies-informer__nav > button:nth-child(2)"}],optOut:[{click:"div.b-cookies-informer__nav > button:nth-child(1)"},{if:{exists:"div.b-cookies-informer__switchers"},then:[{click:"div.b-cookies-informer__switchers input:not([disabled])",all:!0},{click:"div.b-cookies-informer__nav > button"}]}]},{name:"openai",vendorUrl:"https://platform.openai.com/",cosmetic:!1,runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?openai\\.com/"},prehideSelectors:["[data-testid=cookie-consent-banner]"],detectCmp:[{exists:"[data-testid=cookie-consent-banner]"}],detectPopup:[{visible:"[data-testid=cookie-consent-banner]"}],optIn:[{waitForThenClick:"xpath///button[contains(., 'Accept all')]"}],optOut:[{waitForThenClick:"xpath///button[contains(., 'Reject all')]"}],test:[{wait:500},{eval:"EVAL_OPENAI_TEST"}]},{name:"openli",vendorUrl:"https://openli.com",prehideSelectors:[".legalmonster-cleanslate"],detectCmp:[{exists:".legalmonster-cleanslate"}],detectPopup:[{visible:".legalmonster-cleanslate #lm-cookie-wall-container",check:"any"}],optIn:[{waitForThenClick:"#lm-accept-all"}],optOut:[{waitForThenClick:"#lm-accept-necessary"}]},{name:"opera.com",vendorUrl:"https://unknown",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,prehideSelectors:[],detectCmp:[{exists:"#cookie-consent .manage-cookies__btn"}],detectPopup:[{visible:"#cookie-consent .cookie-basic-consent__btn"}],optIn:[{waitForThenClick:"#cookie-consent .cookie-basic-consent__btn"}],optOut:[{waitForThenClick:"#cookie-consent .manage-cookies__btn"},{waitForThenClick:"#cookie-consent .active.marketing_option_switch.cookie-consent__switch",all:!0},{waitForThenClick:"#cookie-consent .cookie-selection__btn"}],test:[{eval:"EVAL_OPERA_0"}]},{name:"osano",prehideSelectors:[".osano-cm-window,.osano-cm-dialog"],detectCmp:[{exists:".osano-cm-window"}],detectPopup:[{visible:".osano-cm-dialog"}],optIn:[{click:".osano-cm-accept-all",optional:!0}],optOut:[{waitForThenClick:".osano-cm-denyAll"}]},{name:"otto.de",prehideSelectors:[".cookieBanner--visibility"],detectCmp:[{exists:".cookieBanner--visibility"}],detectPopup:[{visible:".cookieBanner__wrapper"}],optIn:[{click:".js_cookieBannerPermissionButton"}],optOut:[{click:".js_cookieBannerProhibitionButton"}]},{name:"ourworldindata",vendorUrl:"https://ourworldindata.org/",runContext:{urlPattern:"^https://ourworldindata\\.org/"},prehideSelectors:[".cookie-manager"],detectCmp:[{exists:".cookie-manager"}],detectPopup:[{visible:".cookie-manager .cookie-notice.open"}],optIn:[{waitForThenClick:".cookie-notice [data-test=accept]"}],optOut:[{waitForThenClick:".cookie-notice [data-test=reject]"}]},{name:"pabcogypsum",vendorUrl:"https://unknown",prehideSelectors:[".js-cookie-notice:has(#cookie_settings-form)"],detectCmp:[{exists:".js-cookie-notice #cookie_settings-form"}],detectPopup:[{visible:".js-cookie-notice #cookie_settings-form"}],optIn:[{waitForThenClick:".js-cookie-notice button[value=allow]"}],optOut:[{waitForThenClick:".js-cookie-notice button[value=disable]"}]},{name:"paypal-us",prehideSelectors:["#ccpaCookieContent_wrapper, article.ppvx_modal--overpanel"],detectCmp:[{exists:"#ccpaCookieBanner, .privacy-sheet-content"}],detectPopup:[{visible:"#ccpaCookieBanner, .privacy-sheet-content"}],optIn:[{click:"#acceptAllButton"}],optOut:[{if:{exists:"#bannerDeclineButton"},then:[{click:"#bannerDeclineButton"}],else:[{if:{exists:"a#manageCookiesLink"},then:[{click:"a#manageCookiesLink"}],else:[{waitForVisible:".privacy-sheet-content #formContent"},{click:"#formContent .cookiepref-11m2iee-checkbox_base input:checked",all:!0,optional:!0},{click:".cookieAction.saveCookie,.confirmCookie #submitCookiesBtn"}]}]}]},{name:"paypal.com",prehideSelectors:["#gdprCookieBanner"],detectCmp:[{exists:"#gdprCookieBanner"}],detectPopup:[{visible:"#gdprCookieContent_wrapper"}],optIn:[{click:"#acceptAllButton"}],optOut:[{wait:200},{click:".gdprCookieBanner_decline-button"}],test:[{wait:500},{eval:"EVAL_PAYPAL_0"}]},{name:"pinetools.com",cosmetic:!0,prehideSelectors:["#aviso_cookies"],detectCmp:[{exists:"#aviso_cookies"}],detectPopup:[{exists:".lang_en #aviso_cookies"}],optIn:[{click:"#aviso_cookies .a_boton_cerrar"}],optOut:[{hide:"#aviso_cookies"}]},{name:"pinterest-business",vendorUrl:"https://business.pinterest.com/",runContext:{urlPattern:"^https://.*\\.pinterest\\.com/"},prehideSelectors:[".BusinessCookieConsent"],detectCmp:[{exists:".BusinessCookieConsent"}],detectPopup:[{visible:".BusinessCookieConsent [data-id=cookie-consent-banner-buttons]"}],optIn:[{waitForThenClick:"[data-id=cookie-consent-banner-buttons] > div:nth-child(1) button"}],optOut:[{waitForThenClick:"[data-id=cookie-consent-banner-buttons] > div:nth-child(2) button"}]},{name:"pmc",cosmetic:!0,prehideSelectors:["#pmc-pp-tou--notice"],detectCmp:[{exists:"#pmc-pp-tou--notice"}],detectPopup:[{visible:"#pmc-pp-tou--notice"}],optIn:[{click:"span.pmc-pp-tou--notice-close-btn"}],optOut:[{hide:"#pmc-pp-tou--notice"}]},{name:"pornhub.com",runContext:{urlPattern:"^https://(www\\.)?pornhub\\.com/"},cosmetic:!1,prehideSelectors:["#cookieBanner #cookieBannerContent"],detectCmp:[{exists:"#cookieBanner #cookieBannerContent"}],detectPopup:[{visible:"#cookieBanner #cookieBannerContent"}],optIn:[{waitForThenClick:"#cookieBanner [data-label=accept_all]"}],optOut:[{waitForThenClick:"#cookieBanner [data-label=accept_essential]"}]},{name:"pornpics.com",cosmetic:!0,prehideSelectors:["#cookie-contract"],detectCmp:[{exists:"#cookie-contract"}],detectPopup:[{visible:"#cookie-contract"}],optIn:[{click:"#cookie-contract .icon-cross"}],optOut:[{hide:"#cookie-contract"}]},{name:"PrimeBox CookieBar",prehideSelectors:["#cookie-bar"],detectCmp:[{exists:"#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy"}],detectPopup:[{visible:"#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy",check:"any"}],optIn:[{waitForThenClick:"#cookie-bar .cb-enable"}],optOut:[{click:"#cookie-bar .cb-disable",optional:!0},{hide:"#cookie-bar"}],test:[{eval:"EVAL_PRIMEBOX_0"}]},{name:"privacymanager.io",prehideSelectors:["#gdpr-consent-tool-wrapper",'iframe[src^="https://cmp-consent-tool.privacymanager.io"]'],runContext:{urlPattern:"^https://cmp-consent-tool\\.privacymanager\\.io/",main:!1,frame:!0},detectCmp:[{exists:"button#save"}],detectPopup:[{visible:"button#save"}],optIn:[{click:"button#save"}],optOut:[{if:{exists:"#denyAll"},then:[{click:"#denyAll"},{waitForThenClick:".okButton"}],else:[{waitForThenClick:"#manageSettings"},{waitFor:".purposes-overview-list"},{waitFor:"button#saveAndExit"},{click:"span[role=checkbox][aria-checked=true]",all:!0,optional:!0},{click:"button#saveAndExit"}]}]},{name:"productz.com",vendorUrl:"https://productz.com/",runContext:{urlPattern:"^https://productz\\.com/"},prehideSelectors:[],detectCmp:[{exists:".c-modal.is-active"}],detectPopup:[{visible:".c-modal.is-active"}],optIn:[{waitForThenClick:".c-modal.is-active .is-accept"}],optOut:[{waitForThenClick:".c-modal.is-active .is-dismiss"}]},{name:"pubtech",prehideSelectors:["#pubtech-cmp"],detectCmp:[{exists:"#pubtech-cmp"}],detectPopup:[{visible:"#pubtech-cmp #pt-actions"}],optIn:[{if:{exists:"#pt-accept-all"},then:[{click:"#pubtech-cmp #pt-actions #pt-accept-all"}],else:[{click:"#pubtech-cmp #pt-actions button:nth-of-type(2)"}]}],optOut:[{click:"#pubtech-cmp #pt-close"}],test:[{eval:"EVAL_PUBTECH_0"}]},{name:"quantcast",prehideSelectors:["#qc-cmp2-main,#qc-cmp2-container"],detectCmp:[{exists:"#qc-cmp2-container"}],detectPopup:[{visible:"#qc-cmp2-ui"}],optOut:[{waitFor:'.qc-cmp2-summary-buttons > button[mode="secondary"]',timeout:2e3},{if:{exists:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(2)'},then:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(2)'}],else:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(1)'},{waitFor:"#qc-cmp2-ui"},{click:'.qc-cmp2-toggle-switch > button[aria-checked="true"]',all:!0,optional:!0},{click:'.qc-cmp2-main button[aria-label="REJECT ALL"]',optional:!0},{waitForThenClick:'.qc-cmp2-main button[aria-label="SAVE & EXIT"],.qc-cmp2-buttons-desktop > button[mode="primary"]',timeout:5e3}]}],optIn:[{click:'.qc-cmp2-summary-buttons > button[mode="primary"]'}]},{name:"reddit.com",runContext:{urlPattern:"^https://www\\.reddit\\.com/"},prehideSelectors:["[bundlename=reddit_cookie_banner]"],detectCmp:[{exists:"reddit-cookie-banner"}],detectPopup:[{visible:"reddit-cookie-banner"}],optIn:[{waitForThenClick:["reddit-cookie-banner","#accept-all-cookies-button > button"]}],optOut:[{waitForThenClick:["reddit-cookie-banner","#reject-nonessential-cookies-button > button"]}],test:[{eval:"EVAL_REDDIT_0"}]},{name:"roblox",vendorUrl:"https://roblox.com",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?roblox\\.com/"},prehideSelectors:[],detectCmp:[{exists:".cookie-banner-wrapper"}],detectPopup:[{visible:".cookie-banner-wrapper .cookie-banner"}],optIn:[{waitForThenClick:".cookie-banner-wrapper button.btn-cta-lg"}],optOut:[{waitForThenClick:".cookie-banner-wrapper button.btn-secondary-lg"}],test:[{eval:"EVAL_ROBLOX_TEST"}]},{name:"rog-forum.asus.com",runContext:{urlPattern:"^https://rog-forum\\.asus\\.com/"},prehideSelectors:["#cookie-policy-info"],detectCmp:[{exists:"#cookie-policy-info"}],detectPopup:[{visible:"#cookie-policy-info"}],optIn:[{click:'div.cookie-btn-box > div[aria-label="Accept"]'}],optOut:[{click:'div.cookie-btn-box > div[aria-label="Reject"]'},{waitForThenClick:'.cookie-policy-lightbox-bottom > div[aria-label="Save Settings"]'}]},{name:"roofingmegastore.co.uk",runContext:{urlPattern:"^https://(www\\.)?roofingmegastore\\.co\\.uk"},prehideSelectors:["#m-cookienotice"],detectCmp:[{exists:"#m-cookienotice"}],detectPopup:[{visible:"#m-cookienotice"}],optIn:[{click:"#accept-cookies"}],optOut:[{click:"#manage-cookies"},{waitForThenClick:"#accept-selected"}]},{name:"samsung.com",runContext:{urlPattern:"^https://www\\.samsung\\.com/"},cosmetic:!0,prehideSelectors:["div.cookie-bar"],detectCmp:[{exists:"div.cookie-bar"}],detectPopup:[{visible:"div.cookie-bar"}],optIn:[{click:"div.cookie-bar__manage > a"}],optOut:[{hide:"div.cookie-bar"}]},{name:"setapp.com",vendorUrl:"https://setapp.com/",cosmetic:!0,runContext:{urlPattern:"^https://setapp\\.com/"},prehideSelectors:[],detectCmp:[{exists:".cookie-banner.js-cookie-banner"}],detectPopup:[{visible:".cookie-banner.js-cookie-banner"}],optIn:[{waitForThenClick:".cookie-banner.js-cookie-banner button"}],optOut:[{hide:".cookie-banner.js-cookie-banner"}]},{name:"sibbo",prehideSelectors:["sibbo-cmp-layout"],detectCmp:[{exists:"sibbo-cmp-layout"}],detectPopup:[{visible:"#rejectAllMain"}],optIn:[{click:"#acceptAllMain"}],optOut:[{click:"#rejectAllMain"}]},{name:"similarweb.com",cosmetic:!0,prehideSelectors:[".app-cookies-notification"],detectCmp:[{exists:".app-cookies-notification"}],detectPopup:[{exists:".app-layout .app-cookies-notification"}],optIn:[{click:"button.app-cookies-notification__dismiss"}],optOut:[{hide:".app-layout .app-cookies-notification"}]},{name:"Sirdata",cosmetic:!1,prehideSelectors:["#sd-cmp"],detectCmp:[{exists:"#sd-cmp"}],detectPopup:[{visible:"#sd-cmp"}],optIn:[{waitForThenClick:"#sd-cmp .sd-cmp-3cRQ2"}],optOut:[{waitForThenClick:["#sd-cmp","xpath///span[contains(., 'Do not accept') or contains(., 'Acceptera inte') or contains(., 'No aceptar') or contains(., 'Ikke acceptere') or contains(., 'Nicht akzeptieren') or contains(., 'Не приемам') or contains(., 'Να μην γίνει αποδοχή') or contains(., 'Niet accepteren') or contains(., 'Nepřijímat') or contains(., 'Nie akceptuj') or contains(., 'Nu acceptați') or contains(., 'Não aceitar') or contains(., 'Continuer sans accepter') or contains(., 'Non accettare') or contains(., 'Nem fogad el')]"]}]},{name:"snigel",detectCmp:[{exists:".snigel-cmp-framework"}],detectPopup:[{visible:".snigel-cmp-framework"}],optOut:[{click:"#sn-b-custom"},{click:"#sn-b-save"}],test:[{eval:"EVAL_SNIGEL_0"}],optIn:[{click:".snigel-cmp-framework #accept-choices"}]},{name:"steampowered.com",detectCmp:[{exists:".cookiepreferences_popup"},{visible:".cookiepreferences_popup"}],detectPopup:[{visible:".cookiepreferences_popup"}],optOut:[{click:"#rejectAllButton"}],optIn:[{click:"#acceptAllButton"}],test:[{wait:1e3},{eval:"EVAL_STEAMPOWERED_0"}]},{name:"strato.de",prehideSelectors:[".consent__wrapper"],runContext:{urlPattern:"^https://www\\.strato\\.de/"},detectCmp:[{exists:".consent"}],detectPopup:[{visible:".consent"}],optIn:[{click:"button.consentAgree"}],optOut:[{click:"button.consentSettings"},{waitForThenClick:"button#consentSubmit"}]},{name:"svt.se",vendorUrl:"https://www.svt.se/",runContext:{urlPattern:"^https://www\\.svt\\.se/"},prehideSelectors:["[class*=CookieConsent__root___]"],detectCmp:[{exists:"[class*=CookieConsent__root___]"}],detectPopup:[{visible:"[class*=CookieConsent__modal___]"}],optIn:[{waitForThenClick:"[class*=CookieConsent__modal___] > div > button[class*=primary]"}],optOut:[{waitForThenClick:"[class*=CookieConsent__modal___] > div > button[class*=secondary]:nth-child(2)"}],test:[{eval:"EVAL_SVT_TEST"}]},{name:"takealot.com",cosmetic:!0,prehideSelectors:['div[class^="cookies-banner-module_"]'],detectCmp:[{exists:'div[class^="cookies-banner-module_cookie-banner_"]'}],detectPopup:[{exists:'div[class^="cookies-banner-module_cookie-banner_"]'}],optIn:[{click:'button[class*="cookies-banner-module_dismiss-button_"]'}],optOut:[{hide:'div[class^="cookies-banner-module_"]'},{if:{exists:'div[class^="cookies-banner-module_small-cookie-banner_"]'},then:[{eval:"EVAL_TAKEALOT_0"}],else:[]}]},{name:"tarteaucitron.js",prehideSelectors:["#tarteaucitronRoot"],detectCmp:[{exists:"#tarteaucitronRoot"}],detectPopup:[{visible:"#tarteaucitronRoot #tarteaucitronAlertBig",check:"any"}],optIn:[{eval:"EVAL_TARTEAUCITRON_1"}],optOut:[{eval:"EVAL_TARTEAUCITRON_0"}],test:[{eval:"EVAL_TARTEAUCITRON_2",comment:"sometimes there are required categories, so we check that at least something is false"}]},{name:"taunton",vendorUrl:"https://www.taunton.com/",prehideSelectors:["#taunton-user-consent__overlay"],detectCmp:[{exists:"#taunton-user-consent__overlay"}],detectPopup:[{exists:"#taunton-user-consent__overlay:not([aria-hidden=true])"}],optIn:[{click:"#taunton-user-consent__toolbar input[type=checkbox]:not(:checked)"},{click:"#taunton-user-consent__toolbar button[type=submit]"}],optOut:[{click:"#taunton-user-consent__toolbar input[type=checkbox]:checked",optional:!0,all:!0},{click:"#taunton-user-consent__toolbar button[type=submit]"}],test:[{eval:"EVAL_TAUNTON_TEST"}]},{name:"Tealium",prehideSelectors:["#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs,#__tealiumImplicitmodal,#consent-layer"],detectCmp:[{exists:"#__tealiumGDPRecModal *,#__tealiumGDPRcpPrefs *,#__tealiumImplicitmodal *"},{eval:"EVAL_TEALIUM_0"}],detectPopup:[{visible:"#__tealiumGDPRecModal *,#__tealiumGDPRcpPrefs *,#__tealiumImplicitmodal *",check:"any"}],optOut:[{eval:"EVAL_TEALIUM_1"},{eval:"EVAL_TEALIUM_DONOTSELL"},{hide:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs,#__tealiumImplicitmodal"},{waitForThenClick:"#cm-acceptNone,.js-accept-essential-cookies",timeout:1e3,optional:!0}],optIn:[{hide:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs"},{eval:"EVAL_TEALIUM_2"}],test:[{eval:"EVAL_TEALIUM_3"},{eval:"EVAL_TEALIUM_DONOTSELL_CHECK"},{visible:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs",check:"none"}]},{name:"temu",vendorUrl:"https://temu.com",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?temu\\.com/"},prehideSelectors:[],detectCmp:[{exists:'div > div > div > div > span[href*="/cookie-and-similar-technologies-policy.html"]'}],detectPopup:[{visible:'div > div > div > div > span[href*="/cookie-and-similar-technologies-policy.html"]'}],optIn:[{waitForThenClick:'div > div > div:has(> div > span[href*="/cookie-and-similar-technologies-policy.html"]) > [role=button]:nth-child(3)'}],optOut:[{if:{exists:"xpath///span[contains(., 'Alle afwijzen') or contains(., 'Reject all') or contains(., 'Tümünü reddet') or contains(., 'Odrzuć wszystko')]"},then:[{waitForThenClick:"xpath///span[contains(., 'Alle afwijzen') or contains(., 'Reject all') or contains(., 'Tümünü reddet') or contains(., 'Odrzuć wszystko')]"}],else:[{waitForThenClick:'div > div > div:has(> div > span[href*="/cookie-and-similar-technologies-policy.html"]) > [role=button]:nth-child(2)'}]}]},{name:"Termly",prehideSelectors:["#termly-code-snippet-support"],detectCmp:[{exists:"#termly-code-snippet-support"}],detectPopup:[{visible:"#termly-code-snippet-support div"}],optIn:[{waitForThenClick:'[data-tid="banner-accept"]'}],optOut:[{if:{exists:'[data-tid="banner-decline"]'},then:[{click:'[data-tid="banner-decline"]'}],else:[{click:".t-preference-button"},{wait:500},{if:{exists:".t-declineAllButton"},then:[{click:".t-declineAllButton"}],else:[{waitForThenClick:".t-preference-modal input[type=checkbox][checked]:not([disabled])",all:!0},{waitForThenClick:".t-saveButton"}]}]}]},{name:"termsfeed",vendorUrl:"https://termsfeed.com",comment:"v4.x.x",prehideSelectors:[".termsfeed-com---nb"],detectCmp:[{exists:".termsfeed-com---nb"}],detectPopup:[{visible:".termsfeed-com---nb"}],optIn:[{waitForThenClick:".cc-nb-okagree"}],optOut:[{waitForThenClick:".cc-nb-reject"}]},{name:"termsfeed3",vendorUrl:"https://termsfeed.com",comment:"v3.x.x",prehideSelectors:[".cc_dialog.cc_css_reboot,.cc_overlay_lock"],detectCmp:[{exists:".cc_dialog.cc_css_reboot"}],detectPopup:[{visible:".cc_dialog.cc_css_reboot"}],optIn:[{waitForThenClick:".cc_dialog.cc_css_reboot .cc_b_ok"}],optOut:[{if:{exists:".cc_dialog.cc_css_reboot .cc_b_cp"},then:[{click:".cc_dialog.cc_css_reboot .cc_b_cp"},{waitForVisible:".cookie-consent-preferences-dialog .cc_cp_f_save button"},{waitForThenClick:".cookie-consent-preferences-dialog .cc_cp_f_save button"}],else:[{hide:".cc_dialog.cc_css_reboot,.cc_overlay_lock"}]}]},{name:"tesco",vendorUrl:"https://www.tesco.com",cosmetic:!1,runContext:{urlPattern:"^https://(www\\.)?tesco\\.com/"},prehideSelectors:["[class*=CookieBanner__Sizer]"],detectCmp:[{exists:"[aria-label=consent-banner]"}],detectPopup:[{visible:"[aria-label=consent-banner]"}],optIn:[{wait:1e3},{waitForThenClick:"xpath///button[contains(., 'Accept all')]"}],optOut:[{wait:1e3},{waitForThenClick:"xpath///button[contains(., 'Reject all')]"}]},{name:"tesla",vendorUrl:"https://tesla.com/",runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?tesla\\.com/"},prehideSelectors:[],detectCmp:[{exists:"#cookie_banner"}],detectPopup:[{visible:"#cookie_banner"}],optIn:[{waitForThenClick:"#tsla-accept-cookie"}],optOut:[{waitForThenClick:"#tsla-reject-cookie"}],test:[{eval:"EVAL_TESLA_TEST"}]},{name:"Test page cosmetic CMP",cosmetic:!0,prehideSelectors:["#privacy-test-page-cmp-test-prehide"],detectCmp:[{exists:"#privacy-test-page-cmp-test-banner"}],detectPopup:[{visible:"#privacy-test-page-cmp-test-banner"}],optIn:[{waitFor:"#accept-all"},{click:"#accept-all"}],optOut:[{hide:"#privacy-test-page-cmp-test-banner"}],test:[{wait:500},{eval:"EVAL_TESTCMP_COSMETIC_0"}]},{name:"Test page CMP",prehideSelectors:["#reject-all"],detectCmp:[{exists:"#privacy-test-page-cmp-test"}],detectPopup:[{visible:"#privacy-test-page-cmp-test"}],optIn:[{waitFor:"#accept-all"},{click:"#accept-all"}],optOut:[{waitFor:"#reject-all"},{click:"#reject-all"}],test:[{eval:"EVAL_TESTCMP_0"}]},{name:"thalia.de",prehideSelectors:[".consent-banner-box"],detectCmp:[{exists:"consent-banner[component=consent-banner]"}],detectPopup:[{visible:".consent-banner-box"}],optIn:[{click:".button-zustimmen"}],optOut:[{click:"button[data-consent=disagree]"}]},{name:"thefreedictionary.com",prehideSelectors:["#cmpBanner"],detectCmp:[{exists:"#cmpBanner"}],detectPopup:[{visible:"#cmpBanner"}],optIn:[{eval:"EVAL_THEFREEDICTIONARY_1"}],optOut:[{eval:"EVAL_THEFREEDICTIONARY_0"}]},{name:"theverge",runContext:{frame:!1,main:!0,urlPattern:"^https://(www)?\\.theverge\\.com"},intermediate:!1,prehideSelectors:[".duet--cta--cookie-banner"],detectCmp:[{exists:".duet--cta--cookie-banner"}],detectPopup:[{visible:".duet--cta--cookie-banner"}],optIn:[{click:".duet--cta--cookie-banner button.tracking-12",all:!1}],optOut:[{click:".duet--cta--cookie-banner button.tracking-12 > span"}],test:[{eval:"EVAL_THEVERGE_0"}]},{name:"tidbits-com",cosmetic:!0,prehideSelectors:["#eu_cookie_law_widget-2"],detectCmp:[{exists:"#eu_cookie_law_widget-2"}],detectPopup:[{visible:"#eu_cookie_law_widget-2"}],optIn:[{click:"#eu-cookie-law form > input.accept"}],optOut:[{hide:"#eu_cookie_law_widget-2"}]},{name:"tractor-supply",runContext:{urlPattern:"^https://www\\.tractorsupply\\.com/"},cosmetic:!0,prehideSelectors:[".tsc-cookie-banner"],detectCmp:[{exists:".tsc-cookie-banner"}],detectPopup:[{visible:".tsc-cookie-banner"}],optIn:[{click:"#cookie-banner-cancel"}],optOut:[{hide:".tsc-cookie-banner"}]},{name:"trader-joes-com",cosmetic:!0,prehideSelectors:['div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'],detectCmp:[{exists:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}],detectPopup:[{visible:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}],optIn:[{click:'div[class^="CookiesAlert_cookiesAlert__container__"] button'}],optOut:[{hide:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}]},{name:"transcend",vendorUrl:"https://unknown",cosmetic:!0,prehideSelectors:["#transcend-consent-manager"],detectCmp:[{exists:"#transcend-consent-manager"}],detectPopup:[{visible:"#transcend-consent-manager"}],optIn:[{waitForThenClick:["#transcend-consent-manager","#consentManagerMainDialog .inner-container button"]}],optOut:[{hide:"#transcend-consent-manager"}]},{name:"transip-nl",runContext:{urlPattern:"^https://www\\.transip\\.nl/"},prehideSelectors:["#consent-modal"],detectCmp:[{any:[{exists:"#consent-modal"},{exists:"#privacy-settings-content"}]}],detectPopup:[{any:[{visible:"#consent-modal"},{visible:"#privacy-settings-content"}]}],optIn:[{click:'button[type="submit"]'}],optOut:[{if:{exists:"#privacy-settings-content"},then:[{click:'button[type="submit"]'}],else:[{click:"div.one-modal__action-footer-column--secondary > a"}]}]},{name:"tropicfeel-com",prehideSelectors:["#shopify-section-cookies-controller"],detectCmp:[{exists:"#shopify-section-cookies-controller"}],detectPopup:[{visible:"#shopify-section-cookies-controller #cookies-controller-main-pane",check:"any"}],optIn:[{waitForThenClick:"#cookies-controller-main-pane form[data-form-allow-all] button"}],optOut:[{click:"#cookies-controller-main-pane a[data-tab-target=manage-cookies]"},{waitFor:"#manage-cookies-pane.active"},{click:"#manage-cookies-pane.active input[type=checkbox][checked]:not([disabled])",all:!0},{click:"#manage-cookies-pane.active button[type=submit]"}],test:[]},{name:"true-car",runContext:{urlPattern:"^https://www\\.truecar\\.com/"},cosmetic:!0,prehideSelectors:[['div[aria-labelledby="cookie-banner-heading"]']],detectCmp:[{exists:'div[aria-labelledby="cookie-banner-heading"]'}],detectPopup:[{visible:'div[aria-labelledby="cookie-banner-heading"]'}],optIn:[{click:'div[aria-labelledby="cookie-banner-heading"] > button[aria-label="Close"]'}],optOut:[{hide:'div[aria-labelledby="cookie-banner-heading"]'}]},{name:"truyo",prehideSelectors:["#truyo-consent-module"],detectCmp:[{exists:"#truyo-cookieBarContent"}],detectPopup:[{visible:"#truyo-consent-module"}],optIn:[{click:"button#acceptAllCookieButton"}],optOut:[{click:"button#declineAllCookieButton"}]},{name:"twcc",vendorUrl:"https://unknown",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:""},prehideSelectors:["#twcc__mechanism"],detectCmp:[{exists:"#twcc__mechanism .twcc__notice"}],detectPopup:[{visible:"#twcc__mechanism .twcc__notice"}],optIn:[{waitForThenClick:"#twcc__accept-button"}],optOut:[{waitForThenClick:"#twcc__decline-button"}],test:[{eval:"EVAL_TWCC_TEST"}]},{name:"twitch-mobile",vendorUrl:"https://m.twitch.tv/",cosmetic:!0,runContext:{urlPattern:"^https?://m\\.twitch\\.tv"},prehideSelectors:[],detectCmp:[{exists:'.ReactModal__Overlay [href="https://www.twitch.tv/p/cookie-policy"]'}],detectPopup:[{visible:'.ReactModal__Overlay [href="https://www.twitch.tv/p/cookie-policy"]'}],optIn:[{waitForThenClick:'.ReactModal__Overlay:has([href="https://www.twitch.tv/p/cookie-policy"]) button'}],optOut:[{hide:'.ReactModal__Overlay:has([href="https://www.twitch.tv/p/cookie-policy"])'}]},{name:"twitch.tv",runContext:{urlPattern:"^https?://(www\\.)?twitch\\.tv"},prehideSelectors:["div:has(> .consent-banner .consent-banner__content--gdpr-v2),.ReactModalPortal:has([data-a-target=consent-modal-save])"],detectCmp:[{exists:".consent-banner .consent-banner__content--gdpr-v2"}],detectPopup:[{visible:".consent-banner .consent-banner__content--gdpr-v2"}],optIn:[{click:'button[data-a-target="consent-banner-accept"]'}],optOut:[{hide:"div:has(> .consent-banner .consent-banner__content--gdpr-v2)"},{click:'button[data-a-target="consent-banner-manage-preferences"]'},{waitFor:"input[type=checkbox][data-a-target=tw-checkbox]"},{click:"input[type=checkbox][data-a-target=tw-checkbox][checked]:not([disabled])",all:!0,optional:!0},{waitForThenClick:"[data-a-target=consent-modal-save]"},{waitForVisible:".ReactModalPortal:has([data-a-target=consent-modal-save])",check:"none"}]},{name:"twitter",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?(twitter|x)\\.com/"},prehideSelectors:['[data-testid="BottomBar"]'],detectCmp:[{exists:'[data-testid="BottomBar"] div'}],detectPopup:[{visible:'[data-testid="BottomBar"] div'}],optIn:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>button[role=button]>span) > div:last-child > button[role=button]:first-child'}],optOut:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>button[role=button]>span) > div:last-child > button[role=button]:last-child'}],TODOtest:[{eval:"EVAL_document.cookie.includes('d_prefs=MjoxLGNvbnNlbnRfdmVyc2lvbjoy')"}]},{name:"ubuntu.com",prehideSelectors:["dialog.cookie-policy"],detectCmp:[{any:[{exists:"dialog.cookie-policy header"},{exists:'xpath///*[@id="modal"]/div/header'}]}],detectPopup:[{any:[{visible:"dialog header"},{visible:'xpath///*[@id="modal"]/div/header'}]}],optIn:[{any:[{waitForThenClick:"#cookie-policy-button-accept"},{waitForThenClick:'xpath///*[@id="cookie-policy-button-accept"]'}]}],optOut:[{any:[{waitForThenClick:"button.js-manage"},{waitForThenClick:'xpath///*[@id="cookie-policy-content"]/p[4]/button[2]'}]},{waitForThenClick:"dialog.cookie-policy .p-switch__input:checked",optional:!0,all:!0,timeout:500},{any:[{waitForThenClick:"dialog.cookie-policy .js-save-preferences"},{waitForThenClick:'xpath///*[@id="modal"]/div/button'}]}],test:[{eval:"EVAL_UBUNTU_COM_0"}]},{name:"UK Cookie Consent",prehideSelectors:["#catapult-cookie-bar"],cosmetic:!0,detectCmp:[{exists:"#catapult-cookie-bar"}],detectPopup:[{exists:".has-cookie-bar #catapult-cookie-bar"}],optIn:[{click:"#catapultCookie"}],optOut:[{hide:"#catapult-cookie-bar"}],test:[{eval:"EVAL_UK_COOKIE_CONSENT_0"}]},{name:"urbanarmorgear-com",cosmetic:!0,prehideSelectors:['div[class^="Layout__CookieBannerContainer-"]'],detectCmp:[{exists:'div[class^="Layout__CookieBannerContainer-"]'}],detectPopup:[{visible:'div[class^="Layout__CookieBannerContainer-"]'}],optIn:[{click:'button[class^="CookieBanner__AcceptButton"]'}],optOut:[{hide:'div[class^="Layout__CookieBannerContainer-"]'}]},{name:"usercentrics-api",detectCmp:[{exists:"#usercentrics-root,#usercentrics-cmp-ui"}],detectPopup:[{eval:"EVAL_USERCENTRICS_API_0"},{if:{exists:"#usercentrics-cmp-ui"},then:[{waitForVisible:"#usercentrics-cmp-ui",timeout:2e3}],else:[{exists:["#usercentrics-root","[data-testid=uc-container]"]},{waitForVisible:"#usercentrics-root",timeout:2e3}]}],optIn:[{eval:"EVAL_USERCENTRICS_API_3"},{eval:"EVAL_USERCENTRICS_API_1"},{eval:"EVAL_USERCENTRICS_API_5"}],optOut:[{eval:"EVAL_USERCENTRICS_API_1"},{eval:"EVAL_USERCENTRICS_API_2"}],test:[{eval:"EVAL_USERCENTRICS_API_6"}]},{name:"usercentrics-button",detectCmp:[{exists:"#usercentrics-button"}],detectPopup:[{visible:"#usercentrics-button #uc-btn-accept-banner"}],optIn:[{click:"#usercentrics-button #uc-btn-accept-banner"}],optOut:[{click:"#usercentrics-button #uc-btn-deny-banner"}],test:[{eval:"EVAL_USERCENTRICS_BUTTON_0"}]},{name:"uswitch.com",runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?uswitch\\.com/"},prehideSelectors:[".ucb"],detectCmp:[{exists:".ucb-banner"}],detectPopup:[{visible:".ucb-banner"}],optIn:[{waitForThenClick:".ucb-banner .ucb-btn-accept"}],optOut:[{waitForThenClick:".ucb-banner .ucb-btn-save"}]},{name:"vodafone.de",runContext:{urlPattern:"^https://www\\.vodafone\\.de/"},prehideSelectors:[".dip-consent,.dip-consent-container"],detectCmp:[{exists:".dip-consent-container"}],detectPopup:[{visible:".dip-consent-content"}],optOut:[{click:'.dip-consent-btn[tabindex="2"]'}],optIn:[{click:'.dip-consent-btn[tabindex="1"]'}]},{name:"waitrose.com",prehideSelectors:["div[aria-labelledby=CookieAlertModalHeading]","section[data-test=initial-waitrose-cookie-consent-banner]","section[data-test=cookie-consent-modal]"],detectCmp:[{exists:"section[data-test=initial-waitrose-cookie-consent-banner]"}],detectPopup:[{visible:"section[data-test=initial-waitrose-cookie-consent-banner]"}],optIn:[{click:"button[data-test=accept-all]"}],optOut:[{click:"button[data-test=manage-cookies]"},{wait:200},{eval:"EVAL_WAITROSE_0"},{click:"button[data-test=submit]"}],test:[{eval:"EVAL_WAITROSE_1"}]},{name:"webflow",vendorUrl:"https://webflow.com/",prehideSelectors:[".fs-cc-components"],detectCmp:[{exists:".fs-cc-components"}],detectPopup:[{visible:".fs-cc-components"},{visible:"[fs-cc=banner]"}],optIn:[{wait:500},{waitForThenClick:"[fs-cc=banner] [fs-cc=allow]"}],optOut:[{wait:500},{waitForThenClick:"[fs-cc=banner] [fs-cc=deny]"}]},{name:"wetransfer.com",detectCmp:[{exists:".welcome__cookie-notice"}],detectPopup:[{visible:".welcome__cookie-notice"}],optIn:[{click:".welcome__button--accept"}],optOut:[{click:".welcome__button--decline"}]},{name:"whitepages.com",runContext:{urlPattern:"^https://www\\.whitepages\\.com/"},cosmetic:!0,prehideSelectors:[".cookie-wrapper, .cookie-overlay"],detectCmp:[{exists:".cookie-wrapper"}],detectPopup:[{visible:".cookie-overlay"}],optIn:[{click:'button[aria-label="Got it"]'}],optOut:[{hide:".cookie-wrapper"}]},{name:"wolframalpha",vendorUrl:"https://www.wolframalpha.com",prehideSelectors:[],cosmetic:!0,runContext:{urlPattern:"^https://www\\.wolframalpha\\.com/"},detectCmp:[{exists:"section._a_yb"}],detectPopup:[{visible:"section._a_yb"}],optIn:[{waitForThenClick:"section._a_yb button"}],optOut:[{hide:"section._a_yb"}]},{name:"woo-commerce-com",prehideSelectors:[".wccom-comp-privacy-banner .wccom-privacy-banner"],detectCmp:[{exists:".wccom-comp-privacy-banner .wccom-privacy-banner"}],detectPopup:[{exists:".wccom-comp-privacy-banner .wccom-privacy-banner"}],optIn:[{click:".wccom-privacy-banner__content-buttons button.is-primary"}],optOut:[{click:".wccom-privacy-banner__content-buttons button.is-secondary"},{waitForThenClick:"input[type=checkbox][checked]:not([disabled])",all:!0},{click:"div.wccom-modal__footer > button"}]},{name:"WP Cookie Notice for GDPR",vendorUrl:"https://wordpress.org/plugins/gdpr-cookie-consent/",prehideSelectors:["#gdpr-cookie-consent-bar"],detectCmp:[{exists:"#gdpr-cookie-consent-bar"}],detectPopup:[{visible:"#gdpr-cookie-consent-bar"}],optIn:[{waitForThenClick:"#gdpr-cookie-consent-bar #cookie_action_accept"}],optOut:[{waitForThenClick:"#gdpr-cookie-consent-bar #cookie_action_reject"}],test:[{eval:"EVAL_WP_COOKIE_NOTICE_0"}]},{name:"wpcc",cosmetic:!0,prehideSelectors:[".wpcc-container"],detectCmp:[{exists:".wpcc-container"}],detectPopup:[{exists:".wpcc-container .wpcc-message"}],optIn:[{click:".wpcc-compliance .wpcc-btn"}],optOut:[{hide:".wpcc-container"}]},{name:"xe.com",vendorUrl:"https://www.xe.com/",runContext:{urlPattern:"^https://www\\.xe\\.com/"},prehideSelectors:["[class*=ConsentBanner]"],detectCmp:[{exists:"[class*=ConsentBanner]"}],detectPopup:[{visible:"[class*=ConsentBanner]"}],optIn:[{waitForThenClick:"[class*=ConsentBanner] .egnScw"}],optOut:[{wait:1e3},{waitForThenClick:"[class*=ConsentBanner] .frDWEu"},{waitForThenClick:"[class*=ConsentBanner] .hXIpFU"}],test:[{eval:"EVAL_XE_TEST"}]},{name:"xhamster-eu",prehideSelectors:[".cookies-modal"],detectCmp:[{exists:".cookies-modal"}],detectPopup:[{exists:".cookies-modal"}],optIn:[{click:"button.cmd-button-accept-all"}],optOut:[{click:"button.cmd-button-reject-all"}]},{name:"xhamster-us",runContext:{urlPattern:"^https://(www\\.)?xhamster\\d?\\.com"},cosmetic:!0,prehideSelectors:[".cookie-announce"],detectCmp:[{exists:".cookie-announce"}],detectPopup:[{visible:".cookie-announce .announce-text"}],optIn:[{click:".cookie-announce button.xh-button"}],optOut:[{hide:".cookie-announce"}]},{name:"xing.com",detectCmp:[{exists:"div[class^=cookie-consent-CookieConsent]"}],detectPopup:[{exists:"div[class^=cookie-consent-CookieConsent]"}],optIn:[{click:"#consent-accept-button"}],optOut:[{click:"#consent-settings-button"},{click:".consent-banner-button-accept-overlay"}],test:[{eval:"EVAL_XING_0"}]},{name:"xnxx-com",cosmetic:!0,prehideSelectors:["#cookies-use-alert"],detectCmp:[{exists:"#cookies-use-alert"}],detectPopup:[{visible:"#cookies-use-alert"}],optIn:[{click:"#cookies-use-alert .close"}],optOut:[{hide:"#cookies-use-alert"}]},{name:"xvideos",vendorUrl:"https://xvideos.com",runContext:{urlPattern:"^https://[^/]*xvideos\\.com/"},prehideSelectors:[],detectCmp:[{exists:".disclaimer-opened #disclaimer-cookies"}],detectPopup:[{visible:".disclaimer-opened #disclaimer-cookies"}],optIn:[{waitForThenClick:"#disclaimer-accept_cookies"}],optOut:[{waitForThenClick:"#disclaimer-reject_cookies"}]},{name:"Yahoo",runContext:{urlPattern:"^https://consent\\.yahoo\\.com/v2/"},prehideSelectors:["#reject-all"],detectCmp:[{exists:"#consent-page"}],detectPopup:[{visible:"#consent-page"}],optIn:[{waitForThenClick:"#consent-page button[value=agree]"}],optOut:[{waitForThenClick:"#consent-page button[value=reject]"}]},{name:"youporn.com",cosmetic:!0,prehideSelectors:[".euCookieModal, #js_euCookieModal"],detectCmp:[{exists:".euCookieModal"}],detectPopup:[{exists:".euCookieModal, #js_euCookieModal"}],optIn:[{click:'button[name="user_acceptCookie"]'}],optOut:[{hide:".euCookieModal"}]},{name:"youtube-desktop",prehideSelectors:["tp-yt-iron-overlay-backdrop.opened","ytd-consent-bump-v2-lightbox"],detectCmp:[{exists:"ytd-consent-bump-v2-lightbox tp-yt-paper-dialog"},{exists:'ytd-consent-bump-v2-lightbox tp-yt-paper-dialog a[href^="https://consent.youtube.com/"]'}],detectPopup:[{visible:"ytd-consent-bump-v2-lightbox tp-yt-paper-dialog"}],optIn:[{waitForThenClick:"ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:last-child #button,ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:last-child button"},{wait:500}],optOut:[{waitForThenClick:"ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:first-child #button,ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:first-child button"},{wait:500}],test:[{wait:500},{eval:"EVAL_YOUTUBE_DESKTOP_0"}]},{name:"youtube-mobile",prehideSelectors:[".consent-bump-v2-lightbox"],detectCmp:[{exists:"ytm-consent-bump-v2-renderer"}],detectPopup:[{visible:"ytm-consent-bump-v2-renderer"}],optIn:[{waitForThenClick:"ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons c3-material-button:first-child button, ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons ytm-button-renderer:first-child button"},{wait:500}],optOut:[{waitForThenClick:"ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons c3-material-button:nth-child(2) button, ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons ytm-button-renderer:nth-child(2) button"},{wait:500}],test:[{wait:500},{eval:"EVAL_YOUTUBE_MOBILE_0"}]},{name:"zdf",prehideSelectors:["#zdf-cmp-banner-sdk"],detectCmp:[{exists:"#zdf-cmp-banner-sdk"}],detectPopup:[{visible:"#zdf-cmp-main.zdf-cmp-show"}],optIn:[{waitForThenClick:"#zdf-cmp-main #zdf-cmp-accept-btn"}],optOut:[{waitForThenClick:"#zdf-cmp-main #zdf-cmp-deny-btn"}],test:[]},{name:"zentralruf-de",runContext:{urlPattern:"^https://(www\\.)?zentralruf\\.de"},prehideSelectors:["#cookie_modal_wrapper"],detectCmp:[{exists:"#cookie_modal_wrapper"}],detectPopup:[{visible:"#cookie_modal_wrapper"}],optIn:[{waitForThenClick:"#cookie_modal_wrapper #cookie_modal_button_consent_all"}],optOut:[{waitForThenClick:"#cookie_modal_wrapper #cookie_modal_button_choose"}]}],fn={"didomi.io":{detectors:[{presentMatcher:{target:{selector:"#didomi-host, #didomi-notice"},type:"css"},showingMatcher:{target:{selector:"body.didomi-popup-open, .didomi-notice-banner"},type:"css"}}],methods:[{action:{target:{selector:".didomi-popup-notice-buttons .didomi-button:not(.didomi-button-highlight), .didomi-notice-banner .didomi-learn-more-button"},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{retries:50,target:{selector:"#didomi-purpose-cookies"},type:"waitcss",waitTime:50},{consents:[{description:"Share (everything) with others",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-share_whith_others]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-share_whith_others]:last-child"},type:"click"},type:"X"},{description:"Information storage and access",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-cookies]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-cookies]:last-child"},type:"click"},type:"D"},{description:"Content selection, offers and marketing",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-CL-T1Rgm7]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-CL-T1Rgm7]:last-child"},type:"click"},type:"E"},{description:"Analytics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-analytics]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-analytics]:last-child"},type:"click"},type:"B"},{description:"Analytics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-M9NRHJe3G]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-M9NRHJe3G]:last-child"},type:"click"},type:"B"},{description:"Ad and content selection",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-advertising_personalization]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-advertising_personalization]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection",falseAction:{parent:{childFilter:{target:{selector:"#didomi-purpose-pub-ciblee"}},selector:".didomi-consent-popup-data-processing, .didomi-components-accordion-label-container"},target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-pub-ciblee]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-pub-ciblee]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - basics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-q4zlJqdcD]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-q4zlJqdcD]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - partners and subsidiaries",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-partenaire-cAsDe8jC]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-partenaire-cAsDe8jC]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-p4em9a8m]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-p4em9a8m]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - others",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-autres-pub]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-autres-pub]:last-child"},type:"click"},type:"F"},{description:"Social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-reseauxsociaux]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-reseauxsociaux]:last-child"},type:"click"},type:"A"},{description:"Social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-social_media]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-social_media]:last-child"},type:"click"},type:"A"},{description:"Content selection",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-content_personalization]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-content_personalization]:last-child"},type:"click"},type:"E"},{description:"Ad delivery",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-ad_delivery]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-ad_delivery]:last-child"},type:"click"},type:"F"}],type:"consent"},{action:{consents:[{matcher:{childFilter:{target:{selector:":not(.didomi-components-radio__option--selected)"}},type:"css"},trueAction:{target:{selector:":nth-child(2)"},type:"click"},falseAction:{target:{selector:":first-child"},type:"click"},type:"X"}],type:"consent"},target:{selector:".didomi-components-radio"},type:"foreach"}],type:"list"},name:"DO_CONSENT"},{action:{parent:{selector:".didomi-consent-popup-footer .didomi-consent-popup-actions"},target:{selector:".didomi-components-button:first-child"},type:"click"},name:"SAVE_CONSENT"}]},oil:{detectors:[{presentMatcher:{target:{selector:".as-oil-content-overlay"},type:"css"},showingMatcher:{target:{selector:".as-oil-content-overlay"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".as-js-advanced-settings"},type:"click"},{retries:"10",target:{selector:".as-oil-cpc__purpose-container"},type:"waitcss",waitTime:"250"}],type:"list"},name:"OPEN_OPTIONS"},{action:{actions:[{consents:[{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Information storage and access","Opbevaring af og adgang til oplysninger på din enhed"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Information storage and access","Opbevaring af og adgang til oplysninger på din enhed"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"D"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personlige annoncer","Personalisation"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personlige annoncer","Personalisation"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"E"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Annoncevalg, levering og rapportering","Ad selection, delivery, reporting"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Annoncevalg, levering og rapportering","Ad selection, delivery, reporting"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"F"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personalisering af indhold","Content selection, delivery, reporting"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personalisering af indhold","Content selection, delivery, reporting"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"E"},{matcher:{parent:{childFilter:{target:{selector:".as-oil-cpc__purpose-header",textFilter:["Måling","Measurement"]}},selector:".as-oil-cpc__purpose-container"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{childFilter:{target:{selector:".as-oil-cpc__purpose-header",textFilter:["Måling","Measurement"]}},selector:".as-oil-cpc__purpose-container"},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"B"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:"Google"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:"Google"},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"F"}],type:"consent"}],type:"list"},name:"DO_CONSENT"},{action:{target:{selector:".as-oil__btn-optin"},type:"click"},name:"SAVE_CONSENT"},{action:{target:{selector:"div.as-oil"},type:"hide"},name:"HIDE_CMP"}]},optanon:{detectors:[{presentMatcher:{target:{selector:"#optanon-menu, .optanon-alert-box-wrapper"},type:"css"},showingMatcher:{target:{displayFilter:!0,selector:".optanon-alert-box-wrapper"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".optanon-alert-box-wrapper .optanon-toggle-display, a[onclick*='OneTrust.ToggleInfoDisplay()'], a[onclick*='Optanon.ToggleInfoDisplay()']"},type:"click"}],type:"list"},name:"OPEN_OPTIONS"},{action:{actions:[{target:{selector:".preference-menu-item #Your-privacy"},type:"click"},{target:{selector:"#optanon-vendor-consent-text"},type:"click"},{action:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},target:{selector:"#optanon-vendor-consent-list .vendor-item"},type:"foreach"},{target:{selector:".vendor-consent-back-link"},type:"click"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-performance"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-performance"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-functional"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-functional"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-advertising"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-advertising"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-social"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-social"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Social Media Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Social Media Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalisation"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalisation"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Site monitoring cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Site monitoring cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Third party privacy-enhanced content"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Third party privacy-enhanced content"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Performance & Advertising Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Performance & Advertising Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Information storage and access"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Information storage and access"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"D"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad selection, delivery, reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad selection, delivery, reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content selection, delivery, reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content selection, delivery, reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Measurement"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Measurement"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Recommended Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Recommended Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Unclassified Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Unclassified Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Analytical Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Analytical Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Marketing Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Marketing Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalization"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalization"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad Selection, Delivery & Reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad Selection, Delivery & Reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content Selection, Delivery & Reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content Selection, Delivery & Reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"}],type:"list"},name:"DO_CONSENT"},{action:{parent:{selector:".optanon-save-settings-button"},target:{selector:".optanon-white-button-middle"},type:"click"},name:"SAVE_CONSENT"},{action:{actions:[{target:{selector:"#optanon-popup-wrapper"},type:"hide"},{target:{selector:"#optanon-popup-bg"},type:"hide"},{target:{selector:".optanon-alert-box-wrapper"},type:"hide"}],type:"list"},name:"HIDE_CMP"}]},quantcast2:{detectors:[{presentMatcher:{target:{selector:"[data-tracking-opt-in-overlay]"},type:"css"},showingMatcher:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-learn-more]"},type:"css"}}],methods:[{action:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-learn-more]"},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{type:"wait",waitTime:500},{action:{actions:[{target:{selector:"div",textFilter:["Information storage and access"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"D"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Personalization"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"F"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Ad selection, delivery, reporting"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"F"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Content selection, delivery, reporting"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"E"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Measurement"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"B"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Other Partners"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},type:"ifcss"}],type:"list"},parent:{childFilter:{target:{selector:"input"}},selector:"[data-tracking-opt-in-overlay] > div > div"},target:{childFilter:{target:{selector:"input"}},selector:":scope > div"},type:"foreach"}],type:"list"},name:"DO_CONSENT"},{action:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-save]"},type:"click"},name:"SAVE_CONSENT"}]},springer:{detectors:[{presentMatcher:{parent:null,target:{selector:".cmp-app_gdpr"},type:"css"},showingMatcher:{parent:null,target:{displayFilter:!0,selector:".cmp-popup_popup"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".cmp-intro_rejectAll"},type:"click"},{type:"wait",waitTime:250},{target:{selector:".cmp-purposes_purposeItem:not(.cmp-purposes_selectedPurpose)"},type:"click"}],type:"list"},name:"OPEN_OPTIONS"},{action:{consents:[{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Przechowywanie informacji na urządzeniu lub dostęp do nich",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Przechowywanie informacji na urządzeniu lub dostęp do nich",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"D"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór podstawowych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór podstawowych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"F"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"F"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"E"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"E"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Stosowanie badań rynkowych w celu generowania opinii odbiorców",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Stosowanie badań rynkowych w celu generowania opinii odbiorców",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"X"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Opracowywanie i ulepszanie produktów",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Opracowywanie i ulepszanie produktów",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"X"}],type:"consent"},name:"DO_CONSENT"},{action:{target:{selector:".cmp-details_save"},type:"click"},name:"SAVE_CONSENT"}]},wordpressgdpr:{detectors:[{presentMatcher:{parent:null,target:{selector:".wpgdprc-consent-bar"},type:"css"},showingMatcher:{parent:null,target:{displayFilter:!0,selector:".wpgdprc-consent-bar"},type:"css"}}],methods:[{action:{parent:null,target:{selector:".wpgdprc-consent-bar .wpgdprc-consent-bar__settings",textFilter:null},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{target:{selector:".wpgdprc-consent-modal .wpgdprc-button",textFilter:"Eyeota"},type:"click"},{consents:[{description:"Eyeota Cookies",matcher:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Eyeota"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Eyeota"},target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},{target:{selector:".wpgdprc-consent-modal .wpgdprc-button",textFilter:"Advertising"},type:"click"},{consents:[{description:"Advertising Cookies",matcher:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Advertising"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Advertising"},target:{selector:"label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},name:"DO_CONSENT"},{action:{parent:null,target:{selector:".wpgdprc-button",textFilter:"Save my settings"},type:"click"},name:"SAVE_CONSENT"}]}},kn={autoconsent:gn,consentomatic:fn},bn=Object.freeze({__proto__:null,autoconsent:gn,consentomatic:fn,default:kn}); +!function(){"use strict";var e=class e{static setBase(t){e.base=t}static findElement(t,o=null,i=!1){let n=null;return n=null!=o?Array.from(o.querySelectorAll(t.selector)):null!=e.base?Array.from(e.base.querySelectorAll(t.selector)):Array.from(document.querySelectorAll(t.selector)),null!=t.textFilter&&(n=n.filter((e=>{const o=e.textContent.toLowerCase();if(Array.isArray(t.textFilter)){let e=!1;for(const i of t.textFilter)if(-1!==o.indexOf(i.toLowerCase())){e=!0;break}return e}return null!=t.textFilter&&-1!==o.indexOf(t.textFilter.toLowerCase())}))),null!=t.styleFilters&&(n=n.filter((e=>{const o=window.getComputedStyle(e);let i=!0;for(const e of t.styleFilters){const t=o[e.option];i=e.negated?i&&t!==e.value:i&&t===e.value}return i}))),null!=t.displayFilter&&(n=n.filter((e=>t.displayFilter?0!==e.offsetHeight:0===e.offsetHeight))),null!=t.iframeFilter&&(n=n.filter((()=>t.iframeFilter?window.location!==window.parent.location:window.location===window.parent.location))),null!=t.childFilter&&(n=n.filter((o=>{const i=e.base;e.setBase(o);const n=e.find(t.childFilter);return e.setBase(i),null!=n.target}))),i?n:(n.length>1&&console.warn("Multiple possible targets: ",n,t,o),n[0])}static find(t,o=!1){const i=[];if(null!=t.parent){const n=e.findElement(t.parent,null,o);if(null!=n){if(n instanceof Array)return n.forEach((n=>{const s=e.findElement(t.target,n,o);s instanceof Array?s.forEach((e=>{i.push({parent:n,target:e})})):i.push({parent:n,target:s})})),i;{const s=e.findElement(t.target,n,o);s instanceof Array?s.forEach((e=>{i.push({parent:n,target:e})})):i.push({parent:n,target:s})}}}else{const n=e.findElement(t.target,null,o);n instanceof Array?n.forEach((e=>{i.push({parent:null,target:e})})):i.push({parent:null,target:n})}return 0===i.length&&i.push({parent:null,target:null}),o?i:(1!==i.length&&console.warn("Multiple results found, even though multiple false",i),i[0])}};e.base=null;var t=e;function o(e){const o=t.find(e);return"css"===e.type?!!o.target:"checkbox"===e.type?!!o.target&&o.target.checked:void 0}async function i(e,c){switch(e.type){case"click":return async function(e){const o=t.find(e);null!=o.target&&o.target.click();return s(n)}(e);case"list":return async function(e,t){for(const o of e.actions)await i(o,t)}(e,c);case"consent":return async function(e,t){for(const n of e.consents){const e=-1!==t.indexOf(n.type);if(n.matcher&&n.toggleAction){o(n.matcher)!==e&&await i(n.toggleAction)}else e?await i(n.trueAction):await i(n.falseAction)}}(e,c);case"ifcss":return async function(e,o){const n=t.find(e);n.target?e.falseAction&&await i(e.falseAction,o):e.trueAction&&await i(e.trueAction,o)}(e,c);case"waitcss":return async function(e){await new Promise((o=>{let i=e.retries||10;const n=e.waitTime||250,s=()=>{const c=t.find(e);(e.negated&&c.target||!e.negated&&!c.target)&&i>0?(i-=1,setTimeout(s,n)):o()};s()}))}(e);case"foreach":return async function(e,o){const n=t.find(e,!0),s=t.base;for(const s of n)s.target&&(t.setBase(s.target),await i(e.action,o));t.setBase(s)}(e,c);case"hide":return async function(e){const o=t.find(e);o.target&&o.target.classList.add("Autoconsent-Hidden")}(e);case"slide":return async function(e){const o=t.find(e),i=t.find(e.dragTarget);if(o.target){const e=o.target.getBoundingClientRect(),t=i.target.getBoundingClientRect();let n=t.top-e.top,s=t.left-e.left;"y"===this.config.axis.toLowerCase()&&(s=0),"x"===this.config.axis.toLowerCase()&&(n=0);const c=window.screenX+e.left+e.width/2,r=window.screenY+e.top+e.height/2,a=e.left+e.width/2,l=e.top+e.height/2,p=document.createEvent("MouseEvents");p.initMouseEvent("mousedown",!0,!0,window,0,c,r,a,l,!1,!1,!1,!1,0,o.target);const d=document.createEvent("MouseEvents");d.initMouseEvent("mousemove",!0,!0,window,0,c+s,r+n,a+s,l+n,!1,!1,!1,!1,0,o.target);const u=document.createEvent("MouseEvents");u.initMouseEvent("mouseup",!0,!0,window,0,c+s,r+n,a+s,l+n,!1,!1,!1,!1,0,o.target),o.target.dispatchEvent(p),await this.waitTimeout(10),o.target.dispatchEvent(d),await this.waitTimeout(10),o.target.dispatchEvent(u)}}(e);case"close":return async function(){window.close()}();case"wait":return async function(e){await s(e.waitTime)}(e);case"eval":return async function(e){return console.log("eval!",e.code),new Promise((t=>{try{e.async?(window.eval(e.code),setTimeout((()=>{t(window.eval("window.__consentCheckResult"))}),e.timeout||250)):t(window.eval(e.code))}catch(o){console.warn("eval error",o,e.code),t(!1)}}))}(e);default:throw new Error("Unknown action type: "+e.type)}}var n=0;function s(e){return new Promise((t=>{setTimeout((()=>{t()}),e)}))}function c(){return crypto&&void 0!==crypto.randomUUID?crypto.randomUUID():Math.random().toString()}var r=class{constructor(e,t=1e3){this.id=e,this.promise=new Promise(((e,t)=>{this.resolve=e,this.reject=t})),this.timer=window.setTimeout((()=>{this.reject(new Error("timeout"))}),t)}},a={pending:new Map,sendContentMessage:null};var l={EVAL_0:()=>console.log(1),EVAL_CONSENTMANAGER_1:()=>window.__cmp&&"object"==typeof __cmp("getCMPData"),EVAL_CONSENTMANAGER_2:()=>!__cmp("consentStatus").userChoiceExists,EVAL_CONSENTMANAGER_3:()=>__cmp("setConsent",0),EVAL_CONSENTMANAGER_4:()=>__cmp("setConsent",1),EVAL_CONSENTMANAGER_5:()=>__cmp("consentStatus").userChoiceExists,EVAL_COOKIEBOT_1:()=>!!window.Cookiebot,EVAL_COOKIEBOT_2:()=>!window.Cookiebot.hasResponse&&!0===window.Cookiebot.dialog?.visible,EVAL_COOKIEBOT_3:()=>window.Cookiebot.withdraw()||!0,EVAL_COOKIEBOT_4:()=>window.Cookiebot.hide()||!0,EVAL_COOKIEBOT_5:()=>!0===window.Cookiebot.declined,EVAL_KLARO_1:()=>{const e=globalThis.klaroConfig||globalThis.klaro?.getManager&&globalThis.klaro.getManager().config;if(!e)return!0;const t=(e.services||e.apps).filter((e=>!e.required)).map((e=>e.name));if(klaro&&klaro.getManager){const e=klaro.getManager();return t.every((t=>!e.consents[t]))}if(klaroConfig&&"cookie"===klaroConfig.storageMethod){const e=klaroConfig.cookieName||klaroConfig.storageName,o=JSON.parse(decodeURIComponent(document.cookie.split(";").find((t=>t.trim().startsWith(e))).split("=")[1]));return Object.keys(o).filter((e=>t.includes(e))).every((e=>!1===o[e]))}},EVAL_KLARO_OPEN_POPUP:()=>{klaro.show(void 0,!0)},EVAL_KLARO_TRY_API_OPT_OUT:()=>{if(window.klaro&&"function"==typeof klaro.show&&"function"==typeof klaro.getManager)try{return klaro.getManager().changeAll(!1),klaro.getManager().saveAndApplyConsents(),!0}catch(e){return console.warn(e),!1}return!1},EVAL_ONETRUST_1:()=>window.OnetrustActiveGroups.split(",").filter((e=>e.length>0)).length<=1,EVAL_TRUSTARC_TOP:()=>window&&window.truste&&"0"===window.truste.eu.bindMap.prefCookie,EVAL_TRUSTARC_FRAME_TEST:()=>window&&window.QueryString&&"0"===window.QueryString.preferences,EVAL_TRUSTARC_FRAME_GTM:()=>window&&window.QueryString&&"1"===window.QueryString.gtm,EVAL_ABC_TEST:()=>document.cookie.includes("trackingconsent"),EVAL_ADROLL_0:()=>!document.cookie.includes("__adroll_fpc"),EVAL_ALMACMP_0:()=>document.cookie.includes('"name":"Google","consent":false'),EVAL_AFFINITY_SERIF_COM_0:()=>document.cookie.includes("serif_manage_cookies_viewed")&&!document.cookie.includes("serif_allow_analytics"),EVAL_ARBEITSAGENTUR_TEST:()=>document.cookie.includes("cookie_consent=denied"),EVAL_AXEPTIO_0:()=>document.cookie.includes("axeptio_authorized_vendors=%2C%2C"),EVAL_BAHN_TEST:()=>1===utag.gdpr.getSelectedCategories().length,EVAL_BING_0:()=>document.cookie.includes("AD=0"),EVAL_BLOCKSY_0:()=>document.cookie.includes("blocksy_cookies_consent_accepted=no"),EVAL_BORLABS_0:()=>!JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>-1!==e.indexOf("borlabs-cookie"))).split("=",2)[1])).consents.statistics,EVAL_BUNDESREGIERUNG_DE_0:()=>document.cookie.match("cookie-allow-tracking=0"),EVAL_CANVA_0:()=>!document.cookie.includes("gtm_fpc_engagement_event"),EVAL_CC_BANNER2_0:()=>!!document.cookie.match(/sncc=[^;]+D%3Dtrue/),EVAL_CLICKIO_0:()=>document.cookie.includes("__lxG__consent__v2_daisybit="),EVAL_CLINCH_0:()=>document.cookie.includes("ctc_rejected=1"),EVAL_COOKIECONSENT2_TEST:()=>document.cookie.includes("cc_cookie="),EVAL_COOKIECONSENT3_TEST:()=>document.cookie.includes("cc_cookie="),EVAL_COINBASE_0:()=>JSON.parse(decodeURIComponent(document.cookie.match(/cm_(eu|default)_preferences=([0-9a-zA-Z\\{\\}\\[\\]%:]*);?/)[2])).consent.length<=1,EVAL_COMPLIANZ_BANNER_0:()=>document.cookie.includes("cmplz_banner-status=dismissed"),EVAL_COOKIE_LAW_INFO_0:()=>CLI.disableAllCookies()||CLI.reject_close()||!0,EVAL_COOKIE_LAW_INFO_1:()=>-1===document.cookie.indexOf("cookielawinfo-checkbox-non-necessary=yes"),EVAL_COOKIE_LAW_INFO_DETECT:()=>!!window.CLI,EVAL_COOKIE_MANAGER_POPUP_0:()=>!1===JSON.parse(document.cookie.split(";").find((e=>e.trim().startsWith("CookieLevel"))).split("=")[1]).social,EVAL_COOKIEALERT_0:()=>document.querySelector("body").removeAttribute("style")||!0,EVAL_COOKIEALERT_1:()=>document.querySelector("body").removeAttribute("style")||!0,EVAL_COOKIEALERT_2:()=>!0===window.CookieConsent.declined,EVAL_COOKIEFIRST_0:()=>{return!1===(e=JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>-1!==e.indexOf("cookiefirst"))).trim()).split("=")[1])).performance&&!1===e.functional&&!1===e.advertising;var e},EVAL_COOKIEFIRST_1:()=>document.querySelectorAll("button[data-cookiefirst-accent-color=true][role=checkbox]:not([disabled])").forEach((e=>"true"===e.getAttribute("aria-checked")&&e.click()))||!0,EVAL_COOKIEINFORMATION_0:()=>CookieInformation.declineAllCategories()||!0,EVAL_COOKIEINFORMATION_1:()=>CookieInformation.submitAllCategories()||!0,EVAL_COOKIEINFORMATION_2:()=>document.cookie.includes("CookieInformationConsent="),EVAL_COOKIEYES_0:()=>document.cookie.includes("advertisement:no"),EVAL_DAILYMOTION_0:()=>!!document.cookie.match("dm-euconsent-v2"),EVAL_DNDBEYOND_TEST:()=>document.cookie.includes("cookie-consent=denied"),EVAL_DSGVO_0:()=>!document.cookie.includes("sp_dsgvo_cookie_settings"),EVAL_DUNELM_0:()=>document.cookie.includes("cc_functional=0")&&document.cookie.includes("cc_targeting=0"),EVAL_ETSY_0:()=>document.querySelectorAll(".gdpr-overlay-body input").forEach((e=>{e.checked=!1}))||!0,EVAL_ETSY_1:()=>document.querySelector(".gdpr-overlay-view button[data-wt-overlay-close]").click()||!0,EVAL_EU_COOKIE_COMPLIANCE_0:()=>-1===document.cookie.indexOf("cookie-agreed=2"),EVAL_EU_COOKIE_LAW_0:()=>!document.cookie.includes("euCookie"),EVAL_EZOIC_0:()=>ezCMP.handleAcceptAllClick(),EVAL_EZOIC_1:()=>!!document.cookie.match(/ez-consent-tcf/),EVAL_FIDES_DETECT_POPUP:()=>window.Fides?.initialized,EVAL_GOOGLE_0:()=>!!document.cookie.match(/SOCS=CAE/),EVAL_HEMA_TEST_0:()=>document.cookie.includes("cookies_rejected=1"),EVAL_IUBENDA_0:()=>document.querySelectorAll(".purposes-item input[type=checkbox]:not([disabled])").forEach((e=>{e.checked&&e.click()}))||!0,EVAL_IUBENDA_1:()=>!!document.cookie.match(/_iub_cs-\d+=/),EVAL_IWINK_TEST:()=>document.cookie.includes("cookie_permission_granted=no"),EVAL_JQUERY_COOKIEBAR_0:()=>!document.cookie.includes("cookies-state=accepted"),EVAL_KETCH_TEST:()=>document.cookie.includes("_ketch_consent_v1_"),EVAL_MEDIAVINE_0:()=>document.querySelectorAll('[data-name="mediavine-gdpr-cmp"] input[type=checkbox]').forEach((e=>e.checked&&e.click()))||!0,EVAL_MICROSOFT_0:()=>Array.from(document.querySelectorAll("div > button")).filter((e=>e.innerText.match("Reject|Ablehnen")))[0].click()||!0,EVAL_MICROSOFT_1:()=>Array.from(document.querySelectorAll("div > button")).filter((e=>e.innerText.match("Accept|Annehmen")))[0].click()||!0,EVAL_MICROSOFT_2:()=>!!document.cookie.match("MSCC|GHCC"),EVAL_MOOVE_0:()=>document.querySelectorAll("#moove_gdpr_cookie_modal input").forEach((e=>{e.disabled||(e.checked="moove_gdpr_strict_cookies"===e.name||"moove_gdpr_strict_cookies"===e.id)}))||!0,EVAL_ONENINETWO_0:()=>document.cookie.includes("CC_ADVERTISING=NO")&&document.cookie.includes("CC_ANALYTICS=NO"),EVAL_OPENAI_TEST:()=>document.cookie.includes("oai-allow-ne=false"),EVAL_OPERA_0:()=>document.cookie.includes("cookie_consent_essential=true")&&!document.cookie.includes("cookie_consent_marketing=true"),EVAL_PAYPAL_0:()=>!0===document.cookie.includes("cookie_prefs"),EVAL_PRIMEBOX_0:()=>!document.cookie.includes("cb-enabled=accepted"),EVAL_PUBTECH_0:()=>document.cookie.includes("euconsent-v2")&&(document.cookie.match(/.YAAAAAAAAAAA/)||document.cookie.match(/.aAAAAAAAAAAA/)||document.cookie.match(/.YAAACFgAAAAA/)),EVAL_REDDIT_0:()=>document.cookie.includes("eu_cookie={%22opted%22:true%2C%22nonessential%22:false}"),EVAL_ROBLOX_TEST:()=>document.cookie.includes("RBXcb"),EVAL_SKYSCANNER_TEST:()=>document.cookie.match(/gdpr=[^;]*adverts:::false/)&&!document.cookie.match(/gdpr=[^;]*init:::true/),EVAL_SIRDATA_UNBLOCK_SCROLL:()=>(document.documentElement.classList.forEach((e=>{e.startsWith("sd-cmp-")&&document.documentElement.classList.remove(e)})),!0),EVAL_SNIGEL_0:()=>!!document.cookie.match("snconsent"),EVAL_STEAMPOWERED_0:()=>2===JSON.parse(decodeURIComponent(document.cookie.split(";").find((e=>e.trim().startsWith("cookieSettings"))).split("=")[1])).preference_state,EVAL_SVT_TEST:()=>document.cookie.includes('cookie-consent-1={"optedIn":true,"functionality":false,"statistics":false}'),EVAL_TAKEALOT_0:()=>document.body.classList.remove("freeze")||(document.body.style="")||!0,EVAL_TARTEAUCITRON_0:()=>tarteaucitron.userInterface.respondAll(!1)||!0,EVAL_TARTEAUCITRON_1:()=>tarteaucitron.userInterface.respondAll(!0)||!0,EVAL_TARTEAUCITRON_2:()=>document.cookie.match(/tarteaucitron=[^;]*/)?.[0].includes("false"),EVAL_TAUNTON_TEST:()=>document.cookie.includes("taunton_user_consent_submitted=true"),EVAL_TEALIUM_0:()=>void 0!==window.utag&&"object"==typeof utag.gdpr,EVAL_TEALIUM_1:()=>utag.gdpr.setConsentValue(!1)||!0,EVAL_TEALIUM_DONOTSELL:()=>utag.gdpr.dns?.setDnsState(!1)||!0,EVAL_TEALIUM_2:()=>utag.gdpr.setConsentValue(!0)||!0,EVAL_TEALIUM_3:()=>1!==utag.gdpr.getConsentState(),EVAL_TEALIUM_DONOTSELL_CHECK:()=>1!==utag.gdpr.dns?.getDnsState(),EVAL_TESLA_TEST:()=>document.cookie.includes("tsla-cookie-consent=rejected"),EVAL_TESTCMP_STEP:()=>!!document.querySelector("#reject-all"),EVAL_TESTCMP_0:()=>"button_clicked"===window.results.results[0],EVAL_TESTCMP_COSMETIC_0:()=>"banner_hidden"===window.results.results[0],EVAL_THEFREEDICTIONARY_0:()=>cmpUi.showPurposes()||cmpUi.rejectAll()||!0,EVAL_THEFREEDICTIONARY_1:()=>cmpUi.allowAll()||!0,EVAL_THEVERGE_0:()=>document.cookie.includes("_duet_gdpr_acknowledged=1"),EVAL_TWCC_TEST:()=>document.cookie.includes("twCookieConsent="),EVAL_UBUNTU_COM_0:()=>document.cookie.includes("_cookies_accepted=essential"),EVAL_UK_COOKIE_CONSENT_0:()=>!document.cookie.includes("catAccCookies"),EVAL_USERCENTRICS_API_0:()=>"object"==typeof UC_UI,EVAL_USERCENTRICS_API_1:()=>!!UC_UI.closeCMP(),EVAL_USERCENTRICS_API_2:()=>!!UC_UI.denyAllConsents(),EVAL_USERCENTRICS_API_3:()=>!!UC_UI.acceptAllConsents(),EVAL_USERCENTRICS_API_4:()=>!!UC_UI.closeCMP(),EVAL_USERCENTRICS_API_5:()=>!0===UC_UI.areAllConsentsAccepted(),EVAL_USERCENTRICS_API_6:()=>!1===UC_UI.areAllConsentsAccepted(),EVAL_USERCENTRICS_BUTTON_0:()=>JSON.parse(localStorage.getItem("usercentrics")).consents.every((e=>e.isEssential||!e.consentStatus)),EVAL_WAITROSE_0:()=>Array.from(document.querySelectorAll("label[id$=cookies-deny-label]")).forEach((e=>e.click()))||!0,EVAL_WAITROSE_1:()=>document.cookie.includes("wtr_cookies_advertising=0")&&document.cookie.includes("wtr_cookies_analytics=0"),EVAL_WP_COOKIE_NOTICE_0:()=>document.cookie.includes("wpl_viewed_cookie=no"),EVAL_XE_TEST:()=>document.cookie.includes("xeConsentState={%22performance%22:false%2C%22marketing%22:false%2C%22compliance%22:false}"),EVAL_XING_0:()=>document.cookie.includes("userConsent=%7B%22marketing%22%3Afalse"),EVAL_YOUTUBE_DESKTOP_0:()=>!!document.cookie.match(/SOCS=CAE/),EVAL_YOUTUBE_MOBILE_0:()=>!!document.cookie.match(/SOCS=CAE/)};var p={main:!0,frame:!1,urlPattern:""},d=class{constructor(e){this.runContext=p,this.autoconsent=e}get hasSelfTest(){throw new Error("Not Implemented")}get isIntermediate(){throw new Error("Not Implemented")}get isCosmetic(){throw new Error("Not Implemented")}mainWorldEval(e){const t=l[e];if(!t)return console.warn("Snippet not found",e),Promise.resolve(!1);const o=this.autoconsent.config.logs;if(this.autoconsent.config.isMainWorld){o.evals&&console.log("inline eval:",e,t);let i=!1;try{i=!!t.call(globalThis)}catch(t){o.evals&&console.error("error evaluating rule",e,t)}return Promise.resolve(i)}const i=`(${t.toString()})()`;return o.evals&&console.log("async eval:",e,i),function(e,t){const o=c();a.sendContentMessage({type:"eval",id:o,code:e,snippetId:t});const i=new r(o);return a.pending.set(i.id,i),i.promise}(i,e).catch((t=>(o.evals&&console.error("error evaluating rule",e,t),!1)))}checkRunContext(){const e={...p,...this.runContext},t=window.top===window;return!(t&&!e.main)&&(!(!t&&!e.frame)&&!(e.urlPattern&&!window.location.href.match(e.urlPattern)))}detectCmp(){throw new Error("Not Implemented")}async detectPopup(){return!1}optOut(){throw new Error("Not Implemented")}optIn(){throw new Error("Not Implemented")}openCmp(){throw new Error("Not Implemented")}async test(){return Promise.resolve(!0)}click(e,t=!1){return this.autoconsent.domActions.click(e,t)}elementExists(e){return this.autoconsent.domActions.elementExists(e)}elementVisible(e,t){return this.autoconsent.domActions.elementVisible(e,t)}waitForElement(e,t){return this.autoconsent.domActions.waitForElement(e,t)}waitForVisible(e,t,o){return this.autoconsent.domActions.waitForVisible(e,t,o)}waitForThenClick(e,t,o){return this.autoconsent.domActions.waitForThenClick(e,t,o)}wait(e){return this.autoconsent.domActions.wait(e)}hide(e,t){return this.autoconsent.domActions.hide(e,t)}prehide(e){return this.autoconsent.domActions.prehide(e)}undoPrehide(){return this.autoconsent.domActions.undoPrehide()}querySingleReplySelector(e,t){return this.autoconsent.domActions.querySingleReplySelector(e,t)}querySelectorChain(e){return this.autoconsent.domActions.querySelectorChain(e)}elementSelector(e){return this.autoconsent.domActions.elementSelector(e)}},u=class extends d{constructor(e,t){super(t),this.rule=e,this.name=e.name,this.runContext=e.runContext||p}get hasSelfTest(){return!!this.rule.test}get isIntermediate(){return!!this.rule.intermediate}get isCosmetic(){return!!this.rule.cosmetic}get prehideSelectors(){return this.rule.prehideSelectors}async detectCmp(){return!!this.rule.detectCmp&&this._runRulesParallel(this.rule.detectCmp)}async detectPopup(){return!!this.rule.detectPopup&&this._runRulesSequentially(this.rule.detectPopup)}async optOut(){const e=this.autoconsent.config.logs;return!!this.rule.optOut&&(e.lifecycle&&console.log("Initiated optOut()",this.rule.optOut),this._runRulesSequentially(this.rule.optOut))}async optIn(){const e=this.autoconsent.config.logs;return!!this.rule.optIn&&(e.lifecycle&&console.log("Initiated optIn()",this.rule.optIn),this._runRulesSequentially(this.rule.optIn))}async openCmp(){return!!this.rule.openCmp&&this._runRulesSequentially(this.rule.openCmp)}async test(){return this.hasSelfTest?this._runRulesSequentially(this.rule.test):super.test()}async evaluateRuleStep(e){const t=[],o=this.autoconsent.config.logs;if(e.exists&&t.push(this.elementExists(e.exists)),e.visible&&t.push(this.elementVisible(e.visible,e.check)),e.eval){const o=this.mainWorldEval(e.eval);t.push(o)}if(e.waitFor&&t.push(this.waitForElement(e.waitFor,e.timeout)),e.waitForVisible&&t.push(this.waitForVisible(e.waitForVisible,e.timeout,e.check)),e.click&&t.push(this.click(e.click,e.all)),e.waitForThenClick&&t.push(this.waitForThenClick(e.waitForThenClick,e.timeout,e.all)),e.wait&&t.push(this.wait(e.wait)),e.hide&&t.push(this.hide(e.hide,e.method)),e.if){if(!e.if.exists&&!e.if.visible)return console.error("invalid conditional rule",e.if),!1;const i=await this.evaluateRuleStep(e.if);o.rulesteps&&console.log("Condition is",i),i?t.push(this._runRulesSequentially(e.then)):e.else?t.push(this._runRulesSequentially(e.else)):t.push(!0)}if(e.any){for(const t of e.any)if(await this.evaluateRuleStep(t))return!0;return!1}if(0===t.length)return o.errors&&console.warn("Unrecognized rule",e),!1;return(await Promise.all(t)).reduce(((e,t)=>e&&t),!0)}async _runRulesParallel(e){const t=e.map((e=>this.evaluateRuleStep(e)));return(await Promise.all(t)).every((e=>!!e))}async _runRulesSequentially(e){const t=this.autoconsent.config.logs;for(const o of e){t.rulesteps&&console.log("Running rule...",o);const e=await this.evaluateRuleStep(o);if(t.rulesteps&&console.log("...rule result",e),!e&&!o.optional)return!1}return!0}},h=class{constructor(e,t){this.name=e,this.config=t,this.methods=new Map,this.runContext=p,this.isCosmetic=!1,t.methods.forEach((e=>{e.action&&this.methods.set(e.name,e.action)})),this.hasSelfTest=!1}get isIntermediate(){return!1}checkRunContext(){return!0}async detectCmp(){return this.config.detectors.map((e=>o(e.presentMatcher))).some((e=>!!e))}async detectPopup(){return this.config.detectors.map((e=>o(e.showingMatcher))).some((e=>!!e))}async executeAction(e,t){return!this.methods.has(e)||i(this.methods.get(e),t)}async optOut(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),await this.executeAction("HIDE_CMP"),await this.executeAction("DO_CONSENT",[]),await this.executeAction("SAVE_CONSENT"),!0}async optIn(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),await this.executeAction("HIDE_CMP"),await this.executeAction("DO_CONSENT",["D","A","B","E","F","X"]),await this.executeAction("SAVE_CONSENT"),!0}async openCmp(){return await this.executeAction("HIDE_CMP"),await this.executeAction("OPEN_OPTIONS"),!0}async test(){return!0}};function m(e="autoconsent-css-rules"){const t=`style#${e}`,o=document.querySelector(t);if(o&&o instanceof HTMLStyleElement)return o;{const t=document.head||document.getElementsByTagName("head")[0]||document.documentElement,o=document.createElement("style");return o.id=e,t.appendChild(o),o}}function A(e){return`${"opacity"===e?"opacity: 0":"display: none"} !important; z-index: -1 !important; pointer-events: none !important;`}function g(e,t,o="display"){const i=`${t} { ${A(o)} } `;return e instanceof HTMLStyleElement&&(e.innerText+=i,t.length>0)}async function f(e,t,o){const i=await e();return!i&&t>0?new Promise((i=>{setTimeout((async()=>{i(f(e,t-1,o))}),o)})):Promise.resolve(i)}function k(e){if(!e)return!1;if(null!==e.offsetParent)return!0;{const t=window.getComputedStyle(e);if("fixed"===t.position&&"none"!==t.display)return!0}return!1}function b(e){const t={enabled:!0,autoAction:"optOut",disabledCmps:[],enablePrehide:!0,enableCosmeticRules:!0,detectRetries:20,isMainWorld:!1,prehideTimeout:2e3,enableFilterList:!1,logs:{lifecycle:!1,rulesteps:!1,evals:!1,errors:!0,messages:!1}},o=(i=t,globalThis.structuredClone?structuredClone(i):JSON.parse(JSON.stringify(i)));var i;for(const i of Object.keys(t))void 0!==e[i]&&(o[i]=e[i]);return o}var y="#truste-show-consent",w="#truste-consent-track",v=[class extends d{constructor(e){super(e),this.name="TrustArc-top",this.prehideSelectors=[".trustarc-banner-container",`.truste_popframe,.truste_overlay,.truste_box_overlay,${w}`],this.runContext={main:!0,frame:!1},this._shortcutButton=null,this._optInDone=!1}get hasSelfTest(){return!0}get isIntermediate(){return!this._optInDone&&!this._shortcutButton}get isCosmetic(){return!1}async detectCmp(){const e=this.elementExists(`${y},${w}`);return e&&(this._shortcutButton=document.querySelector("#truste-consent-required")),e}async detectPopup(){return this.elementVisible(`#truste-consent-content,#trustarc-banner-overlay,${w}`,"any")}openFrame(){this.click(y)}async optOut(){return this._shortcutButton?(this._shortcutButton.click(),!0):(g(m(),`.truste_popframe, .truste_overlay, .truste_box_overlay, ${w}`),this.click(y),setTimeout((()=>{m().remove()}),1e4),!0)}async optIn(){return this._optInDone=!0,this.click("#truste-consent-button")}async openCmp(){return!0}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_TRUSTARC_TOP")}},class extends d{constructor(){super(...arguments),this.name="TrustArc-frame",this.runContext={main:!1,frame:!0,urlPattern:"^https://consent-pref\\.trustarc\\.com/\\?"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return!0}async detectPopup(){return this.elementVisible("#defaultpreferencemanager","any")&&this.elementVisible(".mainContent","any")}async navigateToSettings(){return await f((async()=>this.elementExists(".shp")||this.elementVisible(".advance","any")||this.elementExists(".switch span:first-child")),10,500),this.elementExists(".shp")&&this.click(".shp"),await this.waitForElement(".prefPanel",5e3),this.elementVisible(".advance","any")&&this.click(".advance"),await f((()=>this.elementVisible(".switch span:first-child","any")),5,1e3)}async optOut(){if(await this.mainWorldEval("EVAL_TRUSTARC_FRAME_TEST"))return!0;let e=3e3;return await this.mainWorldEval("EVAL_TRUSTARC_FRAME_GTM")&&(e=1500),await f((()=>"complete"===document.readyState),20,100),await this.waitForElement(".mainContent[aria-hidden=false]",e),!!this.click(".rejectAll")||(this.elementExists(".prefPanel")&&await this.waitForElement('.prefPanel[style="visibility: visible;"]',e),this.click("#catDetails0")?(this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",e),!0):this.click(".required")?(this.waitForThenClick("#gwt-debug-close_id",e),!0):(await this.navigateToSettings(),this.click(".switch span:nth-child(1):not(.active)",!0),this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",10*e),!0))}async optIn(){return this.click(".call")||(await this.navigateToSettings(),this.click(".switch span:nth-child(2)",!0),this.click(".submit"),this.waitForElement("#gwt-debug-close_id",3e5).then((()=>{this.click("#gwt-debug-close_id")}))),!0}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_TRUSTARC_FRAME_TEST")}},class extends d{constructor(){super(...arguments),this.name="Cybotcookiebot",this.prehideSelectors=["#CybotCookiebotDialog,#CybotCookiebotDialogBodyUnderlay,#dtcookie-container,#cookiebanner,#cb-cookieoverlay,.modal--cookie-banner,#cookiebanner_outer,#CookieBanner"]}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return await this.mainWorldEval("EVAL_COOKIEBOT_1")}async detectPopup(){return this.mainWorldEval("EVAL_COOKIEBOT_2")}async optOut(){await this.wait(500);let e=await this.mainWorldEval("EVAL_COOKIEBOT_3");return await this.wait(500),e=e&&await this.mainWorldEval("EVAL_COOKIEBOT_4"),e}async optIn(){return this.elementExists("#dtcookie-container")?this.click(".h-dtcookie-accept"):(this.click(".CybotCookiebotDialogBodyLevelButton:not(:checked):enabled",!0),this.click("#CybotCookiebotDialogBodyLevelButtonAccept"),this.click("#CybotCookiebotDialogBodyButtonAccept"),!0)}async test(){return await this.wait(500),await this.mainWorldEval("EVAL_COOKIEBOT_5")}},class extends d{constructor(){super(...arguments),this.name="Sourcepoint-frame",this.prehideSelectors=["div[id^='sp_message_container_'],.message-overlay","#sp_privacy_manager_container"],this.ccpaNotice=!1,this.ccpaPopup=!1,this.runContext={main:!0,frame:!0}}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){const e=new URL(location.href);return e.searchParams.has("message_id")&&"ccpa-notice.sp-prod.net"===e.hostname?(this.ccpaNotice=!0,!0):"ccpa-pm.sp-prod.net"===e.hostname?(this.ccpaPopup=!0,!0):("/index.html"===e.pathname||"/privacy-manager/index.html"===e.pathname||"/ccpa_pm/index.html"===e.pathname)&&(e.searchParams.has("message_id")||e.searchParams.has("requestUUID")||e.searchParams.has("consentUUID"))}async detectPopup(){return!!this.ccpaNotice||(this.ccpaPopup?await this.waitForElement(".priv-save-btn",2e3):(await this.waitForElement(".sp_choice_type_11,.sp_choice_type_12,.sp_choice_type_13,.sp_choice_type_ACCEPT_ALL,.sp_choice_type_SAVE_AND_EXIT",2e3),!this.elementExists(".sp_choice_type_9")))}async optIn(){return await this.waitForElement(".sp_choice_type_11,.sp_choice_type_ACCEPT_ALL",2e3),!!this.click(".sp_choice_type_11")||!!this.click(".sp_choice_type_ACCEPT_ALL")}isManagerOpen(){return"/privacy-manager/index.html"===location.pathname||"/ccpa_pm/index.html"===location.pathname}async optOut(){const e=this.autoconsent.config.logs;if(this.ccpaPopup){const e=document.querySelectorAll(".priv-purpose-container .sp-switch-arrow-block a.neutral.on .right");for(const t of e)t.click();const t=document.querySelectorAll(".priv-purpose-container .sp-switch-arrow-block a.switch-bg.on");for(const e of t)e.click();return this.click(".priv-save-btn")}if(!this.isManagerOpen()){if(!await this.waitForElement(".sp_choice_type_12,.sp_choice_type_13"))return!1;if(!this.elementExists(".sp_choice_type_12"))return this.click(".sp_choice_type_13");this.click(".sp_choice_type_12"),await f((()=>this.isManagerOpen()),200,100)}await this.waitForElement(".type-modal",2e4),this.waitForThenClick(".ccpa-stack .pm-switch[aria-checked=true] .slider",500,!0);try{const e=".sp_choice_type_REJECT_ALL",t=".reject-toggle",o=await Promise.race([this.waitForElement(e,2e3).then((e=>e?0:-1)),this.waitForElement(t,2e3).then((e=>e?1:-1)),this.waitForElement(".pm-features",2e3).then((e=>e?2:-1))]);if(0===o)return await this.waitForVisible(e),this.click(e);1===o?this.click(t):2===o&&(await this.waitForElement(".pm-features",1e4),this.click(".checked > span",!0),this.click(".chevron"))}catch(t){e.errors&&console.warn(t)}return this.click(".sp_choice_type_SAVE_AND_EXIT")}},class extends d{constructor(){super(...arguments),this.name="consentmanager.net",this.prehideSelectors=["#cmpbox,#cmpbox2"],this.apiAvailable=!1}get hasSelfTest(){return this.apiAvailable}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.apiAvailable=await this.mainWorldEval("EVAL_CONSENTMANAGER_1"),!!this.apiAvailable||this.elementExists("#cmpbox")}async detectPopup(){return this.apiAvailable?(await this.wait(500),await this.mainWorldEval("EVAL_CONSENTMANAGER_2")):this.elementVisible("#cmpbox .cmpmore","any")}async optOut(){return await this.wait(500),this.apiAvailable?await this.mainWorldEval("EVAL_CONSENTMANAGER_3"):!!this.click(".cmpboxbtnno")||(this.elementExists(".cmpwelcomeprpsbtn")?(this.click(".cmpwelcomeprpsbtn > a[aria-checked=true]",!0),this.click(".cmpboxbtnsave"),!0):(this.click(".cmpboxbtncustom"),await this.waitForElement(".cmptblbox",2e3),this.click(".cmptdchoice > a[aria-checked=true]",!0),this.click(".cmpboxbtnyescustomchoices"),this.hide("#cmpwrapper,#cmpbox","display"),!0))}async optIn(){return this.apiAvailable?await this.mainWorldEval("EVAL_CONSENTMANAGER_4"):this.click(".cmpboxbtnyes")}async test(){if(this.apiAvailable)return await this.mainWorldEval("EVAL_CONSENTMANAGER_5")}},class extends d{constructor(){super(...arguments),this.name="Evidon"}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("#_evidon_banner")}async detectPopup(){return this.elementVisible("#_evidon_banner","any")}async optOut(){return this.click("#_evidon-decline-button")||(g(m(),"#evidon-prefdiag-overlay,#evidon-prefdiag-background,#_evidon-background"),await this.waitForThenClick("#_evidon-option-button"),await this.waitForElement("#evidon-prefdiag-overlay",5e3),await this.wait(500),await this.waitForThenClick("#evidon-prefdiag-decline")),!0}async optIn(){return this.click("#_evidon-accept-button")}},class extends d{constructor(){super(...arguments),this.name="Onetrust",this.prehideSelectors=["#onetrust-banner-sdk,#onetrust-consent-sdk,.onetrust-pc-dark-filter,.js-consent-banner"],this.runContext={urlPattern:"^(?!.*https://www\\.nba\\.com/)"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("#onetrust-banner-sdk,#onetrust-pc-sdk")}async detectPopup(){return this.elementVisible("#onetrust-banner-sdk,#onetrust-pc-sdk","any")}async optOut(){return this.elementVisible("#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies","any")?this.click("#onetrust-reject-all-handler,.ot-pc-refuse-all-handler,.js-reject-cookies"):(this.elementExists("#onetrust-pc-btn-handler")?this.click("#onetrust-pc-btn-handler"):this.click(".ot-sdk-show-settings,button.js-cookie-settings"),await this.waitForElement("#onetrust-consent-sdk",2e3),await this.wait(1e3),this.click("#onetrust-consent-sdk input.category-switch-handler:checked,.js-editor-toggle-state:checked",!0),await this.wait(1e3),await this.waitForElement(".save-preference-btn-handler,.js-consent-save",2e3),this.click(".save-preference-btn-handler,.js-consent-save"),await this.waitForVisible("#onetrust-banner-sdk",5e3,"none"),!0)}async optIn(){return this.click("#onetrust-accept-btn-handler,#accept-recommended-btn-handler,.js-accept-cookies")}async test(){return await f((()=>this.mainWorldEval("EVAL_ONETRUST_1")),10,500)}},class extends d{constructor(){super(...arguments),this.name="Klaro",this.prehideSelectors=[".klaro"],this.settingsOpen=!1}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".klaro > .cookie-modal")?(this.settingsOpen=!0,!0):this.elementExists(".klaro > .cookie-notice")}async detectPopup(){return this.elementVisible(".klaro > .cookie-notice,.klaro > .cookie-modal","any")}async optOut(){return!!await this.mainWorldEval("EVAL_KLARO_TRY_API_OPT_OUT")||(!!this.click(".klaro .cn-decline")||(await this.mainWorldEval("EVAL_KLARO_OPEN_POPUP"),!!this.click(".klaro .cn-decline")||(this.click(".cm-purpose:not(.cm-toggle-all) > input:not(.half-checked,.required,.only-required),.cm-purpose:not(.cm-toggle-all) > div > input:not(.half-checked,.required,.only-required)",!0),this.click(".cm-btn-accept,.cm-button"))))}async optIn(){return!!this.click(".klaro .cm-btn-accept-all")||(this.settingsOpen?(this.click(".cm-purpose:not(.cm-toggle-all) > input.half-checked",!0),this.click(".cm-btn-accept")):this.click(".klaro .cookie-notice .cm-btn-success"))}async test(){return await this.mainWorldEval("EVAL_KLARO_1")}},class extends d{constructor(){super(...arguments),this.name="Uniconsent"}get prehideSelectors(){return[".unic",".modal:has(.unic)"]}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".unic .unic-box,.unic .unic-bar,.unic .unic-modal")}async detectPopup(){return this.elementVisible(".unic .unic-box,.unic .unic-bar,.unic .unic-modal","any")}async optOut(){if(await this.waitForElement(".unic button",1e3),document.querySelectorAll(".unic button").forEach((e=>{const t=e.textContent;(t.includes("Manage Options")||t.includes("Optionen verwalten"))&&e.click()})),await this.waitForElement(".unic input[type=checkbox]",1e3)){await this.waitForElement(".unic button",1e3),document.querySelectorAll(".unic input[type=checkbox]").forEach((e=>{e.checked&&e.click()}));for(const e of document.querySelectorAll(".unic button")){const t=e.textContent;for(const o of["Confirm Choices","Save Choices","Auswahl speichern"])if(t.includes(o))return e.click(),await this.wait(500),!0}}return!1}async optIn(){return this.waitForThenClick(".unic #unic-agree")}async test(){await this.wait(1e3);return!this.elementExists(".unic .unic-box,.unic .unic-bar")}},class extends d{constructor(){super(...arguments),this.prehideSelectors=[".cmp-root"],this.name="Conversant"}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists(".cmp-root .cmp-receptacle")}async detectPopup(){return this.elementVisible(".cmp-root .cmp-receptacle","any")}async optOut(){if(!await this.waitForThenClick(".cmp-main-button:not(.cmp-main-button--primary)"))return!1;if(!await this.waitForElement(".cmp-view-tab-tabs"))return!1;await this.waitForThenClick(".cmp-view-tab-tabs > :first-child"),await this.waitForThenClick(".cmp-view-tab-tabs > .cmp-view-tab--active:first-child");for(const e of Array.from(document.querySelectorAll(".cmp-accordion-item"))){e.querySelector(".cmp-accordion-item-title").click(),await f((()=>!!e.querySelector(".cmp-accordion-item-content.cmp-active")),10,50);const t=e.querySelector(".cmp-accordion-item-content.cmp-active");t.querySelectorAll(".cmp-toggle-actions .cmp-toggle-deny:not(.cmp-toggle-deny--active)").forEach((e=>e.click())),t.querySelectorAll(".cmp-toggle-actions .cmp-toggle-checkbox:not(.cmp-toggle-checkbox--active)").forEach((e=>e.click()))}return await this.click(".cmp-main-button:not(.cmp-main-button--primary)"),!0}async optIn(){return this.waitForThenClick(".cmp-main-button.cmp-main-button--primary")}async test(){return document.cookie.includes("cmp-data=0")}},class extends d{constructor(){super(...arguments),this.name="tiktok.com",this.runContext={urlPattern:"tiktok"}}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}getShadowRoot(){const e=document.querySelector("tiktok-cookie-banner");return e?e.shadowRoot:null}async detectCmp(){return this.elementExists("tiktok-cookie-banner")}async detectPopup(){return k(this.getShadowRoot().querySelector(".tiktok-cookie-banner"))}async optOut(){const e=this.autoconsent.config.logs,t=this.getShadowRoot().querySelector(".button-wrapper button:first-child");return t?(e.rulesteps&&console.log("[clicking]",t),t.click(),!0):(e.errors&&console.log("no decline button found"),!1)}async optIn(){const e=this.autoconsent.config.logs,t=this.getShadowRoot().querySelector(".button-wrapper button:last-child");return t?(e.rulesteps&&console.log("[clicking]",t),t.click(),!0):(e.errors&&console.log("no accept button found"),!1)}async test(){const e=document.cookie.match(/cookie-consent=([^;]+)/);if(!e)return!1;const t=JSON.parse(decodeURIComponent(e[1]));return Object.values(t).every((e=>"boolean"!=typeof e||!1===e))}},class extends d{constructor(){super(...arguments),this.name="airbnb",this.runContext={urlPattern:"^https://(www\\.)?airbnb\\.[^/]+/"},this.prehideSelectors=["div[data-testid=main-cookies-banner-container]",'div:has(> div:first-child):has(> div:last-child):has(> section [data-testid="strictly-necessary-cookies"])']}get hasSelfTest(){return!0}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("div[data-testid=main-cookies-banner-container]")}async detectPopup(){return this.elementVisible("div[data-testid=main-cookies-banner-container","any")}async optOut(){let e;for(await this.waitForThenClick("div[data-testid=main-cookies-banner-container] button._snbhip0");e=document.querySelector("[data-testid=modal-container] button[aria-checked=true]:not([disabled])");)e.click();return this.waitForThenClick("button[data-testid=save-btn]")}async optIn(){return this.waitForThenClick("div[data-testid=main-cookies-banner-container] button._148dgdpk")}async test(){return await f((()=>!!document.cookie.match("OptanonAlertBoxClosed")),20,200)}},class extends d{constructor(){super(...arguments),this.name="tumblr-com",this.runContext={urlPattern:"^https://(www\\.)?tumblr\\.com/"}}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}get prehideSelectors(){return["#cmp-app-container"]}async detectCmp(){return this.elementExists("#cmp-app-container")}async detectPopup(){return this.elementVisible("#cmp-app-container","any")}async optOut(){let e=document.querySelector("#cmp-app-container iframe"),t=e.contentDocument?.querySelector(".cmp-components-button.is-secondary");return!!t&&(t.click(),await f((()=>{const e=document.querySelector("#cmp-app-container iframe");return!!e.contentDocument?.querySelector(".cmp__dialog input")}),5,500),e=document.querySelector("#cmp-app-container iframe"),t=e.contentDocument?.querySelector(".cmp-components-button.is-secondary"),!!t&&(t.click(),!0))}async optIn(){const e=document.querySelector("#cmp-app-container iframe").contentDocument.querySelector(".cmp-components-button.is-primary");return!!e&&(e.click(),!0)}},class extends d{constructor(){super(...arguments),this.name="Admiral"}get hasSelfTest(){return!1}get isIntermediate(){return!1}get isCosmetic(){return!1}async detectCmp(){return this.elementExists("div > div[class*=Card] > div[class*=Frame] > div[class*=Pills] > button[class*=Pills__StyledPill]")}async detectPopup(){return this.elementVisible("div > div[class*=Card] > div[class*=Frame] > div[class*=Pills] > button[class*=Pills__StyledPill]","any")}async optOut(){const e="xpath///button[contains(., 'Afvis alle') or contains(., 'Reject all') or contains(., 'Odbaci sve') or contains(., 'Rechazar todo') or contains(., 'Atmesti visus') or contains(., 'Odmítnout vše') or contains(., 'Απόρριψη όλων') or contains(., 'Rejeitar tudo') or contains(., 'Tümünü reddet') or contains(., 'Отклонить все') or contains(., 'Noraidīt visu') or contains(., 'Avvisa alla') or contains(., 'Odrzuć wszystkie') or contains(., 'Alles afwijzen') or contains(., 'Отхвърляне на всички') or contains(., 'Rifiuta tutto') or contains(., 'Zavrni vse') or contains(., 'Az összes elutasítása') or contains(., 'Respingeți tot') or contains(., 'Alles ablehnen') or contains(., 'Tout rejeter') or contains(., 'Odmietnuť všetko') or contains(., 'Lükka kõik tagasi') or contains(., 'Hylkää kaikki')]";if(await this.waitForElement(e,500))return this.click(e);const t="xpath///button[contains(., 'Spara & avsluta') or contains(., 'Save & exit') or contains(., 'Uložit a ukončit') or contains(., 'Enregistrer et quitter') or contains(., 'Speichern & Verlassen') or contains(., 'Tallenna ja poistu') or contains(., 'Išsaugoti ir išeiti') or contains(., 'Opslaan & afsluiten') or contains(., 'Guardar y salir') or contains(., 'Shrani in zapri') or contains(., 'Uložiť a ukončiť') or contains(., 'Kaydet ve çıkış yap') or contains(., 'Сохранить и выйти') or contains(., 'Salvesta ja välju') or contains(., 'Salva ed esci') or contains(., 'Gem & afslut') or contains(., 'Αποθήκευση και έξοδος') or contains(., 'Saglabāt un iziet') or contains(., 'Mentés és kilépés') or contains(., 'Guardar e sair') or contains(., 'Zapisz & zakończ') or contains(., 'Salvare și ieșire') or contains(., 'Spremi i izađi') or contains(., 'Запазване и изход')]";if(await this.waitForThenClick("xpath///button[contains(., 'Zwecke') or contains(., 'Σκοποί') or contains(., 'Purposes') or contains(., 'Цели') or contains(., 'Eesmärgid') or contains(., 'Tikslai') or contains(., 'Svrhe') or contains(., 'Cele') or contains(., 'Účely') or contains(., 'Finalidades') or contains(., 'Mērķi') or contains(., 'Scopuri') or contains(., 'Fines') or contains(., 'Ändamål') or contains(., 'Finalités') or contains(., 'Doeleinden') or contains(., 'Tarkoitukset') or contains(., 'Scopi') or contains(., 'Amaçlar') or contains(., 'Nameni') or contains(., 'Célok') or contains(., 'Formål')]")&&await this.waitForVisible(t)){return this.elementSelector(t)[0].parentElement.parentElement.querySelectorAll("input[type=checkbox]:checked").forEach((e=>e.click())),this.click(t)}return!1}async optIn(){return this.click("xpath///button[contains(., 'Sprejmi vse') or contains(., 'Prihvati sve') or contains(., 'Godkänn alla') or contains(., 'Prijať všetko') or contains(., 'Принять все') or contains(., 'Aceptar todo') or contains(., 'Αποδοχή όλων') or contains(., 'Zaakceptuj wszystkie') or contains(., 'Accetta tutto') or contains(., 'Priimti visus') or contains(., 'Pieņemt visu') or contains(., 'Tümünü kabul et') or contains(., 'Az összes elfogadása') or contains(., 'Accept all') or contains(., 'Приемане на всички') or contains(., 'Accepter alle') or contains(., 'Hyväksy kaikki') or contains(., 'Tout accepter') or contains(., 'Alles accepteren') or contains(., 'Aktsepteeri kõik') or contains(., 'Přijmout vše') or contains(., 'Alles akzeptieren') or contains(., 'Aceitar tudo') or contains(., 'Acceptați tot')]")}}],_=class{constructor(e){this.autoconsentInstance=e}click(e,t=!1){const o=this.elementSelector(e);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[click]",e,t,o),o.length>0&&(t?o.forEach((e=>e.click())):o[0].click()),o.length>0}elementExists(e){return this.elementSelector(e).length>0}elementVisible(e,t){const o=this.elementSelector(e),i=new Array(o.length);return o.forEach(((e,t)=>{i[t]=k(e)})),"none"===t?i.every((e=>!e)):0!==i.length&&("any"===t?i.some((e=>e)):i.every((e=>e)))}waitForElement(e,t=1e4){const o=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForElement]",e),f((()=>this.elementSelector(e).length>0),o,200)}waitForVisible(e,t=1e4,o="any"){const i=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForVisible]",e),f((()=>this.elementVisible(e,o)),i,200)}async waitForThenClick(e,t=1e4,o=!1){return await this.waitForElement(e,t),this.click(e,o)}wait(e){return this.autoconsentInstance.config.logs.rulesteps&&this.autoconsentInstance.config.logs.waits&&console.log("[wait]",e),new Promise((t=>{setTimeout((()=>{t(!0)}),e)}))}hide(e,t){this.autoconsentInstance.config.logs.rulesteps&&console.log("[hide]",e);return g(m(),e,t)}prehide(e){const t=m("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[prehide]",t,location.href),g(t,e,"opacity")}undoPrehide(){const e=m("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[undoprehide]",e,location.href),e&&e.remove(),!!e}async createOrUpdateStyleSheet(e,t){return t||(t=new CSSStyleSheet),t=await t.replace(e)}removeStyleSheet(e){return!!e&&(e.replace(""),!0)}querySingleReplySelector(e,t=document){if(e.startsWith("aria/"))return[];if(e.startsWith("xpath/")){const o=e.slice(6),i=document.evaluate(o,t,null,XPathResult.ANY_TYPE,null);let n=null;const s=[];for(;n=i.iterateNext();)s.push(n);return s}return e.startsWith("text/")||e.startsWith("pierce/")?[]:t.shadowRoot?Array.from(t.shadowRoot.querySelectorAll(e)):Array.from(t.querySelectorAll(e))}querySelectorChain(e){let t,o=document;for(const i of e){if(t=this.querySingleReplySelector(i,o),0===t.length)return[];o=t[0]}return t}elementSelector(e){return"string"==typeof e?this.querySingleReplySelector(e):this.querySelectorChain(e)}};function C(){return{chars:new Map,code:void 0}}var x=new Uint8Array(0),S=class{constructor(e,t=3e4){this.trie=function(e){const t=C();for(let o=0;o figure.wp-block-image:has(> img[class^="wp-image-"][src^="https://www.sinhasannews.com/"][width="','"]:not([style^="width: 1px; height: 1px; position: absolute; left: -10000px; top: -"])',"acs, document.createElement, %2Fl%5C.parentNode%5C.insertBefore%5C(s%2F","%2Fvisit%2F%22%5D%5Btitle%5E%3D%22https%3A%2F%2F%22%5D, %5Btitle%5D",", OptanonConsent, groups%3DC0001%253A1%252CC0002%253A0%252CC000","rmnt, script, %2Fh%3DdecodeURIComponent%7CpopundersPerIP%2F",'.project-description [href^="/linkout?remoteUrl="][href*="',':not([style^="position: absolute; left: -5000px"])',"href-sanitizer, a%5Bhref%5E%3D%22https%3A%2F%2F","ra, oncontextmenu%7Condragstart%7Conselectstart",", OptanonAlertBoxClosed, %24currentDate%24","acs, document.querySelectorAll, popMagic","acs, addEventListener, google_ad_client","aost, String.prototype.charCodeAt, ai_","aopr, app_vars.force_disable_adblock","acs, document.addEventListener, ","taboola-below-article-thumbnails","acs, document.getElementById, ","no-fetch-if, googlesyndication","aopr, document.dispatchEvent","no-xhr-if, googlesyndication",", document.createElement, ","acs, String.fromCharCode, ","%2522%253Afalse%252C%2522",", document.oncontextmenu","%2522%253Atrue%252C%2522","aeld, DOMContentLoaded, ","nosiif, visibility, 1000","set-local-storage-item, ","%2522%3Afalse%252C%2522","trusted-click-element, ","set, blurred, false","acs, eval, replace","decodeURIComponent",'[target="_blank"]',"%22%3Afalse%2C%22","^script:has-text(",'[href^="https://','[href^="http://','[href="https://','[src^="https://','[data-testid="',"modal-backdrop","rmnt, script, ","BlockDetected","trusted-set-",".prototype.","contextmenu","no-fetch-if","otification",":has-text(","background",'[class*="','[class^="',"body,html","container","Container","decodeURI","div[class",'div[id^="',"div[style","document.","no-xhr-if","placehold",'[href*="',"#wpsafe-","AAAAAAAA","Detector","disclaim","nano-sib","nextFunc","noopFunc","nostif, ","nowebrtc",'.com/"]',"300x250","article","consent","Consent","content","display","keydown","message","Message","overlay","privacy","sidebar","sponsor","wrapper","-child","[data-","accept","Accept","aopr, ","banner","bottom","cookie","Cookie","google","nosiif","notice","nowoif","policy","Policy","script","widget",":has(",":not(","block","Block","click","deskt","disab","fixed","frame","modal","popup","video",".com","2%3A","aeld","body","butt","foot","gdpr","html","icky","ight","show","tion","true"," > ","%3D","%7C","age","box","div","ent","out","rap","set","__",", ",'"]',"%2","%5",'="',"00","ac","ad","Ad","al","an","ar","at","e-","ed","en","er","he","id","in","la","le","lo","od","ol","om","on","op","or","re","s_","s-","se","st","t-","te","ti","un","_","-",";",":",".","(",")","[","]","*","/","#","^","0","1","2","3","4","5","6","7","8","9","b","B","c","C","d","D","e","E","f","F","g","G","h","H","I","j","J","k","l","L","m","M","n","N","O","p","P","q","Q","R","s","S","t","T","u","U","v","V","w","W","x","y","Y","z"],T=["sandbox allow-forms allow-same-origin allow-scripts allow-modals allow-orientation-lock allow-pointer-lock allow-presentation allow-top-navigation","script-src 'self' 'unsafe-inline' 'unsafe-eval' "," *.google.com *.gstatic.com *.googleapis.com",".com *.google.com *.googletagmanager.com *.","script-src 'self' '*' 'unsafe-inline'","default-src 'unsafe-inline' 'self'","script-src 'self' 'unsafe-eval' "," *.google.com *.gstatic.com *.","t-src 'self' 'unsafe-inline' ","script-src * 'unsafe-inline'",".com *.googleapis.com *."," *.googletagmanager.com",".com *.bootstrapcdn.com","default-src 'self' *.","frame-src 'self' *"," *.cloudflare.com","child-src 'none';","worker-src 'none'","'unsafe-inline'"," data: blob:","*.googleapis","connect-src ","unsafe-eval'","child-src *"," *.gstatic","script-src","style-src ","frame-src","facebook","https://"," 'self'"," allow-",".com *.",".net *.","addthis","captcha","gstatic","youtube","defaul","disqus","google","https:","jquery","data:","http:","media","scrip","-src",".com",".net","n.cc"," *.","age","box","str","vic","yti"," '"," *","*.","al","am","an","as","cd","el","es","il","im","in","or","pi","st","ur","wi","wp"," ","-",";",":",".","'","*","/","3","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y"],O=["/homad-global-configs.schneevonmorgen.com/global_config","/videojs-vast-vpaid@2.0.2/bin/videojs_5.vast.vpaid.min","/etc.clientlibs/logitech-common/clientlibs/onetrust.","/pagead/managed/js/adsense/*/show_ads_impl","/pagead/managed/js/gpt/*/pubads_impl","/wrappermessagingwithoutdetection","/pagead/js/adsbygoogle.js","a-z]{8,15}\\.(?:com|net)\\/","/js/sdkloader/ima3.js","/js/sdkloader/ima3_d","/videojs-contrib-ads","/wp-content/plugins/","/wp-content/uploads/","/wp-content/themes/","/detroitchicago/","*/satellitelib-","/appmeasurement","/413gkwmt/init","/cdn-cgi/trace","/^https?:\\/\\/","[a-zA-Z0-9]{","/^https:\\/\\/","notification","\\/[a-z0-9]{","fingerprint","impression","[0-9a-z]{","/plugins/","affiliate","analytics","telemetry","(.+?\\.)?","/assets/","/images/","/pagead/","pageview","template","tracking","/public","300x250","ampaign","captcha","collect","consent","content","counter","default","metrics","privacy","[a-z]{","/embed","728x90","banner","bundle","client","cookie","detect","dn-cgi","google","iframe","module","prebid","script","source","widget",".aspx",".cgi?",".com/",".html","/api/","/beac","/img/","/java","/stat","0x600","block","click","count","event","manag","media","pixel","popup","tegra","theme","track","type=","video","visit",".css",".gif",".jpg",".min",".php",".png","/jqu","/js/","/lib","/log","/web","/wp-","468x","data","gdpr","gi-b","http","ight","mail","play","plug","publ","show","stat","uild","view",".js","/ad","=*&","age","com","ext","jax","key","log","new","sdk","tag","web","ync",":/","*/","*^","/_","/?","/*","/d","/f","/g","/h","/l","/n","/r","/u","/w","ac","ad","al","am","an","ap","ar","as","at","bo","ce","ch","co","de","e/","ec","ed","el","en","er","et","fi","g/","ic","id","im","in","is","it","js","la","le","li","lo","ma","mo","mp","ol","om","on","op","or","ot","re","ro","s_","s-","s?","s/","sp","ss","st","t/","ti","tm","tr","ub","un","ur","us","ut","ve","_","-",",","?",".","}","*","/","\\","&","^","=","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],P=["securepubads.g.doubleclick",".actonservice.com","googlesyndication","imasdk.googleapis",".cloudfront.net","googletagmanag","-1.xx.fbcdn","analytics.","marketing.","tracking.","metrics.","images.",".co.uk","a8clk.","stats.","a8cv.","click","media","track",".com",".net",".xyz","www.",".io",".jp","a8.","app","cdn","new","web",".b",".c",".d",".f",".h",".k",".m",".n",".p",".s",".t","10","24","a-","a1","a2","a4","ab","ac","ad","af","ag","ah","ai","ak","al","am","an","ap","ar","as","at","au","av","aw","ax","ay","az","be","bi","bl","bo","br","bu","ca","ce","ch","ci","ck","cl","cr","ct","cu","de","di","dn","do","dr","ds","du","dy","e-","eb","ec","ed","ef","eg","el","em","en","ep","er","es","et","eu","ev","ew","ex","ey","fe","ff","fi","fo","fr","ft","ge","gh","gi","gn","go","gr","gu","he","ho","ib","ic","id","ie","if","ig","ik","il","im","in","ip","ir","is","it","iv","ix","iz","jo","ks","la","le","li","ll","lo","lu","ly","ma","me","mo","mp","my","no","ok","ol","om","on","oo","op","or","ot","ou","ph","pl","po","pr","pu","qu","re","ri","ro","ru","s-","sc","se","sh","si","sk","sn","so","sp","ss","st","su","sw","sy","t-","ta","te","th","ti","tn","to","tr","ts","tu","ty","ub","ud","ul","um","un","up","ur","us","ut","ve","vi","vo","wa","we","wh","wn","-",".","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],R=["google-analytics.com/analytics.js","googlesyndication_adsbygoogle.js","googletagmanager.com/gtm.js","googletagservices_gpt.js","googletagmanager_gtm.js","fuckadblock.js-3.2.0","amazon_apstag.js","google-analytics","fingerprint2.js","noop-1s.mp4:10","google-ima.js","noop-0.1s.mp3","prebid-ads.js","nobab2.js:10","noopmp3-0.1s","noop-1s.mp4","hd-main.js","noopmp4-1s","32x32.png","noop.html","noopframe","noop.txt","nooptext","1x1.gif","2x2.png","noop.js","noopjs",".com/",".js:5","noop",":10",".js","ads","bea","_a",":5",".0","ar","ch","ic","in","le","ma","on","re","st","_","-",":",".","/","0","1","2","3","4","5","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","r","s","t","u","v","w","x","y","z"],z=[",redirect=google-ima","/js/sdkloader/ima3.j","/wp-content/plugins/",",redirect-rule=noop",".actonservice.com^",".com^$third-party","googlesyndication","imasdk.googleapis",".cloudfront.net^",",redirect-rule=","$script,domain=",",3p,denyallow=",",redirect=noop","xmlhttprequest","^$third-party","||smetrics.","third-party","marketing.","$document","analytics",",domain=","/assets/","metrics.","subdocum","tracking","$script",".co.uk","$ghide","a8clk.","cookie","google","script",".com^",".xyz^","$doma","a8cv.","click","image","media","track",".com",".fr^",".gif",".jp^",".net","/js/","$doc","$xhr","stat","www.",",1p",",3p",".io",".jp",".js","app","cdn","ent","new","web",".b",".c",".d",".f",".h",".m",".n",".p",".s",".t","@@","/*","/p","||","ab","ac","ad","af","ag","ai","ak","al","am","an","ap","ar","as","at","au","av","aw","ax","ay","az","be","bi","bo","br","ca","ce","ch","ck","cl","ct","cu","de","di","do","e-","e^","ec","ed","el","em","en","ep","er","es","et","ev","ew","ex","fe","ff","fi","fo","fr","g^","ge","gi","go","gr","he","hi","ho","hp","ht","ic","id","ig","il","im","in","ip","ir","is","it","ix","js","ke","le","li","lo","lu","ly","me","mo","mp","ne","no","od","ok","ol","om","on","op","or","ot","ow","pl","po","pr","qu","re","ri","ro","ru","s-","s/","sc","se","sh","si","so","sp","ss","st","su","te","th","ti","to","tr","ts","ty","ub","ud","ul","um","un","up","ur","us","ut","ve","vi","_","-",",","?",".","*","/","^","=","|","~","$","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"],L=["-webkit-touch-callo",", 1year, , domain, ",", googlesyndication",", SOCS, CAISNQgQEit",":style(overflow: au","##^script:has-text(","9udGVuZHVpc2VydmVyX","GgJmaSADGgYIgOu0sgY","ib3FfaWRlbnRpdHlmcm","position: initial !","set-local-storage-i","set, blurred, false","user-select: text !","zIwMjQwNTE0LjA2X3Aw",'[href^="https://',"rmnt, script, ","ut: default !"," !important)","trusted-set-",", document.",", noopFunc)","##body,html","contextmenu","no-fetch-if","otification",".com##+js(",'="https://',"background","important;"," -webkit-",".*,xhamst","container","AAAAAAAA","nostif, ",",google",":style(","consent","message","nowoif)","privacy","-wrapp",",kayak",".co.uk","[class","##+js(","accept","aopr, ","banner","bottom","cookie","Cookie","google","notice","policy","widget",":has(","##div","block","cript","true)",".co.",".com",".de,",".fr,",".net",".nl,",".pl,",".xyz","#@#.","2%3A","gdpr","html","ight","news","text","to !","wrap","www."," > ",",xh","##.","###","%3D","%7C","ent","lay","web","__","-s",", ",",b",",c",",f",",g",",h",",m",",p",",s",",t",": ",".*",".b",".c",".m",".p",".s",'"]',"##","%2","%5",'="',"00","a-","ab","ac","ad","Ad","af","ag","ak","al","am","an","ap","ar","as","at","au","av","ay","az","bo","ch","ck","cl","ct","de","di","do","e-","ed","el","em","en","er","es","et","ex","fi","fo","he","ic","id","if","ig","il","im","in","is","it","iv","le","lo","mo","ol","om","on","op","or","ot","ov","pl","po","re","ro","s_","s-","se","sh","si","sp","st","t-","th","ti","tr","tv","ub","ul","um","un","up","ur","us","ut","vi"," ","_","-",",",":",".","(",")","[","*","/","^","0","1","2","3","4","5","6","7","8","9","a","b","B","c","C","d","D","e","E","f","F","g","h","i","j","k","l","L","m","M","n","o","p","P","q","r","s","S","t","T","u","v","w","x","y","z"],B=class{constructor(){this.cosmeticSelector=new I(F),this.networkCSP=new I(T),this.networkRedirect=new I(R),this.networkHostname=new I(P),this.networkFilter=new I(O),this.networkRaw=new I(z),this.cosmeticRaw=new I(L)}},U=(()=>{let e=0;const t=new Int32Array(256);for(let o=0;256!==o;o+=1)e=o,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,e=1&e?-306674912^e>>>1:e>>>1,t[o]=e;return t})();var N=2147483647,V=36,j=1,M=26,D=38,H=700,W=72,q=128,G="-",$=/[^\0-\x7E]/,K=/[\x2E\u3002\uFF0E\uFF61]/g,Q={"invalid-input":"Invalid input","not-basic":"Illegal input >= 0x80 (not a basic code point)",overflow:"Overflow: input needs wider integers to process"},Y=V-j;function X(e){throw new RangeError(Q[e])}function Z(e,t){return e+22+75*(e<26?1:0)-((0!==t?1:0)<<5)}function J(e,t,o){let i=0;for(e=o?Math.floor(e/H):e>>1,e+=Math.floor(e/t);e>Y*M>>1;i+=V)e=Math.floor(e/Y);return Math.floor(i+(Y+1)*e/(e+D))}function ee(e){const t=[],o=e.length;let i=0,n=q,s=W,c=e.lastIndexOf(G);c<0&&(c=0);for(let o=0;o=128&&X("not-basic"),t.push(e.charCodeAt(o));for(let a=c>0?c+1:0;a=o&&X("invalid-input");const c=(r=e.charCodeAt(a++))-48<10?r-22:r-65<26?r-65:r-97<26?r-97:V;(c>=V||c>Math.floor((N-i)/t))&&X("overflow"),i+=c*t;const l=n<=s?j:n>=s+M?M:n-s;if(cMath.floor(N/p)&&X("overflow"),t*=p}const l=t.length+1;s=J(i-c,l,0===c),Math.floor(i/l)>N-n&&X("overflow"),n+=Math.floor(i/l),i%=l,t.splice(i++,0,n)}var r;return String.fromCodePoint.apply(null,t)}function te(e){const t=[],o=function(e){const t=[];let o=0;const i=e.length;for(;o=55296&&n<=56319&&o=n&&iMath.floor((N-s)/i)&&X("overflow"),s+=(e-n)*i,n=e;for(let e=0;eN&&X("overflow"),l===n){let e=s;for(let o=V;;o+=V){const i=o<=c?j:o>=c+M?M:o-c;if(e{const e=new B;return ce=()=>e,e};function re(e){return e<=127?1:5}function ae(e,t){return le(e.length,t)}function le(e,t){return(t?3:0)+e+re(e)}function pe(e){return e.length+re(e.length)}function de(e){const t=te(e).length;return t+re(t)}function ue(e){return e.byteLength+re(e.length)}var he,me=class e{static empty(t){return e.fromUint8Array(ie,t)}static fromUint8Array(t,o){return new e(t,o)}static allocate(t,o){return new e(new Uint8Array(t),o)}constructor(e,{enableCompression:t}){if(!1===se)throw new Error("Adblocker currently does not support Big-endian systems");!0===t&&this.enableCompression(),this.buffer=e,this.pos=0}enableCompression(){this.compression=ce()}checksum(){return function(e,t,o){let i=-1;const n=o-7;let s=t;for(;s>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])],i=i>>>8^U[255&(i^e[s++])];for(;s>>8^U[255&(i^e[s++])];return(-1^i)>>>0}(this.buffer,0,this.pos)}dataAvailable(){return this.pos>>8,this.buffer[this.pos++]=e}getUint16(){return(this.buffer[this.pos++]<<8|this.buffer[this.pos++])>>>0}pushUint32(e){this.buffer[this.pos++]=e>>>24,this.buffer[this.pos++]=e>>>16,this.buffer[this.pos++]=e>>>8,this.buffer[this.pos++]=e}getUint32(){return(this.buffer[this.pos++]<<24>>>0)+(this.buffer[this.pos++]<<16|this.buffer[this.pos++]<<8|this.buffer[this.pos++])>>>0}pushUint32Array(e){this.pushLength(e.length);for(const t of e)this.pushUint32(t)}getUint32Array(){const e=this.getLength(),t=new Uint32Array(e);for(let o=0;othis.buffer.byteLength)throw new Error(`StaticDataView too small: ${this.buffer.byteLength}, but required ${this.pos} bytes`)}pushLength(e){e<=127?this.pushUint8(e):(this.pushUint8(128),this.pushUint32(e))}getLength(){const e=this.getUint8();return 128===e?this.getUint32():e}},Ae=class e{static deserialize(t){return new e({debug:t.getBool(),enableCompression:t.getBool(),enableHtmlFiltering:t.getBool(),enableInMemoryCache:t.getBool(),enableMutationObserver:t.getBool(),enableOptimizations:t.getBool(),enablePushInjectionsOnNavigationEvents:t.getBool(),guessRequestTypeFromUrl:t.getBool(),integrityCheck:t.getBool(),loadCSPFilters:t.getBool(),loadCosmeticFilters:t.getBool(),loadExceptionFilters:t.getBool(),loadExtendedSelectors:t.getBool(),loadGenericCosmeticsFilters:t.getBool(),loadNetworkFilters:t.getBool(),loadPreprocessors:t.getBool()})}constructor({debug:e=!1,enableCompression:t=!1,enableHtmlFiltering:o=!1,enableInMemoryCache:i=!0,enableMutationObserver:n=!0,enableOptimizations:s=!0,enablePushInjectionsOnNavigationEvents:c=!0,guessRequestTypeFromUrl:r=!1,integrityCheck:a=!0,loadCSPFilters:l=!0,loadCosmeticFilters:p=!0,loadExceptionFilters:d=!0,loadExtendedSelectors:u=!1,loadGenericCosmeticsFilters:h=!0,loadNetworkFilters:m=!0,loadPreprocessors:A=!1}={}){this.debug=e,this.enableCompression=t,this.enableHtmlFiltering=o,this.enableInMemoryCache=i,this.enableMutationObserver=n,this.enableOptimizations=s,this.enablePushInjectionsOnNavigationEvents=c,this.guessRequestTypeFromUrl=r,this.integrityCheck=a,this.loadCSPFilters=l,this.loadCosmeticFilters=p,this.loadExceptionFilters=d,this.loadExtendedSelectors=u,this.loadGenericCosmeticsFilters=h,this.loadNetworkFilters=m,this.loadPreprocessors=A}getSerializedSize(){return 16}serialize(e){e.pushBool(this.debug),e.pushBool(this.enableCompression),e.pushBool(this.enableHtmlFiltering),e.pushBool(this.enableInMemoryCache),e.pushBool(this.enableMutationObserver),e.pushBool(this.enableOptimizations),e.pushBool(this.enablePushInjectionsOnNavigationEvents),e.pushBool(this.guessRequestTypeFromUrl),e.pushBool(this.integrityCheck),e.pushBool(this.loadCSPFilters),e.pushBool(this.loadCosmeticFilters),e.pushBool(this.loadExceptionFilters),e.pushBool(this.loadExtendedSelectors),e.pushBool(this.loadGenericCosmeticsFilters),e.pushBool(this.loadNetworkFilters),e.pushBool(this.loadPreprocessors)}},ge="undefined"!=typeof window&&"function"==typeof window.queueMicrotask?e=>window.queueMicrotask(e):e=>(he||(he=Promise.resolve())).then(e).catch((e=>setTimeout((()=>{throw e}),0)));function fe(e,t,o){let i=o.get(e);void 0===i&&(i=[],o.set(e,i)),i.push(t)}function ke(e,t,o){const i=o.get(e);if(void 0!==i){const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}function be(e,t,o){if(0===o.size)return!1;const i=o.get(e);return void 0!==i&&(ge((()=>{for(const e of i)e(...t)})),!0)}var ye=class{constructor(){this.onceListeners=new Map,this.onListeners=new Map}on(e,t){fe(e,t,this.onListeners)}once(e,t){fe(e,t,this.onceListeners)}unsubscribe(e,t){ke(e,t,this.onListeners),ke(e,t,this.onceListeners)}emit(e,...t){be(e,t,this.onListeners),!0===be(e,t,this.onceListeners)&&this.onceListeners.delete(e)}};function we(e,t){return function(e,t){let o=3;const i=()=>e(t).catch((e=>{if(o>0)return o-=1,new Promise(((e,t)=>{setTimeout((()=>{i().then(e).catch(t)}),500)}));throw e}));return i()}(e,t).then((e=>e.text()))}var ve="https://raw.githubusercontent.com/ghostery/adblocker/master/packages/adblocker/assets",_e=[`${ve}/easylist/easylist.txt`,`${ve}/peter-lowe/serverlist.txt`,`${ve}/ublock-origin/badware.txt`,`${ve}/ublock-origin/filters-2020.txt`,`${ve}/ublock-origin/filters-2021.txt`,`${ve}/ublock-origin/filters-2022.txt`,`${ve}/ublock-origin/filters-2023.txt`,`${ve}/ublock-origin/filters-2024.txt`,`${ve}/ublock-origin/filters.txt`,`${ve}/ublock-origin/quick-fixes.txt`,`${ve}/ublock-origin/resource-abuse.txt`,`${ve}/ublock-origin/unbreak.txt`],Ce=[..._e,`${ve}/easylist/easyprivacy.txt`,`${ve}/ublock-origin/privacy.txt`],xe=[...Ce,`${ve}/easylist/easylist-cookie.txt`,`${ve}/ublock-origin/annoyances-others.txt`,`${ve}/ublock-origin/annoyances-cookies.txt`];var Se=new Set(["any","dir","has","host-context","if","if-not","is","matches","not","where"]),Ee={attribute:/\[\s*(?:(?\*|[-\w]*)\|)?(?[-\w\u{0080}-\u{FFFF}]+)\s*(?:(?\W?=)\s*(?.+?)\s*(?[iIsS])?\s*)?\]/gu,id:/#(?(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,class:/\.(?(?:[-\w\u{0080}-\u{FFFF}]|\\.)+)/gu,comma:/\s*,\s*/g,combinator:/\s*[\s>+~]\s*/g,"pseudo-element":/::(?[-\w\u{0080}-\u{FFFF}]+)(?:\((?:¶*)\))?/gu,"pseudo-class":/:(?[-\w\u{0080}-\u{FFFF}]+)(?:\((?¶*)\))?/gu,type:/(?:(?\*|[-\w]*)\|)?(?[-\w\u{0080}-\u{FFFF}]+)|\*/gu},Ie=new Set(["pseudo-class","pseudo-element"]),Fe=new Set([...Ie,"attribute"]),Te=new Set(["combinator","comma"]),Oe=Object.assign({},Ee);function Pe(e,t){e.lastIndex=0;const o=e.exec(t);if(null===o)return;const i=o.index-1,n=o[0],s=t.slice(0,i+1),c=t.slice(i+n.length+1);return[s,[n,o.groups||{}],c]}Oe["pseudo-element"]=RegExp(Ee["pseudo-element"].source.replace("(?¶*)","(?.*?)"),"gu"),Oe["pseudo-class"]=RegExp(Ee["pseudo-class"].source.replace("(?¶*)","(?.*)"),"gu");var Re=[e=>{const t=Pe(Ee.attribute,e);if(void 0===t)return;const[o,[i,{name:n,operator:s,value:c,namespace:r,caseSensitive:a}],l]=t;return void 0!==n?[o,{type:"attribute",content:i,length:i.length,namespace:r,caseSensitive:a,pos:[],name:n,operator:s,value:c},l]:void 0},e=>{const t=Pe(Ee.id,e);if(void 0===t)return;const[o,[i,{name:n}],s]=t;return void 0!==n?[o,{type:"id",content:i,length:i.length,pos:[],name:n},s]:void 0},e=>{const t=Pe(Ee.class,e);if(void 0===t)return;const[o,[i,{name:n}],s]=t;return void 0!==n?[o,{type:"class",content:i,length:i.length,pos:[],name:n},s]:void 0},e=>{const t=Pe(Ee.comma,e);if(void 0===t)return;const[o,[i],n]=t;return[o,{type:"comma",content:i,length:i.length,pos:[]},n]},e=>{const t=Pe(Ee.combinator,e);if(void 0===t)return;const[o,[i],n]=t;return[o,{type:"combinator",content:i,length:i.length,pos:[]},n]},e=>{const t=Pe(Ee["pseudo-element"],e);if(void 0===t)return;const[o,[i,{name:n}],s]=t;return void 0!==n?[o,{type:"pseudo-element",content:i,length:i.length,pos:[],name:n},s]:void 0},e=>{const t=Pe(Ee["pseudo-class"],e);if(void 0===t)return;const[o,[i,{name:n,argument:s}],c]=t;return void 0!==n?[o,{type:"pseudo-class",content:i,length:i.length,pos:[],name:n,argument:s,subtree:void 0},c]:void 0},e=>{const t=Pe(Ee.type,e);if(void 0===t)return;const[o,[i,{name:n,namespace:s}],c]=t;return[o,{type:"type",content:i,length:i.length,namespace:s,pos:[],name:n},c]}];function ze(e,t,o,i){for(const n of t)for(const t of e)if(i.has(t.type)&&t.pos[0]=0&&"\\"===e[t];)o+=1,t-=1;return o%2!=0}function Be(e,t,o){let i=o+1;for(;-1!==(i=e.indexOf(t,i))&&!0===Le(e,i);)i+=1;if(-1!==i)return e.slice(o,i+1)}function Ue(e,t){let o=0;for(let i=t;i0))return;o-=1}if(0===o)return e.slice(t,i+1)}}function Ne(e,t,o,i){const n=[];let s=0;for(;-1!==(s=e.indexOf(o,s));){const o=i(e,s);if(void 0===o)break;n.push({str:o,start:s}),e=`${e.slice(0,s+1)}${t.repeat(o.length-2)}${e.slice(s+o.length-1)}`,s+=o.length}return[n,e]}function Ve(e){if("string"!=typeof e)return[];if(0===(e=e.trim()).length)return[];const[t,o]=Ne(e,"§",'"',((e,t)=>Be(e,'"',t))),[i,n]=Ne(o,"§","'",((e,t)=>Be(e,"'",t))),[s,c]=Ne(n,"¶","(",Ue),r=function(e){if(!e)return[];const t=[e];for(const e of Re)for(let o=0;o0!==e.length)))}}let o=0;for(const e of t)"string"!=typeof e&&(e.pos=[o,o+e.length],Te.has(e.type)&&(e.content=e.content.trim()||" ")),o+=e.length;return t.every((e=>"string"!=typeof e))?t:[]}(c);return ze(r,s,/\(¶*\)/,Ie),ze(r,t,/"§*"/,Fe),ze(r,i,/'§*'/,Fe),r}function je(e,{list:t=!0}={}){if(!0===t&&e.some((e=>"comma"===e.type))){const t=[],o=[];for(let i=0;i=0;t--){const o=e[t];if("combinator"===o.type){const i=je(e.slice(0,t)),n=je(e.slice(t+1));if(void 0===n)return;if(" "!==o.content&&"~"!==o.content&&"+"!==o.content&&">"!==o.content)return;return{type:"complex",combinator:o.content,left:i,right:n}}}if(0!==e.length)return function(e){return e.every((e=>"comma"!==e.type&&"combinator"!==e.type))}(e)?1===e.length?e[0]:{type:"compound",compound:[...e]}:void 0}function Me(e,t,o,i){if(void 0!==e){if("complex"===e.type)Me(e.left,t,o,e),Me(e.right,t,o,e);else if("compound"===e.type)for(const i of e.compound)Me(i,t,o,e);else"pseudo-class"===e.type&&void 0!==e.subtree&&void 0!==o&&"pseudo-class"===o.type&&void 0!==o.subtree&&Me(e.subtree,t,o,e);t(e,i)}}function De(e,{recursive:t=!0,list:o=!0}={}){const i=Ve(e);if(0===i.length)return;const n=je(i,{list:o});return!0===t&&Me(n,(e=>{"pseudo-class"===e.type&&e.argument&&void 0!==e.name&&Se.has(e.name)&&(e.subtree=De(e.argument,{recursive:!0,list:!0}))})),n}var He,We,qe=new Set(["has","has-text","if"]),Ge=new Set(["active","any","any-link","blank","checked","default","defined","dir","disabled","empty","enabled","first","first-child","first-of-type","focus","focus-visible","focus-within","fullscreen","host","host-context","hover","in-range","indeterminate","invalid","is","lang","last-child","last-of-type","left","link","matches","not","nth-child","nth-last-child","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","placeholder-shown","read-only","read-write","required","right","root","scope","target","valid","visited","where"]),$e=new Set(["after","before","first-letter","first-line"]);function Ke(e){if(-1===e.indexOf(":"))return He.Normal;const t=Ve(e);let o=!1;for(const e of t)if("pseudo-class"===e.type){const{name:t}=e;if(!0===qe.has(t))o=!0;else if(!1===Ge.has(t)&&!1===$e.has(t))return He.Invalid;if(!1===o&&void 0!==e.argument&&!0===Se.has(t)){const t=Ke(e.argument);if(t===He.Invalid)return t;t===He.Extended&&(o=!0)}}return!0===o?He.Extended:He.Normal}(We=He||(He={}))[We.Normal=0]="Normal",We[We.Extended=1]="Extended",We[We.Invalid=2]="Invalid";var Qe=new Set(["htm","html","xhtml"]),Ye=new Set(["eot","otf","sfnt","ttf","woff","woff2"]),Xe=new Set(["apng","bmp","cur","dib","eps","gif","heic","heif","ico","j2k","jfi","jfif","jif","jp2","jpe","jpeg","jpf","jpg","jpm","jpx","mj2","pjp","pjpeg","png","svg","svgz","tif","tiff","webp"]),Ze=new Set(["avi","flv","mp3","mp4","ogg","wav","weba","webm","wmv"]),Je=new Set(["js","ts","jsx","esm"]),et=new Set(["css","scss"]);function tt(e,t){let o=0,i=e.length,n=!1;if(!t){if(e.startsWith("data:"))return null;for(;oo+1&&e.charCodeAt(i-1)<=32;)i-=1;if(47===e.charCodeAt(o)&&47===e.charCodeAt(o+1))o+=2;else{const t=e.indexOf(":/",o);if(-1!==t){const i=t-o,n=e.charCodeAt(o),s=e.charCodeAt(o+1),c=e.charCodeAt(o+2),r=e.charCodeAt(o+3),a=e.charCodeAt(o+4);if(5===i&&104===n&&116===s&&116===c&&112===r&&115===a);else if(4===i&&104===n&&116===s&&116===c&&112===r);else if(3===i&&119===n&&115===s&&115===c);else if(2===i&&119===n&&115===s);else for(let i=o;i=97&&t<=122||t>=48&&t<=57||46===t||45===t||43===t))return null}for(o=t+2;47===e.charCodeAt(o);)o+=1}}let t=-1,s=-1,c=-1;for(let r=o;r=65&&o<=90&&(n=!0)}if(-1!==t&&t>o&&to&&co+1&&46===e.charCodeAt(i-1);)i-=1;const s=0!==o||i!==e.length?e.slice(o,i):e;return n?s.toLowerCase():s}function ot(e){return e>=97&&e<=122||e>=48&&e<=57||e>127}function it(e){if(e.length>255)return!1;if(0===e.length)return!1;if(!ot(e.charCodeAt(0))&&46!==e.charCodeAt(0)&&95!==e.charCodeAt(0))return!1;let t=-1,o=-1;const i=e.length;for(let n=0;n64||46===o||45===o||95===o)return!1;t=n}else if(!ot(i)&&45!==i&&95!==i)return!1;o=i}return i-t-1<=63&&45!==o}var nt=function({allowIcannDomains:e=!0,allowPrivateDomains:t=!1,detectIp:o=!0,extractHostname:i=!0,mixedInputs:n=!0,validHosts:s=null,validateHostname:c=!0}){return{allowIcannDomains:e,allowPrivateDomains:t,detectIp:o,extractHostname:i,mixedInputs:n,validHosts:s,validateHostname:c}}({});function st(e,t,o,i,n){const s=function(e){return void 0===e?nt:function({allowIcannDomains:e=!0,allowPrivateDomains:t=!1,detectIp:o=!0,extractHostname:i=!0,mixedInputs:n=!0,validHosts:s=null,validateHostname:c=!0}){return{allowIcannDomains:e,allowPrivateDomains:t,detectIp:o,extractHostname:i,mixedInputs:n,validHosts:s,validateHostname:c}}(e)}(i);return"string"!=typeof e?n:(s.extractHostname?s.mixedInputs?n.hostname=tt(e,it(e)):n.hostname=tt(e,!1):n.hostname=e,0===t||null===n.hostname||s.detectIp&&(n.isIp=function(e){if(e.length<3)return!1;let t=e.startsWith("[")?1:0,o=e.length;if("]"===e[o-1]&&(o-=1),o-t>39)return!1;let i=!1;for(;t=48&&o<=57||o>=97&&o<=102||o>=65&&o<=90))return!1}return i}(c=n.hostname)||function(e){if(e.length<7)return!1;if(e.length>15)return!1;let t=0;for(let o=0;o57)return!1}return 3===t&&46!==e.charCodeAt(0)&&46!==e.charCodeAt(e.length-1)}(c),n.isIp)?n:s.validateHostname&&s.extractHostname&&!it(n.hostname)?(n.hostname=null,n):(o(n.hostname,s,n),2===t||null===n.publicSuffix?n:(n.domain=function(e,t,o){if(null!==o.validHosts){const e=o.validHosts;for(const o of e)if(function(e,t){return!!e.endsWith(t)&&(e.length===t.length||"."===e[e.length-t.length-1])}(t,o))return o}let i=0;if(t.startsWith("."))for(;i=i)return!1;let n=o,s=i-1;for(;n<=s;){const o=n+s>>>1,i=e[o];if(it))return!0;s=o-1}}return!1}var at=new Uint32Array(20);function lt(e,t,o){if(function(e,t,o){if(!t.allowPrivateDomains&&e.length>3){const t=e.length-1,i=e.charCodeAt(t),n=e.charCodeAt(t-1),s=e.charCodeAt(t-2),c=e.charCodeAt(t-3);if(109===i&&111===n&&99===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="com",!0;if(103===i&&114===n&&111===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="org",!0;if(117===i&&100===n&&101===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="edu",!0;if(118===i&&111===n&&103===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="gov",!0;if(116===i&&101===n&&110===s&&46===c)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="net",!0;if(101===i&&100===n&&46===s)return o.isIcann=!0,o.isPrivate=!1,o.publicSuffix="de",!0}return!1}(e,t,o))return;const{allowIcannDomains:i,allowPrivateDomains:n}=t;let s=-1,c=0,r=0,a=1;const l=function(e,t){let o=5381,i=0;for(let n=e.length-1;n>=0;n-=1){const s=e.charCodeAt(n);if(46===s&&(at[i<<1]=o>>>0,at[1+(i<<1)]=n+1,i+=1,i===t))return i;o=33*o^s}return at[i<<1]=o>>>0,at[1+(i<<1)]=0,i+=1,i}(e,ct[0]);for(let e=0;er;)t.shift();o.publicSuffix=t.join(".")}else o.publicSuffix=e.slice(at[1+(r-2<<1)]);else o.publicSuffix=1===l?e:e.slice(at[1])}function pt(e,t={}){return st(e,5,lt,t,{domain:null,domainWithoutSuffix:null,hostname:null,isIcann:null,isIp:null,isPrivate:null,publicSuffix:null,subdomain:null})}var dt=new class{constructor(e){this.pos=0,this.buffer=new Uint32Array(e)}reset(){this.pos=0}slice(){return this.buffer.slice(0,this.pos)}push(e){this.buffer[this.pos++]=e}empty(){return 0===this.pos}full(){return this.pos===this.buffer.length}remaining(){return this.buffer.length-this.pos}}(1024),ut=37,ht=5011;function mt(e){return 16843009*((e=(858993459&(e-=e>>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135)>>24}function At(e,t){return!!(e&t)}function gt(e,t){return e|t}function ft(e,t){return e&~t}function kt(e,t,o){let i=ht;for(let n=t;n>>0}function bt(e){return"string"!=typeof e||0===e.length?ht:kt(e,0,e.length)}function yt(e){const t=new Uint32Array(e.length);let o=0;for(const i of e)t[o++]=bt(i);return t}function wt(e,t){if(e.length=48&&e<=57}function Ct(e){return e>=97&&e<=122||e>=65&&e<=90}function xt(e){return Ct(e)||_t(e)||37===e||function(e){return e>=192&&e<=450}(e)||function(e){return e>=1024&&e<=1279}(e)}function St(e,t,o,i){const n=Math.min(e.length,2*i.remaining());let s=!1,c=0,r=ht;for(let o=0;o1&&(!1===t||0!==c)&&i.push(r>>>0))}!0===s&&!1===o&&e.length-c>1&&!1===i.full()&&i.push(r>>>0)}function Et(e,t){const o=Math.min(e.length,2*t.remaining());let i=!1,n=0,s=ht;for(let c=0;c1&&t.push(s>>>0))}!0===i&&e.length-n>1&&!1===t.full()&&t.push(s>>>0)}function It(e,t){return-1!==function(e,t){if(0===e.length)return-1;let o=0,i=e.length-1;for(;o<=i;){const n=o+i>>>1,s=e[n];if(st))return n;i=n-1}}return-1}(e,t)}var Ft=/[^\u0000-\u00ff]/;function Tt(e){return Ft.test(e)}var Ot={extractHostname:!0,mixedInputs:!1,validateHostname:!1},Pt={beacon:bt("type:beacon"),cspReport:bt("type:csp"),csp_report:bt("type:csp"),cspviolationreport:bt("type:cspviolationreport"),document:bt("type:document"),eventsource:bt("type:other"),fetch:bt("type:xhr"),font:bt("type:font"),image:bt("type:image"),imageset:bt("type:image"),mainFrame:bt("type:document"),main_frame:bt("type:document"),manifest:bt("type:other"),media:bt("type:media"),object:bt("type:object"),object_subrequest:bt("type:object"),other:bt("type:other"),ping:bt("type:ping"),prefetch:bt("type:other"),preflight:bt("type:preflight"),script:bt("type:script"),signedexchange:bt("type:signedexchange"),speculative:bt("type:other"),stylesheet:bt("type:stylesheet"),subFrame:bt("type:subdocument"),sub_frame:bt("type:subdocument"),texttrack:bt("type:other"),webSocket:bt("type:websocket"),web_manifest:bt("type:other"),websocket:bt("type:websocket"),xhr:bt("type:xhr"),xml_dtd:bt("type:other"),xmlhttprequest:bt("type:xhr"),xslt:bt("type:other")};function Rt(e){let t=ht;for(let o=e.length-1;o>=0;o-=1)t=t*ut^e.charCodeAt(o);return t>>>0}function zt(e,t,o){dt.reset();let i=ht;for(let n=t-1;n>=0;n-=1){const t=e.charCodeAt(n);46===t&&n>>0),i=i*ut^t}return dt.push(i>>>0),dt.slice()}function Lt(e,t){const o=function(e,t){let o=null;const i=t.indexOf(".");if(-1!==i){const n=t.slice(i+1);o=e.slice(0,-n.length-1)}return o}(e,t);return null!==o?zt(o,o.length,o.length):ne}function Bt(e,t){return zt(e,e.length,e.length-t.length)}var Ut=class e{static fromRawDetails({requestId:t="0",tabId:o=0,url:i="",hostname:n,domain:s,sourceUrl:c="",sourceHostname:r,sourceDomain:a,type:l="main_frame",_originalRequestDetails:p}){if(i=i.toLowerCase(),void 0===n||void 0===s){const e=pt(i,Ot);n=n||e.hostname||"",s=s||e.domain||""}if(void 0===r||void 0===a){const e=pt(r||a||c,Ot);r=r||e.hostname||"",a=a||e.domain||r||""}return new e({requestId:t,tabId:o,domain:s,hostname:n,url:i,sourceDomain:a,sourceHostname:r,sourceUrl:c,type:l,_originalRequestDetails:p})}constructor({requestId:e,tabId:t,type:o,domain:i,hostname:n,url:s,sourceDomain:c,sourceHostname:r,_originalRequestDetails:a}){if(this.tokens=void 0,this.hostnameHashes=void 0,this.entityHashes=void 0,this._originalRequestDetails=a,this.id=e,this.tabId=t,this.type=o,this.url=s,this.hostname=n,this.domain=i,this.sourceHostnameHashes=0===r.length?ne:Bt(r,c),this.sourceEntityHashes=0===r.length?ne:Lt(r,c),this.isThirdParty=function(e,t,o,i,n){return"main_frame"!==n&&"mainFrame"!==n&&(0!==t.length&&0!==i.length?t!==i:0!==t.length&&0!==o.length?t!==o:0!==i.length&&0!==e.length&&e!==i)}(n,i,r,c,o),this.isFirstParty=!this.isThirdParty,this.isSupported=!0,"websocket"===this.type||this.url.startsWith("ws:")||this.url.startsWith("wss:"))this.isHttp=!1,this.isHttps=!1,this.type="websocket",this.isSupported=!0;else if(this.url.startsWith("http:"))this.isHttp=!0,this.isHttps=!1;else if(this.url.startsWith("https:"))this.isHttps=!0,this.isHttp=!1;else if(this.url.startsWith("data:")){this.isHttp=!1,this.isHttps=!1;const e=this.url.indexOf(",");-1!==e&&(this.url=this.url.slice(0,e))}else this.isHttp=!1,this.isHttps=!1,this.isSupported=!1}getHostnameHashes(){return void 0===this.hostnameHashes&&(this.hostnameHashes=0===this.hostname.length?ne:Bt(this.hostname,this.domain)),this.hostnameHashes}getEntityHashes(){return void 0===this.entityHashes&&(this.entityHashes=0===this.hostname.length?ne:Lt(this.hostname,this.domain)),this.entityHashes}getTokens(){if(void 0===this.tokens){dt.reset();for(const e of this.sourceHostnameHashes)dt.push(e);dt.push(Pt[this.type]),Et(this.url,dt),this.tokens=dt.slice()}return this.tokens}isMainFrame(){return"main_frame"===this.type||"mainFrame"===this.type}isSubFrame(){return"sub_frame"===this.type||"subFrame"===this.type}guessTypeOfRequest(){const e=this.type;return this.type=function(e){const t=function(e){let t=e.length;const o=e.indexOf("#");-1!==o&&(t=o);const i=e.indexOf("?");-1!==i&&i=0&&(s=e.charCodeAt(n),0!=(s>=65&&s<=90||s>=97&&s<=122||s>=48&&s<=57));n-=1);return 46!==s||n<0||t-n>=10?"":e.slice(n+1,t)}(e);return Xe.has(t)||e.startsWith("data:image/")||e.startsWith("https://frog.wix.com/bt")?"image":Ze.has(t)||e.startsWith("data:audio/")||e.startsWith("data:video/")?"media":et.has(t)||e.startsWith("data:text/css")?"stylesheet":Je.has(t)||e.startsWith("data:")&&(e.startsWith("data:application/ecmascript")||e.startsWith("data:application/javascript")||e.startsWith("data:application/x-ecmascript")||e.startsWith("data:application/x-javascript")||e.startsWith("data:text/ecmascript")||e.startsWith("data:text/javascript")||e.startsWith("data:text/javascript1.0")||e.startsWith("data:text/javascript1.1")||e.startsWith("data:text/javascript1.2")||e.startsWith("data:text/javascript1.3")||e.startsWith("data:text/javascript1.4")||e.startsWith("data:text/javascript1.5")||e.startsWith("data:text/jscript")||e.startsWith("data:text/livescript")||e.startsWith("data:text/x-ecmascript")||e.startsWith("data:text/x-javascript"))||e.startsWith("https://maps.googleapis.com/maps/api/js")||e.startsWith("https://www.googletagmanager.com/gtag/js")?"script":Qe.has(t)||e.startsWith("data:text/html")||e.startsWith("data:application/xhtml")||e.startsWith("https://www.youtube.com/embed/")||e.startsWith("https://www.google.com/gen_204")?"document":Ye.has(t)||e.startsWith("data:font/")?"font":"other"}(this.url),e!==this.type&&(this.tokens=void 0),this.type}},Nt=class e{static parse(t,o=!1){if(0===t.length)return;const i=[],n=[],s=[],c=[];for(let e of t){Tt(e)&&(e=oe(e));const t=126===e.charCodeAt(0),o=42===e.charCodeAt(e.length-1)&&46===e.charCodeAt(e.length-2),r=t?1:0,a=o?e.length-2:e.length,l=Rt(!0===t||!0===o?e.slice(r,a):e);t?o?n.push(l):c.push(l):o?i.push(l):s.push(l)}return new e({entities:0!==i.length?new Uint32Array(i).sort():void 0,hostnames:0!==s.length?new Uint32Array(s).sort():void 0,notEntities:0!==n.length?new Uint32Array(n).sort():void 0,notHostnames:0!==c.length?new Uint32Array(c).sort():void 0,parts:!0===o?t.join(","):void 0})}static deserialize(t){const o=t.getUint8();return new e({entities:1==(1&o)?t.getUint32Array():void 0,hostnames:2==(2&o)?t.getUint32Array():void 0,notEntities:4==(4&o)?t.getUint32Array():void 0,notHostnames:8==(8&o)?t.getUint32Array():void 0,parts:16==(16&o)?t.getUTF8():void 0})}constructor({entities:e,hostnames:t,notEntities:o,notHostnames:i,parts:n}){this.entities=e,this.hostnames=t,this.notEntities=o,this.notHostnames=i,this.parts=n}updateId(e){const{hostnames:t,entities:o,notHostnames:i,notEntities:n}=this;if(void 0!==t)for(const o of t)e=e*ut^o;if(void 0!==o)for(const t of o)e=e*ut^t;if(void 0!==i)for(const t of i)e=e*ut^t;if(void 0!==n)for(const t of n)e=e*ut^t;return e}serialize(e){const t=e.getPos();e.pushUint8(0);let o=0;void 0!==this.entities&&(o|=1,e.pushUint32Array(this.entities)),void 0!==this.hostnames&&(o|=2,e.pushUint32Array(this.hostnames)),void 0!==this.notEntities&&(o|=4,e.pushUint32Array(this.notEntities)),void 0!==this.notHostnames&&(o|=8,e.pushUint32Array(this.notHostnames)),void 0!==this.parts&&(o|=16,e.pushUTF8(this.parts)),e.setByte(t,o)}getSerializedSize(){let e=1;return void 0!==this.entities&&(e+=ue(this.entities)),void 0!==this.hostnames&&(e+=ue(this.hostnames)),void 0!==this.notHostnames&&(e+=ue(this.notHostnames)),void 0!==this.notEntities&&(e+=ue(this.notEntities)),void 0!==this.parts&&(e+=de(this.parts)),e}match(e,t){if(void 0!==this.notHostnames)for(const t of e)if(It(this.notHostnames,t))return!1;if(void 0!==this.notEntities)for(const e of t)if(It(this.notEntities,e))return!1;if(void 0!==this.hostnames||void 0!==this.entities){if(void 0!==this.hostnames)for(const t of e)if(It(this.hostnames,t))return!0;if(void 0!==this.entities)for(const e of t)if(It(this.entities,e))return!0;return!1}return!0}};function Vt(e){if(!1===e.startsWith("^script"))return;const t=":has-text(",o=[];let i=7;for(;e.startsWith(t,i);){i+=10;let t=1;const n=i;let s=-1;for(;i=48&&o<=57||o>=65&&o<=90||o>=97&&o<=122)){if(t{}},t=/^[#.]?[\w-.]+$/;return function(o){if(t.test(o))return!0;try{(t=>{e.matches(t)})(o)}catch(e){return!1}return!0}})();function Yt(e,t){const o=e.getSelector();if(!1===e.isScriptInject())return o;const i=e.parseScript();if(void 0===i)return o;const n=t(i.name);return void 0===n?o:o.replace(i.name,n)}(Kt=$t||($t={}))[Kt.unhide=1]="unhide",Kt[Kt.scriptInject=2]="scriptInject",Kt[Kt.isUnicode=4]="isUnicode",Kt[Kt.isClassSelector=8]="isClassSelector",Kt[Kt.isIdSelector=16]="isIdSelector",Kt[Kt.isHrefSelector=32]="isHrefSelector",Kt[Kt.remove=64]="remove",Kt[Kt.extended=128]="extended";var Xt=class e{static parse(t,o=!1){const i=t;let n,s,c,r=0;const a=t.indexOf("#"),l=a+1;let p=l+1;if(t.length>l&&("@"===t[l]?(r=gt(r,$t.unhide),p+=1):"?"===t[l]&&(p+=1)),p>=t.length)return null;if(a>0&&(s=Nt.parse(t.slice(0,a).split(","),o)),t.endsWith(":remove()"))r=gt(r,$t.remove),r=gt(r,$t.extended),t=t.slice(0,-9);else if(t.length-p>=8&&t.endsWith(")")&&-1!==t.indexOf(":style(",p)){const e=t.indexOf(":style(",p);c=t.slice(e+7,-1),t=t.slice(0,e)}if(94===t.charCodeAt(p)){if(!1===vt(t,"script:has-text(",p+1)||41!==t.charCodeAt(t.length-1))return null;if(n=t.slice(p,t.length),void 0===Vt(n))return null}else if(t.length-p>4&&43===t.charCodeAt(p)&&vt(t,"+js(",p)){if((void 0===s||void 0===s.hostnames&&void 0===s.entities)&&!1===At(r,$t.unhide))return null;if(r=gt(r,$t.scriptInject),n=t.slice(p+4,t.length-1),!1===At(r,$t.unhide)&&0===n.length)return null}else{n=t.slice(p);const e=Ke(n);if(e===He.Extended)r=gt(r,$t.extended);else if(e===He.Invalid||!Qt(n))return null}if(void 0===s&&!0===At(r,$t.extended))return null;if(void 0!==n&&(Tt(n)&&(r=gt(r,$t.isUnicode)),!1===At(r,$t.scriptInject)&&!1===At(r,$t.remove)&&!1===At(r,$t.extended)&&!1===n.startsWith("^"))){const e=n.charCodeAt(0),t=n.charCodeAt(1),o=n.charCodeAt(2);!1===At(r,$t.scriptInject)&&(46===e&&qt(n)?r=gt(r,$t.isClassSelector):35===e&&qt(n)?r=gt(r,$t.isIdSelector):(97===e&&91===t&&104===o&&Gt(n,2)||91===e&&104===t&&Gt(n,1))&&(r=gt(r,$t.isHrefSelector)))}return new e({mask:r,rawLine:!0===o?i:void 0,selector:n,style:c,domains:s})}static deserialize(t){const o=t.getUint8(),i=At(o,$t.isUnicode),n=t.getUint8(),s=i?t.getUTF8():t.getCosmeticSelector();return new e({mask:o,selector:s,domains:1==(1&n)?Nt.deserialize(t):void 0,rawLine:2==(2&n)?t.getRawCosmetic():void 0,style:4==(4&n)?t.getASCII():void 0})}constructor({mask:e,selector:t,domains:o,rawLine:i,style:n}){this.mask=e,this.selector=t,this.domains=o,this.style=n,this.id=void 0,this.rawLine=i,this.scriptletDetails=void 0}isCosmeticFilter(){return!0}isNetworkFilter(){return!1}serialize(e){e.pushUint8(this.mask);const t=e.getPos();e.pushUint8(0),this.isUnicode()?e.pushUTF8(this.selector):e.pushCosmeticSelector(this.selector);let o=0;void 0!==this.domains&&(o|=1,this.domains.serialize(e)),void 0!==this.rawLine&&(o|=2,e.pushRawCosmetic(this.rawLine)),void 0!==this.style&&(o|=4,e.pushASCII(this.style)),e.setByte(t,o)}getSerializedSize(e){let t=2;return this.isUnicode()?t+=de(this.selector):t+=function(e,t){return!0===t?le(ce().cosmeticSelector.getCompressedSize(e),!1):pe(e)}(this.selector,e),void 0!==this.domains&&(t+=this.domains.getSerializedSize()),void 0!==this.rawLine&&(t+=function(e,t){return!0===t?le(ce().cosmeticRaw.getCompressedSize(te(e)),!1):de(e)}(this.rawLine,e)),void 0!==this.style&&(t+=pe(this.style)),t}toString(){if(void 0!==this.rawLine)return this.rawLine;let e="";return void 0!==this.domains&&(void 0!==this.domains.parts?e+=this.domains.parts:e+=""),this.isUnhide()?e+="#@#":e+="##",this.isScriptInject()?(e+="+js(",e+=this.selector,e+=")"):e+=this.selector,e}match(e,t){return!1===this.hasHostnameConstraint()||!(!e&&this.hasHostnameConstraint())&&(void 0===this.domains||this.domains.match(0===e.length?ne:Bt(e,t),0===e.length?ne:Lt(e,t)))}getTokens(){const e=[];if(void 0!==this.domains){const{hostnames:t,entities:o}=this.domains;if(void 0!==t)for(const o of t)e.push(new Uint32Array([o]));if(void 0!==o)for(const t of o)e.push(new Uint32Array([t]))}if(0===e.length&&!1===this.isUnhide())if(this.isIdSelector()||this.isClassSelector()){let t=1;const o=this.selector;for(;t0?n=!0:"'"===p&&e.indexOf("'",o+1)>0?s=!0:"{"===p&&e.indexOf("}",o+1)>0?r+=1:"/"===p&&e.indexOf("/",o+1)>0?c=!0:l=!0)),","===p&&(t.push(e.slice(i+1,o).trim()),i=o,l=!1))),a="\\"===p}if(t.push(e.slice(i+1).trim()),0===t.length)return;const p=t.slice(1).map((e=>e.startsWith("'")&&e.endsWith("'")||e.startsWith('"')&&e.endsWith('"')?e.substring(1,e.length-1):e)).map((e=>e.replace(Dt,",").replace(Ht,"\\").replace(Wt,",")));return this.scriptletDetails={name:t[0],args:p},this.scriptletDetails}getScript(e){const t=this.parseScript();if(void 0===t)return;const{name:o,args:i}=t;let n=e(o);if(void 0!==n){for(let e=0;e>>0}(this.mask,this.selector,this.domains,this.style)),this.id}hasCustomStyle(){return void 0!==this.style}getStyle(e=Mt){return this.style||e}getStyleAttributeHash(){return`s${bt(this.getStyle())}`}getSelector(){return this.selector}getSelectorAST(){return De(this.getSelector())}getExtendedSelector(){return Vt(this.selector)}isExtended(){return At(this.mask,$t.extended)}isRemove(){return At(this.mask,$t.remove)}isUnhide(){return At(this.mask,$t.unhide)}isScriptInject(){return At(this.mask,$t.scriptInject)}isCSS(){return!1===this.isScriptInject()}isIdSelector(){return At(this.mask,$t.isIdSelector)}isClassSelector(){return At(this.mask,$t.isClassSelector)}isHrefSelector(){return At(this.mask,$t.isHrefSelector)}isUnicode(){return At(this.mask,$t.isUnicode)}isHtmlFiltering(){return this.getSelector().startsWith("^")}isGenericHide(){var e,t;return void 0===(null===(e=null==this?void 0:this.domains)||void 0===e?void 0:e.hostnames)&&void 0===(null===(t=null==this?void 0:this.domains)||void 0===t?void 0:t.entities)}},Zt=class{constructor(){this.options=new Set,this.prefix=void 0,this.infix=void 0,this.suffix=void 0,this.redirect=void 0}blockRequestsWithType(e){if(this.options.has(e))throw new Error(`Already blocking type ${e}`);return this.options.add(e),this}images(){return this.blockRequestsWithType("image")}scripts(){return this.blockRequestsWithType("script")}frames(){return this.blockRequestsWithType("frame")}fonts(){return this.blockRequestsWithType("font")}medias(){return this.blockRequestsWithType("media")}styles(){return this.blockRequestsWithType("css")}redirectTo(e){if(void 0!==this.redirect)throw new Error(`Already redirecting: ${this.redirect}`);return this.redirect=`redirect=${e}`,this}urlContains(e){if(void 0!==this.infix)throw new Error(`Already matching pattern: ${this.infix}`);return this.infix=e,this}urlStartsWith(e){if(void 0!==this.prefix)throw new Error(`Already matching prefix: ${this.prefix}`);return this.prefix=`|${e}`,this}urlEndsWith(e){if(void 0!==this.suffix)throw new Error(`Already matching suffix: ${this.suffix}`);return this.suffix=`${e}|`,this}withHostname(e){if(void 0!==this.prefix)throw new Error(`Cannot match hostname if filter already has prefix: ${this.prefix}`);return this.prefix=`||${e}^`,this}toString(){const e=[];void 0!==this.prefix&&e.push(this.prefix),void 0!==this.infix&&e.push(this.infix),void 0!==this.suffix&&e.push(this.suffix);const t=["important"];if(0!==this.options.size)for(const e of this.options)t.push(e);return void 0!==this.redirect&&t.push(this.redirect),`${0===e.length?"*":e.join("*")}$${t.join(",")}`}};function Jt(){return new Zt}var eo,to,oo=bt("http"),io=bt("https");(to=eo||(eo={}))[to.fromDocument=1]="fromDocument",to[to.fromFont=2]="fromFont",to[to.fromHttp=4]="fromHttp",to[to.fromHttps=8]="fromHttps",to[to.fromImage=16]="fromImage",to[to.fromMedia=32]="fromMedia",to[to.fromObject=64]="fromObject",to[to.fromOther=128]="fromOther",to[to.fromPing=256]="fromPing",to[to.fromScript=512]="fromScript",to[to.fromStylesheet=1024]="fromStylesheet",to[to.fromSubdocument=2048]="fromSubdocument",to[to.fromWebsocket=4096]="fromWebsocket",to[to.fromXmlHttpRequest=8192]="fromXmlHttpRequest",to[to.firstParty=16384]="firstParty",to[to.thirdParty=32768]="thirdParty",to[to.isReplace=65536]="isReplace",to[to.isBadFilter=131072]="isBadFilter",to[to.isCSP=262144]="isCSP",to[to.isGenericHide=524288]="isGenericHide",to[to.isImportant=1048576]="isImportant",to[to.isSpecificHide=2097152]="isSpecificHide",to[to.isFullRegex=4194304]="isFullRegex",to[to.isRegex=8388608]="isRegex",to[to.isUnicode=16777216]="isUnicode",to[to.isLeftAnchor=33554432]="isLeftAnchor",to[to.isRightAnchor=67108864]="isRightAnchor",to[to.isException=134217728]="isException",to[to.isHostnameAnchor=268435456]="isHostnameAnchor",to[to.isRedirectRule=536870912]="isRedirectRule",to[to.isRedirect=1073741824]="isRedirect";var no=eo.fromDocument|eo.fromFont|eo.fromImage|eo.fromMedia|eo.fromObject|eo.fromOther|eo.fromPing|eo.fromScript|eo.fromStylesheet|eo.fromSubdocument|eo.fromWebsocket|eo.fromXmlHttpRequest,so={beacon:eo.fromPing,document:eo.fromDocument,cspviolationreport:eo.fromOther,fetch:eo.fromXmlHttpRequest,font:eo.fromFont,image:eo.fromImage,imageset:eo.fromImage,mainFrame:eo.fromDocument,main_frame:eo.fromDocument,media:eo.fromMedia,object:eo.fromObject,object_subrequest:eo.fromObject,ping:eo.fromPing,script:eo.fromScript,stylesheet:eo.fromStylesheet,subFrame:eo.fromSubdocument,sub_frame:eo.fromSubdocument,webSocket:eo.fromWebsocket,websocket:eo.fromWebsocket,xhr:eo.fromXmlHttpRequest,xmlhttprequest:eo.fromXmlHttpRequest,cspReport:eo.fromOther,csp_report:eo.fromOther,eventsource:eo.fromOther,manifest:eo.fromOther,other:eo.fromOther,prefetch:eo.fromOther,preflight:eo.fromOther,signedexchange:eo.fromOther,speculative:eo.fromOther,texttrack:eo.fromOther,web_manifest:eo.fromOther,xml_dtd:eo.fromOther,xslt:eo.fromOther};function co(e){const t=[];return e.fromDocument()&&t.push("document"),e.fromImage()&&t.push("image"),e.fromMedia()&&t.push("media"),e.fromObject()&&t.push("object"),e.fromOther()&&t.push("other"),e.fromPing()&&t.push("ping"),e.fromScript()&&t.push("script"),e.fromStylesheet()&&t.push("stylesheet"),e.fromSubdocument()&&t.push("sub_frame"),e.fromWebsocket()&&t.push("websocket"),e.fromXmlHttpRequest()&&t.push("xhr"),e.fromFont()&&t.push("font"),t}function ro(e,t,o,i,n,s){let c=ht*ut^e;if(void 0!==i&&(c=i.updateId(c)),void 0!==n&&(c=n.updateId(c)),void 0!==t)for(let e=0;e>>0}function ao(e,t,o,i){return!0===i?new RegExp(e.slice(1,e.length-1),"i"):(e=(e=(e=e.replace(/([|.$+?{}()[\]\\])/g,"\\$1")).replace(/\*/g,".*")).replace(/\^/g,"(?:[^\\w\\d_.%-]|$)"),o&&(e=`${e}$`),t&&(e=`^${e}`),new RegExp(e))}function lo(e,t,o){const i=t;for(;t=48&&e<=57||e<=65&&e<=70||e>=97&&e<=102}function mo(e,t,o){const i=e.charCodeAt(t+1);return 44===i||47===i?[t+1,!1]:function(e,t,o){const i=e.charCodeAt(t+1);if(44===i||uo.has(i))return[t+1,!0];if(99===i){const o=e.charCodeAt(t+2);if(o>=65&&o<=90||o>=97&&o<=122)return[t+2,!0]}if(120===i&&ho(e.charCodeAt(t+2))&&ho(e.charCodeAt(t+3)))return[t+3,!0];if(117===i)if(123===e.charCodeAt(t+2)){const o=e.indexOf("}",t+3),i=o-t+3;if(i>=1&&i<=6)return[o,!0]}else if(ho(e.charCodeAt(t+2))&&ho(e.charCodeAt(t+3))&&ho(e.charCodeAt(t+4))&&ho(e.charCodeAt(t+5)))return[t+5,!0];return[t+1,!1]}(e,t)}function Ao(e,t,o){if(47!==e.charCodeAt(t++))return[o,void 0];const i=["","",""];let n=t,s=0;for(;t0&&92===e.charCodeAt(o-1);)o=e.lastIndexOf(t,o-1);return o}(t,"$");if(-1!==u&&47!==t.charCodeAt(u+1)){d=u;for(const e of function(e,t,o){const i=[];let n,s;for(;t0&&(c=p);break;case"ehide":case"elemhide":if(t)return null;r=gt(r,eo.isGenericHide),r=gt(r,eo.isSpecificHide);break;case"shide":case"specifichide":if(t)return null;r=gt(r,eo.isSpecificHide);break;case"ghide":case"generichide":if(t)return null;r=gt(r,eo.isGenericHide);break;case"inline-script":if(t)return null;r=gt(r,eo.isCSP),c="script-src 'self' 'unsafe-eval' http: https: data: blob: mediastream: filesystem:";break;case"inline-font":if(t)return null;r=gt(r,eo.isCSP),c="font-src 'self' 'unsafe-eval' http: https: data: blob: mediastream: filesystem:";break;case"replace":case"content":if(t||(0===p.length?!1===At(r,eo.isException):null===go(p)))return null;r=gt(r,eo.isReplace),c=p;break;default:{let e=0;switch(i){case"all":if(t)return null;break;case"image":e=eo.fromImage;break;case"media":e=eo.fromMedia;break;case"object":case"object-subrequest":e=eo.fromObject;break;case"other":e=eo.fromOther;break;case"ping":case"beacon":e=eo.fromPing;break;case"script":e=eo.fromScript;break;case"css":case"stylesheet":e=eo.fromStylesheet;break;case"frame":case"subdocument":e=eo.fromSubdocument;break;case"xhr":case"xmlhttprequest":e=eo.fromXmlHttpRequest;break;case"websocket":e=eo.fromWebsocket;break;case"font":e=eo.fromFont;break;case"doc":case"document":e=eo.fromDocument;break;default:return null}t?l=ft(l,e):a=gt(a,e);break}}}}let h;if(r|=0===a?l:l===no?a:a&l,d-p>=2&&47===t.charCodeAt(p)&&47===t.charCodeAt(d-1)){h=t.slice(p,d);try{ao(h,!1,!1,!0)}catch(e){return null}r=gt(r,eo.isFullRegex)}else{if(d>0&&124===t.charCodeAt(d-1)&&(r=gt(r,eo.isRightAnchor),d-=1),p0&&42===t.charCodeAt(d-1)&&(d-=1),!1===At(r,eo.isHostnameAnchor)&&d-p>0&&42===t.charCodeAt(p)&&(r=ft(r,eo.isLeftAnchor),p+=1),At(r,eo.isLeftAnchor)&&(d-p==5&&vt(t,"ws://",p)?(r=gt(r,eo.fromWebsocket),r=ft(r,eo.isLeftAnchor),r=ft(r,eo.fromHttp),r=ft(r,eo.fromHttps),p=d):d-p==7&&vt(t,"http://",p)?(r=gt(r,eo.fromHttp),r=ft(r,eo.fromHttps),r=ft(r,eo.isLeftAnchor),p=d):d-p==8&&vt(t,"https://",p)?(r=gt(r,eo.fromHttps),r=ft(r,eo.fromHttp),r=ft(r,eo.isLeftAnchor),p=d):d-p==8&&vt(t,"http*://",p)&&(r=gt(r,eo.fromHttps),r=gt(r,eo.fromHttp),r=ft(r,eo.isLeftAnchor),p=d)),d-p>0&&(h=t.slice(p,d).toLowerCase(),r=bo(r,eo.isUnicode,Tt(h)),!1===At(r,eo.isRegex)&&(r=bo(r,eo.isRegex,function(e,t,o){const i=e.indexOf("^",t);if(-1!==i&&it.length)return!1;if(e.length===t.length)return e===t;const i=t.indexOf(e);if(-1===i)return!1;if(0===i)return!0===o||46===t.charCodeAt(e.length)||46===e.charCodeAt(e.length-1);if(t.length===i+e.length)return 46===t.charCodeAt(i-1)||46===e.charCodeAt(0);return!(!0!==o&&46!==t.charCodeAt(e.length)&&46!==e.charCodeAt(e.length-1)||46!==t.charCodeAt(i-1)&&46!==e.charCodeAt(0))}(i,t.hostname,void 0!==e.filter&&42===e.filter.charCodeAt(0)))return!1;if(e.isRegex())return e.getRegex().test(t.url.slice(t.url.indexOf(i)+i.length));if(e.isRightAnchor()&&e.isLeftAnchor()){return o===t.url.slice(t.url.indexOf(i)+i.length)}if(e.isRightAnchor()){const n=t.hostname;return!1===e.hasFilter()?i.length===n.length||n.endsWith(i):t.url.endsWith(o)}return e.isLeftAnchor()?vt(t.url,o,t.url.indexOf(i)+i.length):!1===e.hasFilter()||-1!==t.url.indexOf(o,t.url.indexOf(i)+i.length)}if(e.isRegex())return e.getRegex().test(t.url);if(e.isLeftAnchor()&&e.isRightAnchor())return t.url===o;if(e.isLeftAnchor())return wt(t.url,o);if(e.isRightAnchor())return t.url.endsWith(o);if(!1===e.hasFilter())return!0;return-1!==t.url.indexOf(o)}(this,e)}serialize(e){e.pushUint32(this.mask);const t=e.getPos();e.pushUint8(0);let o=0;void 0!==this.filter&&(o|=1,this.isUnicode()?e.pushUTF8(this.filter):e.pushNetworkFilter(this.filter)),void 0!==this.hostname&&(o|=2,e.pushNetworkHostname(this.hostname)),void 0!==this.domains&&(o|=4,this.domains.serialize(e)),void 0!==this.rawLine&&(o|=8,e.pushRawNetwork(this.rawLine)),void 0!==this.denyallow&&(o|=16,this.denyallow.serialize(e)),void 0!==this.optionValue&&(o|=32,this.isCSP()?e.pushNetworkCSP(this.optionValue):this.isRedirect()?e.pushNetworkRedirect(this.optionValue):e.pushUTF8(this.optionValue)),e.setByte(t,o)}getSerializedSize(e){let t=5;return void 0!==this.filter&&(!0===this.isUnicode()?t+=de(this.filter):t+=function(e,t){return!0===t?le(ce().networkFilter.getCompressedSize(e),!1):pe(e)}(this.filter,e)),void 0!==this.hostname&&(t+=function(e,t){return!0===t?le(ce().networkHostname.getCompressedSize(e),!1):pe(e)}(this.hostname,e)),void 0!==this.domains&&(t+=this.domains.getSerializedSize()),void 0!==this.rawLine&&(t+=function(e,t){return!0===t?le(ce().networkRaw.getCompressedSize(te(e)),!1):de(e)}(this.rawLine,e)),void 0!==this.denyallow&&(t+=this.denyallow.getSerializedSize()),void 0!==this.optionValue&&(this.isCSP()?t+=function(e,t){return!0===t?le(ce().networkCSP.getCompressedSize(e),!1):pe(e)}(this.optionValue,e):this.isRedirect()?t+=function(e,t){return!0===t?le(ce().networkRedirect.getCompressedSize(e),!1):pe(e)}(this.optionValue,e):t+=de(this.optionValue)),t}toString(e){if(void 0!==this.rawLine)return this.rawLine;let t="";this.isException()&&(t+="@@"),this.isHostnameAnchor()?t+="||":this.fromHttp()!==this.fromHttps()?this.fromHttp()?t+="|http://":t+="|https://":this.isLeftAnchor()&&(t+="|"),this.hasHostname()&&(t+=this.getHostname(),t+="^"),this.isFullRegex()?t+=`/${this.getRegex().source}/`:this.isRegex()?t+=this.getRegex().source:t+=this.getFilter(),this.isRightAnchor()&&"^"!==t[t.length-1]&&(t+="|");const o=[];if(!1===this.fromAny()){const e=mt(this.getCptMask());if(mt(no)-e")),void 0!==this.denyallow&&(void 0!==this.denyallow.parts?o.push(`denyallow=${this.denyallow.parts}`):o.push("denyallow=")),this.isBadFilter()&&o.push("badfilter"),o.length>0&&(t+="function"==typeof e?`$${o.map(e).join(",")}`:`$${o.join(",")}`),t}getIdWithoutBadFilter(){return ro(this.mask&~eo.isBadFilter,this.filter,this.hostname,this.domains,this.denyallow,this.optionValue)}getId(){return void 0===this.id&&(this.id=ro(this.mask,this.filter,this.hostname,this.domains,this.denyallow,this.optionValue)),this.id}hasFilter(){return void 0!==this.filter}hasDomains(){return void 0!==this.domains}getMask(){return this.mask}getCptMask(){return this.getMask()&no}isRedirect(){return At(this.getMask(),eo.isRedirect)}isRedirectRule(){return At(this.mask,eo.isRedirectRule)}getRedirect(){var e;return null!==(e=this.optionValue)&&void 0!==e?e:""}isReplace(){return At(this.getMask(),eo.isReplace)}getHtmlModifier(){var e;return 0===(null===(e=this.optionValue)||void 0===e?void 0:e.length)?null:go(this.optionValue)}isHtmlFilteringRule(){return this.isReplace()}getRedirectResource(){const e=this.getRedirect(),t=e.lastIndexOf(":");return-1===t?e:e.slice(0,t)}getRedirectPriority(){const e=this.getRedirect(),t=e.lastIndexOf(":");return-1===t?0:Number(e.slice(t+1))}hasHostname(){return void 0!==this.hostname}getHostname(){return this.hostname||""}getFilter(){return this.filter||""}getRegex(){return void 0===this.regex&&(this.regex=void 0!==this.filter&&this.isRegex()?ao(this.filter,this.isLeftAnchor(),this.isRightAnchor(),this.isFullRegex()):fo),this.regex}getTokens(){if(dt.reset(),void 0!==this.domains&&void 0!==this.domains.hostnames&&void 0===this.domains.entities&&void 0===this.domains.notHostnames&&void 0===this.domains.notEntities&&1===this.domains.hostnames.length&&dt.push(this.domains.hostnames[0]),!1===this.isFullRegex()){if(void 0!==this.filter){const e=!this.isRightAnchor(),t=!this.isLeftAnchor();!function(e,t,o,i){const n=Math.min(e.length,2*i.remaining());let s=!1,c=0,r=0,a=ht;for(let o=0;o1&&42!==n&&42!==c&&(!1===t||0!==r)&&i.push(a>>>0)),c=n)}!1===o&&!0===s&&42!==c&&e.length-r>1&&!1===i.full()&&i.push(a>>>0)}(this.filter,t,e,dt)}void 0!==this.hostname&&St(this.hostname,!1,void 0!==this.filter&&42===this.filter.charCodeAt(0),dt)}else void 0!==this.filter&&function(e,t){let o=e.length-1,i=1,n=0;for(;i=i;o-=1){const t=e.charCodeAt(o);if(124===t)return;if(41===t||42===t||43===t||63===t||93===t||125===t||46===t&&92!==e.charCodeAt(o-1)||92===t&&Ct(n))break;n=t}if(o1&&St(e.slice(1,i),94!==e.charCodeAt(1),!0,t),oObject.prototype.hasOwnProperty.call(Io,e),To=(e,t)=>"true"===e&&!t.has("true")||!("false"===e&&!t.has("false"))&&!!t.get(e),Oo=(e,t)=>{if(0===e.length)return!1;if((e=>Eo.test(e))(e))return"!"===e[0]?!To(e.slice(1),t):To(e,t);const o=(e=>e.match(So))(e);if(!o||0===o.length)return!1;if(e.length!==o.reduce(((e,t)=>e+t.length),0))return!1;const i=[],n=[];for(const e of o)if("("===e)n.push(e);else if(")"===e){for(;0!==n.length&&"("!==n[n.length-1];)i.push(n.pop());if(0===n.length)return!1;n.pop()}else if(Fo(e)){for(;n.length&&Fo(n[n.length-1])&&Io[e]<=Io[n[n.length-1]];)i.push(n.pop());n.push(e)}else i.push(To(e,t));if("("===n[0]||")"===n[0])return!1;for(;0!==n.length;)i.push(n.pop());for(const e of i)if(!0===e||!1===e)n.push(e);else if("!"===e)n.push(!n.pop());else if(Fo(e)){const t=n.pop(),o=n.pop();"&&"===e?n.push(o&&t):n.push(o||t)}return!0===n[0]},Po=class e{static getCondition(e){return e.slice(5).replace(/\s/g,"")}static parse(t,o){return new this({condition:e.getCondition(t),filterIDs:o})}static deserialize(e){const t=e.getUTF8(),o=new Set;for(let t=0,i=e.getUint32();t2)for(;e4&&32===t.charCodeAt(0)&&32===t.charCodeAt(1)&&32===t.charCodeAt(2)&&32===t.charCodeAt(3)&&32!==t.charCodeAt(4)))break;a+=t.slice(4),e+=1}0!==a.length&&a.charCodeAt(a.length-1)<=32&&(a=a.trim());const l=Ro(a,{extendedNonSupportedTypes:!0});if(l===Co.NETWORK&&!0===t.loadNetworkFilters){const i=ko.parse(a,t.debug);null!==i?(o.push(i),r.length>0&&r[r.length-1].filterIDs.add(i.getId())):n.push({lineNumber:e,filter:a,filterType:l})}else if(l===Co.COSMETIC&&!0===t.loadCosmeticFilters){const o=Xt.parse(a,t.debug);null!==o?!0!==t.loadGenericCosmeticsFilters&&!1!==o.isGenericHide()||(i.push(o),r.length>0&&r[r.length-1].filterIDs.add(o.getId())):n.push({lineNumber:e,filter:a,filterType:Co.COSMETIC})}else if(t.loadPreprocessors){const t=_o(a);if(t===yo.BEGIF)r.length>0?r.push(new Po({condition:`(${r[r.length-1].condition})&&(${Po.getCondition(a)})`})):r.push(Po.parse(a));else if((t===yo.ENDIF||t===yo.ELSE)&&r.length>0){const e=r.pop();c.push(e),t===yo.ELSE&&r.push(new Po({condition:`!(${e.condition})`}))}else l===Co.NOT_SUPPORTED_ADGUARD&&n.push({lineNumber:e,filter:a,filterType:l})}else l===Co.NOT_SUPPORTED_ADGUARD&&n.push({lineNumber:e,filter:a,filterType:l})}return{networkFilters:o,cosmeticFilters:i,preprocessors:c.filter((e=>e.filterIDs.size>0)),notSupportedFilters:n}}(xo=Co||(Co={}))[xo.NOT_SUPPORTED=0]="NOT_SUPPORTED",xo[xo.NETWORK=1]="NETWORK",xo[xo.COSMETIC=2]="COSMETIC",xo[xo.NOT_SUPPORTED_EMPTY=100]="NOT_SUPPORTED_EMPTY",xo[xo.NOT_SUPPORTED_COMMENT=101]="NOT_SUPPORTED_COMMENT",xo[xo.NOT_SUPPORTED_ADGUARD=102]="NOT_SUPPORTED_ADGUARD";var Lo="video/flv",Bo={contentType:`${Lo};base64`,aliases:[Lo,".flv","flv"],body:"RkxWAQEAAAAJAAAAABIAALgAAAAAAAAAAgAKb25NZXRhRGF0YQgAAAAIAAhkdXJhdGlvbgAAAAAAAAAAAAAFd2lkdGgAP/AAAAAAAAAABmhlaWdodAA/8AAAAAAAAAANdmlkZW9kYXRhcmF0ZQBAaGoAAAAAAAAJZnJhbWVyYXRlAEBZAAAAAAAAAAx2aWRlb2NvZGVjaWQAQAAAAAAAAAAAB2VuY29kZXICAA1MYXZmNTcuNDEuMTAwAAhmaWxlc2l6ZQBAaoAAAAAAAAAACQAAAMM="},Uo="image/gif",No={contentType:`${Uo};base64`,aliases:[Uo,".gif","gif"],body:"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"},Vo="text/html",jo={contentType:Vo,aliases:[Vo,".html","html",".htm","htm","noopframe","noop.html"],body:""},Mo="image/vnd.microsoft.icon",Do={contentType:`${Mo};base64`,aliases:[Mo,".ico","ico"],body:"AAABAAEAAQEAAAEAGAAwAAAAFgAAACgAAAABAAAAAgAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAA=="},Ho="image/jpeg",Wo={contentType:`${Ho};base64`,aliases:[Ho,".jpg","jpg",".jpeg","jpeg"],body:"/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k="},qo="application/javascript",Go={contentType:qo,aliases:[qo,".js","js","javascript",".jsx","jsx","typescript",".ts","ts","noop.js","noopjs"],body:""},$o="application/json",Ko={contentType:$o,aliases:[$o,".json","json"],body:"0"},Qo="audio/mpeg",Yo={contentType:`${Qo};base64`,aliases:[Qo,".mp3","mp3","noop-0.1s.mp3","noopmp3-0.1s"],body:"/+MYxAAAAANIAAAAAExBTUUzLjk4LjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},Xo="video/mp4",Zo={contentType:`${Xo};base64`,aliases:[Xo,".mp4","mp4",".m4a","m4a",".m4p","m4p",".m4b","m4b",".m4r","m4r",".m4v","m4v","noop-1s.mp4","noopmp4-1s"],body:"AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAC721kYXQhEAUgpBv/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3pwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcCEQBSCkG//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADengAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAsJtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAALwABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAB7HRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAIAAAAAAAAALwAAAAAAAAAAAAAAAQEAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAC8AAAAAAAEAAAAAAWRtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAAKxEAAAIAFXEAAAAAAAtaGRscgAAAAAAAAAAc291bgAAAAAAAAAAAAAAAFNvdW5kSGFuZGxlcgAAAAEPbWluZgAAABBzbWhkAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAADTc3RibAAAAGdzdHNkAAAAAAAAAAEAAABXbXA0YQAAAAAAAAABAAAAAAAAAAAAAgAQAAAAAKxEAAAAAAAzZXNkcwAAAAADgICAIgACAASAgIAUQBUAAAAAAfQAAAHz+QWAgIACEhAGgICAAQIAAAAYc3R0cwAAAAAAAAABAAAAAgAABAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAIAAAABAAAAHHN0c3oAAAAAAAAAAAAAAAIAAAFzAAABdAAAABRzdGNvAAAAAAAAAAEAAAAsAAAAYnVkdGEAAABabWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcmFwcGwAAAAAAAAAAAAAAAAtaWxzdAAAACWpdG9vAAAAHWRhdGEAAAABAAAAAExhdmY1Ni40MC4xMDE="},Jo="application/pdf",ei={contentType:`${Jo};base64`,aliases:[Jo,".pdf","pdf"],body:"JVBERi0xLgoxIDAgb2JqPDwvUGFnZXMgMiAwIFI+PmVuZG9iagoyIDAgb2JqPDwvS2lkc1szIDAgUl0vQ291bnQgMT4+ZW5kb2JqCjMgMCBvYmo8PC9QYXJlbnQgMiAwIFI+PmVuZG9iagp0cmFpbGVyIDw8L1Jvb3QgMSAwIFI+Pg=="},ti="image/png",oi={contentType:`${ti};base64`,aliases:[ti,".png","png"],body:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg=="},ii="image/svg+xml",ni={contentType:ii,aliases:[ii,".svg","svg"],body:"https://raw.githubusercontent.com/mathiasbynens/small/master/svg.svg"},si="text/plain",ci={contentType:si,aliases:[si,".txt","txt","text","nooptext","noop.txt"],body:""},ri="audio/wav",ai={contentType:`${ri};base64`,aliases:[ri,".wav","wav"],body:"UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA="},li="video/webm",pi={contentType:`${li};base64`,aliases:[li,".webm","webm"],body:"GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA="},di="image/webp",ui={contentType:`${di};base64`,aliases:[di,".webp","webp"],body:"UklGRhIAAABXRUJQVlA4TAYAAAAvQWxvAGs="},hi="video/wmv",mi={contentType:`${hi};base64`,aliases:[hi,".wmv","wmv"],body:"MCaydY5mzxGm2QCqAGLObOUBAAAAAAAABQAAAAECodyrjEepzxGO5ADADCBTZWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcCAAAAAAAAAIA+1d6xnQEAAAAAAAAAAMAF2QEAAAAAAAAAAAAAAAAcDAAAAAAAAAIAAACADAAAgAwAAEANAwC1A79fLqnPEY7jAMAMIFNlLgAAAAAAAAAR0tOruqnPEY7mAMAMIFNlBgAAAAAAQKTQ0gfj0hGX8ACgyV6oUGQAAAAAAAAAAQAoAFcATQAvAEUAbgBjAG8AZABpAG4AZwBTAGUAdAB0AGkAbgBnAHMAAAAAABwATABhAHYAZgA1ADcALgA0ADEALgAxADAAMAAAAJEH3Le3qc8RjuYAwAwgU2WBAAAAAAAAAMDvGbxNW88RqP0AgF9cRCsAV/sgVVvPEaj9AIBfXEQrAAAAAAAAAAAzAAAAAAAAAAEAAAAAAAEAAAABAAAAAigAKAAAAAEAAAABAAAAAQAYAE1QNDMDAAAAAAAAAAAAAAAAAAAAAAAAAEBS0YYdMdARo6QAoMkDSPZMAAAAAAAAAEFS0YYdMdARo6QAoMkDSPYBAAAAAQAKAG0AcwBtAHAAZQBnADQAdgAzAAAAAAAEAE1QNDM2JrJ1jmbPEabZAKoAYs5sMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQ=="},Ai=(()=>{const e={};for(const t of[Bo,No,jo,Do,Wo,Go,Ko,Yo,Zo,ei,oi,ni,ci,ai,pi,ui,mi])for(const o of t.aliases)e[o]=t;return e})();function gi(e){return Ai[e]||ci}function fi(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{name:t,aliases:o,body:i,contentType:n}=e;return"string"==typeof t&&(!(!Array.isArray(o)||!o.every((e=>"string"==typeof e)))&&("string"==typeof i&&"string"==typeof n))}function ki(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{name:t,aliases:o,body:i,dependencies:n,executionWorld:s,requiresTrust:c}=e;return"string"==typeof t&&(!(!Array.isArray(o)||!o.every((e=>"string"==typeof e)))&&("string"==typeof i&&(!(!Array.isArray(n)||!n.every((e=>"string"==typeof e)))&&((void 0===s||"MAIN"===s||"ISOLATED"===s)&&(void 0===c||"boolean"==typeof c)))))}var bi=class e{static deserialize(t){const o=t.getASCII(),i=[],n=[];for(let e=0,o=t.getUint16();e["if (typeof scriptletGlobals === 'undefined') { var scriptletGlobals = {}; }",...t,`(${e})(...['{{1}}','{{2}}','{{3}}','{{4}}','{{5}}','{{6}}','{{7}}','{{8}}','{{9}}','{{10}}'].filter((a,i) => a !== '{{'+(i+1)+'}}').map((a) => decodeURIComponent(a)))`].join(";"))(t.body,i),this.scriptletsCache.set(t.name,o),o}getSurrogate(e){const t=this.resourcesByName.get(e.endsWith(".js")?e:`${e}.js`);if(void 0!==t&&"application/javascript"===t.contentType)return t.body}getScriptletCanonicalName(e){var t;return null===(t=this.getRawScriptlet(e))||void 0===t?void 0:t.name}getRawScriptlet(e){if(!e.endsWith(".fn"))return this.scriptletsByName.get(e.endsWith(".js")?e:`${e}.js`)}getScriptletDependencies(e){const t=new Map,o=[...e.dependencies];for(;o.length>0;){const e=o.pop();if(t.has(e))continue;const i=this.scriptletsByName.get(e);t.set(e,i.body),o.push(...i.dependencies)}return Array.from(t.values())}getSerializedSize(){let e=pe(this.checksum);e+=2;for(const{name:t,aliases:o,body:i,contentType:n}of this.resources)e+=pe(t),e+=o.reduce(((e,t)=>e+pe(t)),2),e+=de(i),e+=pe(n);e+=2;for(const{name:t,aliases:o,body:i,dependencies:n}of this.scriptlets)e+=pe(t),e+=o.reduce(((e,t)=>e+pe(t)),2),e+=de(i),e+=1,e+=1,e+=1,e+=1,e+=n.reduce(((e,t)=>e+pe(t)),2);return e}serialize(e){e.pushASCII(this.checksum),e.pushUint16(this.resources.length);for(const{name:t,aliases:o,body:i,contentType:n}of this.resources){e.pushASCII(t),e.pushUint16(o.length);for(const t of o)e.pushASCII(t);e.pushUTF8(i),e.pushASCII(n)}e.pushUint16(this.scriptlets.length);for(const{name:t,aliases:o,body:i,dependencies:n,executionWorld:s,requiresTrust:c}of this.scriptlets){e.pushASCII(t),e.pushUint16(o.length);for(const t of o)e.pushASCII(t);e.pushUTF8(i),e.pushBool(void 0!==s),e.pushBool("ISOLATED"===s),e.pushBool(void 0!==c),e.pushBool(!0===c),e.pushUint16(n.length),n.forEach((t=>e.pushASCII(t)))}}};var yi=new Uint32Array(0);function wi(e){return`(?:${e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&")})`}function vi(e,t,o){let i=e.get(t);void 0===i&&(i=[],e.set(t,i)),i.push(o)}function _i(e,t){const o=new Map;for(const i of e)vi(o,t(i),i);return Array.from(o.values())}function Ci(e,t){const o=[],i=[];for(const n of e)t(n)?o.push(n):i.push(n);return{negative:i,positive:o}}var xi=[{description:"Remove duplicated filters by ID",fusion:e=>e[0],groupByCriteria:e=>""+e.getId(),select:()=>!0},{description:"Group idential filter with same mask but different domains in single filters",fusion:e=>{const t=[],o=new Set,i=new Set,n=new Set,s=new Set;for(const{domains:c}of e)if(void 0!==c){if(void 0!==c.parts&&t.push(c.parts),void 0!==c.hostnames)for(const e of c.hostnames)o.add(e);if(void 0!==c.entities)for(const e of c.entities)n.add(e);if(void 0!==c.notHostnames)for(const e of c.notHostnames)i.add(e);if(void 0!==c.notEntities)for(const e of c.notEntities)s.add(e)}return new ko(Object.assign({},e[0],{domains:new Nt({hostnames:0!==o.size?new Uint32Array(o).sort():void 0,entities:0!==n.size?new Uint32Array(n).sort():void 0,notHostnames:0!==i.size?new Uint32Array(i).sort():void 0,notEntities:0!==s.size?new Uint32Array(s).sort():void 0,parts:0!==t.length?t.join(","):void 0}),rawLine:void 0!==e[0].rawLine?e.map((({rawLine:e})=>e)).join(" <+> "):void 0}))},groupByCriteria:e=>{var t;return e.getHostname()+e.getFilter()+e.getMask()+(null!==(t=e.optionValue)&&void 0!==t?t:"")},select:e=>!e.isCSP()&&void 0===e.denyallow&&void 0!==e.domains},{description:"Group simple patterns, into a single filter",fusion:e=>{const t=[];for(const o of e)o.isRegex()?t.push(`(?:${o.getRegex().source})`):o.isRightAnchor()?t.push(`${wi(o.getFilter())}$`):o.isLeftAnchor()?t.push(`^${wi(o.getFilter())}`):t.push(wi(o.getFilter()));return new ko(Object.assign({},e[0],{mask:gt(e[0].mask,eo.isRegex),rawLine:void 0!==e[0].rawLine?e.map((({rawLine:e})=>e)).join(" <+> "):void 0,regex:new RegExp(t.join("|"))}))},groupByCriteria:e=>""+(e.getMask()&~eo.isRegex&~eo.isFullRegex),select:e=>void 0===e.domains&&void 0===e.denyallow&&!e.isHostnameAnchor()&&!e.isRedirect()&&!e.isCSP()}];function Si(e){return e}function Ei(e){return e}function Ii(e){const t=[];let o=e;for(const{select:e,fusion:i,groupByCriteria:n}of xi){const{positive:s,negative:c}=Ci(o,e);o=c;const r=_i(s,n);for(const e of r)e.length>1?t.push(i(e)):o.push(e[0])}for(const e of o)t.push(e);return t}function Fi(e){return e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,e|=e>>16,++e}var Ti=1;var Oi=Number.MAX_SAFE_INTEGER>>>0,Pi=class e{static deserialize(t,o,i,n){const s=t.getUint32(),c=t.getUint32(),r=t.getUint32(),a=me.fromUint8Array(t.getBytes(!0),n),l=a.getUint32ArrayView(s),p=a.getUint32ArrayView(c),d=a.pos;return a.seekZero(),new e({config:n,deserialize:o,filters:[],optimize:i}).updateInternals({bucketsIndex:p,filtersIndexStart:d,numberOfFilters:r,tokensLookupIndex:l,view:a})}constructor({deserialize:e,filters:t,optimize:o,config:i}){this.bucketsIndex=ne,this.filtersIndexStart=0,this.numberOfFilters=0,this.tokensLookupIndex=ne,this.cache=new Map,this.view=me.empty(i),this.deserializeFilter=e,this.optimize=o,this.config=i,0!==t.length&&this.update(t,void 0)}getFilters(){const e=[];if(0===this.numberOfFilters)return e;this.view.setPos(this.filtersIndexStart);for(let t=0;t!t.has(e.getId())||(r-=e.getSerializedSize(o),!1))));for(const t of e)r+=t.getSerializedSize(o),a.push(t)}else{a=e;for(const t of e)r+=t.getSerializedSize(o)}if(0===a.length)return void this.updateInternals({bucketsIndex:ne,filtersIndexStart:0,numberOfFilters:0,tokensLookupIndex:ne,view:me.empty(this.config)});!0===this.config.debug&&a.sort(((e,t)=>e.getId()-t.getId()));const l=new Uint32Array(Math.max(Fi(2*a.length),256));for(const e of a){const t=e.getTokens();s.push(t),c+=2*t.length,n+=t.length;for(const e of t){i+=e.length;for(const t of e)l[t%l.length]+=1}}r+=4*c;const p=Math.max(2,Fi(n)),d=p-1,u=[];for(let e=0;e1?this.optimize(c):c,lastRequestSeen:-1},!0===this.config.enableInMemoryCache&&this.cache.set(e,i)}if(i.lastRequestSeen!==t){i.lastRequestSeen=t;const e=i.filters;for(let t=0;t0){const o=e[t];e[t]=e[t-1],e[t-1]=o}return!1}}return!0}},Ri=new Uint8Array(4),zi=class e{static deserialize(t,o,i){const n=new e({deserialize:o,config:i,filters:[]});return n.filters=t.getBytes(),n}constructor({config:e,deserialize:t,filters:o}){this.deserialize=t,this.filters=Ri,this.config=e,0!==o.length&&this.update(o,void 0)}update(e,t){let o=this.filters.byteLength,i=[];const n=this.config.enableCompression,s=this.getFilters();if(0!==s.length)if(void 0===t||0===t.size)i=s;else for(const e of s)!1===t.has(e.getId())?i.push(e):o-=e.getSerializedSize(n);const c=i.length!==s.length,r=i.length;for(const t of e)o+=t.getSerializedSize(n),i.push(t);const a=i.length>r;if(0===i.length)this.filters=Ri;else if(!0===a||!0===c){const e=me.allocate(o,this.config);e.pushUint32(i.length),!0===this.config.debug&&i.sort(((e,t)=>e.getId()-t.getId()));for(const t of i)t.serialize(e);this.filters=e.buffer}}getSerializedSize(){return ae(this.filters,!1)}serialize(e){e.pushBytes(this.filters)}getFilters(){if(this.filters.byteLength<=4)return[];const e=[],t=me.fromUint8Array(this.filters,this.config),o=t.getUint32();for(let i=0;i(!0!==c&&!0!==o.isScriptInject()||!o.match(t,e)||(null==p?void 0:p(o))||u.push(o),!0))),!0===s&&!0===a){const o=this.getGenericRules(l);for(const i of o)!0!==i.match(t,e)||(null==p?void 0:p(i))||u.push(i)}!0===s&&!0===r&&0!==o.length&&this.classesIndex.iterMatchingFilters(yt(o),(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&u.push(o),!0))),!0===s&&!0===r&&0!==n.length&&this.idsIndex.iterMatchingFilters(yt(n),(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&u.push(o),!0))),!0===s&&!0===r&&0!==i.length&&this.hrefsIndex.iterMatchingFilters(function(e){const t=e.sort();let o=1;for(let e=1;e{return t=e,dt.reset(),Et(t,dt),dt.slice();var t})))),(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&u.push(o),!0)));const h=[];return 0!==u.length&&this.unhideIndex.iterMatchingFilters(d,(o=>(o.match(t,e)&&!(null==p?void 0:p(o))&&h.push(o),!0))),{filters:u,unhides:h}}getStylesheetsFromFilters({filters:e,extendedFilters:t},{getBaseRules:o,allowGenericHides:i,hidingStyle:n=Mt}){let s=!1===o||!1===i?"":this.getBaseStylesheet(n);0!==e.length&&(0!==s.length&&(s+="\n\n"),s+=Ui(e,n));const c=[];if(0!==t.length){const e=new Map;for(const o of t){const t=o.getSelectorAST();if(void 0!==t){const i=o.isRemove()?void 0:o.getStyleAttributeHash();void 0!==i&&e.set(o.getStyle(n),i),c.push({ast:t,remove:o.isRemove(),attribute:i})}}0!==e.size&&(0!==s.length&&(s+="\n\n"),s+=[...e.entries()].map((([e,t])=>`[${t}] { ${e} }`)).join("\n\n"))}return{stylesheet:s,extended:c}}getGenericRules(e){return null===this.extraGenericRules?this.lazyPopulateGenericRulesCache(e).genericRules:this.extraGenericRules}getBaseStylesheet(e){return null===this.baseStylesheet?this.lazyPopulateGenericRulesCache(e).baseStylesheet:this.baseStylesheet}lazyPopulateGenericRulesCache(e){if(null===this.baseStylesheet||null===this.extraGenericRules){const t=this.unhideIndex.getFilters(),o=new Set;for(const e of t)o.add(e.getSelector());const i=this.genericRules.getFilters(),n=[],s=[];for(const e of i)e.hasCustomStyle()||e.isScriptInject()||e.hasHostnameConstraint()||o.has(e.getSelector())?s.push(e):n.push(e);this.baseStylesheet=Ui(n,e),this.extraGenericRules=s}return{baseStylesheet:this.baseStylesheet,genericRules:this.extraGenericRules}}},ji=class e{static deserialize(t,o){const i=new e({config:o});return i.index=Pi.deserialize(t,ko.deserialize,o.enableOptimizations?Ii:Si,o),i.badFilters=zi.deserialize(t,ko.deserialize,o),i}constructor({filters:e=[],config:t}){this.index=new Pi({config:t,deserialize:ko.deserialize,filters:[],optimize:t.enableOptimizations?Ii:Si}),this.badFiltersIds=null,this.badFilters=new zi({config:t,deserialize:ko.deserialize,filters:[]}),0!==e.length&&this.update(e,void 0)}getFilters(){return[].concat(this.badFilters.getFilters(),this.index.getFilters())}update(e,t){const o=[],i=[];for(const t of e)t.isBadFilter()?o.push(t):i.push(t);this.badFilters.update(o,t),this.index.update(i,t),this.badFiltersIds=null}getSerializedSize(){return this.badFilters.getSerializedSize()+this.index.getSerializedSize()}serialize(e){this.index.serialize(e),this.badFilters.serialize(e)}matchAll(e,t){const o=[];return this.index.iterMatchingFilters(e.getTokens(),(i=>(i.match(e)&&!1===this.isFilterDisabled(i)&&!(null==t?void 0:t(i))&&o.push(i),!0))),o}match(e,t){let o;return this.index.iterMatchingFilters(e.getTokens(),(i=>!(i.match(e)&&!1===this.isFilterDisabled(i)&&!(null==t?void 0:t(i)))||(o=i,!1))),o}isFilterDisabled(e){if(null===this.badFiltersIds){const e=this.badFilters.getFilters();if(0===e.length)return!1;const t=new Set;for(const o of e)t.add(o.getIdWithoutBadFilter());this.badFiltersIds=t}return this.badFiltersIds.has(e.getId())}},Mi=class e{static deserialize(t,o){const i=new e({config:o});return i.networkIndex=Pi.deserialize(t,ko.deserialize,o.enableOptimizations?Ii:Si,o),i.exceptionsIndex=Pi.deserialize(t,ko.deserialize,o.enableOptimizations?Ii:Si,o),i.cosmeticIndex=Pi.deserialize(t,Xt.deserialize,Ei,o),i.unhideIndex=Pi.deserialize(t,Xt.deserialize,Ei,o),i}constructor({filters:e=[],config:t}){this.config=t,this.networkIndex=new Pi({config:t,deserialize:ko.deserialize,filters:[],optimize:t.enableOptimizations?Ii:Si}),this.exceptionsIndex=new Pi({config:t,deserialize:ko.deserialize,filters:[],optimize:t.enableOptimizations?Ii:Si}),this.cosmeticIndex=new Pi({config:t,deserialize:Xt.deserialize,filters:[],optimize:Ei}),this.unhideIndex=new Pi({config:t,deserialize:Xt.deserialize,filters:[],optimize:Ei}),0!==e.length&&this.update(e,void 0)}update(e,t){const o=[],i=[],n=[],s=[];for(const t of e)t.isNetworkFilter()?t.isException()?i.push(t):o.push(t):t.isCosmeticFilter()&&(t.isUnhide()?s.push(t):n.push(t));this.networkIndex.update(o,t),this.exceptionsIndex.update(i,t),this.cosmeticIndex.update(n,t),this.unhideIndex.update(s,t)}serialize(e){this.networkIndex.serialize(e),this.exceptionsIndex.serialize(e),this.cosmeticIndex.serialize(e),this.unhideIndex.serialize(e)}getSerializedSize(){return this.networkIndex.getSerializedSize()+this.exceptionsIndex.getSerializedSize()+this.cosmeticIndex.getSerializedSize()+this.unhideIndex.getSerializedSize()}getHTMLFilters(e,t){const o=[],i=[],n=[],s=[];if(!0===this.config.loadNetworkFilters&&this.networkIndex.iterMatchingFilters(e.getTokens(),(i=>(i.match(e)&&!(null==t?void 0:t(i))&&o.push(i),!0))),0!==o.length&&this.exceptionsIndex.iterMatchingFilters(e.getTokens(),(o=>(o.match(e)&&!(null==t?void 0:t(o))&&n.push(o),!0))),!0===this.config.loadCosmeticFilters&&e.isMainFrame()){const{hostname:o,domain:n=""}=e,c=Ni(o,n);this.cosmeticIndex.iterMatchingFilters(c,(e=>(e.match(o,n)&&!(null==t?void 0:t(e))&&i.push(e),!0))),0!==i.length&&this.unhideIndex.iterMatchingFilters(c,(e=>(e.match(o,n)&&!(null==t?void 0:t(e))&&s.push(e),!0)))}return{networkFilters:o,cosmeticFilters:i,unhides:s,exceptions:n}}getFilters(){return[].concat(this.networkIndex.getFilters(),this.exceptionsIndex.getFilters(),this.cosmeticIndex.getFilters(),this.unhideIndex.getFilters())}},Di=Number.MAX_SAFE_INTEGER>>>0,Hi=class e{static deserialize(t,o){const i=t.getUint32(),n=t.getUint32(),s=t.getUint32(),c=me.fromUint8Array(t.getBytes(!0),{enableCompression:!1}),r=c.getUint32ArrayView(i),a=c.getUint32ArrayView(n),l=c.pos;return c.seekZero(),new e({deserialize:o,values:[],getKeys:()=>[],getSerializedSize:()=>0,serialize:()=>{}}).updateInternals({bucketsIndex:a,valuesIndexStart:l,numberOfValues:s,tokensLookupIndex:r,view:c})}constructor({serialize:e,deserialize:t,getKeys:o,getSerializedSize:i,values:n}){if(this.cache=new Map,this.bucketsIndex=ne,this.tokensLookupIndex=ne,this.valuesIndexStart=0,this.numberOfValues=0,this.view=me.empty({enableCompression:!1}),this.deserializeValue=t,0!==n.length){const t=[];let s=0,c=0;for(const e of n)c+=i(e);if(0===n.length)return void this.updateInternals({bucketsIndex:ne,valuesIndexStart:0,numberOfValues:0,tokensLookupIndex:ne,view:me.empty({enableCompression:!1})});for(const e of n){const i=o(e);t.push(i),s+=2*i.length}c+=4*s;const r=Math.max(2,Fi(n.length)),a=r-1,l=[];for(let e=0;e[qi(e)],serialize:$i,deserialize:Ki,values:e})}function Yi(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{key:t,name:o,description:i,country:n,website_url:s,privacy_policy_url:c,privacy_contact:r,ghostery_id:a}=e;return"string"==typeof t&&("string"==typeof o&&((null===i||"string"==typeof i)&&((null===n||"string"==typeof n)&&((null===s||"string"==typeof s)&&((null===c||"string"==typeof c)&&((null===r||"string"==typeof r)&&(null===a||"string"==typeof a)))))))}function Xi(e){return bt(e.key)}function Zi(e){return de(e.key)+de(e.name)+de(e.description||"")+de(e.website_url||"")+de(e.country||"")+de(e.privacy_policy_url||"")+de(e.privacy_contact||"")+de(e.ghostery_id||"")}function Ji(e,t){t.pushUTF8(e.key),t.pushUTF8(e.name),t.pushUTF8(e.description||""),t.pushUTF8(e.website_url||""),t.pushUTF8(e.country||""),t.pushUTF8(e.privacy_policy_url||""),t.pushUTF8(e.privacy_contact||""),t.pushUTF8(e.ghostery_id||"")}function en(e){return{key:e.getUTF8(),name:e.getUTF8(),description:e.getUTF8()||null,website_url:e.getUTF8()||null,country:e.getUTF8()||null,privacy_policy_url:e.getUTF8()||null,privacy_contact:e.getUTF8()||null,ghostery_id:e.getUTF8()||null}}function tn(e){return new Hi({getSerializedSize:Zi,getKeys:e=>[Xi(e)],serialize:Ji,deserialize:en,values:e})}function on(e){if(null===e)return!1;if("object"!=typeof e)return!1;const{key:t,name:o,category:i,organization:n,alias:s,website_url:c,domains:r,filters:a}=e;return"string"==typeof t&&("string"==typeof o&&("string"==typeof i&&((null===n||"string"==typeof n)&&(("string"==typeof s||null===s)&&((null===c||"string"==typeof c)&&(!(!Array.isArray(r)||!r.every((e=>"string"==typeof e)))&&!(!Array.isArray(a)||!a.every((e=>"string"==typeof e)))))))))}function nn(e){const t=[];for(const o of e.filters){const e=ko.parse(o);null!==e&&t.push(e.getId())}for(const o of e.domains){const e=ko.parse(`||${o}^`);null!==e&&t.push(e.getId())}return[...new Set(t)]}function sn(e){let t=re(e.domains.length);for(const o of e.domains)t+=de(o);let o=re(e.filters.length);for(const t of e.filters)o+=de(t);return de(e.key)+de(e.name)+de(e.category)+de(e.organization||"")+de(e.alias||"")+de(e.website_url||"")+de(e.ghostery_id||"")+t+o}function cn(e,t){t.pushUTF8(e.key),t.pushUTF8(e.name),t.pushUTF8(e.category),t.pushUTF8(e.organization||""),t.pushUTF8(e.alias||""),t.pushUTF8(e.website_url||""),t.pushUTF8(e.ghostery_id||""),t.pushLength(e.domains.length);for(const o of e.domains)t.pushUTF8(o);t.pushLength(e.filters.length);for(const o of e.filters)t.pushUTF8(o)}function rn(e){const t=e.getUTF8(),o=e.getUTF8(),i=e.getUTF8(),n=e.getUTF8()||null,s=e.getUTF8()||null,c=e.getUTF8()||null,r=e.getUTF8()||null,a=e.getLength(),l=[];for(let t=0;t=2;t.shift()){const e=t.join("."),o=ko.parse(`||${e}^`);if(null===o)continue;const i=this.fromId(o.getId());if(i.length>0)return i}return[]}fromId(e){var t,o;const i=[];for(const n of this.patterns.get(e))i.push({pattern:n,category:null===(t=this.categories.get(qi({key:n.category})))||void 0===t?void 0:t[0],organization:null!==n.organization?null===(o=this.organizations.get(Xi({key:n.organization})))||void 0===o?void 0:o[0]:null});return i}},pn=class{static deserialize(e){const t=new Set;for(let o=0,i=e.getUint32();ot.condition===e.condition));if(t)for(const o of e.filterIDs)t.filterIDs.delete(o)}if(e)for(const t of e){const e=this.preprocessors.find((e=>e.condition===t.condition));if(e)for(const o of t.filterIDs)e.filterIDs.add(o);else this.preprocessors.push(t)}(t&&0!==t.length||e&&0!==e.length)&&this.updateEnv(o)}serialize(e){e.pushUint32(this.excluded.size);for(const t of this.excluded)e.pushUint32(t);e.pushUint32(this.preprocessors.length);for(const t of this.preprocessors)t.serialize(e)}getSerializedSize(){let e=4*(1+this.excluded.size);e+=4;for(const t of this.preprocessors)e+=t.getSerializedSize();return e}};function dn(e){if(0===e.length)return!1;let t,o=0;for(const i of e){const e=(i.isImportant()?4:0)|(i.isException()?1:2);e>=o&&(o=e,t=i)}return void 0!==t&&t.isException()}var un=class extends ye{static fromCached(e,t){if(void 0===t)return e();const{path:o,read:i,write:n}=t;return i(o).then((e=>this.deserialize(e))).catch((()=>e().then((e=>n(o,e.serialize()).then((()=>e))))))}static empty(e={}){return new this({config:e})}static fromLists(e,t,o={},i){return this.fromCached((()=>{const i=function(e,t){return Promise.all(t.map((t=>we(e,t))))}(e,t),n=function(e){return we(e,`${ve}/ublock-origin/resources.json`)}(e);return Promise.all([i,n]).then((([e,t])=>{const i=this.parse(e.join("\n"),o);return void 0!==t&&i.updateResources(t,""+t.length),i}))}),i)}static fromPrebuiltAdsOnly(e=fetch,t){return this.fromLists(e,_e,{},t)}static fromPrebuiltAdsAndTracking(e=fetch,t){return this.fromLists(e,Ce,{},t)}static fromPrebuiltFull(e=fetch,t){return this.fromLists(e,xe,{},t)}static fromTrackerDB(e,t={}){const o=new Ae(t),i=new ln(e),n=[];for(const e of i.getPatterns())n.push(...e.filters);const s=this.parse(n.join("\n"),o);return s.metadata=i,s}static merge(e,{skipResources:t=!1}={}){if(!e||e.length<2)throw new Error("merging engines requires at least two engines");const o=e[0].config,i=new Map,n=new Map,s=new Map,c=[],r={organizations:{},categories:{},patterns:{}},a=[],l=Object.keys(o).filter((function(e){return"boolean"==typeof o[e]&&!a.includes(e)}));for(const t of e){for(const e of l)if(o[e]!==t.config[e])throw new Error(`config "${e}" of all merged engines must be the same`);const e=t.getFilters();for(const t of e.networkFilters)n.set(t.getId(),t);for(const t of e.cosmeticFilters)s.set(t.getId(),t);for(const e of t.preprocessors.preprocessors)c.push(e);for(const[e,o]of t.lists)i.has(e)||i.set(e,o);if(void 0!==t.metadata){for(const e of t.metadata.organizations.getValues())void 0===r.organizations[e.key]&&(r.organizations[e.key]=e);for(const e of t.metadata.categories.getValues())void 0===r.categories[e.key]&&(r.categories[e.key]=e);for(const e of t.metadata.patterns.getValues())void 0===r.patterns[e.key]&&(r.patterns[e.key]=e)}}const p=new this({networkFilters:Array.from(n.values()),cosmeticFilters:Array.from(s.values()),preprocessors:c,lists:i,config:o});if(Object.keys(r.categories).length+Object.keys(r.organizations).length+Object.keys(r.patterns).length!==0&&(p.metadata=new ln(r)),!0!==t){for(const t of e.slice(1))if(t.resources.checksum!==e[0].resources.checksum)throw new Error(`resource checksum of all merged engines must match with the first one: "${e[0].resources.checksum}" but got: "${t.resources.checksum}"`);p.resources=bi.copy(e[0].resources)}return p}static parse(e,t={}){const o=new Ae(t);return new this({...zo(e,o),config:o})}static deserialize(e){const t=me.fromUint8Array(e,{enableCompression:!1}),o=t.getUint16();if(699!==o)throw new Error(`serialized engine version mismatch, expected 699 but got ${o}`);const i=Ae.deserialize(t);if(i.enableCompression&&t.enableCompression(),i.integrityCheck){const o=t.pos;t.pos=e.length-4;const i=t.checksum(),n=t.getUint32();if(i!==n)throw new Error(`serialized engine checksum mismatch, expected ${n} but got ${i}`);t.pos=o}const n=new this({config:i});n.resources=bi.deserialize(t);const s=new Map,c=t.getUint16();for(let e=0;ee.getId()))).concat(o.map((e=>e.getId()))));l.push(new Po({condition:e,filterIDs:n}))}if(void 0!==t.added&&0!==t.added.length){const{networkFilters:o,cosmeticFilters:i}=zo(t.added.join("\n"),this.config),n=new Set([].concat(i.map((e=>e.getId()))).concat(o.map((e=>e.getId()))));c.push(new Po({condition:e,filterIDs:n}))}}return this.update({newCosmeticFilters:n,newNetworkFilters:s,newPreprocessors:c,removedCosmeticFilters:r.map((e=>e.getId())),removedNetworkFilters:a.map((e=>e.getId())),removedPreprocessors:l},i)}getHtmlFilters(e){const t=[];if(!1===this.config.enableHtmlFiltering)return t;const{networkFilters:o,exceptions:i,cosmeticFilters:n,unhides:s}=this.htmlFilters.getHTMLFilters(e,this.isFilterExcluded.bind(this));if(0!==n.length){const o=new Map(s.map((e=>[e.getSelector(),e])));for(const i of n){const n=i.getExtendedSelector();if(void 0===n)continue;const s=o.get(i.getSelector());void 0===s&&t.push(n),this.emit("filter-matched",{filter:i,exception:s},{request:e,filterType:Co.COSMETIC})}}if(0!==o.length){const n=new Map;let s;for(const e of i){const t=e.optionValue;if(""===t){s=e;break}n.set(t,e)}for(const i of o){const o=i.getHtmlModifier();if(null===o)continue;const c=s||n.get(i.optionValue);this.emit("filter-matched",{filter:i,exception:c},{request:e,filterType:Co.NETWORK}),void 0===c&&t.push(["replace",o])}}return 0!==t.length&&this.emit("html-filtered",t,e.url),t}getCosmeticsFilters({url:e,hostname:t,domain:o,classes:i,hrefs:n,ids:s,getBaseRules:c=!0,getInjectionRules:r=!0,getExtendedRules:a=!0,getRulesFromDOM:l=!0,getRulesFromHostname:p=!0,hidingStyle:d,callerContext:u}){if(!1===this.config.loadCosmeticFilters)return{active:!1,extended:[],scripts:[],styles:""};o||(o="");let h=!0,m=!0;const A=this.hideExceptions.matchAll(Ut.fromRawDetails({domain:o,hostname:t,url:e,sourceDomain:"",sourceHostname:"",sourceUrl:""}),this.isFilterExcluded.bind(this)),g=[],f=[];for(const e of A){if(e.isElemHide()){h=!1,m=!1;break}e.isSpecificHide()?f.push(e):e.isGenericHide()&&g.push(e)}!0===h&&(h=!1===dn(g)),!0===m&&(m=!1===dn(f));const{filters:k,unhides:b}=this.cosmetics.getCosmeticsFilters({domain:o,hostname:t,classes:i,hrefs:n,ids:s,allowGenericHides:h,allowSpecificHides:m,getRulesFromDOM:l,getRulesFromHostname:p,hidingStyle:d,isFilterExcluded:this.isFilterExcluded.bind(this)});let y=!1;const w=new Map;for(const e of b)!0===e.isScriptInject()&&!0===e.isUnhide()&&0===e.getSelector().length&&(y=!0),w.set(Yt(e,this.resources.getScriptletCanonicalName.bind(this.resources)),e);const v=[],_=[],C=[];if(0!==k.length)for(const t of k){const o=w.get(Yt(t,this.resources.getScriptletCanonicalName.bind(this.resources)));if(void 0!==o)continue;let i=!1;!0===t.isScriptInject()?!0===r&&!1===y&&(v.push(t),i=!0):t.isExtended()?!0===a&&(C.push(t),i=!0):(_.push(t),i=!0),i&&this.emit("filter-matched",{filter:t,exception:o},{url:e,callerContext:u,filterType:Co.COSMETIC})}const x=[];for(const t of v){const o=t.getScript(this.resources.getScriptlet.bind(this.resources));void 0!==o&&(this.emit("script-injected",o,e),x.push(o))}const{stylesheet:S,extended:E}=this.cosmetics.getStylesheetsFromFilters({filters:_,extendedFilters:C},{getBaseRules:c,allowGenericHides:h,hidingStyle:d});return 0!==S.length&&this.emit("style-injected",S,e),{active:!0,extended:E,scripts:x,styles:S}}matchAll(e){const t=[];return e.isSupported&&(Array.prototype.push.apply(t,this.importants.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.filters.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.exceptions.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.csp.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.hideExceptions.matchAll(e,this.isFilterExcluded.bind(this))),Array.prototype.push.apply(t,this.redirects.matchAll(e,this.isFilterExcluded.bind(this)))),new Set(t)}getCSPDirectives(e){if(!this.config.loadNetworkFilters)return;if(!0!==e.isSupported||!1===e.isMainFrame())return;const t=this.csp.matchAll(e,this.isFilterExcluded.bind(this));if(0===t.length)return;const o=new Map,i=[];for(const n of t)if(n.isException()){if(void 0===n.csp)return void this.emit("filter-matched",{exception:n},{request:e,filterType:Co.NETWORK});o.set(n.csp,n)}else i.push(n);if(0===i.length)return;const n=new Set;for(const t of i.values()){const i=o.get(t.csp);void 0===i&&n.add(t.csp),this.emit("filter-matched",{filter:t,exception:i},{request:e,filterType:Co.NETWORK})}const s=Array.from(n).join("; ");return s.length>0&&this.emit("csp-injected",e,s),s}match(e,t=!1){const o={exception:void 0,filter:void 0,match:!1,redirect:void 0,metadata:void 0};if(!this.config.loadNetworkFilters)return o;if(e.isSupported){let t,i;if(o.filter=this.importants.match(e,this.isFilterExcluded.bind(this)),void 0===o.filter){const n=this.redirects.matchAll(e,this.isFilterExcluded.bind(this)).sort(((e,t)=>t.getRedirectPriority()-e.getRedirectPriority()));if(0!==n.length)for(const e of n)"none"===e.getRedirectResource()?t=e:e.isRedirectRule()?void 0===i&&(i=e):void 0===o.filter&&(o.filter=e);void 0===o.filter&&(o.filter=this.filters.match(e,this.isFilterExcluded.bind(this)),void 0!==i&&void 0!==o.filter&&(o.filter=i)),void 0!==o.filter&&(o.exception=this.exceptions.match(e,this.isFilterExcluded.bind(this)))}void 0!==o.filter&&void 0===o.exception&&o.filter.isRedirect()&&(void 0!==t?o.exception=t:o.redirect=this.resources.getResource(o.filter.getRedirectResource()))}return o.match=void 0===o.exception&&void 0!==o.filter,o.filter&&this.emit("filter-matched",{filter:o.filter,exception:o.exception},{request:e,filterType:Co.NETWORK}),void 0!==o.exception?this.emit("request-whitelisted",e,o):void 0!==o.redirect?this.emit("request-redirected",e,o):void 0!==o.filter?this.emit("request-blocked",e,o):this.emit("request-allowed",e,o),!0===t&&void 0!==o.filter&&this.metadata&&(o.metadata=this.metadata.fromFilter(o.filter)),o}getPatternMetadata(e,{getDomainMetadata:t=!1}={}){if(void 0===this.metadata)return[];const o=new Set,i=[];for(const t of this.matchAll(e))for(const e of this.metadata.fromFilter(t))o.has(e.pattern.key)||(o.add(e.pattern.key),i.push(e));if(t)for(const t of this.metadata.fromDomain(e.hostname))o.has(t.pattern.key)||(o.add(t.pattern.key),i.push(t));return i}blockScripts(){return this.updateFromDiff({added:[Jt().scripts().redirectTo("javascript").toString()]}),this}blockImages(){return this.updateFromDiff({added:[Jt().images().redirectTo("png").toString()]}),this}blockMedias(){return this.updateFromDiff({added:[Jt().medias().redirectTo("mp4").toString()]}),this}blockFrames(){return this.updateFromDiff({added:[Jt().frames().redirectTo("html").toString()]}),this}blockFonts(){return this.updateFromDiff({added:[Jt().fonts().toString()]}),this}blockStyles(){return this.updateFromDiff({added:[Jt().styles().toString()]}),this}};function hn(e){const t=new Set(["br","head","link","meta","script","style","s"]),o=new Set,i=new Set,n=new Set,s=new Set;for(const c of e)for(const e of[c,...c.querySelectorAll("[id]:not(html):not(body),[class]:not(html):not(body),[href]:not(html):not(body)")]){if(s.has(e))continue;if(s.add(e),t.has(e.nodeName.toLowerCase()))continue;const c=e.getAttribute("id");"string"==typeof c&&n.add(c);const r=e.classList;for(const e of r)o.add(e);const a=e.getAttribute("href");"string"==typeof a&&i.add(a)}return{classes:Array.from(o),hrefs:Array.from(i),ids:Array.from(n)}}function mn(e){try{const t=pt(location.href),o=t.hostname||"",i=t.domain||"";return e.getCosmeticsFilters({url:location.href,hostname:o,domain:i,...hn([document.documentElement]),getBaseRules:!0,getInjectionRules:!1,getExtendedRules:!0,getRulesFromDOM:!0,getRulesFromHostname:!0,hidingStyle:A("opacity")}).styles}catch(e){return console.error("Error getting cosmetic rules",e),""}}function An(e){if(e){return e.replace(/\s*{[^\\}]*}\s*/g,",").replace(/,$/,"")}return""}var gn=new Uint8Array([]);var fn=[{name:"192.com",detectCmp:[{exists:".ont-cookies"}],detectPopup:[{visible:".ont-cookies"}],optIn:[{click:".ont-btn-main.ont-cookies-btn.js-ont-btn-ok2"}],optOut:[{click:".ont-cookes-btn-manage"},{click:".ont-btn-main.ont-cookies-btn.js-ont-btn-choose"}],test:[{eval:"EVAL_ONENINETWO_0"}]},{name:"1password-com",cosmetic:!0,prehideSelectors:['footer #footer-root [aria-label="Cookie Consent"]'],detectCmp:[{exists:'footer #footer-root [aria-label="Cookie Consent"]'}],detectPopup:[{visible:'footer #footer-root [aria-label="Cookie Consent"]'}],optIn:[{click:'footer #footer-root [aria-label="Cookie Consent"] button'}],optOut:[{hide:'footer #footer-root [aria-label="Cookie Consent"]'}]},{name:"aa",vendorUrl:"https://aa.com",prehideSelectors:[],cosmetic:!0,detectCmp:[{exists:"#aa_optoutmulti-Modal,#cookieBannerMessage"}],detectPopup:[{visible:"#aa_optoutmulti-Modal,#cookieBannerMessage"}],optIn:[{hide:"#aa_optoutmulti-Modal,#cookieBannerMessage"},{waitForThenClick:"#aa_optoutmulti_checkBox"},{waitForThenClick:"#aa_optoutmulti-Modal button.optoutmulti_button"}],optOut:[{hide:"#aa_optoutmulti-Modal,#cookieBannerMessage"}]},{name:"abc",vendorUrl:"https://abc.net.au",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?abc\\.net\\.au/"},prehideSelectors:[],detectCmp:[{exists:"[data-component=CookieBanner]"}],detectPopup:[{visible:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptAll]"}],optIn:[{waitForThenClick:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptAll]"}],optOut:[{waitForThenClick:"[data-component=CookieBanner] [data-component=CookieBanner_AcceptABCRequired]"}],test:[{eval:"EVAL_ABC_TEST"}]},{name:"abconcerts.be",vendorUrl:"https://unknown",intermediate:!1,prehideSelectors:["dialog.cookie-consent"],detectCmp:[{exists:"dialog.cookie-consent form.cookie-consent__form"}],detectPopup:[{visible:"dialog.cookie-consent form.cookie-consent__form"}],optIn:[{waitForThenClick:"dialog.cookie-consent form.cookie-consent__form button[value=yes]"}],optOut:[{if:{exists:"dialog.cookie-consent form.cookie-consent__form button[value=no]"},then:[{click:"dialog.cookie-consent form.cookie-consent__form button[value=no]"}],else:[{click:"dialog.cookie-consent form.cookie-consent__form button.cookie-consent__options-toggle"},{waitForThenClick:'dialog.cookie-consent form.cookie-consent__form button[value="save_options"]'}]}]},{name:"acris",prehideSelectors:["div.acris-cookie-consent"],detectCmp:[{exists:"[data-acris-cookie-consent]"}],detectPopup:[{visible:".acris-cookie-consent.is--modal"}],optIn:[{waitForVisible:"#ccConsentAcceptAllButton",check:"any"},{wait:500},{waitForThenClick:"#ccConsentAcceptAllButton"}],optOut:[{waitForVisible:"#ccAcceptOnlyFunctional",check:"any"},{wait:500},{waitForThenClick:"#ccAcceptOnlyFunctional"}]},{name:"activobank.pt",runContext:{urlPattern:"^https://(www\\.)?activobank\\.pt"},prehideSelectors:["aside#cookies,.overlay-cookies"],detectCmp:[{exists:"#cookies .cookies-btn"}],detectPopup:[{visible:"#cookies #submitCookies"}],optIn:[{waitForThenClick:"#cookies #submitCookies"}],optOut:[{waitForThenClick:"#cookies #rejectCookies"}]},{name:"Adroll",prehideSelectors:["#adroll_consent_container"],detectCmp:[{exists:"#adroll_consent_container"}],detectPopup:[{visible:"#adroll_consent_container"}],optIn:[{waitForThenClick:"#adroll_consent_accept"}],optOut:[{waitForThenClick:"#adroll_consent_reject"}],test:[{eval:"EVAL_ADROLL_0"}]},{name:"affinity.serif.com",detectCmp:[{exists:".c-cookie-banner button[data-qa='allow-all-cookies']"}],detectPopup:[{visible:".c-cookie-banner"}],optIn:[{click:'button[data-qa="allow-all-cookies"]'}],optOut:[{click:'button[data-qa="manage-cookies"]'},{waitFor:'.c-cookie-banner ~ [role="dialog"]'},{waitForThenClick:'.c-cookie-banner ~ [role="dialog"] input[type="checkbox"][value="true"]',all:!0},{click:'.c-cookie-banner ~ [role="dialog"] .c-modal__action button'}],test:[{wait:500},{eval:"EVAL_AFFINITY_SERIF_COM_0"}]},{name:"agolde.com",cosmetic:!0,prehideSelectors:["#modal-1 div[data-micromodal-close]"],detectCmp:[{exists:"#modal-1 div[aria-labelledby=modal-1-title]"}],detectPopup:[{exists:"#modal-1 div[data-micromodal-close]"}],optIn:[{click:'button[aria-label="Close modal"]'}],optOut:[{hide:"#modal-1 div[data-micromodal-close]"}]},{name:"aliexpress",vendorUrl:"https://aliexpress.com/",runContext:{urlPattern:"^https://.*\\.aliexpress\\.com/"},prehideSelectors:["#gdpr-new-container"],detectCmp:[{exists:"#gdpr-new-container,#voyager-gdpr > div"}],detectPopup:[{visible:"#gdpr-new-container,#voyager-gdpr > div"}],optIn:[{waitForThenClick:"#gdpr-new-container .btn-accept,#voyager-gdpr > div > div > button:nth-child(1)"}],optOut:[{if:{exists:"#voyager-gdpr > div"},then:[{waitForThenClick:"#voyager-gdpr > div > div > button:nth-child(2)"}],else:[{waitForThenClick:"#gdpr-new-container .btn-more"},{waitFor:"#gdpr-new-container .gdpr-dialog-switcher"},{click:"#gdpr-new-container .switcher-on",all:!0,optional:!0},{click:"#gdpr-new-container .btn-save"}]}]},{name:"almacmp",prehideSelectors:["#alma-cmpv2-container"],detectCmp:[{exists:"#alma-cmpv2-container"}],detectPopup:[{visible:"#alma-cmpv2-container #almacmp-modal-layer1"}],optIn:[{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer1 #almacmp-modalConfirmBtn"}],optOut:[{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer1 #almacmp-modalSettingBtn"},{waitFor:"#alma-cmpv2-container #almacmp-modal-layer2"},{waitForThenClick:"#alma-cmpv2-container #almacmp-modal-layer2 #almacmp-reject-all-layer2"}],test:[{eval:"EVAL_ALMACMP_0"}]},{name:"altium.com",cosmetic:!0,prehideSelectors:[".altium-privacy-bar"],detectCmp:[{exists:".altium-privacy-bar"}],detectPopup:[{exists:".altium-privacy-bar"}],optIn:[{click:"a.altium-privacy-bar__btn"}],optOut:[{hide:".altium-privacy-bar"}]},{name:"amazon.com",prehideSelectors:['span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'],detectCmp:[{exists:'span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'}],detectPopup:[{visible:'span[data-action="sp-cc"][data-sp-cc*="rejectAllAction"]'}],optIn:[{waitForVisible:"#sp-cc-accept"},{wait:500},{click:"#sp-cc-accept"}],optOut:[{waitForVisible:"#sp-cc-rejectall-link"},{wait:500},{click:"#sp-cc-rejectall-link"}]},{name:"amex",vendorUrl:"https://www.americanexpress.com/",cosmetic:!1,prehideSelectors:["#user-consent-management-granular-banner-overlay"],detectCmp:[{exists:"#user-consent-management-granular-banner-overlay"}],detectPopup:[{visible:"#user-consent-management-granular-banner-overlay"}],optIn:[{waitForThenClick:"[data-testid=granular-banner-button-accept-all]"}],optOut:[{waitForThenClick:"[data-testid=granular-banner-button-decline-all]"}]},{name:"aquasana.com",prehideSelectors:["#consent-tracking"],detectCmp:[{exists:"#consent-tracking"}],detectPopup:[{exists:"#consent-tracking"}],optIn:[{waitForThenClick:"#consent-tracking .affirm.btn"}],optOut:[{if:{exists:"#consent-tracking .decline.btn"},then:[{click:"#consent-tracking .decline.btn"}],else:[{hide:"#consent-tracking"}]}]},{name:"arbeitsagentur",vendorUrl:"https://www.arbeitsagentur.de/",prehideSelectors:[".modal-open bahf-cookie-disclaimer-dpl3"],detectCmp:[{exists:"bahf-cookie-disclaimer-dpl3"}],detectPopup:[{visible:"bahf-cookie-disclaimer-dpl3"}],optIn:[{waitForThenClick:["bahf-cookie-disclaimer-dpl3","#bahf-cookie-disclaimer-modal .ba-btn-primary"]}],optOut:[{waitForThenClick:["bahf-cookie-disclaimer-dpl3","#bahf-cookie-disclaimer-modal .ba-btn-contrast"]}],test:[{eval:"EVAL_ARBEITSAGENTUR_TEST"}]},{name:"asus",vendorUrl:"https://www.asus.com/",runContext:{urlPattern:"^https://www\\.asus\\.com/"},prehideSelectors:["#cookie-policy-info,#cookie-policy-info-bg"],detectCmp:[{exists:"#cookie-policy-info"}],detectPopup:[{visible:"#cookie-policy-info"}],optIn:[{waitForThenClick:'#cookie-policy-info [data-agree="Accept Cookies"]'}],optOut:[{if:{exists:"#cookie-policy-info .btn-reject"},then:[{waitForThenClick:"#cookie-policy-info .btn-reject"}],else:[{waitForThenClick:"#cookie-policy-info .btn-setting"},{waitForThenClick:'#cookie-policy-lightbox-wrapper [data-agree="Save Settings"]'}]}]},{name:"athlinks-com",runContext:{urlPattern:"^https://(www\\.)?athlinks\\.com/"},cosmetic:!0,prehideSelectors:["#footer-container ~ div"],detectCmp:[{exists:"#footer-container ~ div"}],detectPopup:[{visible:"#footer-container > div"}],optIn:[{click:"#footer-container ~ div button"}],optOut:[{hide:"#footer-container ~ div"}]},{name:"ausopen.com",cosmetic:!0,detectCmp:[{exists:".gdpr-popup__message"}],detectPopup:[{visible:".gdpr-popup__message"}],optOut:[{hide:".gdpr-popup__message"}],optIn:[{click:".gdpr-popup__message button"}]},{name:"automattic-cmp-optout",prehideSelectors:['form[class*="cookie-banner"][method="post"]'],detectCmp:[{exists:'form[class*="cookie-banner"][method="post"]'}],detectPopup:[{visible:'form[class*="cookie-banner"][method="post"]'}],optIn:[{click:'a[class*="accept-all-button"]'}],optOut:[{click:'form[class*="cookie-banner"] div[class*="simple-options"] a[class*="customize-button"]'},{waitForThenClick:"input[type=checkbox][checked]:not([disabled])",all:!0},{click:'a[class*="accept-selection-button"]'}]},{name:"aws.amazon.com",prehideSelectors:["#awsccc-cb-content","#awsccc-cs-container","#awsccc-cs-modalOverlay","#awsccc-cs-container-inner"],detectCmp:[{exists:"#awsccc-cb-content"}],detectPopup:[{visible:"#awsccc-cb-content"}],optIn:[{click:"button[data-id=awsccc-cb-btn-accept"}],optOut:[{click:"button[data-id=awsccc-cb-btn-customize]"},{waitFor:"input[aria-checked]"},{click:"input[aria-checked=true]",all:!0,optional:!0},{click:"button[data-id=awsccc-cs-btn-save]"}]},{name:"axeptio",prehideSelectors:[".axeptio_widget"],detectCmp:[{exists:".axeptio_widget"}],detectPopup:[{visible:".axeptio_widget"}],optIn:[{waitFor:".axeptio-widget--open"},{click:"button#axeptio_btn_acceptAll"}],optOut:[{waitFor:".axeptio-widget--open"},{click:"button#axeptio_btn_dismiss"}],test:[{eval:"EVAL_AXEPTIO_0"}]},{name:"baden-wuerttemberg.de",prehideSelectors:[".cookie-alert.t-dark"],cosmetic:!0,detectCmp:[{exists:".cookie-alert.t-dark"}],detectPopup:[{visible:".cookie-alert.t-dark"}],optIn:[{click:".cookie-alert__form input:not([disabled]):not([checked])"},{click:".cookie-alert__button button"}],optOut:[{hide:".cookie-alert.t-dark"}]},{name:"bahn-de",vendorUrl:"https://www.bahn.de/",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?bahn\\.de/"},intermediate:!1,prehideSelectors:[],detectCmp:[{exists:["body > div:first-child","#consent-layer"]}],detectPopup:[{visible:["body > div:first-child","#consent-layer"]}],optIn:[{waitForThenClick:["body > div:first-child","#consent-layer .js-accept-all-cookies"]}],optOut:[{waitForThenClick:["body > div:first-child","#consent-layer .js-accept-essential-cookies"]}],test:[{eval:"EVAL_BAHN_TEST"}]},{name:"bbb.org",runContext:{urlPattern:"^https://www\\.bbb\\.org/"},cosmetic:!0,prehideSelectors:['div[aria-label="use of cookies on bbb.org"]'],detectCmp:[{exists:'div[aria-label="use of cookies on bbb.org"]'}],detectPopup:[{visible:'div[aria-label="use of cookies on bbb.org"]'}],optIn:[{click:'div[aria-label="use of cookies on bbb.org"] button.bds-button-unstyled span.visually-hidden'}],optOut:[{hide:'div[aria-label="use of cookies on bbb.org"]'}]},{name:"bing.com",prehideSelectors:["#bnp_container"],detectCmp:[{exists:"#bnp_cookie_banner"}],detectPopup:[{visible:"#bnp_cookie_banner"},{visible:"#bnp_btn_accept,#bnp_btn_reject"}],optIn:[{waitForThenClick:"#bnp_btn_accept"}],optOut:[{wait:500},{waitForThenClick:"#bnp_btn_reject"}],test:[{eval:"EVAL_BING_0"}]},{name:"blocksy",vendorUrl:"https://creativethemes.com/blocksy/docs/extensions/cookies-consent/",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,prehideSelectors:[".cookie-notification"],detectCmp:[{exists:"#blocksy-ext-cookies-consent-styles-css"}],detectPopup:[{visible:".cookie-notification"}],optIn:[{click:".cookie-notification .ct-cookies-decline-button"}],optOut:[{waitForThenClick:".cookie-notification .ct-cookies-decline-button"}],test:[{eval:"EVAL_BLOCKSY_0"}]},{name:"borlabs",detectCmp:[{exists:"._brlbs-block-content"}],detectPopup:[{visible:"._brlbs-bar-wrap,._brlbs-box-wrap"}],optIn:[{click:"a[data-cookie-accept-all]"}],optOut:[{click:"a[data-cookie-individual]"},{waitForVisible:".cookie-preference"},{click:"input[data-borlabs-cookie-checkbox]:checked",all:!0,optional:!0},{click:"#CookiePrefSave"},{wait:500}],prehideSelectors:["#BorlabsCookieBox"],test:[{eval:"EVAL_BORLABS_0"}]},{name:"bundesregierung.de",prehideSelectors:[".bpa-cookie-banner"],detectCmp:[{exists:".bpa-cookie-banner"}],detectPopup:[{visible:".bpa-cookie-banner .bpa-module-full-hero"}],optIn:[{click:".bpa-accept-all-button"}],optOut:[{wait:500,comment:"click is not immediately recognized"},{waitForThenClick:".bpa-close-button"}],test:[{eval:"EVAL_BUNDESREGIERUNG_DE_0"}]},{name:"burpee.com",cosmetic:!0,prehideSelectors:["#notice-cookie-block"],detectCmp:[{exists:"#notice-cookie-block"}],detectPopup:[{exists:"#html-body #notice-cookie-block"}],optIn:[{click:"#btn-cookie-allow"}],optOut:[{hide:"#html-body #notice-cookie-block, #notice-cookie"}]},{name:"canva.com",prehideSelectors:['div[role="dialog"] a[data-anchor-id="cookie-policy"]'],detectCmp:[{exists:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'}],detectPopup:[{exists:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'}],optIn:[{click:'div[role="dialog"] button:nth-child(1)'}],optOut:[{if:{exists:'div[role="dialog"] button:nth-child(3)'},then:[{click:'div[role="dialog"] button:nth-child(2)'}],else:[{click:'div[role="dialog"] button:nth-child(2)'},{waitFor:'div[role="dialog"] a[data-anchor-id="cookie-policy"]'},{waitFor:'div[role="dialog"] button[role=switch]'},{click:'div[role="dialog"] button:nth-child(2):not([role])'},{click:'div[role="dialog"] div:last-child button:only-child'}]}],test:[{eval:"EVAL_CANVA_0"}]},{name:"canyon.com",runContext:{urlPattern:"^https://www\\.canyon\\.com/"},prehideSelectors:["div.modal.cookiesModal.is-open"],detectCmp:[{exists:"div.modal.cookiesModal.is-open"}],detectPopup:[{visible:"div.modal.cookiesModal.is-open"}],optIn:[{click:'div.cookiesModal__buttonWrapper > button[data-closecause="close-by-submit"]'}],optOut:[{click:'div.cookiesModal__buttonWrapper > button[data-closecause="close-by-manage-cookies"]'},{waitForThenClick:"button#js-manage-data-privacy-save-button"}]},{name:"cassie",vendorUrl:"https://trustcassie.com",cosmetic:!1,runContext:{main:!0,frame:!1},prehideSelectors:[".cassie-cookie-module"],detectCmp:[{exists:".cassie-pre-banner"}],detectPopup:[{visible:"#cassie_pre_banner_text"}],optIn:[{waitForThenClick:".cassie-accept-all"}],optOut:[{waitForThenClick:".cassie-reject-all"}]},{name:"cc-banner-springer",prehideSelectors:[".cc-banner[data-cc-banner]"],detectCmp:[{exists:".cc-banner[data-cc-banner]"}],detectPopup:[{visible:".cc-banner[data-cc-banner]"}],optIn:[{waitForThenClick:".cc-banner[data-cc-banner] button[data-cc-action=accept]"}],optOut:[{if:{exists:".cc-banner[data-cc-banner] button[data-cc-action=reject]"},then:[{click:".cc-banner[data-cc-banner] button[data-cc-action=reject]"}],else:[{waitForThenClick:".cc-banner[data-cc-banner] button[data-cc-action=preferences]"},{waitFor:".cc-preferences[data-cc-preferences]"},{click:".cc-preferences[data-cc-preferences] input[type=radio][data-cc-action=toggle-category][value=off]",all:!0,optional:!0},{if:{exists:".cc-preferences[data-cc-preferences] button[data-cc-action=reject]"},then:[{click:".cc-preferences[data-cc-preferences] button[data-cc-action=reject]"}],else:[{click:".cc-preferences[data-cc-preferences] button[data-cc-action=save]"}]}]}],test:[{eval:"EVAL_CC_BANNER2_0"}]},{name:"cc_banner",cosmetic:!0,prehideSelectors:[".cc_banner-wrapper"],detectCmp:[{exists:".cc_banner-wrapper"}],detectPopup:[{visible:".cc_banner"}],optIn:[{click:".cc_btn_accept_all"}],optOut:[{hide:".cc_banner-wrapper"}]},{name:"check24-partnerprogramm-de",prehideSelectors:["[data-modal-content]:has([data-toggle-target^='cookie'])"],detectCmp:[{exists:"[data-toggle-target^='cookie']"}],detectPopup:[{visible:"[data-toggle-target^='cookie']",check:"any"}],optIn:[{waitForThenClick:"[data-cookie-accept-all]"}],optOut:[{waitForThenClick:"[data-cookie-dismiss-all]"}]},{name:"ciaopeople.it",prehideSelectors:["#cp-gdpr-choices"],detectCmp:[{exists:"#cp-gdpr-choices"}],detectPopup:[{visible:"#cp-gdpr-choices"}],optIn:[{waitForThenClick:".gdpr-btm__right > button:nth-child(2)"}],optOut:[{waitForThenClick:".gdpr-top-content > button"},{waitFor:".gdpr-top-back"},{waitForThenClick:".gdpr-btm__right > button:nth-child(1)"}],test:[{visible:"#cp-gdpr-choices",check:"none"}]},{vendorUrl:"https://www.civicuk.com/cookie-control/",name:"civic-cookie-control",prehideSelectors:["#ccc-module,#ccc-overlay,#ccc"],detectCmp:[{exists:"#ccc-module,#ccc-notify"}],detectPopup:[{visible:"#ccc"},{visible:"#ccc-module,#ccc-notify"}],optOut:[{if:{exists:"#ccc-notify"},then:[{waitForThenClick:["#ccc #ccc-notify .ccc-notify-buttons","xpath///button[contains(., 'Settings') or contains(., 'Cookie Preferences')]"]},{waitForVisible:"#ccc-module"}]},{if:{exists:"#ccc-reject-settings"},then:[{waitForThenClick:"#ccc-reject-settings"}],else:[{waitForThenClick:"#ccc-dismiss-button"}]}],optIn:[{waitForThenClick:"#ccc-recommended-settings,#ccc-notify-accept"}]},{name:"click.io",prehideSelectors:["#cl-consent"],detectCmp:[{exists:"#cl-consent"}],detectPopup:[{visible:"#cl-consent"}],optIn:[{waitForThenClick:'#cl-consent [data-role="b_agree"]'}],optOut:[{waitFor:'#cl-consent [data-role="b_options"]'},{wait:500},{click:'#cl-consent [data-role="b_options"]'},{waitFor:'.cl-consent-popup.cl-consent-visible [data-role="alloff"]'},{click:'.cl-consent-popup.cl-consent-visible [data-role="alloff"]',all:!0},{click:'[data-role="b_save"]'}],test:[{eval:"EVAL_CLICKIO_0",comment:"TODO: this only checks if we interacted at all"}]},{name:"clinch",intermediate:!1,runContext:{frame:!1,main:!0},prehideSelectors:[".consent-modal[role=dialog]"],detectCmp:[{exists:".consent-modal[role=dialog]"}],detectPopup:[{visible:".consent-modal[role=dialog]"}],optIn:[{click:"#consent_agree"}],optOut:[{if:{exists:"#consent_reject"},then:[{click:"#consent_reject"}],else:[{click:"#manage_cookie_preferences"},{click:"#cookie_consent_preferences input:checked",all:!0,optional:!0},{click:"#consent_save"}]}],test:[{eval:"EVAL_CLINCH_0"}]},{name:"clustrmaps.com",runContext:{urlPattern:"^https://(www\\.)?clustrmaps\\.com/"},cosmetic:!0,prehideSelectors:["#gdpr-cookie-message"],detectCmp:[{exists:"#gdpr-cookie-message"}],detectPopup:[{visible:"#gdpr-cookie-message"}],optIn:[{click:"button#gdpr-cookie-accept"}],optOut:[{hide:"#gdpr-cookie-message"}]},{name:"coinbase",intermediate:!1,runContext:{frame:!0,main:!0,urlPattern:"^https://(www|help)\\.coinbase\\.com"},prehideSelectors:[],detectCmp:[{exists:"div[class^=CookieBannerContent__Container]"}],detectPopup:[{visible:"div[class^=CookieBannerContent__Container]"}],optIn:[{click:"div[class^=CookieBannerContent__CTA] :nth-last-child(1)"}],optOut:[{click:"button[class^=CookieBannerContent__Settings]"},{click:"div[class^=CookiePreferencesModal__CategoryContainer] input:checked",all:!0,optional:!0},{click:"div[class^=CookiePreferencesModal__ButtonContainer] > button"}],test:[{eval:"EVAL_COINBASE_0"}]},{name:"Complianz banner",prehideSelectors:["#cmplz-cookiebanner-container"],detectCmp:[{exists:"#cmplz-cookiebanner-container .cmplz-cookiebanner"}],detectPopup:[{visible:"#cmplz-cookiebanner-container .cmplz-cookiebanner",check:"any"}],optIn:[{waitForThenClick:".cmplz-cookiebanner .cmplz-accept"}],optOut:[{waitForThenClick:".cmplz-cookiebanner .cmplz-deny"}],test:[{eval:"EVAL_COMPLIANZ_BANNER_0"}]},{name:"Complianz categories",prehideSelectors:['.cc-type-categories[aria-describedby="cookieconsent:desc"]'],detectCmp:[{exists:'.cc-type-categories[aria-describedby="cookieconsent:desc"]'}],detectPopup:[{visible:'.cc-type-categories[aria-describedby="cookieconsent:desc"]'}],optIn:[{any:[{click:".cc-accept-all"},{click:".cc-allow-all"},{click:".cc-allow"},{click:".cc-dismiss"}]}],optOut:[{if:{exists:'.cc-type-categories[aria-describedby="cookieconsent:desc"] .cc-dismiss'},then:[{click:".cc-dismiss"}],else:[{click:".cc-type-categories input[type=checkbox]:not([disabled]):checked",all:!0,optional:!0},{click:".cc-save"}]}]},{name:"Complianz notice",prehideSelectors:['.cc-type-info[aria-describedby="cookieconsent:desc"]'],cosmetic:!0,detectCmp:[{exists:'.cc-type-info[aria-describedby="cookieconsent:desc"] .cc-compliance .cc-btn'}],detectPopup:[{visible:'.cc-type-info[aria-describedby="cookieconsent:desc"] .cc-compliance .cc-btn'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{if:{exists:".cc-deny"},then:[{click:".cc-deny"}],else:[{hide:'[aria-describedby="cookieconsent:desc"]'}]}]},{name:"Complianz opt-both",prehideSelectors:['[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'],detectCmp:[{exists:'[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'}],detectPopup:[{visible:'[aria-describedby="cookieconsent:desc"] .cc-type-opt-both'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{waitForThenClick:".cc-deny"}]},{name:"Complianz opt-out",prehideSelectors:['[aria-describedby="cookieconsent:desc"].cc-type-opt-out'],detectCmp:[{exists:'[aria-describedby="cookieconsent:desc"].cc-type-opt-out'}],detectPopup:[{visible:'[aria-describedby="cookieconsent:desc"].cc-type-opt-out'}],optIn:[{click:".cc-accept-all",optional:!0},{click:".cc-allow",optional:!0},{click:".cc-dismiss",optional:!0}],optOut:[{if:{exists:".cc-deny"},then:[{click:".cc-deny"}],else:[{if:{exists:".cmp-pref-link"},then:[{click:".cmp-pref-link"},{waitForThenClick:".cmp-body [id*=rejectAll]"},{waitForThenClick:".cmp-body .cmp-save-btn"}]}]}]},{name:"Complianz optin",prehideSelectors:['.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'],detectCmp:[{exists:'.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'}],detectPopup:[{visible:'.cc-type-opt-in[aria-describedby="cookieconsent:desc"]'}],optIn:[{any:[{click:".cc-accept-all"},{click:".cc-allow"},{click:".cc-dismiss"}]}],optOut:[{if:{visible:".cc-deny"},then:[{click:".cc-deny"}],else:[{if:{visible:".cc-settings"},then:[{waitForThenClick:".cc-settings"},{waitForVisible:".cc-settings-view"},{click:".cc-settings-view input[type=checkbox]:not([disabled]):checked",all:!0,optional:!0},{click:".cc-settings-view .cc-btn-accept-selected"}],else:[{click:".cc-dismiss"}]}]}]},{name:"cookie-consent-spice",cosmetic:!1,runContext:{main:!0,frame:!1},prehideSelectors:[".spicy-consent-wrapper",".spicy-consent-bar"],detectCmp:[{exists:".spicy-consent-bar"}],detectPopup:[{visible:".spicy-consent-bar"}],optIn:[{waitForThenClick:".spicy-consent-bar__action-accept"}],optOut:[{waitForThenClick:".js-decline-all-cookies"}]},{name:"cookie-law-info",prehideSelectors:["#cookie-law-info-bar"],detectCmp:[{exists:"#cookie-law-info-bar"},{eval:"EVAL_COOKIE_LAW_INFO_DETECT"}],detectPopup:[{visible:"#cookie-law-info-bar"}],optIn:[{click:'[data-cli_action="accept_all"]'}],optOut:[{hide:"#cookie-law-info-bar"},{eval:"EVAL_COOKIE_LAW_INFO_0"}],test:[{eval:"EVAL_COOKIE_LAW_INFO_1"}]},{name:"cookie-manager-popup",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,detectCmp:[{exists:"#notice-cookie-block #allow-functional-cookies, #notice-cookie-block #btn-cookie-settings"}],detectPopup:[{visible:"#notice-cookie-block"}],optIn:[{click:"#btn-cookie-allow"}],optOut:[{if:{exists:"#allow-functional-cookies"},then:[{click:"#allow-functional-cookies"}],else:[{waitForThenClick:"#btn-cookie-settings"},{waitForVisible:".modal-body"},{click:'.modal-body input:checked, .switch[data-switch="on"]',all:!0,optional:!0},{click:'[role="dialog"] .modal-footer button'}]}],prehideSelectors:["#btn-cookie-settings"],test:[{eval:"EVAL_COOKIE_MANAGER_POPUP_0"}]},{name:"cookie-notice",prehideSelectors:["#cookie-notice"],cosmetic:!0,detectCmp:[{visible:"#cookie-notice .cookie-notice-container"}],detectPopup:[{visible:"#cookie-notice"}],optIn:[{click:"#cn-accept-cookie"}],optOut:[{hide:"#cookie-notice"}]},{name:"cookie-script",vendorUrl:"https://cookie-script.com/",prehideSelectors:["#cookiescript_injected"],detectCmp:[{exists:"#cookiescript_injected"}],detectPopup:[{visible:"#cookiescript_injected"}],optOut:[{if:{exists:"#cookiescript_reject"},then:[{wait:100},{click:"#cookiescript_reject"}],else:[{click:"#cookiescript_manage"},{waitForVisible:".cookiescript_fsd_main"},{waitForThenClick:"#cookiescript_reject"}]}],optIn:[{click:"#cookiescript_accept"}]},{name:"cookieacceptbar",vendorUrl:"https://unknown",cosmetic:!0,prehideSelectors:["#cookieAcceptBar.cookieAcceptBar"],detectCmp:[{exists:"#cookieAcceptBar.cookieAcceptBar"}],detectPopup:[{visible:"#cookieAcceptBar.cookieAcceptBar"}],optIn:[{waitForThenClick:"#cookieAcceptBarConfirm"}],optOut:[{hide:"#cookieAcceptBar.cookieAcceptBar"}]},{name:"cookiealert",intermediate:!1,prehideSelectors:[],runContext:{frame:!0,main:!0},detectCmp:[{exists:".cookie-alert-extended"}],detectPopup:[{visible:".cookie-alert-extended-modal"}],optIn:[{click:"button[data-controller='cookie-alert/extended/button/accept']"},{eval:"EVAL_COOKIEALERT_0"}],optOut:[{click:"a[data-controller='cookie-alert/extended/detail-link']"},{click:".cookie-alert-configuration-input:checked",all:!0,optional:!0},{click:"button[data-controller='cookie-alert/extended/button/configuration']"},{eval:"EVAL_COOKIEALERT_0"}],test:[{eval:"EVAL_COOKIEALERT_2"}]},{name:"cookieconsent2",vendorUrl:"https://www.github.com/orestbida/cookieconsent",comment:"supports v2.x.x of the library",prehideSelectors:["#cc--main"],detectCmp:[{exists:"#cc--main"}],detectPopup:[{visible:"#cm"},{exists:"#s-all-bn"}],optIn:[{waitForThenClick:"#s-all-bn"}],optOut:[{waitForThenClick:"#s-rall-bn"}],test:[{eval:"EVAL_COOKIECONSENT2_TEST"}]},{name:"cookieconsent3",vendorUrl:"https://www.github.com/orestbida/cookieconsent",comment:"supports v3.x.x of the library",prehideSelectors:["#cc-main"],detectCmp:[{exists:"#cc-main"}],detectPopup:[{visible:"#cc-main .cm-wrapper"}],optIn:[{waitForThenClick:".cm__btn[data-role=all]"}],optOut:[{waitForThenClick:".cm__btn[data-role=necessary]"}],test:[{eval:"EVAL_COOKIECONSENT3_TEST"}]},{name:"cookiecuttr",vendorUrl:"https://github.com/cdwharton/cookieCuttr",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:""},prehideSelectors:[".cc-cookies"],detectCmp:[{exists:".cc-cookies .cc-cookie-accept"}],detectPopup:[{visible:".cc-cookies .cc-cookie-accept"}],optIn:[{waitForThenClick:".cc-cookies .cc-cookie-accept"}],optOut:[{if:{exists:".cc-cookies .cc-cookie-decline"},then:[{click:".cc-cookies .cc-cookie-decline"}],else:[{hide:".cc-cookies"}]}]},{name:"cookiefirst.com",prehideSelectors:["#cookiefirst-root,.cookiefirst-root,[aria-labelledby=cookie-preference-panel-title]"],detectCmp:[{exists:"#cookiefirst-root,.cookiefirst-root"}],detectPopup:[{visible:"#cookiefirst-root,.cookiefirst-root"}],optIn:[{click:"button[data-cookiefirst-action=accept]"}],optOut:[{if:{exists:"button[data-cookiefirst-action=adjust]"},then:[{click:"button[data-cookiefirst-action=adjust]"},{waitForVisible:"[data-cookiefirst-widget=modal]",timeout:1e3},{eval:"EVAL_COOKIEFIRST_1"},{wait:1e3},{click:"button[data-cookiefirst-action=save]"}],else:[{click:"button[data-cookiefirst-action=reject]"}]}],test:[{eval:"EVAL_COOKIEFIRST_0"}]},{name:"Cookie Information Banner",prehideSelectors:["#cookie-information-template-wrapper"],detectCmp:[{exists:"#cookie-information-template-wrapper"}],detectPopup:[{visible:"#cookie-information-template-wrapper"}],optIn:[{eval:"EVAL_COOKIEINFORMATION_1"}],optOut:[{hide:"#cookie-information-template-wrapper",comment:"some templates don't hide the banner automatically"},{eval:"EVAL_COOKIEINFORMATION_0"}],test:[{eval:"EVAL_COOKIEINFORMATION_2"}]},{name:"cookieyes",prehideSelectors:[".cky-overlay,.cky-consent-container"],detectCmp:[{exists:".cky-consent-container"}],detectPopup:[{visible:".cky-consent-container"}],optIn:[{waitForThenClick:".cky-consent-container [data-cky-tag=accept-button]"}],optOut:[{if:{exists:".cky-consent-container [data-cky-tag=reject-button]"},then:[{waitForThenClick:".cky-consent-container [data-cky-tag=reject-button]"}],else:[{if:{exists:".cky-consent-container [data-cky-tag=settings-button]"},then:[{click:".cky-consent-container [data-cky-tag=settings-button]"},{waitFor:".cky-modal-open input[type=checkbox]"},{click:".cky-modal-open input[type=checkbox]:checked",all:!0,optional:!0},{waitForThenClick:".cky-modal [data-cky-tag=detail-save-button]"}],else:[{hide:".cky-consent-container,.cky-overlay"}]}]}],test:[{eval:"EVAL_COOKIEYES_0"}]},{name:"corona-in-zahlen.de",prehideSelectors:[".cookiealert"],detectCmp:[{exists:".cookiealert"}],detectPopup:[{visible:".cookiealert"}],optOut:[{click:".configurecookies"},{click:".confirmcookies"}],optIn:[{click:".acceptcookies"}]},{name:"crossfit-com",cosmetic:!0,prehideSelectors:['body #modal > div > div[class^="_wrapper_"]'],detectCmp:[{exists:'body #modal > div > div[class^="_wrapper_"]'}],detectPopup:[{visible:'body #modal > div > div[class^="_wrapper_"]'}],optIn:[{click:'button[aria-label="accept cookie policy"]'}],optOut:[{hide:'body #modal > div > div[class^="_wrapper_"]'}]},{name:"csu-landtag-de",runContext:{urlPattern:"^https://(www\\.|)?csu-landtag\\.de"},prehideSelectors:["#cookie-disclaimer"],detectCmp:[{exists:"#cookie-disclaimer"}],detectPopup:[{visible:"#cookie-disclaimer"}],optIn:[{click:"#cookieall"}],optOut:[{click:"#cookiesel"}]},{name:"dailymotion-us",cosmetic:!0,prehideSelectors:['div[class*="CookiePopup__desktopContainer"]:has(div[class*="CookiePopup"])'],detectCmp:[{exists:'div[class*="CookiePopup__desktopContainer"]'}],detectPopup:[{visible:'div[class*="CookiePopup__desktopContainer"]'}],optIn:[{click:'div[class*="CookiePopup__desktopContainer"] > button > span'}],optOut:[{hide:'div[class*="CookiePopup__desktopContainer"]'}]},{name:"dailymotion.com",runContext:{urlPattern:"^https://(www\\.)?dailymotion\\.com/"},prehideSelectors:['div[class*="Overlay__container"]:has(div[class*="TCF2Popup"])'],detectCmp:[{exists:'div[class*="TCF2Popup"]'}],detectPopup:[{visible:'[class*="TCF2Popup"] a[href^="https://www.dailymotion.com/legal/cookiemanagement"]'}],optIn:[{waitForThenClick:'button[class*="TCF2Popup__button"]:not([class*="TCF2Popup__personalize"])'}],optOut:[{waitForThenClick:'button[class*="TCF2ContinueWithoutAcceptingButton"]'}],test:[{eval:"EVAL_DAILYMOTION_0"}]},{name:"dan-com",vendorUrl:"https://unknown",runContext:{main:!0,frame:!1},prehideSelectors:[],detectCmp:[{exists:".cookie-banner.show .cookie-banner__content-all-btn"}],detectPopup:[{visible:".cookie-banner.show .cookie-banner__content-all-btn"}],optIn:[{waitForThenClick:".cookie-banner__content-all-btn"}],optOut:[{waitForThenClick:".cookie-banner__content-essential-btn"}]},{name:"deepl.com",prehideSelectors:[".dl_cookieBanner_container"],detectCmp:[{exists:".dl_cookieBanner_container"}],detectPopup:[{visible:".dl_cookieBanner_container"}],optOut:[{click:".dl_cookieBanner--buttonSelected"}],optIn:[{click:".dl_cookieBanner--buttonAll"}]},{name:"delta.com",runContext:{urlPattern:"^https://www\\.delta\\.com/"},cosmetic:!0,prehideSelectors:["ngc-cookie-banner"],detectCmp:[{exists:"div.cookie-footer-container"}],detectPopup:[{visible:"div.cookie-footer-container"}],optIn:[{click:" button.cookie-close-icon"}],optOut:[{hide:"div.cookie-footer-container"}]},{name:"dmgmedia-us",prehideSelectors:["#mol-ads-cmp-iframe, div.mol-ads-cmp > form > div"],detectCmp:[{exists:"div.mol-ads-cmp > form > div"}],detectPopup:[{waitForVisible:"div.mol-ads-cmp > form > div"}],optIn:[{waitForThenClick:"button.mol-ads-cmp--btn-primary"}],optOut:[{waitForThenClick:"div.mol-ads-ccpa--message > u > a"},{waitForVisible:".mol-ads-cmp--modal-dialog"},{waitForThenClick:"a.mol-ads-cmp-footer-privacy"},{waitForThenClick:"button.mol-ads-cmp--btn-secondary"}]},{name:"dmgmedia",prehideSelectors:['[data-project="mol-fe-cmp"]'],detectCmp:[{exists:'[data-project="mol-fe-cmp"] [class*=footer]'}],detectPopup:[{visible:'[data-project="mol-fe-cmp"] [class*=footer]'}],optIn:[{waitForThenClick:'[data-project="mol-fe-cmp"] button[class*=primary]'}],optOut:[{waitForThenClick:'[data-project="mol-fe-cmp"] button[class*=basic]'},{waitForVisible:'[data-project="mol-fe-cmp"] div[class*="tabContent"]'},{waitForThenClick:'[data-project="mol-fe-cmp"] div[class*="toggle"][class*="enabled"]',all:!0},{waitForThenClick:['[data-project="mol-fe-cmp"] [class*=footer]',"xpath///button[contains(., 'Save & Exit')]"]}]},{name:"dndbeyond",vendorUrl:"https://www.dndbeyond.com/",runContext:{urlPattern:"^https://(www\\.)?dndbeyond\\.com/"},prehideSelectors:["[id^=cookie-consent-banner]"],detectCmp:[{exists:"[id^=cookie-consent-banner]"}],detectPopup:[{visible:"[id^=cookie-consent-banner]"}],optIn:[{waitForThenClick:"#cookie-consent-granted"}],optOut:[{waitForThenClick:"#cookie-consent-denied"}],test:[{eval:"EVAL_DNDBEYOND_TEST"}]},{name:"dpgmedia-nl",prehideSelectors:["#pg-shadow-root-host"],detectCmp:[{exists:"#pg-shadow-root-host"}],detectPopup:[{visible:["#pg-shadow-root-host","#pg-modal"]}],optIn:[{waitForThenClick:["#pg-shadow-root-host","#pg-accept-btn"]}],optOut:[{waitForThenClick:["#pg-shadow-root-host","#pg-configure-btn"]},{waitForThenClick:["#pg-shadow-root-host","#pg-reject-btn"]}]},{name:"Drupal",detectCmp:[{exists:"#drupalorg-crosssite-gdpr"}],detectPopup:[{visible:"#drupalorg-crosssite-gdpr"}],optOut:[{click:".no"}],optIn:[{click:".yes"}]},{name:"WP DSGVO Tools",link:"https://wordpress.org/plugins/shapepress-dsgvo/",prehideSelectors:[".sp-dsgvo"],cosmetic:!0,detectCmp:[{exists:".sp-dsgvo.sp-dsgvo-popup-overlay"}],detectPopup:[{visible:".sp-dsgvo.sp-dsgvo-popup-overlay",check:"any"}],optIn:[{click:".sp-dsgvo-privacy-btn-accept-all",all:!0}],optOut:[{hide:".sp-dsgvo.sp-dsgvo-popup-overlay"}],test:[{eval:"EVAL_DSGVO_0"}]},{name:"dunelm.com",prehideSelectors:["div[data-testid=cookie-consent-modal-backdrop]"],detectCmp:[{exists:"div[data-testid=cookie-consent-message-contents]"}],detectPopup:[{visible:"div[data-testid=cookie-consent-message-contents]"}],optIn:[{click:'[data-testid="cookie-consent-allow-all"]'}],optOut:[{click:"button[data-testid=cookie-consent-adjust-settings]"},{click:"button[data-testid=cookie-consent-preferences-save]"}],test:[{eval:"EVAL_DUNELM_0"}]},{name:"ebay",vendorUrl:"https://ebay.com",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?ebay\\.([.a-z]+)/"},prehideSelectors:["#gdpr-banner"],detectCmp:[{exists:"#gdpr-banner"}],detectPopup:[{visible:"#gdpr-banner"}],optIn:[{waitForThenClick:"#gdpr-banner-accept"}],optOut:[{waitForThenClick:"#gdpr-banner-decline"}]},{name:"ecosia",vendorUrl:"https://www.ecosia.org/",runContext:{urlPattern:"^https://www\\.ecosia\\.org/"},prehideSelectors:[".cookie-wrapper"],detectCmp:[{exists:".cookie-wrapper > .cookie-notice"}],detectPopup:[{visible:".cookie-wrapper > .cookie-notice"}],optIn:[{waitForThenClick:"[data-test-id=cookie-notice-accept]"}],optOut:[{waitForThenClick:"[data-test-id=cookie-notice-reject]"}]},{name:"Ensighten ensModal",prehideSelectors:[".ensModal"],detectCmp:[{exists:".ensModal"}],detectPopup:[{visible:"#ensModalWrapper[style*=block]"}],optIn:[{waitForThenClick:"#modalAcceptButton"}],optOut:[{wait:500},{visible:"#ensModalWrapper[style*=block]"},{waitForThenClick:".ensCheckbox:checked",all:!0},{waitForThenClick:"#ensSave"}]},{name:"Ensighten ensNotifyBanner",prehideSelectors:["#ensNotifyBanner"],detectCmp:[{exists:"#ensNotifyBanner"}],detectPopup:[{visible:"#ensNotifyBanner[style*=block]"}],optIn:[{waitForThenClick:"#ensCloseBanner"}],optOut:[{wait:500},{visible:"#ensNotifyBanner[style*=block]"},{waitForThenClick:"#ensRejectAll,#rejectAll,#ensRejectBanner,.rejectAll,#ensCloseBanner",timeout:2e3}]},{name:"espace-personnel.agirc-arrco.fr",runContext:{urlPattern:"^https://espace-personnel\\.agirc-arrco\\.fr/"},prehideSelectors:[".cdk-overlay-container"],detectCmp:[{exists:".cdk-overlay-container app-esaa-cookie-component"}],detectPopup:[{visible:".cdk-overlay-container app-esaa-cookie-component"}],optIn:[{waitForThenClick:".btn-cookie-accepter"}],optOut:[{waitForThenClick:".btn-cookie-refuser"}]},{name:"etsy",prehideSelectors:["#gdpr-single-choice-overlay","#gdpr-privacy-settings"],detectCmp:[{exists:"#gdpr-single-choice-overlay"}],detectPopup:[{visible:"#gdpr-single-choice-overlay"}],optOut:[{click:"button[data-gdpr-open-full-settings]"},{waitForVisible:".gdpr-overlay-body input",timeout:3e3},{wait:1e3},{eval:"EVAL_ETSY_0"},{eval:"EVAL_ETSY_1"}],optIn:[{click:"button[data-gdpr-single-choice-accept]"}]},{name:"eu-cookie-compliance-banner",detectCmp:[{exists:"body.eu-cookie-compliance-popup-open"}],detectPopup:[{exists:"body.eu-cookie-compliance-popup-open"}],optIn:[{click:".agree-button"}],optOut:[{if:{visible:".decline-button,.eu-cookie-compliance-save-preferences-button"},then:[{click:".decline-button,.eu-cookie-compliance-save-preferences-button"}]},{hide:".eu-cookie-compliance-banner-info, #sliding-popup"}],test:[{eval:"EVAL_EU_COOKIE_COMPLIANCE_0"}]},{name:"EU Cookie Law",prehideSelectors:[".pea_cook_wrapper,.pea_cook_more_info_popover"],cosmetic:!0,detectCmp:[{exists:".pea_cook_wrapper"}],detectPopup:[{wait:500},{visible:".pea_cook_wrapper"}],optIn:[{click:"#pea_cook_btn"}],optOut:[{hide:".pea_cook_wrapper"}],test:[{eval:"EVAL_EU_COOKIE_LAW_0"}]},{name:"europa-eu",vendorUrl:"https://ec.europa.eu/",runContext:{urlPattern:"^https://[^/]*europa\\.eu/"},prehideSelectors:["#cookie-consent-banner"],detectCmp:[{exists:".cck-container"}],detectPopup:[{visible:".cck-container"}],optIn:[{waitForThenClick:'.cck-actions-button[href="#accept"]'}],optOut:[{waitForThenClick:'.cck-actions-button[href="#refuse"]',hide:".cck-container"}]},{name:"EZoic",prehideSelectors:["#ez-cookie-dialog-wrapper"],detectCmp:[{exists:"#ez-cookie-dialog-wrapper"}],detectPopup:[{visible:"#ez-cookie-dialog-wrapper"}],optIn:[{click:"#ez-accept-all",optional:!0},{eval:"EVAL_EZOIC_0",optional:!0}],optOut:[{wait:500},{click:"#ez-manage-settings"},{waitFor:"#ez-cookie-dialog input[type=checkbox]"},{click:"#ez-cookie-dialog input[type=checkbox]:checked",all:!0},{click:"#ez-save-settings"}],test:[{eval:"EVAL_EZOIC_1"}]},{name:"facebook",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?facebook\\.com/"},prehideSelectors:['div[data-testid="cookie-policy-manage-dialog"]'],detectCmp:[{exists:'div[data-testid="cookie-policy-manage-dialog"]'}],detectPopup:[{visible:'div[data-testid="cookie-policy-manage-dialog"]'}],optIn:[{waitForThenClick:'button[data-cookiebanner="accept_button"]'},{waitForVisible:'div[data-testid="cookie-policy-manage-dialog"]',check:"none"}],optOut:[{waitForThenClick:'button[data-cookiebanner="accept_only_essential_button"]'},{waitForVisible:'div[data-testid="cookie-policy-manage-dialog"]',check:"none"}]},{name:"fides",vendorUrl:"https://github.com/ethyca/fides",prehideSelectors:["#fides-overlay"],detectCmp:[{exists:"#fides-overlay #fides-banner"}],detectPopup:[{visible:"#fides-overlay #fides-banner"},{eval:"EVAL_FIDES_DETECT_POPUP"}],optIn:[{waitForThenClick:"#fides-banner .fides-accept-all-button"}],optOut:[{waitForThenClick:"#fides-banner .fides-reject-all-button"}]},{name:"funding-choices",prehideSelectors:[".fc-consent-root,.fc-dialog-container,.fc-dialog-overlay,.fc-dialog-content"],detectCmp:[{exists:".fc-consent-root"}],detectPopup:[{exists:".fc-dialog-container"}],optOut:[{click:".fc-cta-do-not-consent,.fc-cta-manage-options"},{click:".fc-preference-consent:checked,.fc-preference-legitimate-interest:checked",all:!0,optional:!0},{click:".fc-confirm-choices",optional:!0}],optIn:[{click:".fc-cta-consent"}]},{name:"geeks-for-geeks",runContext:{urlPattern:"^https://www\\.geeksforgeeks\\.org/"},cosmetic:!0,prehideSelectors:[".cookie-consent"],detectCmp:[{exists:".cookie-consent"}],detectPopup:[{visible:".cookie-consent"}],optIn:[{click:".cookie-consent button.consent-btn"}],optOut:[{hide:".cookie-consent"}]},{name:"google-consent-standalone",prehideSelectors:[],detectCmp:[{exists:'a[href^="https://policies.google.com/technologies/cookies"'},{exists:'form[action^="https://consent.google."][action$="/save"]'}],detectPopup:[{visible:'a[href^="https://policies.google.com/technologies/cookies"'}],optIn:[{waitForThenClick:'form[action^="https://consent.google."][action$="/save"]:has(input[name=set_eom][value=false]) button'}],optOut:[{waitForThenClick:'form[action^="https://consent.google."][action$="/save"]:has(input[name=set_eom][value=true]) button'}]},{name:"google-cookiebar",vendorUrl:"https://www.android.com/better-together/quick-share-app/",cosmetic:!1,prehideSelectors:[".glue-cookie-notification-bar"],detectCmp:[{exists:".glue-cookie-notification-bar"}],detectPopup:[{visible:".glue-cookie-notification-bar"}],optIn:[{waitForThenClick:".glue-cookie-notification-bar__accept"}],optOut:[{if:{exists:".glue-cookie-notification-bar__reject"},then:[{click:".glue-cookie-notification-bar__reject"}],else:[{hide:".glue-cookie-notification-bar"}]}],test:[]},{name:"google.com",prehideSelectors:[".HTjtHe#xe7COe"],detectCmp:[{exists:".HTjtHe#xe7COe"},{exists:'.HTjtHe#xe7COe a[href^="https://policies.google.com/technologies/cookies"]'}],detectPopup:[{visible:".HTjtHe#xe7COe button#W0wltc"}],optIn:[{waitForThenClick:".HTjtHe#xe7COe button#L2AGLb"}],optOut:[{waitForThenClick:".HTjtHe#xe7COe button#W0wltc"}],test:[{eval:"EVAL_GOOGLE_0"}]},{name:"gov.uk",detectCmp:[{exists:"#global-cookie-message"}],detectPopup:[{exists:"#global-cookie-message"}],optIn:[{click:"button[data-accept-cookies=true]"}],optOut:[{click:"button[data-reject-cookies=true],#reject-cookies"},{click:"button[data-hide-cookie-banner=true],#hide-cookie-decision"}]},{name:"hashicorp",vendorUrl:"https://hashicorp.com/",runContext:{urlPattern:"^https://[^.]*\\.hashicorp\\.com/"},prehideSelectors:["[data-testid=consent-banner]"],detectCmp:[{exists:"[data-testid=consent-banner]"}],detectPopup:[{visible:"[data-testid=consent-banner]"}],optIn:[{waitForThenClick:"[data-testid=accept]"}],optOut:[{waitForThenClick:"[data-testid=manage-preferences]"},{waitForThenClick:"[data-testid=consent-mgr-dialog] [data-ga-button=save-preferences]"}]},{name:"healthline-media",prehideSelectors:["#modal-host > div.no-hash > div.window-wrapper"],detectCmp:[{exists:"#modal-host > div.no-hash > div.window-wrapper, div[data-testid=qualtrics-container]"}],detectPopup:[{exists:"#modal-host > div.no-hash > div.window-wrapper, div[data-testid=qualtrics-container]"}],optIn:[{click:"#modal-host > div.no-hash > div.window-wrapper > div:last-child button"}],optOut:[{if:{exists:'#modal-host > div.no-hash > div.window-wrapper > div:last-child a[href="/privacy-settings"]'},then:[{click:'#modal-host > div.no-hash > div.window-wrapper > div:last-child a[href="/privacy-settings"]'}],else:[{waitForVisible:"div#__next"},{click:"#__next div:nth-child(1) > button:first-child"}]}]},{name:"hema",prehideSelectors:[".cookie-modal"],detectCmp:[{visible:".cookie-modal .cookie-accept-btn"}],detectPopup:[{visible:".cookie-modal .cookie-accept-btn"}],optIn:[{waitForThenClick:".cookie-modal .cookie-accept-btn"}],optOut:[{waitForThenClick:".cookie-modal .js-cookie-reject-btn"}],test:[{eval:"EVAL_HEMA_TEST_0"}]},{name:"hetzner.com",runContext:{urlPattern:"^https://www\\.hetzner\\.com/"},prehideSelectors:["#CookieConsent"],detectCmp:[{exists:"#CookieConsent"}],detectPopup:[{visible:"#CookieConsent"}],optIn:[{click:"#CookieConsentGiven"}],optOut:[{click:"#CookieConsentDeclined"}]},{name:"hl.co.uk",prehideSelectors:[".cookieModalContent","#cookie-banner-overlay"],detectCmp:[{exists:"#cookie-banner-overlay"}],detectPopup:[{exists:"#cookie-banner-overlay"}],optIn:[{click:"#acceptCookieButton"}],optOut:[{click:"#manageCookie"},{hide:".cookieSettingsModal"},{waitFor:"#AOCookieToggle"},{click:"#AOCookieToggle[aria-pressed=true]",optional:!0},{waitFor:"#TPCookieToggle"},{click:"#TPCookieToggle[aria-pressed=true]",optional:!0},{click:"#updateCookieButton"}]},{name:"holidaymedia",vendorUrl:"https://holidaymedia.nl/",prehideSelectors:["dialog[data-cookie-consent]"],detectCmp:[{exists:"dialog[data-cookie-consent]"}],detectPopup:[{visible:"dialog[data-cookie-consent]"}],optIn:[{waitForThenClick:"button.cookie-consent__button--accept-all"}],optOut:[{waitForThenClick:'a[data-cookie-accept="functional"]',timeout:2e3}]},{name:"hu-manity",vendorUrl:"https://hu-manity.co/",prehideSelectors:["#hu.hu-wrapper"],detectCmp:[{exists:"#hu.hu-visible"}],detectPopup:[{visible:"#hu.hu-visible"}],optIn:[{waitForThenClick:"[data-hu-action=cookies-notice-consent-choices-3]"},{waitForThenClick:"#hu-cookies-save"}],optOut:[{waitForThenClick:"#hu-cookies-save"}]},{name:"hubspot",detectCmp:[{exists:"#hs-eu-cookie-confirmation"}],detectPopup:[{visible:"#hs-eu-cookie-confirmation"}],optIn:[{click:"#hs-eu-confirmation-button"}],optOut:[{click:"#hs-eu-decline-button"}]},{name:"indeed.com",cosmetic:!0,prehideSelectors:["#CookiePrivacyNotice"],detectCmp:[{exists:"#CookiePrivacyNotice"}],detectPopup:[{visible:"#CookiePrivacyNotice"}],optIn:[{click:"#CookiePrivacyNotice button[data-gnav-element-name=CookiePrivacyNoticeOk]"}],optOut:[{hide:"#CookiePrivacyNotice"}]},{name:"ing.de",runContext:{urlPattern:"^https://www\\.ing\\.de/"},cosmetic:!0,prehideSelectors:['div[slot="backdrop"]'],detectCmp:[{exists:'[data-tag-name="ing-cc-dialog-frame"]'}],detectPopup:[{visible:'[data-tag-name="ing-cc-dialog-frame"]'}],optIn:[{click:['[data-tag-name="ing-cc-dialog-level0"]','[data-tag-name="ing-cc-button"][class*="accept"]']}],optOut:[{click:['[data-tag-name="ing-cc-dialog-level0"]','[data-tag-name="ing-cc-button"][class*="more"]']}]},{name:"instagram",vendorUrl:"https://instagram.com",runContext:{urlPattern:"^https://www\\.instagram\\.com/"},prehideSelectors:[],detectCmp:[{exists:'xpath///span[contains(., "Vill du tillåta användningen av cookies från Instagram i den här webbläsaren?") or contains(., "Allow the use of cookies from Instagram on this browser?") or contains(., "Povolit v prohlížeči použití souborů cookie z Instagramu?") or contains(., "Dopustiti upotrebu kolačića s Instagrama na ovom pregledniku?") or contains(., "Разрешить использование файлов cookie от Instagram в этом браузере?") or contains(., "Vuoi consentire l\'uso dei cookie di Instagram su questo browser?") or contains(., "Povoliť používanie cookies zo služby Instagram v tomto prehliadači?") or contains(., "Die Verwendung von Cookies durch Instagram in diesem Browser erlauben?") or contains(., "Sallitaanko Instagramin evästeiden käyttö tällä selaimella?") or contains(., "Engedélyezed az Instagram cookie-jainak használatát ebben a böngészőben?") or contains(., "Het gebruik van cookies van Instagram toestaan in deze browser?") or contains(., "Bu tarayıcıda Instagram\'dan çerez kullanımına izin verilsin mi?") or contains(., "Permitir o uso de cookies do Instagram neste navegador?") or contains(., "Permiţi folosirea modulelor cookie de la Instagram în acest browser?") or contains(., "Autoriser l’utilisation des cookies d’Instagram sur ce navigateur ?") or contains(., "¿Permitir el uso de cookies de Instagram en este navegador?") or contains(., "Zezwolić na użycie plików cookie z Instagramu w tej przeglądarce?") or contains(., "Να επιτρέπεται η χρήση cookies από τo Instagram σε αυτό το πρόγραμμα περιήγησης;") or contains(., "Разрешавате ли използването на бисквитки от Instagram на този браузър?") or contains(., "Vil du tillade brugen af cookies fra Instagram i denne browser?") or contains(., "Vil du tillate bruk av informasjonskapsler fra Instagram i denne nettleseren?")]'}],detectPopup:[{visible:'xpath///span[contains(., "Vill du tillåta användningen av cookies från Instagram i den här webbläsaren?") or contains(., "Allow the use of cookies from Instagram on this browser?") or contains(., "Povolit v prohlížeči použití souborů cookie z Instagramu?") or contains(., "Dopustiti upotrebu kolačića s Instagrama na ovom pregledniku?") or contains(., "Разрешить использование файлов cookie от Instagram в этом браузере?") or contains(., "Vuoi consentire l\'uso dei cookie di Instagram su questo browser?") or contains(., "Povoliť používanie cookies zo služby Instagram v tomto prehliadači?") or contains(., "Die Verwendung von Cookies durch Instagram in diesem Browser erlauben?") or contains(., "Sallitaanko Instagramin evästeiden käyttö tällä selaimella?") or contains(., "Engedélyezed az Instagram cookie-jainak használatát ebben a böngészőben?") or contains(., "Het gebruik van cookies van Instagram toestaan in deze browser?") or contains(., "Bu tarayıcıda Instagram\'dan çerez kullanımına izin verilsin mi?") or contains(., "Permitir o uso de cookies do Instagram neste navegador?") or contains(., "Permiţi folosirea modulelor cookie de la Instagram în acest browser?") or contains(., "Autoriser l’utilisation des cookies d’Instagram sur ce navigateur ?") or contains(., "¿Permitir el uso de cookies de Instagram en este navegador?") or contains(., "Zezwolić na użycie plików cookie z Instagramu w tej przeglądarce?") or contains(., "Να επιτρέπεται η χρήση cookies από τo Instagram σε αυτό το πρόγραμμα περιήγησης;") or contains(., "Разрешавате ли използването на бисквитки от Instagram на този браузър?") or contains(., "Vil du tillade brugen af cookies fra Instagram i denne browser?") or contains(., "Vil du tillate bruk av informasjonskapsler fra Instagram i denne nettleseren?")]'}],optIn:[{waitForThenClick:"xpath///button[contains(., 'Tillad alle cookies') or contains(., 'Alle Cookies erlauben') or contains(., 'Allow all cookies') or contains(., 'Разрешаване на всички бисквитки') or contains(., 'Tillåt alla cookies') or contains(., 'Povolit všechny soubory cookie') or contains(., 'Tüm çerezlere izin ver') or contains(., 'Permite toate modulele cookie') or contains(., 'Να επιτρέπονται όλα τα cookies') or contains(., 'Tillat alle informasjonskapsler') or contains(., 'Povoliť všetky cookies') or contains(., 'Permitir todas las cookies') or contains(., 'Permitir todos os cookies') or contains(., 'Alle cookies toestaan') or contains(., 'Salli kaikki evästeet') or contains(., 'Consenti tutti i cookie') or contains(., 'Az összes cookie engedélyezése') or contains(., 'Autoriser tous les cookies') or contains(., 'Zezwól na wszystkie pliki cookie') or contains(., 'Разрешить все cookie') or contains(., 'Dopusti sve kolačiće')]"}],optOut:[{waitForThenClick:"xpath///button[contains(., 'Отклонить необязательные файлы cookie') or contains(., 'Decline optional cookies') or contains(., 'Refuser les cookies optionnels') or contains(., 'Hylkää valinnaiset evästeet') or contains(., 'Afvis valgfrie cookies') or contains(., 'Odmietnuť nepovinné cookies') or contains(., 'Απόρριψη προαιρετικών cookies') or contains(., 'Neka valfria cookies') or contains(., 'Optionale Cookies ablehnen') or contains(., 'Rifiuta cookie facoltativi') or contains(., 'Odbij neobavezne kolačiće') or contains(., 'Avvis valgfrie informasjonskapsler') or contains(., 'İsteğe bağlı çerezleri reddet') or contains(., 'Recusar cookies opcionais') or contains(., 'Optionele cookies afwijzen') or contains(., 'Rechazar cookies opcionales') or contains(., 'Odrzuć opcjonalne pliki cookie') or contains(., 'Отхвърляне на бисквитките по избор') or contains(., 'Odmítnout volitelné soubory cookie') or contains(., 'Refuză modulele cookie opţionale') or contains(., 'A nem kötelező cookie-k elutasítása')]"},{wait:2e3}]},{name:"ionos.de",prehideSelectors:[".privacy-consent--backdrop",".privacy-consent--modal"],detectCmp:[{exists:".privacy-consent--modal"}],detectPopup:[{visible:".privacy-consent--modal"}],optIn:[{click:"#selectAll"}],optOut:[{click:".footer-config-link"},{click:"#confirmSelection"}]},{name:"itopvpn.com",cosmetic:!0,prehideSelectors:[".pop-cookie"],detectCmp:[{exists:".pop-cookie"}],detectPopup:[{exists:".pop-cookie"}],optIn:[{click:"#_pcookie"}],optOut:[{hide:".pop-cookie"}]},{name:"iubenda",prehideSelectors:["#iubenda-cs-banner"],detectCmp:[{exists:"#iubenda-cs-banner"}],detectPopup:[{visible:".iubenda-cs-accept-btn"}],optIn:[{waitForThenClick:".iubenda-cs-accept-btn"}],optOut:[{waitForThenClick:".iubenda-cs-customize-btn"},{eval:"EVAL_IUBENDA_0"},{waitForThenClick:"#iubFooterBtn"}],test:[{eval:"EVAL_IUBENDA_1"}]},{name:"iWink",prehideSelectors:["body.cookies-request #cookie-bar"],detectCmp:[{exists:"body.cookies-request #cookie-bar"}],detectPopup:[{visible:"body.cookies-request #cookie-bar"}],optIn:[{waitForThenClick:"body.cookies-request #cookie-bar .allow-cookies"}],optOut:[{waitForThenClick:"body.cookies-request #cookie-bar .disallow-cookies"}],test:[{eval:"EVAL_IWINK_TEST"}]},{name:"jdsports",vendorUrl:"https://www.jdsports.co.uk/",runContext:{urlPattern:"^https://(www|m)\\.jdsports\\."},prehideSelectors:[".miniConsent,#PrivacyPolicyBanner"],detectCmp:[{exists:".miniConsent,#PrivacyPolicyBanner"}],detectPopup:[{visible:".miniConsent,#PrivacyPolicyBanner"}],optIn:[{waitForThenClick:".miniConsent .accept-all-cookies"}],optOut:[{if:{exists:"#PrivacyPolicyBanner"},then:[{hide:"#PrivacyPolicyBanner"}],else:[{waitForThenClick:"#cookie-settings"},{waitForThenClick:"#reject-all-cookies"}]}]},{name:"johnlewis.com",prehideSelectors:["div[class^=pecr-cookie-banner-]"],detectCmp:[{exists:"div[class^=pecr-cookie-banner-]"}],detectPopup:[{exists:"div[class^=pecr-cookie-banner-]"}],optOut:[{click:"button[data-test^=manage-cookies]"},{wait:"500"},{click:"label[data-test^=toggle][class*=checked]:not([class*=disabled])",all:!0,optional:!0},{click:"button[data-test=save-preferences]"}],optIn:[{click:"button[data-test=allow-all]"}]},{name:"jquery.cookieBar",vendorUrl:"https://github.com/kovarp/jquery.cookieBar",prehideSelectors:[".cookie-bar"],cosmetic:!0,detectCmp:[{exists:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons"}],detectPopup:[{visible:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons",check:"any"}],optIn:[{click:".cookie-bar .cookie-bar__btn"}],optOut:[{hide:".cookie-bar"}],test:[{visible:".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons",check:"none"},{eval:"EVAL_JQUERY_COOKIEBAR_0"}]},{name:"justwatch.com",prehideSelectors:[".consent-banner"],detectCmp:[{exists:".consent-banner .consent-banner__actions"}],detectPopup:[{visible:".consent-banner .consent-banner__actions"}],optIn:[{click:".consent-banner__actions button.basic-button.primary"}],optOut:[{click:".consent-banner__actions button.basic-button.secondary"},{waitForThenClick:".consent-modal__footer button.basic-button.secondary"},{waitForThenClick:".consent-modal ion-content > div > a:nth-child(9)"},{click:"label.consent-switch input[type=checkbox]:checked",all:!0,optional:!0},{waitForVisible:".consent-modal__footer button.basic-button.primary"},{click:".consent-modal__footer button.basic-button.primary"}]},{name:"kconsent",cosmetic:!1,runContext:{main:!0,frame:!1},prehideSelectors:[".kc-overlay"],detectCmp:[{exists:"#kconsent"}],detectPopup:[{visible:".kc-dialog"}],optIn:[{waitForThenClick:"#kc-acceptAndHide"}],optOut:[{waitForThenClick:"#kc-denyAndHide"}]},{name:"ketch",vendorUrl:"https://www.ketch.com",runContext:{frame:!1,main:!0},intermediate:!1,prehideSelectors:["#lanyard_root div[role='dialog']"],detectCmp:[{exists:"#lanyard_root div[role='dialog']"}],detectPopup:[{visible:"#lanyard_root div[role='dialog']"}],optIn:[{if:{exists:"#lanyard_root button[class='confirmButton']"},then:[{waitForThenClick:"#lanyard_root div[class*=buttons] > :nth-child(2)"},{click:"#lanyard_root button[class='confirmButton']"}],else:[{waitForThenClick:"#lanyard_root div[class*=buttons] > :nth-child(2)"}]}],optOut:[{if:{exists:"#lanyard_root [aria-describedby=banner-description]"},then:[{waitForThenClick:"#lanyard_root div[class*=buttons] > button[class*=secondaryButton], #lanyard_root button[class*=buttons-secondary]",comment:"can be either settings or reject button"}]},{waitFor:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description], #ketch-preferences",timeout:1e3,optional:!0},{if:{exists:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description], #ketch-preferences"},then:[{waitForThenClick:"#lanyard_root button[class*=rejectButton], #lanyard_root button[class*=rejectAllButton]"},{click:"#lanyard_root button[class*=confirmButton],#lanyard_root div[class*=actions_] > button:nth-child(1), #lanyard_root button[class*=actionButton]"}]}],test:[{eval:"EVAL_KETCH_TEST"}]},{name:"kleinanzeigen-de",runContext:{urlPattern:"^https?://(www\\.)?kleinanzeigen\\.de"},prehideSelectors:["#gdpr-banner-container"],detectCmp:[{any:[{exists:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"},{exists:"#ConsentManagementPage"}]}],detectPopup:[{any:[{visible:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"},{visible:"#ConsentManagementPage"}]}],optIn:[{if:{exists:"#gdpr-banner-container #gdpr-banner"},then:[{click:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-accept]"}],else:[{click:"#ConsentManagementPage .Button-primary"}]}],optOut:[{if:{exists:"#gdpr-banner-container #gdpr-banner"},then:[{click:"#gdpr-banner-container #gdpr-banner [data-testid=gdpr-banner-cmp-button]"}],else:[{click:"#ConsentManagementPage .Button-secondary"}]}]},{name:"lightbox",prehideSelectors:[".darken-layer.open,.lightbox.lightbox--cookie-consent"],detectCmp:[{exists:"body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"}],detectPopup:[{visible:"body.cookie-consent-is-active div.lightbox--cookie-consent > div.lightbox__content > div.cookie-consent[data-jsb]"}],optOut:[{click:".cookie-consent__footer > button[type='submit']:not([data-button='selectAll'])"}],optIn:[{click:".cookie-consent__footer > button[type='submit'][data-button='selectAll']"}]},{name:"lineagrafica",vendorUrl:"https://addons.prestashop.com/en/legal/8734-eu-cookie-law-gdpr-banner-blocker.html",cosmetic:!0,prehideSelectors:["#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"],detectCmp:[{exists:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}],detectPopup:[{exists:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}],optIn:[{waitForThenClick:"#lgcookieslaw_accept"}],optOut:[{hide:"#lgcookieslaw_banner,#lgcookieslaw_modal,.lgcookieslaw-overlay"}]},{name:"linkedin.com",prehideSelectors:[".artdeco-global-alert[type=COOKIE_CONSENT]"],detectCmp:[{exists:".artdeco-global-alert[type=COOKIE_CONSENT]"}],detectPopup:[{visible:".artdeco-global-alert[type=COOKIE_CONSENT]"}],optIn:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=ACCEPT]"},{wait:500},{waitForThenClick:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=ACCEPT]"}],optOut:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=DENY]"},{wait:500},{waitForThenClick:".artdeco-global-alert[type=COOKIE_CONSENT] button[action-type=DENY]"}],test:[{waitForVisible:".artdeco-global-alert[type=COOKIE_CONSENT]",check:"none"}]},{name:"livejasmin",vendorUrl:"https://www.livejasmin.com/",runContext:{urlPattern:"^https://(m|www)\\.livejasmin\\.com/"},prehideSelectors:["#consent_modal"],detectCmp:[{exists:"#consent_modal"}],detectPopup:[{visible:"#consent_modal"}],optIn:[{waitForThenClick:"#consent_modal button[data-testid=ButtonStyledButton]:first-of-type"}],optOut:[{waitForThenClick:"#consent_modal button[data-testid=ButtonStyledButton]:nth-of-type(2)"},{waitForVisible:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent]"},{click:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent] input[data-testid=PrivacyPreferenceCenterWithConsentCookieSwitch]:checked",optional:!0,all:!0},{waitForThenClick:"[data-testid=PrivacyPreferenceCenterWithConsentCookieContent] button[data-testid=ButtonStyledButton]:last-child"}]},{name:"macpaw.com",cosmetic:!0,prehideSelectors:['div[data-banner="cookies"]'],detectCmp:[{exists:'div[data-banner="cookies"]'}],detectPopup:[{exists:'div[data-banner="cookies"]'}],optIn:[{click:'button[data-banner-close="cookies"]'}],optOut:[{hide:'div[data-banner="cookies"]'}]},{name:"marksandspencer.com",cosmetic:!0,detectCmp:[{exists:".navigation-cookiebbanner"}],detectPopup:[{visible:".navigation-cookiebbanner"}],optOut:[{hide:".navigation-cookiebbanner"}],optIn:[{click:".navigation-cookiebbanner__submit"}]},{name:"mediamarkt.de",prehideSelectors:["div[aria-labelledby=pwa-consent-layer-title]","div[class^=StyledConsentLayerWrapper-]"],detectCmp:[{exists:"div[aria-labelledby^=pwa-consent-layer-title]"}],detectPopup:[{exists:"div[aria-labelledby^=pwa-consent-layer-title]"}],optOut:[{click:"button[data-test^=pwa-consent-layer-deny-all]"}],optIn:[{click:"button[data-test^=pwa-consent-layer-accept-all"}]},{name:"Mediavine",prehideSelectors:['[data-name="mediavine-gdpr-cmp"]'],detectCmp:[{exists:'[data-name="mediavine-gdpr-cmp"]'}],detectPopup:[{wait:500},{visible:'[data-name="mediavine-gdpr-cmp"]'}],optIn:[{waitForThenClick:'[data-name="mediavine-gdpr-cmp"] [format="primary"]'}],optOut:[{waitForThenClick:'[data-name="mediavine-gdpr-cmp"] [data-view="manageSettings"]'},{waitFor:'[data-name="mediavine-gdpr-cmp"] input[type=checkbox]'},{eval:"EVAL_MEDIAVINE_0",optional:!0},{click:'[data-name="mediavine-gdpr-cmp"] [format="secondary"]'}]},{name:"medium",vendorUrl:"https://medium.com",cosmetic:!0,runContext:{main:!0,frame:!1,urlPattern:"^https://([a-z0-9-]+\\.)?medium\\.com/"},prehideSelectors:[],detectCmp:[{exists:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}],detectPopup:[{visible:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}],optIn:[{waitForThenClick:"[data-testid=close-button]"}],optOut:[{hide:'div:has(> div > div > div[role=alert] > a[href^="https://policy.medium.com/medium-privacy-policy-"])'}]},{name:"microsoft.com",prehideSelectors:["#wcpConsentBannerCtrl"],detectCmp:[{exists:"#wcpConsentBannerCtrl"}],detectPopup:[{exists:"#wcpConsentBannerCtrl"}],optOut:[{eval:"EVAL_MICROSOFT_0"}],optIn:[{eval:"EVAL_MICROSOFT_1"}],test:[{eval:"EVAL_MICROSOFT_2"}]},{name:"midway-usa",runContext:{urlPattern:"^https://www\\.midwayusa\\.com/"},cosmetic:!0,prehideSelectors:["#cookie-container"],detectCmp:[{exists:['div[aria-label="Cookie Policy Banner"]']}],detectPopup:[{visible:"#cookie-container"}],optIn:[{click:"button#cookie-btn"}],optOut:[{hide:'div[aria-label="Cookie Policy Banner"]'}]},{name:"moneysavingexpert.com",detectCmp:[{exists:"dialog[data-testid=accept-our-cookies-dialog]"}],detectPopup:[{visible:"dialog[data-testid=accept-our-cookies-dialog]"}],optIn:[{click:"#banner-accept"}],optOut:[{click:"#banner-manage"},{click:"#pc-confirm"}]},{name:"monzo.com",prehideSelectors:[".cookie-alert, cookie-alert__content"],detectCmp:[{exists:'div.cookie-alert[role="dialog"]'},{exists:'a[href*="monzo"]'}],detectPopup:[{visible:".cookie-alert__content"}],optIn:[{click:".js-accept-cookie-policy"}],optOut:[{click:".js-decline-cookie-policy"}]},{name:"Moove",prehideSelectors:["#moove_gdpr_cookie_info_bar"],detectCmp:[{exists:"#moove_gdpr_cookie_info_bar"}],detectPopup:[{visible:"#moove_gdpr_cookie_info_bar:not(.moove-gdpr-info-bar-hidden)"}],optIn:[{waitForThenClick:".moove-gdpr-infobar-allow-all"}],optOut:[{if:{exists:"#moove_gdpr_cookie_info_bar .change-settings-button"},then:[{click:"#moove_gdpr_cookie_info_bar .change-settings-button"},{waitForVisible:"#moove_gdpr_cookie_modal"},{eval:"EVAL_MOOVE_0"},{click:".moove-gdpr-modal-save-settings"}],else:[{hide:"#moove_gdpr_cookie_info_bar"}]}],test:[{visible:"#moove_gdpr_cookie_info_bar",check:"none"}]},{name:"national-lottery.co.uk",detectCmp:[{exists:".cuk_cookie_consent"}],detectPopup:[{visible:".cuk_cookie_consent",check:"any"}],optOut:[{click:".cuk_cookie_consent_manage_pref"},{click:".cuk_cookie_consent_save_pref"},{click:".cuk_cookie_consent_close"}],optIn:[{click:".cuk_cookie_consent_accept_all"}]},{name:"nba.com",runContext:{urlPattern:"^https://(www\\.)?nba.com/"},cosmetic:!0,prehideSelectors:["#onetrust-banner-sdk"],detectCmp:[{exists:"#onetrust-banner-sdk"}],detectPopup:[{visible:"#onetrust-banner-sdk"}],optIn:[{click:"#onetrust-accept-btn-handler"}],optOut:[{hide:"#onetrust-banner-sdk"}]},{name:"netbeat.de",runContext:{urlPattern:"^https://(www\\.)?netbeat\\.de/"},prehideSelectors:["div#cookieWarning"],detectCmp:[{exists:"div#cookieWarning"}],detectPopup:[{visible:"div#cookieWarning"}],optIn:[{waitForThenClick:"a#btnCookiesAcceptAll"}],optOut:[{waitForThenClick:"a#btnCookiesDenyAll"}]},{name:"netflix.de",detectCmp:[{exists:"#cookie-disclosure"}],detectPopup:[{visible:".cookie-disclosure-message",check:"any"}],optIn:[{click:".btn-accept"}],optOut:[{hide:"#cookie-disclosure"},{click:".btn-reject"}]},{name:"nhs.uk",prehideSelectors:["#nhsuk-cookie-banner"],detectCmp:[{exists:"#nhsuk-cookie-banner"}],detectPopup:[{exists:"#nhsuk-cookie-banner"}],optOut:[{click:"#nhsuk-cookie-banner__link_accept"}],optIn:[{click:"#nhsuk-cookie-banner__link_accept_analytics"}]},{name:"nike",vendorUrl:"https://nike.com",runContext:{urlPattern:"^https://(www\\.)?nike\\.com/"},prehideSelectors:[],detectCmp:[{exists:"[data-testid=cookie-dialog-root]"}],detectPopup:[{visible:"[data-testid=cookie-dialog-root]"}],optIn:[{waitForThenClick:"[data-testid=dialog-accept-button]"}],optOut:[{waitForThenClick:"input[type=radio][id$=-declineLabel]",all:!0},{waitForThenClick:"[data-testid=confirm-choice-button]"}]},{name:"notice-cookie",prehideSelectors:[".button--notice"],cosmetic:!0,detectCmp:[{exists:".notice--cookie"}],detectPopup:[{visible:".notice--cookie"}],optIn:[{click:".button--notice"}],optOut:[{hide:".notice--cookie"}]},{name:"nrk.no",cosmetic:!0,prehideSelectors:[".nrk-masthead__info-banner--cookie"],detectCmp:[{exists:".nrk-masthead__info-banner--cookie"}],detectPopup:[{exists:".nrk-masthead__info-banner--cookie"}],optIn:[{click:"div.nrk-masthead__info-banner--cookie button > span:has(+ svg.nrk-close)"}],optOut:[{hide:".nrk-masthead__info-banner--cookie"}]},{name:"obi.de",prehideSelectors:[".disc-cp--active"],detectCmp:[{exists:".disc-cp-modal__modal"}],detectPopup:[{visible:".disc-cp-modal__modal"}],optIn:[{click:".js-disc-cp-accept-all"}],optOut:[{click:".js-disc-cp-deny-all"}]},{name:"om",vendorUrl:"https://olli-machts.de/en/extension/cookie-manager",prehideSelectors:[".tx-om-cookie-consent"],detectCmp:[{exists:".tx-om-cookie-consent .active[data-omcookie-panel]"}],detectPopup:[{exists:".tx-om-cookie-consent .active[data-omcookie-panel]"}],optIn:[{waitForThenClick:"[data-omcookie-panel-save=all]"}],optOut:[{if:{exists:"[data-omcookie-panel-save=min]"},then:[{waitForThenClick:"[data-omcookie-panel-save=min]"}],else:[{click:"input[data-omcookie-panel-grp]:checked:not(:disabled)",all:!0,optional:!0},{waitForThenClick:"[data-omcookie-panel-save=save]"}]}]},{name:"onlyFans.com",runContext:{urlPattern:"^https://onlyfans\\.com/"},prehideSelectors:["div.b-cookies-informer"],detectCmp:[{exists:"div.b-cookies-informer"}],detectPopup:[{exists:"div.b-cookies-informer"}],optIn:[{click:"div.b-cookies-informer__nav > button:nth-child(2)"}],optOut:[{click:"div.b-cookies-informer__nav > button:nth-child(1)"},{if:{exists:"div.b-cookies-informer__switchers"},then:[{click:"div.b-cookies-informer__switchers input:not([disabled])",all:!0},{click:"div.b-cookies-informer__nav > button"}]}]},{name:"openai",vendorUrl:"https://platform.openai.com/",cosmetic:!1,runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?openai\\.com/"},prehideSelectors:["[data-testid=cookie-consent-banner]"],detectCmp:[{exists:"[data-testid=cookie-consent-banner]"}],detectPopup:[{visible:"[data-testid=cookie-consent-banner]"}],optIn:[{waitForThenClick:"xpath///button[contains(., 'Accept all')]"}],optOut:[{waitForThenClick:"xpath///button[contains(., 'Reject all')]"}],test:[{wait:500},{eval:"EVAL_OPENAI_TEST"}]},{name:"openli",vendorUrl:"https://openli.com",prehideSelectors:[".legalmonster-cleanslate"],detectCmp:[{exists:".legalmonster-cleanslate"}],detectPopup:[{visible:".legalmonster-cleanslate #lm-cookie-wall-container",check:"any"}],optIn:[{waitForThenClick:"#lm-accept-all"}],optOut:[{waitForThenClick:"#lm-accept-necessary"}]},{name:"opera.com",vendorUrl:"https://unknown",cosmetic:!1,runContext:{main:!0,frame:!1},intermediate:!1,prehideSelectors:[],detectCmp:[{exists:"#cookie-consent .manage-cookies__btn"}],detectPopup:[{visible:"#cookie-consent .cookie-basic-consent__btn"}],optIn:[{waitForThenClick:"#cookie-consent .cookie-basic-consent__btn"}],optOut:[{waitForThenClick:"#cookie-consent .manage-cookies__btn"},{waitForThenClick:"#cookie-consent .active.marketing_option_switch.cookie-consent__switch",all:!0},{waitForThenClick:"#cookie-consent .cookie-selection__btn"}],test:[{eval:"EVAL_OPERA_0"}]},{name:"osano",prehideSelectors:[".osano-cm-window,.osano-cm-dialog"],detectCmp:[{exists:".osano-cm-window"}],detectPopup:[{visible:".osano-cm-dialog"}],optIn:[{click:".osano-cm-accept-all",optional:!0}],optOut:[{waitForThenClick:".osano-cm-denyAll"}]},{name:"otto.de",prehideSelectors:[".cookieBanner--visibility"],detectCmp:[{exists:".cookieBanner--visibility"}],detectPopup:[{visible:".cookieBanner__wrapper"}],optIn:[{click:".js_cookieBannerPermissionButton"}],optOut:[{click:".js_cookieBannerProhibitionButton"}]},{name:"ourworldindata",vendorUrl:"https://ourworldindata.org/",runContext:{urlPattern:"^https://ourworldindata\\.org/"},prehideSelectors:[".cookie-manager"],detectCmp:[{exists:".cookie-manager"}],detectPopup:[{visible:".cookie-manager .cookie-notice.open"}],optIn:[{waitForThenClick:".cookie-notice [data-test=accept]"}],optOut:[{waitForThenClick:".cookie-notice [data-test=reject]"}]},{name:"pabcogypsum",vendorUrl:"https://unknown",prehideSelectors:[".js-cookie-notice:has(#cookie_settings-form)"],detectCmp:[{exists:".js-cookie-notice #cookie_settings-form"}],detectPopup:[{visible:".js-cookie-notice #cookie_settings-form"}],optIn:[{waitForThenClick:".js-cookie-notice button[value=allow]"}],optOut:[{waitForThenClick:".js-cookie-notice button[value=disable]"}]},{name:"paypal-us",prehideSelectors:["#ccpaCookieContent_wrapper, article.ppvx_modal--overpanel"],detectCmp:[{exists:"#ccpaCookieBanner, .privacy-sheet-content"}],detectPopup:[{visible:"#ccpaCookieBanner, .privacy-sheet-content"}],optIn:[{click:"#acceptAllButton"}],optOut:[{if:{exists:"#bannerDeclineButton"},then:[{click:"#bannerDeclineButton"}],else:[{if:{exists:"a#manageCookiesLink"},then:[{click:"a#manageCookiesLink"}],else:[{waitForVisible:".privacy-sheet-content #formContent"},{click:"#formContent .cookiepref-11m2iee-checkbox_base input:checked",all:!0,optional:!0},{click:".cookieAction.saveCookie,.confirmCookie #submitCookiesBtn"}]}]}]},{name:"paypal.com",prehideSelectors:["#gdprCookieBanner"],detectCmp:[{exists:"#gdprCookieBanner"}],detectPopup:[{visible:"#gdprCookieContent_wrapper"}],optIn:[{click:"#acceptAllButton"}],optOut:[{wait:200},{click:".gdprCookieBanner_decline-button"}],test:[{wait:500},{eval:"EVAL_PAYPAL_0"}]},{name:"pinetools.com",cosmetic:!0,prehideSelectors:["#aviso_cookies"],detectCmp:[{exists:"#aviso_cookies"}],detectPopup:[{exists:".lang_en #aviso_cookies"}],optIn:[{click:"#aviso_cookies .a_boton_cerrar"}],optOut:[{hide:"#aviso_cookies"}]},{name:"pinterest-business",vendorUrl:"https://business.pinterest.com/",runContext:{urlPattern:"^https://.*\\.pinterest\\.com/"},prehideSelectors:[".BusinessCookieConsent"],detectCmp:[{exists:".BusinessCookieConsent"}],detectPopup:[{visible:".BusinessCookieConsent [data-id=cookie-consent-banner-buttons]"}],optIn:[{waitForThenClick:"[data-id=cookie-consent-banner-buttons] > div:nth-child(1) button"}],optOut:[{waitForThenClick:"[data-id=cookie-consent-banner-buttons] > div:nth-child(2) button"}]},{name:"pmc",cosmetic:!0,prehideSelectors:["#pmc-pp-tou--notice"],detectCmp:[{exists:"#pmc-pp-tou--notice"}],detectPopup:[{visible:"#pmc-pp-tou--notice"}],optIn:[{click:"span.pmc-pp-tou--notice-close-btn"}],optOut:[{hide:"#pmc-pp-tou--notice"}]},{name:"pornhub.com",runContext:{urlPattern:"^https://(www\\.)?pornhub\\.com/"},cosmetic:!1,prehideSelectors:["#cookieBanner #cookieBannerContent"],detectCmp:[{exists:"#cookieBanner #cookieBannerContent"}],detectPopup:[{visible:"#cookieBanner #cookieBannerContent"}],optIn:[{waitForThenClick:"#cookieBanner [data-label=accept_all]"}],optOut:[{waitForThenClick:"#cookieBanner [data-label=accept_essential]"}]},{name:"pornpics.com",cosmetic:!0,prehideSelectors:["#cookie-contract"],detectCmp:[{exists:"#cookie-contract"}],detectPopup:[{visible:"#cookie-contract"}],optIn:[{click:"#cookie-contract .icon-cross"}],optOut:[{hide:"#cookie-contract"}]},{name:"PrimeBox CookieBar",prehideSelectors:["#cookie-bar"],detectCmp:[{exists:"#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy"}],detectPopup:[{visible:"#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy",check:"any"}],optIn:[{waitForThenClick:"#cookie-bar .cb-enable"}],optOut:[{click:"#cookie-bar .cb-disable",optional:!0},{hide:"#cookie-bar"}],test:[{eval:"EVAL_PRIMEBOX_0"}]},{name:"privacymanager.io",prehideSelectors:["#gdpr-consent-tool-wrapper",'iframe[src^="https://cmp-consent-tool.privacymanager.io"]'],runContext:{urlPattern:"^https://cmp-consent-tool\\.privacymanager\\.io/",main:!1,frame:!0},detectCmp:[{exists:"button#save"}],detectPopup:[{visible:"button#save"}],optIn:[{click:"button#save"}],optOut:[{if:{exists:"#denyAll"},then:[{click:"#denyAll"},{waitForThenClick:".okButton"}],else:[{waitForThenClick:"#manageSettings"},{waitFor:".purposes-overview-list"},{waitFor:"button#saveAndExit"},{click:"span[role=checkbox][aria-checked=true]",all:!0,optional:!0},{click:"button#saveAndExit"}]}]},{name:"productz.com",vendorUrl:"https://productz.com/",runContext:{urlPattern:"^https://productz\\.com/"},prehideSelectors:[],detectCmp:[{exists:".c-modal.is-active"}],detectPopup:[{visible:".c-modal.is-active"}],optIn:[{waitForThenClick:".c-modal.is-active .is-accept"}],optOut:[{waitForThenClick:".c-modal.is-active .is-dismiss"}]},{name:"pubtech",prehideSelectors:["#pubtech-cmp"],detectCmp:[{exists:"#pubtech-cmp"}],detectPopup:[{visible:"#pubtech-cmp #pt-actions"}],optIn:[{if:{exists:"#pt-accept-all"},then:[{click:"#pubtech-cmp #pt-actions #pt-accept-all"}],else:[{click:"#pubtech-cmp #pt-actions button:nth-of-type(2)"}]}],optOut:[{click:"#pubtech-cmp #pt-close"}],test:[{eval:"EVAL_PUBTECH_0"}]},{name:"quantcast",prehideSelectors:["#qc-cmp2-main,#qc-cmp2-container"],detectCmp:[{exists:"#qc-cmp2-container"}],detectPopup:[{visible:"#qc-cmp2-ui"}],optOut:[{waitFor:'.qc-cmp2-summary-buttons > button[mode="secondary"]',timeout:2e3},{if:{exists:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(2)'},then:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(2)'}],else:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]:nth-of-type(1)'},{waitFor:"#qc-cmp2-ui"},{click:'.qc-cmp2-toggle-switch > button[aria-checked="true"]',all:!0,optional:!0},{click:'.qc-cmp2-main button[aria-label="REJECT ALL"]',optional:!0},{waitForThenClick:'.qc-cmp2-main button[aria-label="SAVE & EXIT"],.qc-cmp2-buttons-desktop > button[mode="primary"]',timeout:5e3}]}],optIn:[{click:'.qc-cmp2-summary-buttons > button[mode="primary"]'}]},{name:"reddit.com",runContext:{urlPattern:"^https://www\\.reddit\\.com/"},prehideSelectors:["[bundlename=reddit_cookie_banner]"],detectCmp:[{exists:"reddit-cookie-banner"}],detectPopup:[{visible:"reddit-cookie-banner"}],optIn:[{waitForThenClick:["reddit-cookie-banner","#accept-all-cookies-button > button"]}],optOut:[{waitForThenClick:["reddit-cookie-banner","#reject-nonessential-cookies-button > button"]}],test:[{eval:"EVAL_REDDIT_0"}]},{name:"roblox",vendorUrl:"https://roblox.com",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?roblox\\.com/"},prehideSelectors:[],detectCmp:[{exists:".cookie-banner-wrapper"}],detectPopup:[{visible:".cookie-banner-wrapper .cookie-banner"}],optIn:[{waitForThenClick:".cookie-banner-wrapper button.btn-cta-lg"}],optOut:[{waitForThenClick:".cookie-banner-wrapper button.btn-secondary-lg"}],test:[{eval:"EVAL_ROBLOX_TEST"}]},{name:"rog-forum.asus.com",runContext:{urlPattern:"^https://rog-forum\\.asus\\.com/"},prehideSelectors:["#cookie-policy-info"],detectCmp:[{exists:"#cookie-policy-info"}],detectPopup:[{visible:"#cookie-policy-info"}],optIn:[{click:'div.cookie-btn-box > div[aria-label="Accept"]'}],optOut:[{click:'div.cookie-btn-box > div[aria-label="Reject"]'},{waitForThenClick:'.cookie-policy-lightbox-bottom > div[aria-label="Save Settings"]'}]},{name:"roofingmegastore.co.uk",runContext:{urlPattern:"^https://(www\\.)?roofingmegastore\\.co\\.uk"},prehideSelectors:["#m-cookienotice"],detectCmp:[{exists:"#m-cookienotice"}],detectPopup:[{visible:"#m-cookienotice"}],optIn:[{click:"#accept-cookies"}],optOut:[{click:"#manage-cookies"},{waitForThenClick:"#accept-selected"}]},{name:"samsung.com",runContext:{urlPattern:"^https://www\\.samsung\\.com/"},cosmetic:!0,prehideSelectors:["div.cookie-bar"],detectCmp:[{exists:"div.cookie-bar"}],detectPopup:[{visible:"div.cookie-bar"}],optIn:[{click:"div.cookie-bar__manage > a"}],optOut:[{hide:"div.cookie-bar"}]},{name:"setapp.com",vendorUrl:"https://setapp.com/",cosmetic:!0,runContext:{urlPattern:"^https://setapp\\.com/"},prehideSelectors:[],detectCmp:[{exists:".cookie-banner.js-cookie-banner"}],detectPopup:[{visible:".cookie-banner.js-cookie-banner"}],optIn:[{waitForThenClick:".cookie-banner.js-cookie-banner button"}],optOut:[{hide:".cookie-banner.js-cookie-banner"}]},{name:"sibbo",prehideSelectors:["sibbo-cmp-layout"],detectCmp:[{exists:"sibbo-cmp-layout"}],detectPopup:[{visible:"#rejectAllMain"}],optIn:[{click:"#acceptAllMain"}],optOut:[{click:"#rejectAllMain"}]},{name:"similarweb.com",cosmetic:!0,prehideSelectors:[".app-cookies-notification"],detectCmp:[{exists:".app-cookies-notification"}],detectPopup:[{exists:".app-layout .app-cookies-notification"}],optIn:[{click:"button.app-cookies-notification__dismiss"}],optOut:[{hide:".app-layout .app-cookies-notification"}]},{name:"Sirdata",cosmetic:!1,prehideSelectors:["#sd-cmp"],detectCmp:[{exists:"#sd-cmp"}],detectPopup:[{visible:"#sd-cmp"}],optIn:[{waitForThenClick:"#sd-cmp .sd-cmp-3cRQ2"}],optOut:[{waitForThenClick:["#sd-cmp","xpath///span[contains(., 'Do not accept') or contains(., 'Acceptera inte') or contains(., 'No aceptar') or contains(., 'Ikke acceptere') or contains(., 'Nicht akzeptieren') or contains(., 'Не приемам') or contains(., 'Να μην γίνει αποδοχή') or contains(., 'Niet accepteren') or contains(., 'Nepřijímat') or contains(., 'Nie akceptuj') or contains(., 'Nu acceptați') or contains(., 'Não aceitar') or contains(., 'Continuer sans accepter') or contains(., 'Non accettare') or contains(., 'Nem fogad el')]"]}]},{name:"skyscanner",vendorUrl:"https://skyscanner.com",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?skyscanner[\\.a-z]+/"},prehideSelectors:[".cookie-banner-wrapper"],detectCmp:[{exists:"#cookieBannerContent"}],detectPopup:[{visible:"#cookieBannerContent"}],optIn:[{waitForThenClick:"[data-tracking-element-id=cookie_banner_accept_all]"}],optOut:[{waitForThenClick:"[data-tracking-element-id=cookie_banner_essential_only]"},{waitForVisible:"#cookieBannerContent",check:"none"}],test:[{eval:"EVAL_SKYSCANNER_TEST"}]},{name:"snigel",detectCmp:[{exists:".snigel-cmp-framework"}],detectPopup:[{visible:".snigel-cmp-framework"}],optOut:[{click:"#sn-b-custom"},{click:"#sn-b-save"}],test:[{eval:"EVAL_SNIGEL_0"}],optIn:[{click:".snigel-cmp-framework #accept-choices"}]},{name:"steampowered.com",detectCmp:[{exists:".cookiepreferences_popup"},{visible:".cookiepreferences_popup"}],detectPopup:[{visible:".cookiepreferences_popup"}],optOut:[{click:"#rejectAllButton"}],optIn:[{click:"#acceptAllButton"}],test:[{wait:1e3},{eval:"EVAL_STEAMPOWERED_0"}]},{name:"strato.de",prehideSelectors:[".consent__wrapper"],runContext:{urlPattern:"^https://www\\.strato\\.de/"},detectCmp:[{exists:".consent"}],detectPopup:[{visible:".consent"}],optIn:[{click:"button.consentAgree"}],optOut:[{click:"button.consentSettings"},{waitForThenClick:"button#consentSubmit"}]},{name:"svt.se",vendorUrl:"https://www.svt.se/",runContext:{urlPattern:"^https://www\\.svt\\.se/"},prehideSelectors:["[class*=CookieConsent__root___]"],detectCmp:[{exists:"[class*=CookieConsent__root___]"}],detectPopup:[{visible:"[class*=CookieConsent__modal___]"}],optIn:[{waitForThenClick:"[class*=CookieConsent__modal___] > div > button[class*=primary]"}],optOut:[{waitForThenClick:"[class*=CookieConsent__modal___] > div > button[class*=secondary]:nth-child(2)"}],test:[{eval:"EVAL_SVT_TEST"}]},{name:"takealot.com",cosmetic:!0,prehideSelectors:['div[class^="cookies-banner-module_"]'],detectCmp:[{exists:'div[class^="cookies-banner-module_cookie-banner_"]'}],detectPopup:[{exists:'div[class^="cookies-banner-module_cookie-banner_"]'}],optIn:[{click:'button[class*="cookies-banner-module_dismiss-button_"]'}],optOut:[{hide:'div[class^="cookies-banner-module_"]'},{if:{exists:'div[class^="cookies-banner-module_small-cookie-banner_"]'},then:[{eval:"EVAL_TAKEALOT_0"}],else:[]}]},{name:"tarteaucitron.js",prehideSelectors:["#tarteaucitronRoot"],detectCmp:[{exists:"#tarteaucitronRoot"}],detectPopup:[{visible:"#tarteaucitronRoot #tarteaucitronAlertBig",check:"any"}],optIn:[{eval:"EVAL_TARTEAUCITRON_1"}],optOut:[{eval:"EVAL_TARTEAUCITRON_0"}],test:[{eval:"EVAL_TARTEAUCITRON_2",comment:"sometimes there are required categories, so we check that at least something is false"}]},{name:"taunton",vendorUrl:"https://www.taunton.com/",prehideSelectors:["#taunton-user-consent__overlay"],detectCmp:[{exists:"#taunton-user-consent__overlay"}],detectPopup:[{exists:"#taunton-user-consent__overlay:not([aria-hidden=true])"}],optIn:[{click:"#taunton-user-consent__toolbar input[type=checkbox]:not(:checked)"},{click:"#taunton-user-consent__toolbar button[type=submit]"}],optOut:[{click:"#taunton-user-consent__toolbar input[type=checkbox]:checked",optional:!0,all:!0},{click:"#taunton-user-consent__toolbar button[type=submit]"}],test:[{eval:"EVAL_TAUNTON_TEST"}]},{name:"Tealium",prehideSelectors:["#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs,#__tealiumImplicitmodal,#consent-layer"],detectCmp:[{exists:"#__tealiumGDPRecModal *,#__tealiumGDPRcpPrefs *,#__tealiumImplicitmodal *"},{eval:"EVAL_TEALIUM_0"}],detectPopup:[{visible:"#__tealiumGDPRecModal *,#__tealiumGDPRcpPrefs *,#__tealiumImplicitmodal *",check:"any"}],optOut:[{eval:"EVAL_TEALIUM_1"},{eval:"EVAL_TEALIUM_DONOTSELL"},{hide:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs,#__tealiumImplicitmodal"},{waitForThenClick:"#cm-acceptNone,.js-accept-essential-cookies,#continueWithoutAccepting",timeout:1e3,optional:!0}],optIn:[{hide:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs"},{eval:"EVAL_TEALIUM_2"}],test:[{eval:"EVAL_TEALIUM_3"},{eval:"EVAL_TEALIUM_DONOTSELL_CHECK"},{visible:"#__tealiumGDPRecModal,#__tealiumGDPRcpPrefs",check:"none"}]},{name:"temu",vendorUrl:"https://temu.com",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?temu\\.com/"},prehideSelectors:[],detectCmp:[{exists:'div > div > div > div > span[href*="/cookie-and-similar-technologies-policy.html"]'}],detectPopup:[{visible:'div > div > div > div > span[href*="/cookie-and-similar-technologies-policy.html"]'}],optIn:[{waitForThenClick:'div > div > div:has(> div > span[href*="/cookie-and-similar-technologies-policy.html"]) > [role=button]:nth-child(3)'}],optOut:[{if:{exists:"xpath///span[contains(., 'Alle afwijzen') or contains(., 'Reject all') or contains(., 'Tümünü reddet') or contains(., 'Odrzuć wszystko')]"},then:[{waitForThenClick:"xpath///span[contains(., 'Alle afwijzen') or contains(., 'Reject all') or contains(., 'Tümünü reddet') or contains(., 'Odrzuć wszystko')]"}],else:[{waitForThenClick:'div > div > div:has(> div > span[href*="/cookie-and-similar-technologies-policy.html"]) > [role=button]:nth-child(2)'}]}]},{name:"Termly",prehideSelectors:["#termly-code-snippet-support"],detectCmp:[{exists:"#termly-code-snippet-support"}],detectPopup:[{visible:"#termly-code-snippet-support div"}],optIn:[{waitForThenClick:'[data-tid="banner-accept"]'}],optOut:[{if:{exists:'[data-tid="banner-decline"]'},then:[{click:'[data-tid="banner-decline"]'}],else:[{click:".t-preference-button"},{wait:500},{if:{exists:".t-declineAllButton"},then:[{click:".t-declineAllButton"}],else:[{waitForThenClick:".t-preference-modal input[type=checkbox][checked]:not([disabled])",all:!0},{waitForThenClick:".t-saveButton"}]}]}]},{name:"termsfeed",vendorUrl:"https://termsfeed.com",comment:"v4.x.x",prehideSelectors:[".termsfeed-com---nb"],detectCmp:[{exists:".termsfeed-com---nb"}],detectPopup:[{visible:".termsfeed-com---nb"}],optIn:[{waitForThenClick:".cc-nb-okagree"}],optOut:[{waitForThenClick:".cc-nb-reject"}]},{name:"termsfeed3",vendorUrl:"https://termsfeed.com",comment:"v3.x.x",prehideSelectors:[".cc_dialog.cc_css_reboot,.cc_overlay_lock"],detectCmp:[{exists:".cc_dialog.cc_css_reboot"}],detectPopup:[{visible:".cc_dialog.cc_css_reboot"}],optIn:[{waitForThenClick:".cc_dialog.cc_css_reboot .cc_b_ok"}],optOut:[{if:{exists:".cc_dialog.cc_css_reboot .cc_b_cp"},then:[{click:".cc_dialog.cc_css_reboot .cc_b_cp"},{waitForVisible:".cookie-consent-preferences-dialog .cc_cp_f_save button"},{waitForThenClick:".cookie-consent-preferences-dialog .cc_cp_f_save button"}],else:[{hide:".cc_dialog.cc_css_reboot,.cc_overlay_lock"}]}]},{name:"tesco",vendorUrl:"https://www.tesco.com",cosmetic:!1,runContext:{urlPattern:"^https://(www\\.)?tesco\\.com/"},prehideSelectors:["[class*=CookieBanner__Sizer]"],detectCmp:[{exists:"[aria-label=consent-banner]"}],detectPopup:[{visible:"[aria-label=consent-banner]"}],optIn:[{wait:1e3},{waitForThenClick:"xpath///button[contains(., 'Accept all')]"}],optOut:[{wait:1e3},{waitForThenClick:"xpath///button[contains(., 'Reject all')]"}]},{name:"tesla",vendorUrl:"https://tesla.com/",runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?tesla\\.com/"},prehideSelectors:[],detectCmp:[{exists:"#cookie_banner"}],detectPopup:[{visible:"#cookie_banner"}],optIn:[{waitForThenClick:"#tsla-accept-cookie"}],optOut:[{waitForThenClick:"#tsla-reject-cookie"}],test:[{eval:"EVAL_TESLA_TEST"}]},{name:"Test page cosmetic CMP",cosmetic:!0,prehideSelectors:["#privacy-test-page-cmp-test-prehide"],detectCmp:[{exists:"#privacy-test-page-cmp-test-banner"}],detectPopup:[{visible:"#privacy-test-page-cmp-test-banner"}],optIn:[{waitFor:"#accept-all"},{click:"#accept-all"}],optOut:[{hide:"#privacy-test-page-cmp-test-banner"}],test:[{wait:500},{eval:"EVAL_TESTCMP_COSMETIC_0"}]},{name:"Test page CMP",prehideSelectors:["#reject-all"],detectCmp:[{exists:"#privacy-test-page-cmp-test"}],detectPopup:[{visible:"#privacy-test-page-cmp-test"}],optIn:[{waitFor:"#accept-all"},{click:"#accept-all"}],optOut:[{waitFor:"#reject-all"},{eval:"EVAL_TESTCMP_STEP"},{click:"#reject-all"}],test:[{eval:"EVAL_TESTCMP_0"}]},{name:"thalia.de",prehideSelectors:[".consent-banner-box"],detectCmp:[{exists:"consent-banner[component=consent-banner]"}],detectPopup:[{visible:".consent-banner-box"}],optIn:[{click:".button-zustimmen"}],optOut:[{click:"button[data-consent=disagree]"}]},{name:"thefreedictionary.com",prehideSelectors:["#cmpBanner"],detectCmp:[{exists:"#cmpBanner"}],detectPopup:[{visible:"#cmpBanner"}],optIn:[{eval:"EVAL_THEFREEDICTIONARY_1"}],optOut:[{eval:"EVAL_THEFREEDICTIONARY_0"}]},{name:"theverge",runContext:{frame:!1,main:!0,urlPattern:"^https://(www)?\\.theverge\\.com"},intermediate:!1,prehideSelectors:[".duet--cta--cookie-banner"],detectCmp:[{exists:".duet--cta--cookie-banner"}],detectPopup:[{visible:".duet--cta--cookie-banner"}],optIn:[{click:".duet--cta--cookie-banner button.tracking-12",all:!1}],optOut:[{click:".duet--cta--cookie-banner button.tracking-12 > span"}],test:[{eval:"EVAL_THEVERGE_0"}]},{name:"tidbits-com",cosmetic:!0,prehideSelectors:["#eu_cookie_law_widget-2"],detectCmp:[{exists:"#eu_cookie_law_widget-2"}],detectPopup:[{visible:"#eu_cookie_law_widget-2"}],optIn:[{click:"#eu-cookie-law form > input.accept"}],optOut:[{hide:"#eu_cookie_law_widget-2"}]},{name:"tractor-supply",runContext:{urlPattern:"^https://www\\.tractorsupply\\.com/"},cosmetic:!0,prehideSelectors:[".tsc-cookie-banner"],detectCmp:[{exists:".tsc-cookie-banner"}],detectPopup:[{visible:".tsc-cookie-banner"}],optIn:[{click:"#cookie-banner-cancel"}],optOut:[{hide:".tsc-cookie-banner"}]},{name:"trader-joes-com",cosmetic:!0,prehideSelectors:['div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'],detectCmp:[{exists:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}],detectPopup:[{visible:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}],optIn:[{click:'div[class^="CookiesAlert_cookiesAlert__container__"] button'}],optOut:[{hide:'div.aem-page > div[class^="CookiesAlert_cookiesAlert__"]'}]},{name:"transcend",vendorUrl:"https://unknown",cosmetic:!0,prehideSelectors:["#transcend-consent-manager"],detectCmp:[{exists:"#transcend-consent-manager"}],detectPopup:[{visible:"#transcend-consent-manager"}],optIn:[{waitForThenClick:["#transcend-consent-manager","#consentManagerMainDialog .inner-container button"]}],optOut:[{hide:"#transcend-consent-manager"}]},{name:"transip-nl",runContext:{urlPattern:"^https://www\\.transip\\.nl/"},prehideSelectors:["#consent-modal"],detectCmp:[{any:[{exists:"#consent-modal"},{exists:"#privacy-settings-content"}]}],detectPopup:[{any:[{visible:"#consent-modal"},{visible:"#privacy-settings-content"}]}],optIn:[{click:'button[type="submit"]'}],optOut:[{if:{exists:"#privacy-settings-content"},then:[{click:'button[type="submit"]'}],else:[{click:"div.one-modal__action-footer-column--secondary > a"}]}]},{name:"tropicfeel-com",prehideSelectors:["#shopify-section-cookies-controller"],detectCmp:[{exists:"#shopify-section-cookies-controller"}],detectPopup:[{visible:"#shopify-section-cookies-controller #cookies-controller-main-pane",check:"any"}],optIn:[{waitForThenClick:"#cookies-controller-main-pane form[data-form-allow-all] button"}],optOut:[{click:"#cookies-controller-main-pane a[data-tab-target=manage-cookies]"},{waitFor:"#manage-cookies-pane.active"},{click:"#manage-cookies-pane.active input[type=checkbox][checked]:not([disabled])",all:!0},{click:"#manage-cookies-pane.active button[type=submit]"}],test:[]},{name:"true-car",runContext:{urlPattern:"^https://www\\.truecar\\.com/"},cosmetic:!0,prehideSelectors:[['div[aria-labelledby="cookie-banner-heading"]']],detectCmp:[{exists:'div[aria-labelledby="cookie-banner-heading"]'}],detectPopup:[{visible:'div[aria-labelledby="cookie-banner-heading"]'}],optIn:[{click:'div[aria-labelledby="cookie-banner-heading"] > button[aria-label="Close"]'}],optOut:[{hide:'div[aria-labelledby="cookie-banner-heading"]'}]},{name:"truyo",prehideSelectors:["#truyo-consent-module"],detectCmp:[{exists:"#truyo-cookieBarContent"}],detectPopup:[{visible:"#truyo-consent-module"}],optIn:[{click:"button#acceptAllCookieButton"}],optOut:[{click:"button#declineAllCookieButton"}]},{name:"twcc",vendorUrl:"https://unknown",cosmetic:!1,runContext:{main:!0,frame:!1,urlPattern:""},prehideSelectors:["#twcc__mechanism"],detectCmp:[{exists:"#twcc__mechanism .twcc__notice"}],detectPopup:[{visible:"#twcc__mechanism .twcc__notice"}],optIn:[{waitForThenClick:"#twcc__accept-button"}],optOut:[{waitForThenClick:"#twcc__decline-button"}],test:[{eval:"EVAL_TWCC_TEST"}]},{name:"twitch-mobile",vendorUrl:"https://m.twitch.tv/",cosmetic:!0,runContext:{urlPattern:"^https?://m\\.twitch\\.tv"},prehideSelectors:[],detectCmp:[{exists:'.ReactModal__Overlay [href="https://www.twitch.tv/p/cookie-policy"]'}],detectPopup:[{visible:'.ReactModal__Overlay [href="https://www.twitch.tv/p/cookie-policy"]'}],optIn:[{waitForThenClick:'.ReactModal__Overlay:has([href="https://www.twitch.tv/p/cookie-policy"]) button'}],optOut:[{hide:'.ReactModal__Overlay:has([href="https://www.twitch.tv/p/cookie-policy"])'}]},{name:"twitch.tv",runContext:{urlPattern:"^https?://(www\\.)?twitch\\.tv"},prehideSelectors:["div:has(> .consent-banner .consent-banner__content--gdpr-v2),.ReactModalPortal:has([data-a-target=consent-modal-save])"],detectCmp:[{exists:".consent-banner .consent-banner__content--gdpr-v2"}],detectPopup:[{visible:".consent-banner .consent-banner__content--gdpr-v2"}],optIn:[{click:'button[data-a-target="consent-banner-accept"]'}],optOut:[{hide:"div:has(> .consent-banner .consent-banner__content--gdpr-v2)"},{click:'button[data-a-target="consent-banner-manage-preferences"]'},{waitFor:"input[type=checkbox][data-a-target=tw-checkbox]"},{click:"input[type=checkbox][data-a-target=tw-checkbox][checked]:not([disabled])",all:!0,optional:!0},{waitForThenClick:"[data-a-target=consent-modal-save]"},{waitForVisible:".ReactModalPortal:has([data-a-target=consent-modal-save])",check:"none"}]},{name:"twitter",runContext:{urlPattern:"^https://([a-z0-9-]+\\.)?(twitter|x)\\.com/"},prehideSelectors:['[data-testid="BottomBar"]'],detectCmp:[{exists:'[data-testid="BottomBar"] div'}],detectPopup:[{visible:'[data-testid="BottomBar"] div'}],optIn:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>button[role=button]>span) > div:last-child > button[role=button]:first-child'}],optOut:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>button[role=button]>span) > div:last-child > button[role=button]:last-child'}],TODOtest:[{eval:"EVAL_document.cookie.includes('d_prefs=MjoxLGNvbnNlbnRfdmVyc2lvbjoy')"}]},{name:"ubuntu.com",prehideSelectors:["dialog.cookie-policy"],detectCmp:[{any:[{exists:"dialog.cookie-policy header"},{exists:'xpath///*[@id="modal"]/div/header'}]}],detectPopup:[{any:[{visible:"dialog header"},{visible:'xpath///*[@id="modal"]/div/header'}]}],optIn:[{any:[{waitForThenClick:"#cookie-policy-button-accept"},{waitForThenClick:'xpath///*[@id="cookie-policy-button-accept"]'}]}],optOut:[{any:[{waitForThenClick:"button.js-manage"},{waitForThenClick:'xpath///*[@id="cookie-policy-content"]/p[4]/button[2]'}]},{waitForThenClick:"dialog.cookie-policy .p-switch__input:checked",optional:!0,all:!0,timeout:500},{any:[{waitForThenClick:"dialog.cookie-policy .js-save-preferences"},{waitForThenClick:'xpath///*[@id="modal"]/div/button'}]}],test:[{eval:"EVAL_UBUNTU_COM_0"}]},{name:"UK Cookie Consent",prehideSelectors:["#catapult-cookie-bar"],cosmetic:!0,detectCmp:[{exists:"#catapult-cookie-bar"}],detectPopup:[{exists:".has-cookie-bar #catapult-cookie-bar"}],optIn:[{click:"#catapultCookie"}],optOut:[{hide:"#catapult-cookie-bar"}],test:[{eval:"EVAL_UK_COOKIE_CONSENT_0"}]},{name:"urbanarmorgear-com",cosmetic:!0,prehideSelectors:['div[class^="Layout__CookieBannerContainer-"]'],detectCmp:[{exists:'div[class^="Layout__CookieBannerContainer-"]'}],detectPopup:[{visible:'div[class^="Layout__CookieBannerContainer-"]'}],optIn:[{click:'button[class^="CookieBanner__AcceptButton"]'}],optOut:[{hide:'div[class^="Layout__CookieBannerContainer-"]'}]},{name:"usercentrics-api",detectCmp:[{exists:"#usercentrics-root,#usercentrics-cmp-ui"}],detectPopup:[{eval:"EVAL_USERCENTRICS_API_0"},{if:{exists:"#usercentrics-cmp-ui"},then:[{waitForVisible:"#usercentrics-cmp-ui",timeout:2e3}],else:[{exists:["#usercentrics-root","[data-testid=uc-container]"]},{waitForVisible:"#usercentrics-root",timeout:2e3}]}],optIn:[{eval:"EVAL_USERCENTRICS_API_3"},{eval:"EVAL_USERCENTRICS_API_1"},{eval:"EVAL_USERCENTRICS_API_5"}],optOut:[{eval:"EVAL_USERCENTRICS_API_1"},{eval:"EVAL_USERCENTRICS_API_2"}],test:[{eval:"EVAL_USERCENTRICS_API_6"}]},{name:"usercentrics-button",detectCmp:[{exists:"#usercentrics-button"}],detectPopup:[{visible:"#usercentrics-button #uc-btn-accept-banner"}],optIn:[{click:"#usercentrics-button #uc-btn-accept-banner"}],optOut:[{click:"#usercentrics-button #uc-btn-deny-banner"}],test:[{eval:"EVAL_USERCENTRICS_BUTTON_0"}]},{name:"uswitch.com",runContext:{main:!0,frame:!1,urlPattern:"^https://(www\\.)?uswitch\\.com/"},prehideSelectors:[".ucb"],detectCmp:[{exists:".ucb-banner"}],detectPopup:[{visible:".ucb-banner"}],optIn:[{waitForThenClick:".ucb-banner .ucb-btn-accept"}],optOut:[{waitForThenClick:".ucb-banner .ucb-btn-save"}]},{name:"vodafone.de",runContext:{urlPattern:"^https://www\\.vodafone\\.de/"},prehideSelectors:[".dip-consent,.dip-consent-container"],detectCmp:[{exists:".dip-consent-container"}],detectPopup:[{visible:".dip-consent-content"}],optOut:[{click:'.dip-consent-btn[tabindex="2"]'}],optIn:[{click:'.dip-consent-btn[tabindex="1"]'}]},{name:"waitrose.com",prehideSelectors:["div[aria-labelledby=CookieAlertModalHeading]","section[data-test=initial-waitrose-cookie-consent-banner]","section[data-test=cookie-consent-modal]"],detectCmp:[{exists:"section[data-test=initial-waitrose-cookie-consent-banner]"}],detectPopup:[{visible:"section[data-test=initial-waitrose-cookie-consent-banner]"}],optIn:[{click:"button[data-test=accept-all]"}],optOut:[{click:"button[data-test=manage-cookies]"},{wait:200},{eval:"EVAL_WAITROSE_0"},{click:"button[data-test=submit]"}],test:[{eval:"EVAL_WAITROSE_1"}]},{name:"webflow",vendorUrl:"https://webflow.com/",prehideSelectors:[".fs-cc-components"],detectCmp:[{exists:".fs-cc-components"}],detectPopup:[{visible:".fs-cc-components"},{visible:"[fs-cc=banner]"}],optIn:[{wait:500},{waitForThenClick:"[fs-cc=banner] [fs-cc=allow]"}],optOut:[{wait:500},{waitForThenClick:"[fs-cc=banner] [fs-cc=deny]"}]},{name:"wetransfer.com",detectCmp:[{exists:".welcome__cookie-notice"}],detectPopup:[{visible:".welcome__cookie-notice"}],optIn:[{click:".welcome__button--accept"}],optOut:[{click:".welcome__button--decline"}]},{name:"whitepages.com",runContext:{urlPattern:"^https://www\\.whitepages\\.com/"},cosmetic:!0,prehideSelectors:[".cookie-wrapper, .cookie-overlay"],detectCmp:[{exists:".cookie-wrapper"}],detectPopup:[{visible:".cookie-overlay"}],optIn:[{click:'button[aria-label="Got it"]'}],optOut:[{hide:".cookie-wrapper"}]},{name:"wolframalpha",vendorUrl:"https://www.wolframalpha.com",prehideSelectors:[],cosmetic:!0,runContext:{urlPattern:"^https://www\\.wolframalpha\\.com/"},detectCmp:[{exists:"section._a_yb"}],detectPopup:[{visible:"section._a_yb"}],optIn:[{waitForThenClick:"section._a_yb button"}],optOut:[{hide:"section._a_yb"}]},{name:"woo-commerce-com",prehideSelectors:[".wccom-comp-privacy-banner .wccom-privacy-banner"],detectCmp:[{exists:".wccom-comp-privacy-banner .wccom-privacy-banner"}],detectPopup:[{exists:".wccom-comp-privacy-banner .wccom-privacy-banner"}],optIn:[{click:".wccom-privacy-banner__content-buttons button.is-primary"}],optOut:[{click:".wccom-privacy-banner__content-buttons button.is-secondary"},{waitForThenClick:"input[type=checkbox][checked]:not([disabled])",all:!0},{click:"div.wccom-modal__footer > button"}]},{name:"WP Cookie Notice for GDPR",vendorUrl:"https://wordpress.org/plugins/gdpr-cookie-consent/",prehideSelectors:["#gdpr-cookie-consent-bar"],detectCmp:[{exists:"#gdpr-cookie-consent-bar"}],detectPopup:[{visible:"#gdpr-cookie-consent-bar"}],optIn:[{waitForThenClick:"#gdpr-cookie-consent-bar #cookie_action_accept"}],optOut:[{waitForThenClick:"#gdpr-cookie-consent-bar #cookie_action_reject"}],test:[{eval:"EVAL_WP_COOKIE_NOTICE_0"}]},{name:"wpcc",cosmetic:!0,prehideSelectors:[".wpcc-container"],detectCmp:[{exists:".wpcc-container"}],detectPopup:[{exists:".wpcc-container .wpcc-message"}],optIn:[{click:".wpcc-compliance .wpcc-btn"}],optOut:[{hide:".wpcc-container"}]},{name:"xe.com",vendorUrl:"https://www.xe.com/",runContext:{urlPattern:"^https://www\\.xe\\.com/"},prehideSelectors:["[class*=ConsentBanner]"],detectCmp:[{exists:"[class*=ConsentBanner]"}],detectPopup:[{visible:"[class*=ConsentBanner]"}],optIn:[{waitForThenClick:"[class*=ConsentBanner] .egnScw"}],optOut:[{wait:1e3},{waitForThenClick:"[class*=ConsentBanner] .frDWEu"},{waitForThenClick:"[class*=ConsentBanner] .hXIpFU"}],test:[{eval:"EVAL_XE_TEST"}]},{name:"xhamster-eu",prehideSelectors:[".cookies-modal"],detectCmp:[{exists:".cookies-modal"}],detectPopup:[{exists:".cookies-modal"}],optIn:[{click:"button.cmd-button-accept-all"}],optOut:[{click:"button.cmd-button-reject-all"}]},{name:"xhamster-us",runContext:{urlPattern:"^https://(www\\.)?xhamster\\d?\\.com"},cosmetic:!0,prehideSelectors:[".cookie-announce"],detectCmp:[{exists:".cookie-announce"}],detectPopup:[{visible:".cookie-announce .announce-text"}],optIn:[{click:".cookie-announce button.xh-button"}],optOut:[{hide:".cookie-announce"}]},{name:"xing.com",detectCmp:[{exists:"div[class^=cookie-consent-CookieConsent]"}],detectPopup:[{exists:"div[class^=cookie-consent-CookieConsent]"}],optIn:[{click:"#consent-accept-button"}],optOut:[{click:"#consent-settings-button"},{click:".consent-banner-button-accept-overlay"}],test:[{eval:"EVAL_XING_0"}]},{name:"xnxx-com",cosmetic:!0,prehideSelectors:["#cookies-use-alert"],detectCmp:[{exists:"#cookies-use-alert"}],detectPopup:[{visible:"#cookies-use-alert"}],optIn:[{click:"#cookies-use-alert .close"}],optOut:[{hide:"#cookies-use-alert"}]},{name:"xvideos",vendorUrl:"https://xvideos.com",runContext:{urlPattern:"^https://[^/]*xvideos\\.com/"},prehideSelectors:[],detectCmp:[{exists:".disclaimer-opened #disclaimer-cookies"}],detectPopup:[{visible:".disclaimer-opened #disclaimer-cookies"}],optIn:[{waitForThenClick:"#disclaimer-accept_cookies"}],optOut:[{waitForThenClick:"#disclaimer-reject_cookies"}]},{name:"Yahoo",runContext:{urlPattern:"^https://consent\\.yahoo\\.com/v2/"},prehideSelectors:["#reject-all"],detectCmp:[{exists:"#consent-page"}],detectPopup:[{visible:"#consent-page"}],optIn:[{waitForThenClick:"#consent-page button[value=agree]"}],optOut:[{waitForThenClick:"#consent-page button[value=reject]"}]},{name:"youporn.com",cosmetic:!0,prehideSelectors:[".euCookieModal, #js_euCookieModal"],detectCmp:[{exists:".euCookieModal"}],detectPopup:[{exists:".euCookieModal, #js_euCookieModal"}],optIn:[{click:'button[name="user_acceptCookie"]'}],optOut:[{hide:".euCookieModal"}]},{name:"youtube-desktop",prehideSelectors:["tp-yt-iron-overlay-backdrop.opened","ytd-consent-bump-v2-lightbox"],detectCmp:[{exists:"ytd-consent-bump-v2-lightbox tp-yt-paper-dialog"},{exists:'ytd-consent-bump-v2-lightbox tp-yt-paper-dialog a[href^="https://consent.youtube.com/"]'}],detectPopup:[{visible:"ytd-consent-bump-v2-lightbox tp-yt-paper-dialog"}],optIn:[{waitForThenClick:"ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:last-child #button,ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:last-child button"},{wait:500}],optOut:[{waitForThenClick:"ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:first-child #button,ytd-consent-bump-v2-lightbox .eom-buttons .eom-button-row:first-child ytd-button-renderer:first-child button"},{wait:500}],test:[{wait:500},{eval:"EVAL_YOUTUBE_DESKTOP_0"}]},{name:"youtube-mobile",prehideSelectors:[".consent-bump-v2-lightbox"],detectCmp:[{exists:"ytm-consent-bump-v2-renderer"}],detectPopup:[{visible:"ytm-consent-bump-v2-renderer"}],optIn:[{waitForThenClick:"ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons c3-material-button:first-child button, ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons ytm-button-renderer:first-child button"},{wait:500}],optOut:[{waitForThenClick:"ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons c3-material-button:nth-child(2) button, ytm-consent-bump-v2-renderer .privacy-terms + .one-col-dialog-buttons ytm-button-renderer:nth-child(2) button"},{wait:500}],test:[{wait:500},{eval:"EVAL_YOUTUBE_MOBILE_0"}]},{name:"zdf",prehideSelectors:["#zdf-cmp-banner-sdk"],detectCmp:[{exists:"#zdf-cmp-banner-sdk"}],detectPopup:[{visible:"#zdf-cmp-main.zdf-cmp-show"}],optIn:[{waitForThenClick:"#zdf-cmp-main #zdf-cmp-accept-btn"}],optOut:[{waitForThenClick:"#zdf-cmp-main #zdf-cmp-deny-btn"}],test:[]},{name:"zentralruf-de",runContext:{urlPattern:"^https://(www\\.)?zentralruf\\.de"},prehideSelectors:["#cookie_modal_wrapper"],detectCmp:[{exists:"#cookie_modal_wrapper"}],detectPopup:[{visible:"#cookie_modal_wrapper"}],optIn:[{waitForThenClick:"#cookie_modal_wrapper #cookie_modal_button_consent_all"}],optOut:[{waitForThenClick:"#cookie_modal_wrapper #cookie_modal_button_choose"}]}],kn={"didomi.io":{detectors:[{presentMatcher:{target:{selector:"#didomi-host, #didomi-notice"},type:"css"},showingMatcher:{target:{selector:"body.didomi-popup-open, .didomi-notice-banner"},type:"css"}}],methods:[{action:{target:{selector:".didomi-popup-notice-buttons .didomi-button:not(.didomi-button-highlight), .didomi-notice-banner .didomi-learn-more-button"},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{retries:50,target:{selector:"#didomi-purpose-cookies"},type:"waitcss",waitTime:50},{consents:[{description:"Share (everything) with others",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-share_whith_others]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-share_whith_others]:last-child"},type:"click"},type:"X"},{description:"Information storage and access",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-cookies]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-cookies]:last-child"},type:"click"},type:"D"},{description:"Content selection, offers and marketing",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-CL-T1Rgm7]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-CL-T1Rgm7]:last-child"},type:"click"},type:"E"},{description:"Analytics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-analytics]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-analytics]:last-child"},type:"click"},type:"B"},{description:"Analytics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-M9NRHJe3G]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-M9NRHJe3G]:last-child"},type:"click"},type:"B"},{description:"Ad and content selection",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-advertising_personalization]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-advertising_personalization]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection",falseAction:{parent:{childFilter:{target:{selector:"#didomi-purpose-pub-ciblee"}},selector:".didomi-consent-popup-data-processing, .didomi-components-accordion-label-container"},target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-pub-ciblee]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-pub-ciblee]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - basics",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-q4zlJqdcD]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-q4zlJqdcD]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - partners and subsidiaries",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-partenaire-cAsDe8jC]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-partenaire-cAsDe8jC]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-p4em9a8m]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-p4em9a8m]:last-child"},type:"click"},type:"F"},{description:"Ad and content selection - others",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-autres-pub]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-autres-pub]:last-child"},type:"click"},type:"F"},{description:"Social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-reseauxsociaux]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-reseauxsociaux]:last-child"},type:"click"},type:"A"},{description:"Social networks",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-social_media]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-social_media]:last-child"},type:"click"},type:"A"},{description:"Content selection",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-content_personalization]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-content_personalization]:last-child"},type:"click"},type:"E"},{description:"Ad delivery",falseAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-ad_delivery]:first-child"},type:"click"},trueAction:{target:{selector:".didomi-components-radio__option[aria-describedby=didomi-purpose-ad_delivery]:last-child"},type:"click"},type:"F"}],type:"consent"},{action:{consents:[{matcher:{childFilter:{target:{selector:":not(.didomi-components-radio__option--selected)"}},type:"css"},trueAction:{target:{selector:":nth-child(2)"},type:"click"},falseAction:{target:{selector:":first-child"},type:"click"},type:"X"}],type:"consent"},target:{selector:".didomi-components-radio"},type:"foreach"}],type:"list"},name:"DO_CONSENT"},{action:{parent:{selector:".didomi-consent-popup-footer .didomi-consent-popup-actions"},target:{selector:".didomi-components-button:first-child"},type:"click"},name:"SAVE_CONSENT"}]},oil:{detectors:[{presentMatcher:{target:{selector:".as-oil-content-overlay"},type:"css"},showingMatcher:{target:{selector:".as-oil-content-overlay"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".as-js-advanced-settings"},type:"click"},{retries:"10",target:{selector:".as-oil-cpc__purpose-container"},type:"waitcss",waitTime:"250"}],type:"list"},name:"OPEN_OPTIONS"},{action:{actions:[{consents:[{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Information storage and access","Opbevaring af og adgang til oplysninger på din enhed"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Information storage and access","Opbevaring af og adgang til oplysninger på din enhed"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"D"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personlige annoncer","Personalisation"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personlige annoncer","Personalisation"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"E"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Annoncevalg, levering og rapportering","Ad selection, delivery, reporting"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Annoncevalg, levering og rapportering","Ad selection, delivery, reporting"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"F"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personalisering af indhold","Content selection, delivery, reporting"]},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:["Personalisering af indhold","Content selection, delivery, reporting"]},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"E"},{matcher:{parent:{childFilter:{target:{selector:".as-oil-cpc__purpose-header",textFilter:["Måling","Measurement"]}},selector:".as-oil-cpc__purpose-container"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{childFilter:{target:{selector:".as-oil-cpc__purpose-header",textFilter:["Måling","Measurement"]}},selector:".as-oil-cpc__purpose-container"},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"B"},{matcher:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:"Google"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".as-oil-cpc__purpose-container",textFilter:"Google"},target:{selector:".as-oil-cpc__switch"},type:"click"},type:"F"}],type:"consent"}],type:"list"},name:"DO_CONSENT"},{action:{target:{selector:".as-oil__btn-optin"},type:"click"},name:"SAVE_CONSENT"},{action:{target:{selector:"div.as-oil"},type:"hide"},name:"HIDE_CMP"}]},optanon:{detectors:[{presentMatcher:{target:{selector:"#optanon-menu, .optanon-alert-box-wrapper"},type:"css"},showingMatcher:{target:{displayFilter:!0,selector:".optanon-alert-box-wrapper"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".optanon-alert-box-wrapper .optanon-toggle-display, a[onclick*='OneTrust.ToggleInfoDisplay()'], a[onclick*='Optanon.ToggleInfoDisplay()']"},type:"click"}],type:"list"},name:"OPEN_OPTIONS"},{action:{actions:[{target:{selector:".preference-menu-item #Your-privacy"},type:"click"},{target:{selector:"#optanon-vendor-consent-text"},type:"click"},{action:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},target:{selector:"#optanon-vendor-consent-list .vendor-item"},type:"foreach"},{target:{selector:".vendor-consent-back-link"},type:"click"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-performance"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-performance"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-functional"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-functional"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-advertising"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-advertising"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-social"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-social"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Social Media Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Social Media Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalisation"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalisation"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Site monitoring cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Site monitoring cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Third party privacy-enhanced content"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Third party privacy-enhanced content"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Performance & Advertising Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Performance & Advertising Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Information storage and access"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Information storage and access"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"D"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad selection, delivery, reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad selection, delivery, reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content selection, delivery, reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content selection, delivery, reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Measurement"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Measurement"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Recommended Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Recommended Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Unclassified Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Unclassified Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"X"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Analytical Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Analytical Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"B"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Marketing Cookies"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Marketing Cookies"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalization"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Personalization"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad Selection, Delivery & Reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Ad Selection, Delivery & Reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},type:"ifcss"},{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content Selection, Delivery & Reporting"},trueAction:{actions:[{parent:{selector:"#optanon-menu, .optanon-menu"},target:{selector:".menu-item-necessary",textFilter:"Content Selection, Delivery & Reporting"},type:"click"},{consents:[{matcher:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status input"},type:"checkbox"},toggleAction:{parent:{selector:"#optanon-popup-body-right"},target:{selector:".optanon-status label"},type:"click"},type:"E"}],type:"consent"}],type:"list"},type:"ifcss"}],type:"list"},name:"DO_CONSENT"},{action:{parent:{selector:".optanon-save-settings-button"},target:{selector:".optanon-white-button-middle"},type:"click"},name:"SAVE_CONSENT"},{action:{actions:[{target:{selector:"#optanon-popup-wrapper"},type:"hide"},{target:{selector:"#optanon-popup-bg"},type:"hide"},{target:{selector:".optanon-alert-box-wrapper"},type:"hide"}],type:"list"},name:"HIDE_CMP"}]},quantcast2:{detectors:[{presentMatcher:{target:{selector:"[data-tracking-opt-in-overlay]"},type:"css"},showingMatcher:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-learn-more]"},type:"css"}}],methods:[{action:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-learn-more]"},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{type:"wait",waitTime:500},{action:{actions:[{target:{selector:"div",textFilter:["Information storage and access"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"D"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Personalization"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"F"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Ad selection, delivery, reporting"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"F"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Content selection, delivery, reporting"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"E"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Measurement"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"B"}],type:"consent"},type:"ifcss"},{target:{selector:"div",textFilter:["Other Partners"]},trueAction:{consents:[{matcher:{target:{selector:"input"},type:"checkbox"},toggleAction:{target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},type:"ifcss"}],type:"list"},parent:{childFilter:{target:{selector:"input"}},selector:"[data-tracking-opt-in-overlay] > div > div"},target:{childFilter:{target:{selector:"input"}},selector:":scope > div"},type:"foreach"}],type:"list"},name:"DO_CONSENT"},{action:{target:{selector:"[data-tracking-opt-in-overlay] [data-tracking-opt-in-save]"},type:"click"},name:"SAVE_CONSENT"}]},springer:{detectors:[{presentMatcher:{parent:null,target:{selector:".cmp-app_gdpr"},type:"css"},showingMatcher:{parent:null,target:{displayFilter:!0,selector:".cmp-popup_popup"},type:"css"}}],methods:[{action:{actions:[{target:{selector:".cmp-intro_rejectAll"},type:"click"},{type:"wait",waitTime:250},{target:{selector:".cmp-purposes_purposeItem:not(.cmp-purposes_selectedPurpose)"},type:"click"}],type:"list"},name:"OPEN_OPTIONS"},{action:{consents:[{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Przechowywanie informacji na urządzeniu lub dostęp do nich",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Przechowywanie informacji na urządzeniu lub dostęp do nich",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"D"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór podstawowych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór podstawowych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"F"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"F"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"E"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Tworzenie profilu spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"E"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Wybór spersonalizowanych treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności reklam",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Pomiar wydajności treści",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"B"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Stosowanie badań rynkowych w celu generowania opinii odbiorców",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Stosowanie badań rynkowych w celu generowania opinii odbiorców",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"X"},{matcher:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Opracowywanie i ulepszanie produktów",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch .cmp-switch_isSelected"},type:"css"},toggleAction:{parent:{selector:".cmp-purposes_detailHeader",textFilter:"Opracowywanie i ulepszanie produktów",childFilter:{target:{selector:".cmp-switch_switch"}}},target:{selector:".cmp-switch_switch:not(.cmp-switch_isSelected)"},type:"click"},type:"X"}],type:"consent"},name:"DO_CONSENT"},{action:{target:{selector:".cmp-details_save"},type:"click"},name:"SAVE_CONSENT"}]},wordpressgdpr:{detectors:[{presentMatcher:{parent:null,target:{selector:".wpgdprc-consent-bar"},type:"css"},showingMatcher:{parent:null,target:{displayFilter:!0,selector:".wpgdprc-consent-bar"},type:"css"}}],methods:[{action:{parent:null,target:{selector:".wpgdprc-consent-bar .wpgdprc-consent-bar__settings",textFilter:null},type:"click"},name:"OPEN_OPTIONS"},{action:{actions:[{target:{selector:".wpgdprc-consent-modal .wpgdprc-button",textFilter:"Eyeota"},type:"click"},{consents:[{description:"Eyeota Cookies",matcher:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Eyeota"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Eyeota"},target:{selector:"label"},type:"click"},type:"X"}],type:"consent"},{target:{selector:".wpgdprc-consent-modal .wpgdprc-button",textFilter:"Advertising"},type:"click"},{consents:[{description:"Advertising Cookies",matcher:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Advertising"},target:{selector:"input"},type:"checkbox"},toggleAction:{parent:{selector:".wpgdprc-consent-modal__description",textFilter:"Advertising"},target:{selector:"label"},type:"click"},type:"F"}],type:"consent"}],type:"list"},name:"DO_CONSENT"},{action:{parent:null,target:{selector:".wpgdprc-button",textFilter:"Save my settings"},type:"click"},name:"SAVE_CONSENT"}]}},bn={autoconsent:fn,consentomatic:kn},yn=Object.freeze({__proto__:null,autoconsent:fn,consentomatic:kn,default:bn}); /*! Bundled license information: @ghostery/adblocker/dist/esm/codebooks/cosmetic-selector.js: @@ -442,4 +442,4 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. *) - */const yn=new class{constructor(e,t=null,o=null){if(this.id=c(),this.rules=[],this.foundCmp=null,this.state={cosmeticFiltersOn:!1,lifecycle:"loading",prehideOn:!1,findCmpAttempts:0,detectedCmps:[],detectedPopups:[],selfTest:null},a.sendContentMessage=e,this.sendContentMessage=e,this.rules=[],this.updateState({lifecycle:"loading"}),this.addDynamicRules(),t)this.initialize(t,o);else{o&&this.parseDeclarativeRules(o);e({type:"init",url:window.location.href}),this.updateState({lifecycle:"waitingForInitResponse"})}this.domActions=new _(this)}initialize(e,t){const o=b(e);if(o.logs.lifecycle&&console.log("autoconsent init",window.location.href),this.config=o,o.enabled){if(t&&this.parseDeclarativeRules(t),e.enableFilterList){try{An&&An.length>0&&(this.filtersEngine=un.deserialize(An))}catch(e){console.error("Error parsing filter list",e)}"loading"===document.readyState?window.addEventListener("DOMContentLoaded",(()=>{this.applyCosmeticFilters()})):this.applyCosmeticFilters()}if(this.rules=function(e,t){return e.filter((e=>(!t.disabledCmps||!t.disabledCmps.includes(e.name))&&(t.enableCosmeticRules||!e.isCosmetic)))}(this.rules,o),e.enablePrehide)if(document.documentElement)this.prehideElements();else{const e=()=>{window.removeEventListener("DOMContentLoaded",e),this.prehideElements()};window.addEventListener("DOMContentLoaded",e)}if("loading"===document.readyState){const e=()=>{window.removeEventListener("DOMContentLoaded",e),this.start()};window.addEventListener("DOMContentLoaded",e)}else this.start();this.updateState({lifecycle:"initialized"})}else o.logs.lifecycle&&console.log("autoconsent is disabled")}addDynamicRules(){v.forEach((e=>{this.rules.push(new e(this))}))}parseDeclarativeRules(e){e.consentomatic&&Object.keys(e.consentomatic).forEach((t=>{this.addConsentomaticCMP(t,e.consentomatic[t])})),e.autoconsent&&e.autoconsent.forEach((e=>{this.addDeclarativeCMP(e)}))}addDeclarativeCMP(e){this.rules.push(new u(e,this))}addConsentomaticCMP(e,t){this.rules.push(new h(`com_${e}`,t))}start(){window.requestIdleCallback?window.requestIdleCallback((()=>this._start()),{timeout:500}):this._start()}async _start(){const e=this.config.logs;e.lifecycle&&console.log(`Detecting CMPs on ${window.location.href}`),this.updateState({lifecycle:"started"});const t=await this.findCmp(this.config.detectRetries);if(this.updateState({detectedCmps:t.map((e=>e.name))}),0===t.length)return e.lifecycle&&console.log("no CMP found",location.href),this.config.enablePrehide&&this.undoPrehide(),this.filterListFallback();this.updateState({lifecycle:"cmpDetected"});const o=[],i=[];for(const e of t)e.isCosmetic?i.push(e):o.push(e);let n=!1,s=await this.detectPopups(o,(async e=>{n=await this.handlePopup(e)}));if(0===s.length&&(s=await this.detectPopups(i,(async e=>{n=await this.handlePopup(e)}))),0===s.length)return e.lifecycle&&console.log("no popup found"),this.config.enablePrehide&&this.undoPrehide(),!1;if(s.length>1){const t={msg:"Found multiple CMPs, check the detection rules.",cmps:s.map((e=>e.name))};e.errors&&console.warn(t.msg,t.cmps),this.sendContentMessage({type:"autoconsentError",details:t})}return n}async findCmp(e){const t=this.config.logs;this.updateState({findCmpAttempts:this.state.findCmpAttempts+1});const o=[];for(const e of this.rules)try{if(!e.checkRunContext())continue;await e.detectCmp()&&(t.lifecycle&&console.log(`Found CMP: ${e.name} ${window.location.href}`),this.sendContentMessage({type:"cmpDetected",url:location.href,cmp:e.name}),o.push(e))}catch(o){t.errors&&console.warn(`error detecting ${e.name}`,o)}return 0===o.length&&e>0?(await this.domActions.wait(500),this.findCmp(e-1)):o}async detectPopup(e){if(await this.waitForPopup(e).catch((t=>(this.config.logs.errors&&console.warn(`error waiting for a popup for ${e.name}`,t),!1))))return this.updateState({detectedPopups:this.state.detectedPopups.concat([e.name])}),this.sendContentMessage({type:"popupFound",cmp:e.name,url:location.href}),e;throw new Error("Popup is not shown")}async detectPopups(e,t){const o=e.map((e=>this.detectPopup(e)));await Promise.any(o).then((e=>{t(e)})).catch((()=>null));const i=await Promise.allSettled(o),n=[];for(const e of i)"fulfilled"===e.status&&n.push(e.value);return n}async handlePopup(e){return this.updateState({lifecycle:"openPopupDetected"}),this.config.enablePrehide&&!this.state.prehideOn&&this.prehideElements(),this.state.cosmeticFiltersOn&&this.undoCosmetics(),this.foundCmp=e,"optOut"===this.config.autoAction?await this.doOptOut():"optIn"===this.config.autoAction?await this.doOptIn():(this.config.logs.lifecycle&&console.log("waiting for opt-out signal...",location.href),!0)}async doOptOut(){const e=this.config.logs;let t;return this.updateState({lifecycle:"runningOptOut"}),this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: opt out on ${window.location.href}`),t=await this.foundCmp.optOut(),e.lifecycle&&console.log(`${this.foundCmp.name}: opt out result ${t}`)):(e.errors&&console.log("no CMP to opt out"),t=!1),this.config.enablePrehide&&this.undoPrehide(),this.sendContentMessage({type:"optOutResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,scheduleSelfTest:this.foundCmp&&this.foundCmp.hasSelfTest,url:location.href}),t&&!this.foundCmp.isIntermediate?(this.sendContentMessage({type:"autoconsentDone",cmp:this.foundCmp.name,isCosmetic:this.foundCmp.isCosmetic,url:location.href}),this.updateState({lifecycle:"done"})):this.updateState({lifecycle:t?"optOutSucceeded":"optOutFailed"}),t}async doOptIn(){const e=this.config.logs;let t;return this.updateState({lifecycle:"runningOptIn"}),this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: opt in on ${window.location.href}`),t=await this.foundCmp.optIn(),e.lifecycle&&console.log(`${this.foundCmp.name}: opt in result ${t}`)):(e.errors&&console.log("no CMP to opt in"),t=!1),this.config.enablePrehide&&this.undoPrehide(),this.sendContentMessage({type:"optInResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,scheduleSelfTest:!1,url:location.href}),t&&!this.foundCmp.isIntermediate?(this.sendContentMessage({type:"autoconsentDone",cmp:this.foundCmp.name,isCosmetic:this.foundCmp.isCosmetic,url:location.href}),this.updateState({lifecycle:"done"})):this.updateState({lifecycle:t?"optInSucceeded":"optInFailed"}),t}async doSelfTest(){const e=this.config.logs;let t;return this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: self-test on ${window.location.href}`),t=await this.foundCmp.test()):(e.errors&&console.log("no CMP to self test"),t=!1),this.sendContentMessage({type:"selfTestResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,url:location.href}),this.updateState({selfTest:t}),t}async waitForPopup(e,t=5,o=500){const i=this.config.logs;i.lifecycle&&console.log("checking if popup is open...",e.name);const n=await e.detectPopup().catch((t=>(i.errors&&console.warn(`error detecting popup for ${e.name}`,t),!1)));return!n&&t>0?(await this.domActions.wait(o),this.waitForPopup(e,t-1,o)):(i.lifecycle&&console.log(e.name,"popup is "+(n?"open":"not open")),n)}prehideElements(){const e=this.config.logs,t=this.rules.filter((e=>e.prehideSelectors&&e.checkRunContext())).reduce(((e,t)=>[...e,...t.prehideSelectors]),["#didomi-popup,.didomi-popup-container,.didomi-popup-notice,.didomi-consent-popup-preferences,#didomi-notice,.didomi-popup-backdrop,.didomi-screen-medium"]);return this.updateState({prehideOn:!0}),setTimeout((()=>{this.config.enablePrehide&&this.state.prehideOn&&!["runningOptOut","runningOptIn"].includes(this.state.lifecycle)&&(e.lifecycle&&console.log("Process is taking too long, unhiding elements"),this.undoPrehide())}),this.config.prehideTimeout||2e3),this.domActions.prehide(t.join(","))}undoPrehide(){return this.updateState({prehideOn:!1}),this.domActions.undoPrehide()}async applyCosmeticFilters(e){if(!this.filtersEngine)return!1;const t=this.config?.logs;e||(e=mn(this.filtersEngine)),this.updateState({cosmeticFiltersOn:!0});try{this.cosmeticStyleSheet=await this.domActions.createOrUpdateStyleSheet(e,this.cosmeticStyleSheet),t?.lifecycle&&console.log("[cosmetics]",this.cosmeticStyleSheet,location.href),document.adoptedStyleSheets.push(this.cosmeticStyleSheet)}catch(e){return this.config.logs&&console.error("Error applying cosmetic filters",e),!1}return!0}undoCosmetics(){this.updateState({cosmeticFiltersOn:!1}),this.config.logs.lifecycle&&console.log("[undocosmetics]",this.cosmeticStyleSheet,location.href),this.domActions.removeStyleSheet(this.cosmeticStyleSheet)}filterListFallback(){if(!this.filtersEngine)return this.updateState({lifecycle:"nothingDetected"}),!1;const e=mn(this.filtersEngine),t=this.domActions.elementVisible(function(e){if(e)return e.replace(/\s*{[^\\}]*}\s*/g,",").replace(/,$/,"");return""}(e),"any"),o=this.config?.logs;return t?(this.applyCosmeticFilters(e),o?.lifecycle&&console.log("Keeping cosmetic filters",location.href),this.updateState({lifecycle:"cosmeticFiltersDetected"}),this.sendContentMessage({type:"cmpDetected",url:location.href,cmp:"filterList"}),this.sendContentMessage({type:"popupFound",cmp:"filterList",url:location.href}),this.sendContentMessage({type:"optOutResult",cmp:"filterList",result:!0,scheduleSelfTest:!1,url:location.href}),this.updateState({lifecycle:"done"}),this.sendContentMessage({type:"autoconsentDone",cmp:"filterList",isCosmetic:!0,url:location.href}),!0):(o?.lifecycle&&console.log("Cosmetic filters didn't work, removing them",location.href),this.undoCosmetics(),this.updateState({lifecycle:"nothingDetected"}),!1)}updateState(e){Object.assign(this.state,e),this.sendContentMessage({type:"report",instanceId:this.id,url:window.location.href,mainFrame:window.top===window.self,state:this.state})}async receiveMessageCallback(e){const t=this.config?.logs;switch(t?.messages&&console.log("received from background",e,window.location.href),e.type){case"initResp":this.initialize(e.config,e.rules);break;case"optIn":await this.doOptIn();break;case"optOut":await this.doOptOut();break;case"selfTest":await this.doSelfTest();break;case"evalResp":!function(e,t){const o=a.pending.get(e);o?(a.pending.delete(e),o.timer&&window.clearTimeout(o.timer),o.resolve(t)):console.warn("no eval #",e)}(e.id,e.result)}}}((e=>{window.webkit.messageHandlers[e.type]&&window.webkit.messageHandlers[e.type].postMessage(e).then((e=>{yn.receiveMessageCallback(e)}))}),null,bn);window.autoconsentMessageCallback=e=>{yn.receiveMessageCallback(e)}}(); + */const wn=new class{constructor(e,t=null,o=null){if(this.id=c(),this.rules=[],this.foundCmp=null,this.state={cosmeticFiltersOn:!1,filterListReported:!1,lifecycle:"loading",prehideOn:!1,findCmpAttempts:0,detectedCmps:[],detectedPopups:[],selfTest:null},a.sendContentMessage=e,this.sendContentMessage=e,this.rules=[],this.updateState({lifecycle:"loading"}),this.addDynamicRules(),t)this.initialize(t,o);else{o&&this.parseDeclarativeRules(o);e({type:"init",url:window.location.href}),this.updateState({lifecycle:"waitingForInitResponse"})}this.domActions=new _(this)}initialize(e,t){const o=b(e);if(o.logs.lifecycle&&console.log("autoconsent init",window.location.href),this.config=o,o.enabled){if(t&&this.parseDeclarativeRules(t),e.enableFilterList){try{gn&&gn.length>0&&(this.filtersEngine=un.deserialize(gn))}catch(e){console.error("Error parsing filter list",e)}"loading"===document.readyState?window.addEventListener("DOMContentLoaded",(()=>{this.applyCosmeticFilters()})):this.applyCosmeticFilters()}if(this.rules=function(e,t){return e.filter((e=>(!t.disabledCmps||!t.disabledCmps.includes(e.name))&&(t.enableCosmeticRules||!e.isCosmetic)))}(this.rules,o),e.enablePrehide)if(document.documentElement)this.prehideElements();else{const e=()=>{window.removeEventListener("DOMContentLoaded",e),this.prehideElements()};window.addEventListener("DOMContentLoaded",e)}if("loading"===document.readyState){const e=()=>{window.removeEventListener("DOMContentLoaded",e),this.start()};window.addEventListener("DOMContentLoaded",e)}else this.start();this.updateState({lifecycle:"initialized"})}else o.logs.lifecycle&&console.log("autoconsent is disabled")}addDynamicRules(){v.forEach((e=>{this.rules.push(new e(this))}))}parseDeclarativeRules(e){e.consentomatic&&Object.keys(e.consentomatic).forEach((t=>{this.addConsentomaticCMP(t,e.consentomatic[t])})),e.autoconsent&&e.autoconsent.forEach((e=>{this.addDeclarativeCMP(e)}))}addDeclarativeCMP(e){this.rules.push(new u(e,this))}addConsentomaticCMP(e,t){this.rules.push(new h(`com_${e}`,t))}start(){!function(e,t=500){globalThis.requestIdleCallback?requestIdleCallback(e,{timeout:t}):setTimeout(e,0)}((()=>this._start()))}async _start(){const e=this.config.logs;e.lifecycle&&console.log(`Detecting CMPs on ${window.location.href}`),this.updateState({lifecycle:"started"});const t=await this.findCmp(this.config.detectRetries);if(this.updateState({detectedCmps:t.map((e=>e.name))}),0===t.length)return e.lifecycle&&console.log("no CMP found",location.href),this.config.enablePrehide&&this.undoPrehide(),this.filterListFallback();this.updateState({lifecycle:"cmpDetected"});const o=[],i=[];for(const e of t)e.isCosmetic?i.push(e):o.push(e);let n=!1,s=await this.detectPopups(o,(async e=>{n=await this.handlePopup(e)}));if(0===s.length&&(s=await this.detectPopups(i,(async e=>{n=await this.handlePopup(e)}))),0===s.length)return e.lifecycle&&console.log("no popup found"),this.config.enablePrehide&&this.undoPrehide(),!1;if(s.length>1){const t={msg:"Found multiple CMPs, check the detection rules.",cmps:s.map((e=>e.name))};e.errors&&console.warn(t.msg,t.cmps),this.sendContentMessage({type:"autoconsentError",details:t})}return n}async findCmp(e){const t=this.config.logs;this.updateState({findCmpAttempts:this.state.findCmpAttempts+1});const o=[];for(const e of this.rules)try{if(!e.checkRunContext())continue;await e.detectCmp()&&(t.lifecycle&&console.log(`Found CMP: ${e.name} ${window.location.href}`),this.sendContentMessage({type:"cmpDetected",url:location.href,cmp:e.name}),o.push(e))}catch(o){t.errors&&console.warn(`error detecting ${e.name}`,o)}return 0===o.length&&e>0?(await this.domActions.wait(500),this.findCmp(e-1)):o}async detectPopup(e){if(await this.waitForPopup(e).catch((t=>(this.config.logs.errors&&console.warn(`error waiting for a popup for ${e.name}`,t),!1))))return this.updateState({detectedPopups:this.state.detectedPopups.concat([e.name])}),this.sendContentMessage({type:"popupFound",cmp:e.name,url:location.href}),e;throw new Error("Popup is not shown")}async detectPopups(e,t){const o=e.map((e=>this.detectPopup(e)));await Promise.any(o).then((e=>{t(e)})).catch((()=>null));const i=await Promise.allSettled(o),n=[];for(const e of i)"fulfilled"===e.status&&n.push(e.value);return n}async handlePopup(e){return this.updateState({lifecycle:"openPopupDetected"}),this.config.enablePrehide&&!this.state.prehideOn&&this.prehideElements(),this.state.cosmeticFiltersOn&&this.undoCosmetics(),this.foundCmp=e,"optOut"===this.config.autoAction?await this.doOptOut():"optIn"===this.config.autoAction?await this.doOptIn():(this.config.logs.lifecycle&&console.log("waiting for opt-out signal...",location.href),!0)}async doOptOut(){const e=this.config.logs;let t;return this.updateState({lifecycle:"runningOptOut"}),this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: opt out on ${window.location.href}`),t=await this.foundCmp.optOut(),e.lifecycle&&console.log(`${this.foundCmp.name}: opt out result ${t}`)):(e.errors&&console.log("no CMP to opt out"),t=!1),this.config.enablePrehide&&this.undoPrehide(),this.sendContentMessage({type:"optOutResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,scheduleSelfTest:this.foundCmp&&this.foundCmp.hasSelfTest,url:location.href}),t&&!this.foundCmp.isIntermediate?(this.sendContentMessage({type:"autoconsentDone",cmp:this.foundCmp.name,isCosmetic:this.foundCmp.isCosmetic,url:location.href}),this.updateState({lifecycle:"done"})):this.updateState({lifecycle:t?"optOutSucceeded":"optOutFailed"}),t}async doOptIn(){const e=this.config.logs;let t;return this.updateState({lifecycle:"runningOptIn"}),this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: opt in on ${window.location.href}`),t=await this.foundCmp.optIn(),e.lifecycle&&console.log(`${this.foundCmp.name}: opt in result ${t}`)):(e.errors&&console.log("no CMP to opt in"),t=!1),this.config.enablePrehide&&this.undoPrehide(),this.sendContentMessage({type:"optInResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,scheduleSelfTest:!1,url:location.href}),t&&!this.foundCmp.isIntermediate?(this.sendContentMessage({type:"autoconsentDone",cmp:this.foundCmp.name,isCosmetic:this.foundCmp.isCosmetic,url:location.href}),this.updateState({lifecycle:"done"})):this.updateState({lifecycle:t?"optInSucceeded":"optInFailed"}),t}async doSelfTest(){const e=this.config.logs;let t;return this.foundCmp?(e.lifecycle&&console.log(`CMP ${this.foundCmp.name}: self-test on ${window.location.href}`),t=await this.foundCmp.test()):(e.errors&&console.log("no CMP to self test"),t=!1),this.sendContentMessage({type:"selfTestResult",cmp:this.foundCmp?this.foundCmp.name:"none",result:t,url:location.href}),this.updateState({selfTest:t}),t}async waitForPopup(e,t=5,o=500){const i=this.config.logs;i.lifecycle&&console.log("checking if popup is open...",e.name);const n=await e.detectPopup().catch((t=>(i.errors&&console.warn(`error detecting popup for ${e.name}`,t),!1)));return!n&&t>0?(await this.domActions.wait(o),this.waitForPopup(e,t-1,o)):(i.lifecycle&&console.log(e.name,"popup is "+(n?"open":"not open")),n)}prehideElements(){const e=this.config.logs,t=this.rules.filter((e=>e.prehideSelectors&&e.checkRunContext())).reduce(((e,t)=>[...e,...t.prehideSelectors]),["#didomi-popup,.didomi-popup-container,.didomi-popup-notice,.didomi-consent-popup-preferences,#didomi-notice,.didomi-popup-backdrop,.didomi-screen-medium"]);return this.updateState({prehideOn:!0}),setTimeout((()=>{this.config.enablePrehide&&this.state.prehideOn&&!["runningOptOut","runningOptIn"].includes(this.state.lifecycle)&&(e.lifecycle&&console.log("Process is taking too long, unhiding elements"),this.undoPrehide())}),this.config.prehideTimeout||2e3),this.domActions.prehide(t.join(","))}undoPrehide(){return this.updateState({prehideOn:!1}),this.domActions.undoPrehide()}async applyCosmeticFilters(e){if(!this.filtersEngine)return!1;const t=this.config?.logs;e||(e=mn(this.filtersEngine)),setTimeout((()=>{if(this.state.cosmeticFiltersOn&&!this.state.filterListReported){this.domActions.elementVisible(An(e),"any")?(t?.lifecycle&&console.log("Prehide cosmetic filters matched",location.href),this.reportFilterlist()):t?.lifecycle&&console.log("Prehide cosmetic filters didn't match",location.href)}}),1e3),this.updateState({cosmeticFiltersOn:!0});try{this.cosmeticStyleSheet=await this.domActions.createOrUpdateStyleSheet(e,this.cosmeticStyleSheet),t?.lifecycle&&console.log("[cosmetics]",this.cosmeticStyleSheet,location.href),document.adoptedStyleSheets.push(this.cosmeticStyleSheet)}catch(e){return this.config.logs&&console.error("Error applying cosmetic filters",e),!1}return!0}undoCosmetics(){this.updateState({cosmeticFiltersOn:!1}),this.config.logs.lifecycle&&console.log("[undocosmetics]",this.cosmeticStyleSheet,location.href),this.domActions.removeStyleSheet(this.cosmeticStyleSheet)}reportFilterlist(){this.sendContentMessage({type:"cmpDetected",url:location.href,cmp:"filterList"}),this.sendContentMessage({type:"popupFound",cmp:"filterList",url:location.href}),this.updateState({filterListReported:!0})}filterListFallback(){if(!this.filtersEngine)return this.updateState({lifecycle:"nothingDetected"}),!1;const e=mn(this.filtersEngine),t=this.domActions.elementVisible(An(e),"any"),o=this.config?.logs;return t?(this.applyCosmeticFilters(e),o?.lifecycle&&console.log("Keeping cosmetic filters",location.href),this.updateState({lifecycle:"cosmeticFiltersDetected"}),this.state.filterListReported||this.reportFilterlist(),this.sendContentMessage({type:"optOutResult",cmp:"filterList",result:!0,scheduleSelfTest:!1,url:location.href}),this.updateState({lifecycle:"done"}),this.sendContentMessage({type:"autoconsentDone",cmp:"filterList",isCosmetic:!0,url:location.href}),!0):(o?.lifecycle&&console.log("Cosmetic filters didn't work, removing them",location.href),this.undoCosmetics(),this.updateState({lifecycle:"nothingDetected"}),!1)}updateState(e){Object.assign(this.state,e),this.sendContentMessage({type:"report",instanceId:this.id,url:window.location.href,mainFrame:window.top===window.self,state:this.state})}async receiveMessageCallback(e){const t=this.config?.logs;switch(t?.messages&&console.log("received from background",e,window.location.href),e.type){case"initResp":this.initialize(e.config,e.rules);break;case"optIn":await this.doOptIn();break;case"optOut":await this.doOptOut();break;case"selfTest":await this.doSelfTest();break;case"evalResp":!function(e,t){const o=a.pending.get(e);o?(a.pending.delete(e),o.timer&&window.clearTimeout(o.timer),o.resolve(t)):console.warn("no eval #",e)}(e.id,e.result)}}}((e=>{window.webkit.messageHandlers[e.type]&&window.webkit.messageHandlers[e.type].postMessage(e).then((e=>{wn.receiveMessageCallback(e)}))}),null,yn);window.autoconsentMessageCallback=e=>{wn.receiveMessageCallback(e)}}(); diff --git a/package-lock.json b/package-lock.json index ebc52c9d11..661d039795 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "ios", "version": "1.0.0", "dependencies": { - "@duckduckgo/autoconsent": "^11.5.0" + "@duckduckgo/autoconsent": "^12.0.0" }, "devDependencies": { "@rollup/plugin-json": "^4.1.0", @@ -121,9 +121,9 @@ } }, "node_modules/@duckduckgo/autoconsent": { - "version": "11.5.0", - "resolved": "https://registry.npmjs.org/@duckduckgo/autoconsent/-/autoconsent-11.5.0.tgz", - "integrity": "sha512-mjMVTtJuHKPnX+poz5ZOPpUCPtoVh7nQeO7oXtsYEXZNSEIO/UIK9ozEWUI3Ta1utzQm4pN5wJwmsgmxNUXi/w==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@duckduckgo/autoconsent/-/autoconsent-12.0.0.tgz", + "integrity": "sha512-ObPv0pE1d8G1Nnj9NtTxvu04mNRnJ8o8cpU1G0YJk1kP2ykipGnlp9wrn9Tkn2fDy5zT8HQqDsOYWEyk3ES1kg==", "license": "MPL-2.0", "dependencies": { "@ghostery/adblocker": "^2.0.4", diff --git a/package.json b/package.json index c20bb4c42f..934d821d22 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,6 @@ "rollup-plugin-terser": "^7.0.2" }, "dependencies": { - "@duckduckgo/autoconsent": "^11.5.0" + "@duckduckgo/autoconsent": "^12.0.0" } } From 89258902326d117706f1aedf6786b2f49276cafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20=C5=9Apiewak?= Date: Mon, 25 Nov 2024 16:15:11 +0100 Subject: [PATCH 56/56] Send daily pixel with open tabs count (#3587) Task/Issue URL: https://app.asana.com/0/1206226850447395/1208014614013438/f Tech Design URL: CC: **Description**: Adds a daily pixel with number of total open tabs and number of new tabs when Tab switcher is opened. **Steps to test this PR**: 1. Modify `DailyPixel.hasBeenFiredToday` to always return `false`. 2. Open a bunch of tabs including a few new tabs. 3. Check Pixel is fired when opening tab switcher containing tabs count buckets that are in line with https://app.asana.com/0/1206226850447395/1208014614013438/f. **Definition of Done (Internal Only)**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- Core/PixelEvent.swift | 2 + DuckDuckGo.xcodeproj/project.pbxproj | 8 ++ DuckDuckGo/MainViewController.swift | 2 + DuckDuckGo/TabSwitcherOpenDailyPixel.swift | 68 +++++++++++++ .../TabSwitcherDailyPixelTests.swift | 99 +++++++++++++++++++ 5 files changed, 179 insertions(+) create mode 100644 DuckDuckGo/TabSwitcherOpenDailyPixel.swift create mode 100644 DuckDuckGoTests/TabSwitcherDailyPixelTests.swift diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index 85416a001c..28b764a87f 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -59,6 +59,7 @@ extension Pixel { case tabSwitcherClickCloseTab case tabSwitcherSwipeCloseTab case tabSwitchLongPressNewTab + case tabSwitcherOpenDaily case settingsDoNotSellShown case settingsDoNotSellOn @@ -910,6 +911,7 @@ extension Pixel.Event { case .tabSwitcherClickCloseTab: return "m_tab_manager_close_tab_click" case .tabSwitcherSwipeCloseTab: return "m_tab_manager_close_tab_swipe" case .tabSwitchLongPressNewTab: return "m_tab_manager_long_press_new_tab" + case .tabSwitcherOpenDaily: return "m_tab_manager_clicked_daily" case .settingsDoNotSellShown: return "ms_dns" case .settingsDoNotSellOn: return "ms_dns_on" diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 61fdf33951..ed5f648507 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -366,6 +366,8 @@ 6FEC0B882C999961006B4F6E /* FavoritesListInteractingAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FEC0B872C999961006B4F6E /* FavoritesListInteractingAdapter.swift */; }; 6FF915822B88E07A0042AC87 /* AdAttributionFetcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF915802B88E0750042AC87 /* AdAttributionFetcherTests.swift */; }; 6FF9AD452CE766F700C5A406 /* NewTabPageControllerPixelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF9AD442CE766F700C5A406 /* NewTabPageControllerPixelTests.swift */; }; + 6FF9AD3F2CE63DD800C5A406 /* TabSwitcherOpenDailyPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF9AD3E2CE63DC200C5A406 /* TabSwitcherOpenDailyPixel.swift */; }; + 6FF9AD412CE6610F00C5A406 /* TabSwitcherDailyPixelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FF9AD402CE6610600C5A406 /* TabSwitcherDailyPixelTests.swift */; }; 7B1604E82CB685B400A44EC6 /* Logger+TipKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1604E72CB685B400A44EC6 /* Logger+TipKit.swift */; }; 7B1604EC2CB68BDA00A44EC6 /* TipKitController+ConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1604EB2CB68BDA00A44EC6 /* TipKitController+ConvenienceInitializers.swift */; }; 7B1604EE2CB68D2600A44EC6 /* TipKitDebugOptionsUIActionHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1604ED2CB68D2600A44EC6 /* TipKitDebugOptionsUIActionHandling.swift */; }; @@ -1678,6 +1680,8 @@ 6FEC0B872C999961006B4F6E /* FavoritesListInteractingAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesListInteractingAdapter.swift; sourceTree = ""; }; 6FF915802B88E0750042AC87 /* AdAttributionFetcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdAttributionFetcherTests.swift; sourceTree = ""; }; 6FF9AD442CE766F700C5A406 /* NewTabPageControllerPixelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabPageControllerPixelTests.swift; sourceTree = ""; }; + 6FF9AD3E2CE63DC200C5A406 /* TabSwitcherOpenDailyPixel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabSwitcherOpenDailyPixel.swift; sourceTree = ""; }; + 6FF9AD402CE6610600C5A406 /* TabSwitcherDailyPixelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabSwitcherDailyPixelTests.swift; sourceTree = ""; }; 7B1604E72CB685B400A44EC6 /* Logger+TipKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+TipKit.swift"; sourceTree = ""; }; 7B1604EB2CB68BDA00A44EC6 /* TipKitController+ConvenienceInitializers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TipKitController+ConvenienceInitializers.swift"; sourceTree = ""; }; 7B1604ED2CB68D2600A44EC6 /* TipKitDebugOptionsUIActionHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TipKitDebugOptionsUIActionHandling.swift; sourceTree = ""; }; @@ -5839,6 +5843,7 @@ F1386BA21E6846320062FC3C /* TabSwitcher */ = { isa = PBXGroup; children = ( + 6FF9AD3E2CE63DC200C5A406 /* TabSwitcherOpenDailyPixel.swift */, 85DFEDF824CF3D0E00973FE7 /* TabsBarCell.swift */, 9872D204247DCAC100CEF398 /* TabPreviewsSource.swift */, 8586A10F24CCCD040049720E /* TabsBarViewController.swift */, @@ -5927,6 +5932,7 @@ F13B4BF71F18C9E800814661 /* Tabs */ = { isa = PBXGroup; children = ( + 6FF9AD402CE6610600C5A406 /* TabSwitcherDailyPixelTests.swift */, 85010503292FFB080033978F /* FireproofFaviconUpdaterTests.swift */, 8565A34C1FC8DFE400239327 /* LaunchTabNotificationTests.swift */, 984D035F24AF49160066CFB8 /* TabPreviewsSourceTests.swift */, @@ -7894,6 +7900,7 @@ C13F3F682B7F88100083BE40 /* AuthConfirmationPromptView.swift in Sources */, F1617C191E573EA800DEDCAF /* TabSwitcherDelegate.swift in Sources */, 4B5C462A2AF2A6E6002A4432 /* VPNIntents.swift in Sources */, + 6FF9AD3F2CE63DD800C5A406 /* TabSwitcherOpenDailyPixel.swift in Sources */, 310742A62848CD780012660B /* BackForwardMenuHistoryItem.swift in Sources */, 9FDEC7B82C9004D600C7A692 /* OnboardingIntroViewModel+Copy.swift in Sources */, 859DB8162CE6263C001F7210 /* TextZoomEditorView.swift in Sources */, @@ -8062,6 +8069,7 @@ C1B7B53428944EFA0098FD6A /* CoreDataTestUtilities.swift in Sources */, 859DB81E2CE62766001F7210 /* TextZoomTests.swift in Sources */, 1DE384E42BC41E2500871AF6 /* PixelExperimentTests.swift in Sources */, + 6FF9AD412CE6610F00C5A406 /* TabSwitcherDailyPixelTests.swift in Sources */, CBDD5DE129A6741300832877 /* MockBundle.swift in Sources */, C158AC7B297AB5DC0008723A /* MockSecureVault.swift in Sources */, 569437342BE4E41500C0881B /* SyncErrorHandlerSyncErrorsAlertsTests.swift in Sources */, diff --git a/DuckDuckGo/MainViewController.swift b/DuckDuckGo/MainViewController.swift index c6b5f59729..8a51278c6f 100644 --- a/DuckDuckGo/MainViewController.swift +++ b/DuckDuckGo/MainViewController.swift @@ -2549,6 +2549,8 @@ extension MainViewController: TabSwitcherButtonDelegate { func showTabSwitcher(_ button: TabSwitcherButton) { Pixel.fire(pixel: .tabBarTabSwitcherPressed) + DailyPixel.fireDaily(.tabSwitcherOpenDaily, withAdditionalParameters: TabSwitcherOpenDailyPixel().parameters(with: tabManager.model.tabs)) + performCancel() showTabSwitcher() } diff --git a/DuckDuckGo/TabSwitcherOpenDailyPixel.swift b/DuckDuckGo/TabSwitcherOpenDailyPixel.swift new file mode 100644 index 0000000000..8b6941ceb2 --- /dev/null +++ b/DuckDuckGo/TabSwitcherOpenDailyPixel.swift @@ -0,0 +1,68 @@ +// +// TabSwitcherOpenDailyPixel.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import Foundation + +struct TabSwitcherOpenDailyPixel { + func parameters(with tabs: [Tab]) -> [String: String] { + var parameters = [String: String]() + + parameters[ParameterName.tabCount] = tabCountBucket(for: tabs) + parameters[ParameterName.newTabCount] = newTabCountBucket(for: tabs) + + return parameters + } + + private func tabCountBucket(for tabs: [Tab]) -> String? { + let count = tabs.count + + switch count { + case 0: return nil + case 1...1: return "1" + case 2...5: return "2-5" + case 6...10: return "6-10" + case 11...20: return "11-20" + case 21...40: return "21-40" + case 41...60: return "41-60" + case 61...80: return "61-80" + case 81...100: return "81-100" + case 101...125: return "101-125" + case 126...150: return "126-150" + case 151...250: return "151-250" + case 251...500: return "251-500" + default: return "501+" + } + + } + + private func newTabCountBucket(for tabs: [Tab]) -> String? { + let count = tabs.count { $0.link == nil } + + switch count { + case 0...1: return "0-1" + case 2...10: return "2-10" + default: return "11+" + } + } + + private enum ParameterName { + static let tabCount = "tab_count" + static let newTabCount = "new_tab_count" + } +} diff --git a/DuckDuckGoTests/TabSwitcherDailyPixelTests.swift b/DuckDuckGoTests/TabSwitcherDailyPixelTests.swift new file mode 100644 index 0000000000..7cc16a6074 --- /dev/null +++ b/DuckDuckGoTests/TabSwitcherDailyPixelTests.swift @@ -0,0 +1,99 @@ +// +// TabSwitcherDailyPixelTests.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// 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. +// + +import XCTest +import Core +@testable import DuckDuckGo + +final class TabSwitcherDailyPixelTests: XCTestCase { + func testPopulatesParameters() { + let tabs = [Tab(), Tab(), Tab()] + let pixel = TabSwitcherOpenDailyPixel() + + let parameters = pixel.parameters(with: tabs) + + XCTAssertNotNil(parameters[ParameterName.tabCount]) + XCTAssertNotNil(parameters[ParameterName.newTabCount]) + } + + func testIncludesProperCountsForParameters() { + let tabs = [Tab(), Tab(), .mock()] + let pixel = TabSwitcherOpenDailyPixel() + + let parameters = pixel.parameters(with: tabs) + + XCTAssertEqual(parameters[ParameterName.tabCount], "2-5") + XCTAssertEqual(parameters[ParameterName.newTabCount], "2-10") + } + + func testBucketsAggregation() { + let bucketValues = [ + 1...1: "1", + 2...5: "2-5", + 6...10: "6-10", + 11...20: "11-20", + 21...40: "21-40", + 41...60: "41-60", + 61...80: "61-80", + 81...100: "81-100", + 101...125: "101-125", + 126...150: "126-150", + 151...250: "151-250", + 251...500: "251-500", + 501...504: "501+"] + + for bucket in bucketValues { + for value in bucket.key { + let tabs = Array(repeating: Tab.mock(), count: value) + + let countParameter = TabSwitcherOpenDailyPixel().parameters(with: tabs)[ParameterName.tabCount] + + XCTAssertEqual(countParameter, bucket.value) + } + } + } + + func testNewTabBucketsAggregation() { + let bucketValues = [ + 0...1: "0-1", + 2...10: "2-10", + 11...20: "11+"] + + for bucket in bucketValues { + for value in bucket.key { + let tabs = Array(repeating: Tab(), count: value) + + let countParameter = TabSwitcherOpenDailyPixel().parameters(with: tabs)[ParameterName.newTabCount] + + XCTAssertEqual(countParameter, bucket.value) + } + } + } +} + +private extension Tab { + static func mock() -> Tab { + Tab(link: Link(title: nil, url: URL("https://example.com")!)) + } +} + +private enum ParameterName { + static let newTabCount = "new_tab_count" + static let tabCount = "tab_count" +}