diff --git a/.github/actions/asana-create-action-item/action.yml b/.github/actions/asana-create-action-item/action.yml index 7f4ee3f3c2..b83f2dd1ad 100644 --- a/.github/actions/asana-create-action-item/action.yml +++ b/.github/actions/asana-create-action-item/action.yml @@ -45,7 +45,7 @@ runs: - id: get-asana-user-id if: github.event_name != 'schedule' - uses: duckduckgo/apple-infra/actions/asana-get-user-id-for-github-handle@main + uses: duckduckgo/apple-toolbox/actions/asana-get-user-id-for-github-handle@main with: access-token: ${{ inputs.access-token }} github-handle: ${{ github.actor }} diff --git a/.github/actions/asana-get-build-variants-list/action.yml b/.github/actions/asana-get-build-variants-list/action.yml new file mode 100644 index 0000000000..38543f750a --- /dev/null +++ b/.github/actions/asana-get-build-variants-list/action.yml @@ -0,0 +1,36 @@ +name: Get The List of Build Variants From Asana +description: | + Fetch the lists of build variants to measure retention (ATB) and attribution (Origin) from different Asana projects and combine them in a list. +inputs: + access-token: + description: "Asana access token" + required: true + type: string + github-token: + description: "GitHub Token" + required: false + type: string + atb-asana-task-id: + description: "Asana Task id for the ATB list." + required: true + type: string + origin-asana-section-id: + description: "Asana Section id for the Origins list" + required: true + type: string +outputs: + build-variants: + description: "The list of build variants to create" + value: ${{ steps.get-build-variants-task.outputs.build-variants }} +runs: + using: "composite" + steps: + - id: get-build-variants-task + shell: bash + env: + ASANA_ACCESS_TOKEN: ${{ inputs.access-token }} + GITHUB_TOKEN: ${{ inputs.github-token || github.token }} + ORIGIN_ASANA_SECTION_ID: ${{ inputs.origin-asana-section-id }} + ATB_ASANA_TASK_ID: ${{ inputs.atb-asana-task-id }} + run: | + ${{ github.action_path }}/get_build_variants_list.sh diff --git a/.github/actions/asana-get-build-variants-list/get_build_variants_list.sh b/.github/actions/asana-get-build-variants-list/get_build_variants_list.sh new file mode 100755 index 0000000000..a42d54ac58 --- /dev/null +++ b/.github/actions/asana-get-build-variants-list/get_build_variants_list.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# +# This scripts fetches Asana tasks from the Origins section defined in the Asana project https://app.asana.com/0/1206716555947156/1206716715679835. +# + +set -e -o pipefail + +asana_api_url="https://app.asana.com/api/1.0" + +# Create a JSON string with the `origin-variant` pairs from the list of . +_create_origins_and_variants() { + local response="$1" + local origin_field="Origin" + local atb_field="ATB" + + # for each element in the data array. + # filter out element with null `origin`. + # select `origin` and `variant` from the custom_fields response and make a key:value pair structure like {origin: , variant: }. + # if variant is not null we need to create two entries. One only with `origin` and one with `origin` and `variant` + # replace the new line with a comma + # remove the trailing comma at the end of the line. + jq -c '.data[] + | select(.custom_fields[] | select(.name == "'"${origin_field}"'").text_value != null) + | {origin: (.custom_fields[] | select(.name == "'"${origin_field}"'") | .text_value), variant: (.custom_fields[] | select(.name == "'"${atb_field}"'") | .text_value)} + | if .variant != null then {origin}, {origin, variant} else {origin} end' <<< "$response" \ + | tr '\n' ',' \ + | sed 's/,$//' +} + +# Fetch all the Asana tasks in the section specified by ORIGIN_ASANA_SECTION_ID for a project. +# This function fetches only uncompleted tasks. +# If there are more than 100 items the function takes care of pagination. +# Returns a JSON string consisting of a list of `origin-variant` pairs concatenated by a comma. Eg. `{"origin":"app","variant":"ab"},{"origin":"app.search","variant":null}`. +_fetch_origin_tasks() { + # Fetches only tasks that have not been completed yet, includes in the response section name, name of the task and its custom fields. + local query="completed_since=now&opt_fields=name,custom_fields.id_prefix,custom_fields.name,custom_fields.text_value&opt_expand=custom_fields&opt_fields=memberships.section.name&limit=100" + + local url="${asana_api_url}/sections/${ORIGIN_ASANA_SECTION_ID}/tasks?${query}" + local response + local origin_variants=() + + # go through all tasks in the section (there may be multiple requests in case there are more than 100 tasks in the section) + # repeat until no more pages (next_page.uri is null) + while true; do + response="$(curl -fLSs "$url" -H "Authorization: Bearer ${ASANA_ACCESS_TOKEN}")" + + # extract the object in the data array and append to result + origin_variants+=("$(_create_origins_and_variants "$response")") + + # set new URL to next page URL + url="$(jq -r .next_page.uri <<< "$response")" + + # break on last page + if [[ "$url" == "null" ]]; then + break + fi + done + + echo "${origin_variants}" +} + +# Create a JSON string from the list of ATB items passed. +_create_atb_variant_pairs() { + local response="$1" + + # read the response raw and format in a compact JSON mode + # map each element to the structure {variant:} + # remove the array + # replace the new line with a comma + # remove the trailing comma at the end of the line. + jq -R -c 'split(",") + | map({variant: .}) + | .[]' <<< "$response" \ + | tr '\n' ',' \ + | sed 's/,$//' +} + +# Fetches all the ATB variants defined in the ATB_ASANA_TASK_ID at the Variants list (comma separated) section. +_fetch_atb_variants() { + local url="${asana_api_url}/tasks/${ATB_ASANA_TASK_ID}?opt_fields=notes" + local atb_variants + + # fetches the items + # read the response raw + # select only Variants list section + # output last line of the input to get all the list of variants. + atb_variants="$(curl -fSsL ${url} \ + -H "Authorization: Bearer ${ASANA_ACCESS_TOKEN}" \ + | jq -r .data.notes \ + | grep -A1 '^Variants list' \ + | tail -1)" + + variants_list=("$(_create_atb_variant_pairs "$atb_variants")") + + echo "${variants_list}" +} + +main() { + # fetch ATB variants + local atb_variants=$(_fetch_atb_variants) + # fetch Origin variants + local origin_variants=$(_fetch_origin_tasks) + # merges the two list together. Use `include` keyword for later usage in matrix. + # for more info see https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations. + local merged_variants="{\"include\": [${atb_variants},${origin_variants}]}" + # write in GitHub output + echo "build-variants=${merged_variants}" >> "$GITHUB_OUTPUT" +} + +main diff --git a/.github/actions/asana-log-message/action.yml b/.github/actions/asana-log-message/action.yml index 288fd832ba..e00cbd2a6d 100644 --- a/.github/actions/asana-log-message/action.yml +++ b/.github/actions/asana-log-message/action.yml @@ -31,7 +31,7 @@ runs: - id: get-asana-user-id if: github.event_name != 'schedule' - uses: duckduckgo/apple-infra/actions/asana-get-user-id-for-github-handle@main + uses: duckduckgo/apple-toolbox/actions/asana-get-user-id-for-github-handle@main with: access-token: ${{ inputs.access-token }} github-handle: ${{ github.actor }} diff --git a/.github/workflows/bump_internal_release.yml b/.github/workflows/bump_internal_release.yml index 4d0d9f440a..13280743b5 100644 --- a/.github/workflows/bump_internal_release.yml +++ b/.github/workflows/bump_internal_release.yml @@ -118,10 +118,10 @@ jobs: curl -fLSs "https://app.asana.com/api/1.0/tasks/${TASK_ID}?opt_fields=notes" \ -H "Authorization: Bearer ${ASANA_ACCESS_TOKEN}" \ | jq -r .data.notes \ - | ./scripts/extract_release_notes.sh > release_notes.txt - release_notes="$(" ]]; then - echo "::error::Release notes are empty. Please add release notes to the Asana task and restart the workflow." + | ./scripts/extract_release_notes.sh -r > raw_release_notes.txt + raw_release_notes="$("* ]]; then + echo "::error::Release notes are empty or contain a placeholder. Please add release notes to the Asana task and restart the workflow." exit 1 fi diff --git a/.github/workflows/code_freeze.yml b/.github/workflows/code_freeze.yml index 2da53a932a..5b7bc475b5 100644 --- a/.github/workflows/code_freeze.yml +++ b/.github/workflows/code_freeze.yml @@ -47,7 +47,7 @@ jobs: - name: Get Asana user ID id: get-asana-user-id - uses: duckduckgo/apple-infra/actions/asana-get-user-id-for-github-handle@main + uses: duckduckgo/apple-toolbox/actions/asana-get-user-id-for-github-handle@main with: access-token: ${{ secrets.ASANA_ACCESS_TOKEN }} github-handle: ${{ github.actor }} @@ -172,6 +172,7 @@ jobs: uses: ./.github/workflows/tag_release.yml with: asana-task-url: ${{ needs.create_release_branch.outputs.asana_task_url }} + base-branch: ${{ github.ref_name }} branch: ${{ needs.create_release_branch.outputs.release_branch_name }} prerelease: true secrets: diff --git a/.github/workflows/create_variant.yml b/.github/workflows/create_variant.yml new file mode 100644 index 0000000000..c51a9c0697 --- /dev/null +++ b/.github/workflows/create_variant.yml @@ -0,0 +1,215 @@ +on: + workflow_dispatch: + inputs: + atb-variant: + description: "ATB variant. Used for measuring attribution and retention." + required: false + type: string + origin-variant: + description: "Origin variant. Used for measuring attribution only." + required: false + type: string + workflow_call: + inputs: + atb-variant: + description: "ATB variant. Used for measuring attribution and retention. Passed by the caller workflow." + required: false + type: string + origin-variant: + description: "Origin variant. Used for measuring attribution only. Passed by the caller workflow." + required: false + type: string + secrets: + BUILD_CERTIFICATE_BASE64: + required: true + P12_PASSWORD: + required: true + KEYCHAIN_PASSWORD: + required: true + REVIEW_PROVISION_PROFILE_BASE64: + required: true + RELEASE_PROVISION_PROFILE_BASE64: + required: true + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: + required: true + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: + required: true + NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2: + required: true + NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2: + required: true + NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2: + required: true + NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64_V2: + required: true + NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64: + required: true + NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64: + required: true + APPLE_API_KEY_BASE64: + required: true + APPLE_API_KEY_ID: + required: true + APPLE_API_KEY_ISSUER: + required: true + ASANA_ACCESS_TOKEN: + required: true + MM_HANDLES_BASE64: + required: true + MM_WEBHOOK_URL: + required: true + AWS_ACCESS_KEY_ID_RELEASE_S3: + required: true + AWS_SECRET_ACCESS_KEY_RELEASE_S3: + required: true + +jobs: + + create-dmg-variant: + + name: Create DMG Variant + + env: + ATB_VARIANT_NAME: ${{ inputs.atb-variant || github.event.inputs.atb-variant }} + ORIGIN_VARIANT_NAME: ${{ inputs.origin-variant || github.event.inputs.origin-variant }} + + runs-on: macos-12 + timeout-minutes: 15 + + steps: + + - name: Check out the code + uses: actions/checkout@v4 + with: + ref: main + sparse-checkout: | + .github + scripts + + - name: Download DMG artifact + id: download-dmg-artifact + continue-on-error: true + uses: actions/download-artifact@v4 + with: + name: duckduckgo-dmg + path: ${{ github.workspace }} + + - name: Download release app + # Download the release app only if download-dmg-artifact fails + if: ${{ steps.download-dmg-artifact.outcome == 'failure' }} + run: | + curl -fLSs "${{ vars.RELEASE_DMG_URL }}" --output duckduckgo.dmg + + - name: Extract App from DMG + id: extract-app-from-dmg + run: | + hdiutil attach duckduckgo.dmg -mountpoint vanilla + mkdir -p dmg + cp -R vanilla/DuckDuckGo.app dmg/DuckDuckGo.app + hdiutil detach vanilla + rm -f duckduckgo.dmg + + - name: Install create-dmg + run: brew install create-dmg + + - name: Install Apple Developer ID Application certificate + uses: ./.github/actions/install-certs-and-profiles + with: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.REVIEW_PROVISION_PROFILE_BASE64 }} + RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }} + NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2 }} + NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2 }} + NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2 }} + NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64_V2 }} + NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64 }} + NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64 }} + + - name: Set up variant + working-directory: ${{ github.workspace }}/dmg + run: | + codesign -d --entitlements :- DuckDuckGo.app > entitlements.plist + echo "${{ env.ATB_VARIANT_NAME }}" > "DuckDuckGo.app/Contents/Resources/variant.txt" + echo "${{ env.ORIGIN_VARIANT_NAME }}" > "DuckDuckGo.app/Contents/Resources/Origin.txt" + sign_identity="$(security find-certificate -a -c "Developer ID Application" -Z | grep ^SHA-1 | cut -d " " -f3 | uniq)" + + /usr/bin/codesign \ + --force \ + --sign ${sign_identity} \ + --options runtime \ + --entitlements entitlements.plist \ + --generate-entitlement-der "DuckDuckGo.app" + rm -f entitlements.plist + + - name: Notarize the app + env: + APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} + working-directory: ${{ github.workspace }}/dmg + run: | + # import API Key from secrets + export APPLE_API_KEY_PATH="$RUNNER_TEMP/apple_api_key.pem" + echo -n "$APPLE_API_KEY_BASE64" | base64 --decode -o $APPLE_API_KEY_PATH + + notarization_zip_path="DuckDuckGo-for-notarization.zip" + + ditto -c -k --keepParent "DuckDuckGo.app" "${notarization_zip_path}" + xcrun notarytool submit \ + --key "${APPLE_API_KEY_PATH}" \ + --key-id "${{ env.APPLE_API_KEY_ID }}" \ + --issuer "${{ env.APPLE_API_KEY_ISSUER }}" \ + --wait \ + "${notarization_zip_path}" + xcrun stapler staple "DuckDuckGo.app" + rm -rf "${notarization_zip_path}" + + - name: Create variant DMG + env: + GH_TOKEN: ${{ github.token }} + run: | + retries=3 + + while [[ $retries -gt 0 ]]; do + if create-dmg --volname "DuckDuckGo" \ + --icon "DuckDuckGo.app" 140 160 \ + --background "scripts/assets/dmg-background.png" \ + --window-size 600 400 \ + --icon-size 120 \ + --app-drop-link 430 160 "duckduckgo.dmg" \ + "dmg" + then + break + fi + retries=$((retries-1)) + done + + - name: Set variant name + id: set-variant-name + run: | + if [ -z "$ORIGIN_VARIANT_NAME" ] && [ -n "$ATB_VARIANT_NAME" ]; then + name=$ATB_VARIANT_NAME + elif [ -n "$ORIGIN_VARIANT_NAME" ] && [ -z "$ATB_VARIANT_NAME" ]; then + name=$ORIGIN_VARIANT_NAME + elif [ -n "$ORIGIN_VARIANT_NAME" ] && [ -n "$ATB_VARIANT_NAME" ]; then + name="${ORIGIN_VARIANT_NAME}-${ATB_VARIANT_NAME}" + else + echo "Neither ATB_VARIANT_NAME nor ORIGIN_VARIANT_NAME is set" + exit 1 + fi + + echo "variant-name=${name}" >> "$GITHUB_OUTPUT" + + - name: Upload variant DMG + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_RELEASE_S3 }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_RELEASE_S3 }} + AWS_DEFAULT_REGION: ${{ vars.AWS_DEFAULT_REGION }} + run: | + aws s3 cp duckduckgo.dmg \ + s3://${{ vars.RELEASE_BUCKET_NAME }}/${{ vars.RELEASE_BUCKET_PREFIX }}/${{ steps.set-variant-name.outputs.variant-name }}/duckduckgo.dmg \ + --acl public-read diff --git a/.github/workflows/create_variants.yml b/.github/workflows/create_variants.yml index 734d71d8ff..eb3acf62ff 100644 --- a/.github/workflows/create_variants.yml +++ b/.github/workflows/create_variants.yml @@ -2,11 +2,7 @@ name: Create DMG Variants on: workflow_dispatch: - inputs: - atb-variants: - description: "ATB variants (comma-separated)" - required: true - type: string + workflow_call: secrets: BUILD_CERTIFICATE_BASE64: @@ -62,164 +58,84 @@ jobs: timeout-minutes: 15 outputs: - atb-variants: ${{ steps.atb-variants.outputs.matrix }} + build-variants: ${{ steps.get-build-variants.outputs.build-variants }} steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Fetch Build Variants + id: get-build-variants + uses: ./.github/actions/asana-get-build-variants-list + with: + access-token: ${{ secrets.ASANA_ACCESS_TOKEN }} + atb-asana-task-id: ${{ vars.DMG_VARIANTS_LIST_TASK_ID }} + origin-asana-section-id: ${{ vars.DMG_VARIANTS_ORIGIN_SECTION_ID }} + + download-dmg-and-upload-artifact: + + name: Download Release App and upload artifact - - name: Set up ATB variants - id: atb-variants - env: - ASANA_TASK_ID: ${{ vars.DMG_VARIANTS_LIST_TASK_ID }} - ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }} - run: | - atb_variants="${{ github.event.inputs.atb-variants }}" - if [[ -z "${atb_variants}" ]]; then - atb_variants="$(curl -fSsL "https://app.asana.com/api/1.0/tasks/${ASANA_TASK_ID}?opt_fields=notes" \ - -H "Authorization: Bearer ${ASANA_ACCESS_TOKEN}" \ - | jq -r .data.notes \ - | grep -A1 '^Variants list' \ - | tail -1)" - fi - echo "atb-variants=${atb_variants}" >> $GITHUB_ENV - variant_matrix="$(sed 's/,/\",\"/g' <<< "${atb_variants}")" - echo "matrix={\"variant\": [\"${variant_matrix}\"]}" >> $GITHUB_OUTPUT - - create-atb-variants: - - name: Create ATB Variant - needs: set-up-variants - - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.set-up-variants.outputs.atb-variants) }} - - runs-on: macos-12 + runs-on: macos-13 timeout-minutes: 15 steps: + - name: Download release app + run: | + curl -fLSs "${{ vars.RELEASE_DMG_URL }}" --output duckduckgo.dmg - - name: Download release app - run: | - curl -fLSs "${{ vars.RELEASE_DMG_URL }}" --output duckduckgo.dmg - hdiutil attach duckduckgo.dmg -mountpoint vanilla - mkdir -p dmg - cp -R vanilla/DuckDuckGo.app dmg/DuckDuckGo.app - hdiutil detach vanilla - rm -f duckduckgo.dmg - - - name: Install create-dmg - run: brew install create-dmg - - - name: Fetch install-certs-and-profiles action - env: - GH_TOKEN: ${{ github.token }} - DEST_DIR: ".github/actions/install-certs-and-profiles" - run: | - mkdir -p "${{ env.DEST_DIR }}" - curl -fLSs $(gh api https://api.github.com/repos/${{ github.repository }}/contents/${{ env.DEST_DIR }}/action.yml?ref=${{ github.ref }} --jq .download_url) \ - --output ${{ env.DEST_DIR }}/action.yml - - - name: Install Apple Developer ID Application certificate - uses: ./.github/actions/install-certs-and-profiles - with: - BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} - P12_PASSWORD: ${{ secrets.P12_PASSWORD }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.REVIEW_PROVISION_PROFILE_BASE64 }} - RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.RELEASE_PROVISION_PROFILE_BASE64 }} - DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }} - DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }} - NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2 }} - NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2 }} - NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2 }} - NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64_V2 }} - NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64 }} - NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64 }} - - - name: Set up variant - working-directory: ${{ github.workspace }}/dmg - run: | - codesign -d --entitlements :- DuckDuckGo.app > entitlements.plist - echo "${{ matrix.variant }}" > "DuckDuckGo.app/Contents/Resources/variant.txt" - sign_identity="$(security find-certificate -a -c "Developer ID Application" -Z | grep ^SHA-1 | cut -d " " -f3 | uniq)" - - /usr/bin/codesign \ - --force \ - --sign ${sign_identity} \ - --options runtime \ - --entitlements entitlements.plist \ - --generate-entitlement-der "DuckDuckGo.app" - rm -f entitlements.plist - - - name: Notarize the app - env: - APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} - APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} - APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} - working-directory: ${{ github.workspace }}/dmg - run: | - # import API Key from secrets - export APPLE_API_KEY_PATH="$RUNNER_TEMP/apple_api_key.pem" - echo -n "$APPLE_API_KEY_BASE64" | base64 --decode -o $APPLE_API_KEY_PATH - - notarization_zip_path="DuckDuckGo-for-notarization.zip" - - ditto -c -k --keepParent "DuckDuckGo.app" "${notarization_zip_path}" - xcrun notarytool submit \ - --key "${APPLE_API_KEY_PATH}" \ - --key-id "${{ env.APPLE_API_KEY_ID }}" \ - --issuer "${{ env.APPLE_API_KEY_ISSUER }}" \ - --wait \ - "${notarization_zip_path}" - xcrun stapler staple "DuckDuckGo.app" - rm -rf "${notarization_zip_path}" - - - name: Create variant DMG - env: - GH_TOKEN: ${{ github.token }} - run: | - curl -fLSs $(gh api https://api.github.com/repos/${{ github.repository }}/contents/scripts/assets/dmg-background.png?ref=${{ github.ref }} --jq .download_url) \ - --output dmg-background.png - - retries=3 - - while [[ $retries -gt 0 ]]; do - if create-dmg --volname "DuckDuckGo" \ - --icon "DuckDuckGo.app" 140 160 \ - --background "dmg-background.png" \ - --window-size 600 400 \ - --icon-size 120 \ - --app-drop-link 430 160 "duckduckgo.dmg" \ - "dmg" - then - break - fi - retries=$((retries-1)) - done + - name: Upload DMG artifact + uses: actions/upload-artifact@v4 + with: + name: duckduckgo-dmg + path: ${{ github.workspace }}/duckduckgo.dmg + retention-days: 1 + create-variants: - - name: Upload variant DMG - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_RELEASE_S3 }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_RELEASE_S3 }} - AWS_DEFAULT_REGION: ${{ vars.AWS_DEFAULT_REGION }} - run: | - aws s3 cp duckduckgo.dmg \ - s3://${{ vars.RELEASE_BUCKET_NAME }}/${{ vars.RELEASE_BUCKET_PREFIX }}/${{ matrix.variant }}/duckduckgo.dmg \ - --acl public-read + name: Create Variant + needs: [set-up-variants, download-dmg-and-upload-artifact] + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.set-up-variants.outputs.build-variants) }} + uses: ./.github/workflows/create_variant.yml + with: + atb-variant: ${{ matrix.variant }} + origin-variant: ${{ matrix.origin }} + secrets: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.REVIEW_PROVISION_PROFILE_BASE64 }} + RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }} + NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2 }} + NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2 }} + NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2 }} + NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64_V2: ${{ secrets.NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64_V2 }} + NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64 }} + NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64 }} + APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_KEY_ISSUER: ${{ secrets.APPLE_API_KEY_ISSUER }} + ASANA_ACCESS_TOKEN: ${{ secrets.ASANA_ACCESS_TOKEN }} + MM_HANDLES_BASE64: ${{ secrets.MM_HANDLES_BASE64 }} + MM_WEBHOOK_URL: ${{ secrets.MM_WEBHOOK_URL }} + AWS_ACCESS_KEY_ID_RELEASE_S3: ${{ secrets.AWS_ACCESS_KEY_ID_RELEASE_S3 }} + AWS_SECRET_ACCESS_KEY_RELEASE_S3: ${{ secrets.AWS_SECRET_ACCESS_KEY_RELEASE_S3 }} + mattermost: - + name: Send Mattermost message - - needs: create-atb-variants - + needs: create-variants runs-on: ubuntu-latest - + env: - success: ${{ needs.create-atb-variants.result == 'success' }} - failure: ${{ needs.create-atb-variants.result == 'failure' }} - + success: ${{ needs.create-variants.result == 'success' }} + failure: ${{ needs.create-variants.result == 'failure' }} + steps: - name: Send Mattermost message if: ${{ env.success || env.failure }} # Don't execute when cancelled @@ -227,15 +143,15 @@ jobs: GH_TOKEN: ${{ github.token }} WORKFLOW_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} run: | - curl -fLSs $(gh api https://api.github.com/repos/${{ github.repository }}/contents/scripts/assets/variants-release-mm-template.json?ref=${{ github.ref }} --jq .download_url) \ + curl -fLSs $(gh api https://api.github.com/repos/${{ github.repository }}/contents/scripts/assets/variants-release-mm-template.json --jq .download_url) \ --output message-template.json - + export MM_USER_HANDLE=$(base64 -d <<< ${{ secrets.MM_HANDLES_BASE64 }} | jq ".${{ github.actor }}" | tr -d '"') - + if [[ -z "${MM_USER_HANDLE}" ]]; then echo "Mattermost user handle not known for ${{ github.actor }}, skipping sending message" else - + if [[ "${{ env.success }}" == "true" ]]; then status="success" else diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index c6e30341ad..fd2341e1b6 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -54,6 +54,36 @@ jobs: env: SHELLCHECK_OPTS: -x -P scripts -P scripts/helpers + bats: + + name: Test Shell Scripts + + runs-on: macos-13 + + steps: + - name: Check out the code + if: github.event_name == 'pull_request' || github.event_name == 'push' + uses: actions/checkout@v4 + + - name: Check out the code + if: github.event_name != 'pull_request' && github.event_name != 'push' + uses: actions/checkout@v4 + with: + ref: ${{ inputs.branch || github.ref_name }} + + - name: Install Bats + run: brew install bats-core + + - name: Run Bats tests + run: bats --formatter junit scripts/tests/* > bats-tests.xml + + - name: Publish unit tests report + uses: mikepenz/action-junit-report@v3 + if: always() # always run even if the previous step fails + with: + check_name: "Test Report: Shell Scripts" + report_paths: 'bats-tests.xml' + tests: name: Test @@ -256,10 +286,6 @@ jobs: # workflow_call is used by bump_internal_release and is followed by a proper release job if: github.actor != 'dependabot[bot]' && (github.event_name == 'push' || github.event_name == 'pull_request') - strategy: - matrix: - scheme: [ "DuckDuckGo Privacy Browser", "DuckDuckGo Privacy Pro" ] - runs-on: macos-13-xlarge timeout-minutes: 30 @@ -311,7 +337,7 @@ jobs: run: | export OS_ACTIVITY_MODE=debug set -o pipefail && xcodebuild \ - -scheme "${{ matrix.scheme }}" \ + -scheme "DuckDuckGo Privacy Browser" \ -derivedDataPath "DerivedData" \ -configuration "Release" \ -skipPackagePluginValidation -skipMacroValidation \ @@ -347,7 +373,7 @@ jobs: create-asana-task: name: Create Asana Task - needs: [swiftlint, tests, release-build, verify-autoconsent-bundle, private-api] + needs: [swiftlint, bats, tests, release-build, verify-autoconsent-bundle, private-api] if: failure() && github.ref_name == 'main' && github.run_attempt == 1 @@ -364,7 +390,7 @@ jobs: close-asana-task: name: Close Asana Task - needs: [swiftlint, tests, release-build, verify-autoconsent-bundle, private-api] + needs: [swiftlint, bats, tests, release-build, verify-autoconsent-bundle, private-api] if: success() && github.ref_name == 'main' && github.run_attempt > 1 diff --git a/.github/workflows/pr_task_url.yml b/.github/workflows/pr_task_url.yml index 820b61ba14..b5e247e02d 100644 --- a/.github/workflows/pr_task_url.yml +++ b/.github/workflows/pr_task_url.yml @@ -2,7 +2,7 @@ name: Asana PR Task URL on: pull_request: - types: [opened, edited, closed, unlabeled, synchronize] + types: [opened, edited, closed, unlabeled, synchronize, review_requested] jobs: @@ -112,6 +112,24 @@ jobs: if: ${{ needs.assert-project-membership.outputs.task_id }} run: exit ${{ needs.assert-project-membership.outputs.failure }} + # When reviewer is assigned create a subtask in Asana if not existing already + create-asana-pr-subtask-if-needed: + + name: "Create the PR subtask in Asana" + + runs-on: ubuntu-latest + if: github.event.action == 'review_requested' + + needs: [assert-project-membership] + + steps: + - name: Create or Update PR Subtask + uses: duckduckgo/apple-toolbox/actions/asana-create-pr-subtask@main + with: + access-token: ${{ secrets.ASANA_ACCESS_TOKEN }} + asana-task-id: ${{ needs.assert-project-membership.outputs.task_id }} + github-reviewer-user: ${{ github.event.requested_reviewer.login }} + # When a PR is merged, move the task to the Waiting for Release section of the App Board. mark-waiting-for-release: diff --git a/.github/workflows/publish_dmg_release.yml b/.github/workflows/publish_dmg_release.yml index 8daecea7be..2dd82d53ed 100644 --- a/.github/workflows/publish_dmg_release.yml +++ b/.github/workflows/publish_dmg_release.yml @@ -145,14 +145,14 @@ jobs: run: | curl -fLSs "https://app.asana.com/api/1.0/tasks/${TASK_ID}?opt_fields=notes" \ -H "Authorization: Bearer ${ASANA_ACCESS_TOKEN}" \ - | jq -r .data.notes \ - | ./scripts/extract_release_notes.sh > release_notes.txt - release_notes="$(" ]]; then - echo "::error::Release notes are empty. Please add release notes to the Asana task and restart the workflow." + | jq -r .data.notes > release_task_content.txt + raw_release_notes="$(./scripts/extract_release_notes.sh -r < release_task_content.txt)" + if [[ ${#raw_release_notes} == 0 || "$raw_release_notes" == *"<-- Add release notes here -->"* ]]; then + echo "::error::Release notes are empty or contain a placeholder. Please add release notes to the Asana task and restart the workflow." exit 1 fi - echo "RELEASE_NOTES_FILE=release_notes.txt" >> $GITHUB_ENV + ./scripts/extract_release_notes.sh < release_task_content.txt > release_notes.html + echo "RELEASE_NOTES_FILE=release_notes.html" >> $GITHUB_ENV - name: Set up Sparkle tools env: @@ -189,21 +189,21 @@ jobs: ./scripts/appcast_manager/appcastManager.swift \ --release-to-internal-channel \ --dmg ${DMG_PATH} \ - --release-notes release_notes.txt \ + --release-notes-html release_notes.html \ --key sparkle_private_key ;; "public") ./scripts/appcast_manager/appcastManager.swift \ --release-to-public-channel \ --version ${VERSION} \ - --release-notes release_notes.txt \ + --release-notes-html release_notes.html \ --key sparkle_private_key ;; "hotfix") ./scripts/appcast_manager/appcastManager.swift \ --release-hotfix-to-public-channel \ --dmg ${DMG_PATH} \ - --release-notes release_notes.txt \ + --release-notes-html release_notes.html \ --key sparkle_private_key ;; *) diff --git a/.github/workflows/stale_pr.yml b/.github/workflows/stale_pr.yml new file mode 100644 index 0000000000..a4a6e92c29 --- /dev/null +++ b/.github/workflows/stale_pr.yml @@ -0,0 +1,19 @@ +name: Close Stale Pull Requests + +on: + schedule: + - cron: '0 0 * * *' + +jobs: + close_stale_prs: + runs-on: ubuntu-latest + steps: + - name: Close stale pull requests + uses: actions/stale@v9 + with: + stale-pr-message: 'This PR has been inactive for more than 7 days and will be automatically closed 7 days from now.' + days-before-pr-stale: 7 + close-pr-message: 'This PR has been closed after 14 days of inactivity. Feel free to reopen it if you plan to continue working on it or have further discussions.' + days-before-pr-close: 7 + stale-pr-label: stale + exempt-draft-pr: true \ No newline at end of file diff --git a/.github/workflows/ui_tests.yml b/.github/workflows/ui_tests.yml new file mode 100644 index 0000000000..44bbfa8410 --- /dev/null +++ b/.github/workflows/ui_tests.yml @@ -0,0 +1,103 @@ +name: UI Tests + +on: + workflow_dispatch: + schedule: + - cron: '0 3 * * 1-5' # 3AM UTC offsetted to legacy to avoid action-junit-report@v4 bug + +jobs: + ui-tests: + name: UI tests + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + runner: [macos-13-xlarge, macos-14-xlarge] + + timeout-minutes: 120 + + steps: + - name: Check out the code + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set cache key hash + run: | + has_only_tags=$(jq '[ .pins[].state | has("version") ] | all' DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved) + if [[ "$has_only_tags" == "true" ]]; then + echo "cache_key_hash=${{ hashFiles('DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }}" >> $GITHUB_ENV + else + echo "Package.resolved contains dependencies specified by branch or commit, skipping cache." + fi + + - name: Cache SPM + if: env.cache_key_hash + uses: actions/cache@v3 + with: + path: DerivedData/SourcePackages + key: ${{ runner.os }}-spm-${{ env.cache_key_hash }} + restore-keys: | + ${{ runner.os }}-spm- + + - name: Install Apple Developer ID Application certificate + uses: ./.github/actions/install-certs-and-profiles + with: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.REVIEW_PROVISION_PROFILE_BASE64 }} + RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_RELEASE_PROVISION_PROFILE_BASE64 }} + DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.DBP_AGENT_REVIEW_PROVISION_PROFILE_BASE64 }} + NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_RELEASE_PROVISION_PROFILE_BASE64_V2 }} + NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_SYSEX_REVIEW_PROVISION_PROFILE_BASE64_V2 }} + NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_AGENT_RELEASE_PROVISION_PROFILE_BASE64_V2 }} + NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_AGENT_REVIEW_PROVISION_PROFILE_BASE64_V2 }} + NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_RELEASE_PROVISION_PROFILE_BASE64 }} + NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64: ${{ secrets.NETP_NOTIFICATIONS_REVIEW_PROVISION_PROFILE_BASE64 }} + + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_$(<.xcode-version).app/Contents/Developer + + - name: Build and run UI Testing + run: | + defaults write com.duckduckgo.macos.browser.review moveToApplicationsFolderAlertSuppress 1 + defaults write com.duckduckgo.macos.browser.review onboarding.finished -bool true + set -o pipefail && xcodebuild test \ + -scheme "UI Tests" \ + -configuration Review \ + -derivedDataPath DerivedData \ + -skipPackagePluginValidation \ + -skipMacroValidation \ + -test-iterations 2 \ + -retry-tests-on-failure \ + | tee xcodebuild.log \ + | xcbeautify --report junit --report-path . --junit-report-filename ui-tests.xml + + # - name: Create Asana task when workflow failed + # if: ${{ failure() }} && github.ref == 'refs/heads/main' + # 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 - UI Tests", "projects": [ "${{ vars.MACOS_APP_DEVELOPMENT_ASANA_PROJECT_ID }}" ], "notes" : "The end to end workflow has failed. See https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" } }' + + - name: Publish tests report + uses: mikepenz/action-junit-report@v4 + if: always() + with: + check_name: "Test Report ${{ matrix.runner }}" + report_paths: ui-tests.xml + + - name: Upload logs when workflow failed + uses: actions/upload-artifact@v4 + if: failure() + with: + name: "BuildLogs ${{ matrix.runner }}" + path: | + xcodebuild.log + DerivedData/Logs/Test/*.xcresult + ~/Library/Logs/DiagnosticReports/* + retention-days: 7 \ No newline at end of file diff --git a/Configuration/App/DBP/DuckDuckGoDBPAgent.xcconfig b/Configuration/App/DBP/DuckDuckGoDBPAgent.xcconfig index be90b0c9b3..edfa557220 100644 --- a/Configuration/App/DBP/DuckDuckGoDBPAgent.xcconfig +++ b/Configuration/App/DBP/DuckDuckGoDBPAgent.xcconfig @@ -47,7 +47,7 @@ PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = PROVISIONING_PROFILE_SPECIFIER[config=Review][sdk=macosx*] = macOS DBP Agent - Review PROVISIONING_PROFILE_SPECIFIER[config=Release][sdk=macosx*] = macOS DBP Agent - Release -FEATURE_FLAGS = FEEDBACK DBP NETWORK_PROTECTION +FEATURE_FLAGS = FEEDBACK DBP GCC_PREPROCESSOR_DEFINITIONS[arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 GCC_PREPROCESSOR_DEFINITIONS[config=CI][arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 DEBUG=1 CI=1 $(inherited) diff --git a/Configuration/App/DBP/DuckDuckGoDBPAgentAppStore.xcconfig b/Configuration/App/DBP/DuckDuckGoDBPAgentAppStore.xcconfig index 154bd9cf6b..e19a23209a 100644 --- a/Configuration/App/DBP/DuckDuckGoDBPAgentAppStore.xcconfig +++ b/Configuration/App/DBP/DuckDuckGoDBPAgentAppStore.xcconfig @@ -49,7 +49,7 @@ PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = PROVISIONING_PROFILE_SPECIFIER[config=Review][sdk=macosx*] = match AppStore com.duckduckgo.mobile.ios.DBP.backgroundAgent.review macos PROVISIONING_PROFILE_SPECIFIER[config=Release][sdk=macosx*] = match AppStore com.duckduckgo.mobile.ios.DBP.backgroundAgent macos -FEATURE_FLAGS = FEEDBACK DBP NETWORK_PROTECTION +FEATURE_FLAGS = FEEDBACK DBP GCC_PREPROCESSOR_DEFINITIONS[arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 GCC_PREPROCESSOR_DEFINITIONS[config=CI][arch=*][sdk=*] = DBP=1 NETP_SYSTEM_EXTENSION=1 DEBUG=1 CI=1 $(inherited) diff --git a/Configuration/App/DuckDuckGo.xcconfig b/Configuration/App/DuckDuckGo.xcconfig index 710327265e..36ec797d04 100644 --- a/Configuration/App/DuckDuckGo.xcconfig +++ b/Configuration/App/DuckDuckGo.xcconfig @@ -26,7 +26,7 @@ CODE_SIGN_IDENTITY[sdk=macosx*] = Developer ID Application CODE_SIGN_IDENTITY[config=Debug][sdk=macosx*] = Apple Development CODE_SIGN_IDENTITY[config=CI][sdk=macosx*] = -FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION SPARKLE DBP SUBSCRIPTION STRIPE +FEATURE_FLAGS = FEEDBACK SPARKLE DBP STRIPE PRODUCT_NAME_PREFIX = DuckDuckGo @@ -34,10 +34,10 @@ PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = PROVISIONING_PROFILE_SPECIFIER[config=Release][sdk=macosx*] = MacOS Browser PROVISIONING_PROFILE_SPECIFIER[config=Review][sdk=macosx*] = MacOS Browser Product Review -GCC_PREPROCESSOR_DEFINITIONS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION=1 -GCC_PREPROCESSOR_DEFINITIONS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION=1 DEBUG=1 CI=1 $(inherited) -GCC_PREPROCESSOR_DEFINITIONS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION=1 DEBUG=1 $(inherited) -GCC_PREPROCESSOR_DEFINITIONS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION=1 REVIEW=1 $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION=1 SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME) +GCC_PREPROCESSOR_DEFINITIONS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION=1 DEBUG=1 CI=1 SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME) $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION=1 DEBUG=1 SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME) $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION=1 REVIEW=1 SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME) $(inherited) SWIFT_ACTIVE_COMPILATION_CONDITIONS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION $(FEATURE_FLAGS) SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION DEBUG CI $(FEATURE_FLAGS) diff --git a/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig b/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig index b3b7f7ef35..6280424f9c 100644 --- a/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig +++ b/Configuration/App/NetworkProtection/DuckDuckGoVPN.xcconfig @@ -49,10 +49,10 @@ PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = PROVISIONING_PROFILE_SPECIFIER[config=Review][sdk=macosx*] = macOS NetP VPN App - Review (XPC) PROVISIONING_PROFILE_SPECIFIER[config=Release][sdk=macosx*] = macOS NetP VPN App - Release (XPC) -FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION +FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION +FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION +FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION SWIFT_OBJC_BRIDGING_HEADER = SKIP_INSTALL = YES diff --git a/Configuration/App/NetworkProtection/DuckDuckGoVPNAppStore.xcconfig b/Configuration/App/NetworkProtection/DuckDuckGoVPNAppStore.xcconfig index cad39a4d7e..d3e404d3ac 100644 --- a/Configuration/App/NetworkProtection/DuckDuckGoVPNAppStore.xcconfig +++ b/Configuration/App/NetworkProtection/DuckDuckGoVPNAppStore.xcconfig @@ -50,10 +50,10 @@ PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*] = PROVISIONING_PROFILE_SPECIFIER[config=Release][sdk=macosx*] = match AppStore com.duckduckgo.mobile.ios.vpn.agent macos PROVISIONING_PROFILE_SPECIFIER[config=Review][sdk=macosx*] = match AppStore com.duckduckgo.mobile.ios.vpn.agent.review macos -FEATURE_FLAGS[arch=*][sdk=*] = NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS[arch=*][sdk=*] = +FEATURE_FLAGS[config=CI][arch=*][sdk=*] = +FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = +FEATURE_FLAGS[config=Review][arch=*][sdk=*] = ENABLE_APP_SANDBOX = YES SWIFT_OBJC_BRIDGING_HEADER = diff --git a/Configuration/AppStore.xcconfig b/Configuration/AppStore.xcconfig index 1fbb567afd..30ec838615 100644 --- a/Configuration/AppStore.xcconfig +++ b/Configuration/AppStore.xcconfig @@ -23,10 +23,10 @@ MAIN_BUNDLE_IDENTIFIER[config=Debug][sdk=*] = $(MAIN_BUNDLE_IDENTIFIER_PREFIX).d MAIN_BUNDLE_IDENTIFIER[config=CI][sdk=*] = $(MAIN_BUNDLE_IDENTIFIER_PREFIX).debug MAIN_BUNDLE_IDENTIFIER[config=Review][sdk=*] = $(MAIN_BUNDLE_IDENTIFIER_PREFIX).review -GCC_PREPROCESSOR_DEFINITIONS[arch=*][sdk=*] = APPSTORE=1 -GCC_PREPROCESSOR_DEFINITIONS[config=CI][arch=*][sdk=*] = APPSTORE=1 DEBUG=1 CI=1 $(inherited) -GCC_PREPROCESSOR_DEFINITIONS[config=Debug][arch=*][sdk=*] = APPSTORE=1 DEBUG=1 $(inherited) -GCC_PREPROCESSOR_DEFINITIONS[config=Review][arch=*][sdk=*] = APPSTORE=1 REVIEW=1 $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[arch=*][sdk=*] = APPSTORE=1 SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME) +GCC_PREPROCESSOR_DEFINITIONS[config=CI][arch=*][sdk=*] = APPSTORE=1 DEBUG=1 CI=1 SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME) $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[config=Debug][arch=*][sdk=*] = APPSTORE=1 DEBUG=1 SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME) $(inherited) +GCC_PREPROCESSOR_DEFINITIONS[config=Review][arch=*][sdk=*] = APPSTORE=1 REVIEW=1 SWIFT_OBJC_INTERFACE_HEADER_NAME=$(SWIFT_OBJC_INTERFACE_HEADER_NAME) $(inherited) MACOSX_DEPLOYMENT_TARGET = 12.3 diff --git a/Configuration/BuildNumber.xcconfig b/Configuration/BuildNumber.xcconfig index a22b48d2cf..e5253b1076 100644 --- a/Configuration/BuildNumber.xcconfig +++ b/Configuration/BuildNumber.xcconfig @@ -1 +1 @@ -CURRENT_PROJECT_VERSION = 150 +CURRENT_PROJECT_VERSION = 183 diff --git a/Configuration/Common.xcconfig b/Configuration/Common.xcconfig index 392d63d532..04c51ab42e 100644 --- a/Configuration/Common.xcconfig +++ b/Configuration/Common.xcconfig @@ -21,7 +21,7 @@ COMBINE_HIDPI_IMAGES = YES DEVELOPMENT_TEAM = HKE973VLUW DEVELOPMENT_TEAM[config=CI][sdk=*] = -FEATURE_FLAGS = FEEDBACK DBP NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS = FEEDBACK DBP GCC_PREPROCESSOR_DEFINITIONS[config=CI][arch=*][sdk=*] = DEBUG=1 CI=1 $(inherited) GCC_PREPROCESSOR_DEFINITIONS[config=Debug][arch=*][sdk=*] = DEBUG=1 $(inherited) diff --git a/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig b/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig index 2fb095fc56..8b58584eab 100644 --- a/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig +++ b/Configuration/Extensions/NetworkProtection/NetworkProtectionAppExtension.xcconfig @@ -30,10 +30,10 @@ GENERATE_INFOPLIST_FILE = YES INFOPLIST_FILE = NetworkProtectionAppExtension/Info.plist INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023 DuckDuckGo. All rights reserved. -FEATURE_FLAGS[arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION +FEATURE_FLAGS[arch=*][sdk=*] = NETWORK_EXTENSION +FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETWORK_EXTENSION +FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETWORK_EXTENSION +FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETWORK_EXTENSION PRODUCT_BUNDLE_IDENTIFIER[sdk=*] = PRODUCT_BUNDLE_IDENTIFIER[config=CI][sdk=*] = $(TUNNEL_EXTENSION_BUNDLE_ID) diff --git a/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig b/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig index 325f9024b7..f815d7c7de 100644 --- a/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig +++ b/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig @@ -31,10 +31,10 @@ INFOPLIST_FILE = NetworkProtectionSystemExtension/Info.plist INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023 DuckDuckGo. All rights reserved. INFOPLIST_KEY_NSSystemExtensionUsageDescription = DuckDuckGo VPN -FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION -FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION SUBSCRIPTION +FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION +FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION +FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION +FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION PRODUCT_BUNDLE_IDENTIFIER[sdk=*] = $(SYSEX_BUNDLE_ID) PRODUCT_BUNDLE_IDENTIFIER[config=CI][sdk=*] = $(SYSEX_BUNDLE_ID) diff --git a/Configuration/Extensions/NetworkProtection/VPNProxyExtension.xcconfig b/Configuration/Extensions/NetworkProtection/VPNProxyExtension.xcconfig index 5f70d87091..c2b25dbe47 100644 --- a/Configuration/Extensions/NetworkProtection/VPNProxyExtension.xcconfig +++ b/Configuration/Extensions/NetworkProtection/VPNProxyExtension.xcconfig @@ -30,10 +30,10 @@ GENERATE_INFOPLIST_FILE = YES INFOPLIST_FILE = VPNProxyExtension/Info.plist INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023 DuckDuckGo. All rights reserved. -FEATURE_FLAGS[arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION -FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETWORK_EXTENSION NETWORK_PROTECTION +FEATURE_FLAGS[arch=*][sdk=*] = NETWORK_EXTENSION +FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETWORK_EXTENSION +FEATURE_FLAGS[config=Debug][arch=*][sdk=*] = NETWORK_EXTENSION +FEATURE_FLAGS[config=Review][arch=*][sdk=*] = NETWORK_EXTENSION PRODUCT_BUNDLE_IDENTIFIER[sdk=*] = PRODUCT_BUNDLE_IDENTIFIER[config=CI][sdk=*] = $(PROXY_EXTENSION_BUNDLE_ID) diff --git a/Configuration/Tests/IntegrationTests.xcconfig b/Configuration/Tests/IntegrationTests.xcconfig index cee1523e37..7bbf931ba5 100644 --- a/Configuration/Tests/IntegrationTests.xcconfig +++ b/Configuration/Tests/IntegrationTests.xcconfig @@ -17,7 +17,7 @@ MACOSX_DEPLOYMENT_TARGET = 11.4 -FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION DBP +FEATURE_FLAGS = FEEDBACK DBP INFOPLIST_FILE = IntegrationTests/Info.plist PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.Integration-Tests diff --git a/Configuration/Tests/TestsServer.xcconfig b/Configuration/Tests/TestsServer.xcconfig index b401906d9b..e8bc6f5e79 100644 --- a/Configuration/Tests/TestsServer.xcconfig +++ b/Configuration/Tests/TestsServer.xcconfig @@ -18,3 +18,5 @@ #include "../Common.xcconfig" PRODUCT_NAME = $(TARGET_NAME); +CODE_SIGNING_ALLOWED[config=Review][sdk=macosx*] = NO +CODE_SIGNING_ALLOWED[config=CI][sdk=macosx*] = NO \ No newline at end of file diff --git a/Configuration/Tests/UnitTests.xcconfig b/Configuration/Tests/UnitTests.xcconfig index b09dee6dc1..1f7cfbaeaf 100644 --- a/Configuration/Tests/UnitTests.xcconfig +++ b/Configuration/Tests/UnitTests.xcconfig @@ -17,7 +17,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION DBP SUBSCRIPTION +FEATURE_FLAGS = FEEDBACK DBP INFOPLIST_FILE = UnitTests/Info.plist PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.macos.browser.DuckDuckGoTests diff --git a/Configuration/Tests/UnitTestsAppStore.xcconfig b/Configuration/Tests/UnitTestsAppStore.xcconfig index b31177d987..e187624399 100644 --- a/Configuration/Tests/UnitTestsAppStore.xcconfig +++ b/Configuration/Tests/UnitTestsAppStore.xcconfig @@ -16,7 +16,7 @@ #include "UnitTests.xcconfig" #include "../AppStore.xcconfig" -FEATURE_FLAGS = FEEDBACK NETWORK_PROTECTION DBP SUBSCRIPTION +FEATURE_FLAGS = FEEDBACK DBP PRODUCT_BUNDLE_IDENTIFIER = com.duckduckgo.mobile.ios.DuckDuckGoTests diff --git a/Configuration/Version.xcconfig b/Configuration/Version.xcconfig index 4aebe00d0f..6b9d59ea7d 100644 --- a/Configuration/Version.xcconfig +++ b/Configuration/Version.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 1.82.0 +MARKETING_VERSION = 1.87.0 diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index c23a180948..900c68ecc9 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -7,10 +7,15 @@ objects = { /* Begin PBXBuildFile section */ + 021EA0802BD2A9D500772C9A /* TabsPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021EA07F2BD2A9D500772C9A /* TabsPreferences.swift */; }; + 021EA0812BD2A9D500772C9A /* TabsPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021EA07F2BD2A9D500772C9A /* TabsPreferences.swift */; }; + 021EA0842BD6E01A00772C9A /* TabsPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021EA0822BD6DF1B00772C9A /* TabsPreferencesTests.swift */; }; + 021EA0852BD6E0EB00772C9A /* TabsPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021EA0822BD6DF1B00772C9A /* TabsPreferencesTests.swift */; }; 0230C0A3272080090018F728 /* KeyedCodingExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0230C0A2272080090018F728 /* KeyedCodingExtension.swift */; }; 026ADE1426C3010C002518EE /* macos-config.json in Resources */ = {isa = PBXBuildFile; fileRef = 026ADE1326C3010C002518EE /* macos-config.json */; }; 028904202A7B25380028369C /* AppConfigurationURLProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0289041E2A7B23CE0028369C /* AppConfigurationURLProviderTests.swift */; }; 028904212A7B25770028369C /* AppConfigurationURLProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0289041E2A7B23CE0028369C /* AppConfigurationURLProviderTests.swift */; }; + 02C0737D2BE5B7E000BFE2F5 /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 02C0737C2BE5B7E000BFE2F5 /* InfoPlist.xcstrings */; }; 142879DA24CE1179005419BB /* SuggestionViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142879D924CE1179005419BB /* SuggestionViewModelTests.swift */; }; 142879DC24CE1185005419BB /* SuggestionContainerViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 142879DB24CE1185005419BB /* SuggestionContainerViewModelTests.swift */; }; 1430DFF524D0580F00B8978C /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1430DFF424D0580F00B8978C /* TabBarViewController.swift */; }; @@ -19,13 +24,10 @@ 14D9B8FB24F7E089000D4D13 /* AddressBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14D9B8F924F7E089000D4D13 /* AddressBarViewController.swift */; }; 1D01A3D02B88CEC600FE8150 /* PreferencesAccessibilityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3CF2B88CEC600FE8150 /* PreferencesAccessibilityView.swift */; }; 1D01A3D12B88CEC600FE8150 /* PreferencesAccessibilityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3CF2B88CEC600FE8150 /* PreferencesAccessibilityView.swift */; }; - 1D01A3D22B88CEC600FE8150 /* PreferencesAccessibilityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3CF2B88CEC600FE8150 /* PreferencesAccessibilityView.swift */; }; 1D01A3D42B88CF7700FE8150 /* AccessibilityPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3D32B88CF7700FE8150 /* AccessibilityPreferences.swift */; }; 1D01A3D52B88CF7700FE8150 /* AccessibilityPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3D32B88CF7700FE8150 /* AccessibilityPreferences.swift */; }; - 1D01A3D62B88CF7700FE8150 /* AccessibilityPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3D32B88CF7700FE8150 /* AccessibilityPreferences.swift */; }; 1D01A3D82B88DF8B00FE8150 /* PreferencesSyncView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3D72B88DF8B00FE8150 /* PreferencesSyncView.swift */; }; 1D01A3D92B88DF8B00FE8150 /* PreferencesSyncView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3D72B88DF8B00FE8150 /* PreferencesSyncView.swift */; }; - 1D01A3DA2B88DF8B00FE8150 /* PreferencesSyncView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3D72B88DF8B00FE8150 /* PreferencesSyncView.swift */; }; 1D02633628D8A9A9005CBB41 /* BWEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D02633528D8A9A9005CBB41 /* BWEncryption.m */; settings = {COMPILER_FLAGS = "-Wno-deprecated -Wno-strict-prototypes"; }; }; 1D074B272909A433006E4AC3 /* PasswordManagerCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D074B262909A433006E4AC3 /* PasswordManagerCoordinator.swift */; }; 1D12F2E2298BC660009A65FD /* InternalUserDeciderStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D12F2E1298BC660009A65FD /* InternalUserDeciderStoreMock.swift */; }; @@ -37,16 +39,12 @@ 1D1C36E729FB019C001FA40C /* HistoryTabExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1C36E529FB019C001FA40C /* HistoryTabExtensionTests.swift */; }; 1D220BF82B86192200F8BBC6 /* PreferencesEmailProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D220BF72B86192200F8BBC6 /* PreferencesEmailProtectionView.swift */; }; 1D220BF92B86192200F8BBC6 /* PreferencesEmailProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D220BF72B86192200F8BBC6 /* PreferencesEmailProtectionView.swift */; }; - 1D220BFA2B86192200F8BBC6 /* PreferencesEmailProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D220BF72B86192200F8BBC6 /* PreferencesEmailProtectionView.swift */; }; 1D220BFC2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D220BFB2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift */; }; 1D220BFD2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D220BFB2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift */; }; - 1D220BFE2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D220BFB2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift */; }; 1D26EBAC2B74BECB0002A93F /* NSImageSendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D26EBAB2B74BECB0002A93F /* NSImageSendable.swift */; }; 1D26EBAD2B74BECB0002A93F /* NSImageSendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D26EBAB2B74BECB0002A93F /* NSImageSendable.swift */; }; - 1D26EBAE2B74BECB0002A93F /* NSImageSendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D26EBAB2B74BECB0002A93F /* NSImageSendable.swift */; }; 1D26EBB02B74DB600002A93F /* TabSnapshotCleanupService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D26EBAF2B74DB600002A93F /* TabSnapshotCleanupService.swift */; }; 1D26EBB12B74DB600002A93F /* TabSnapshotCleanupService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D26EBAF2B74DB600002A93F /* TabSnapshotCleanupService.swift */; }; - 1D26EBB22B74DB600002A93F /* TabSnapshotCleanupService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D26EBAF2B74DB600002A93F /* TabSnapshotCleanupService.swift */; }; 1D2DC00629016798008083A1 /* BWCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF075C28F815AD00EDFBE3 /* BWCredential.swift */; }; 1D2DC0072901679C008083A1 /* BWError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF076028F815AD00EDFBE3 /* BWError.swift */; }; 1D2DC0082901679E008083A1 /* BWResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF076128F815AD00EDFBE3 /* BWResponse.swift */; }; @@ -90,7 +88,6 @@ 1D8C2FF12B70F751005E4BBD /* MockTabSnapshotStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8C2FEF2B70F751005E4BBD /* MockTabSnapshotStore.swift */; }; 1D9A4E5A2B43213B00F449E2 /* TabSnapshotExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9A4E592B43213B00F449E2 /* TabSnapshotExtension.swift */; }; 1D9A4E5B2B43213B00F449E2 /* TabSnapshotExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9A4E592B43213B00F449E2 /* TabSnapshotExtension.swift */; }; - 1D9A4E5C2B43213B00F449E2 /* TabSnapshotExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9A4E592B43213B00F449E2 /* TabSnapshotExtension.swift */; }; 1D9FDEB72B9B5D150040B78C /* SearchPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9FDEB62B9B5D150040B78C /* SearchPreferencesTests.swift */; }; 1D9FDEB82B9B5D150040B78C /* SearchPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9FDEB62B9B5D150040B78C /* SearchPreferencesTests.swift */; }; 1D9FDEBA2B9B5E090040B78C /* WebTrackingProtectionPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D9FDEB92B9B5E090040B78C /* WebTrackingProtectionPreferencesTests.swift */; }; @@ -109,55 +106,43 @@ 1DA6D1032A1FFA3B00540406 /* HTTPCookieTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA6D0FF2A1FF9DC00540406 /* HTTPCookieTests.swift */; }; 1DB67F292B6FE4A6003DF243 /* WebViewSnapshotRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB67F282B6FE4A6003DF243 /* WebViewSnapshotRenderer.swift */; }; 1DB67F2A2B6FEB17003DF243 /* WebViewSnapshotRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB67F282B6FE4A6003DF243 /* WebViewSnapshotRenderer.swift */; }; - 1DB67F2B2B6FEB19003DF243 /* WebViewSnapshotRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB67F282B6FE4A6003DF243 /* WebViewSnapshotRenderer.swift */; }; 1DB67F2D2B6FEFDB003DF243 /* ViewSnapshotRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB67F2C2B6FEFDB003DF243 /* ViewSnapshotRenderer.swift */; }; 1DB67F2E2B6FEFDB003DF243 /* ViewSnapshotRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB67F2C2B6FEFDB003DF243 /* ViewSnapshotRenderer.swift */; }; - 1DB67F2F2B6FEFDB003DF243 /* ViewSnapshotRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB67F2C2B6FEFDB003DF243 /* ViewSnapshotRenderer.swift */; }; 1DB9617A29F1D06D00CF5568 /* InternalUserDeciderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB9617929F1D06D00CF5568 /* InternalUserDeciderMock.swift */; }; 1DB9617B29F1D06D00CF5568 /* InternalUserDeciderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB9617929F1D06D00CF5568 /* InternalUserDeciderMock.swift */; }; 1DB9618229F67F6100CF5568 /* FaviconNullStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB9617F29F67F3E00CF5568 /* FaviconNullStore.swift */; }; 1DB9618329F67F6200CF5568 /* FaviconNullStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB9617F29F67F3E00CF5568 /* FaviconNullStore.swift */; }; 1DC669702B6CF0D700AA0645 /* TabSnapshotStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC6696F2B6CF0D700AA0645 /* TabSnapshotStore.swift */; }; 1DC669712B6CF0D700AA0645 /* TabSnapshotStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC6696F2B6CF0D700AA0645 /* TabSnapshotStore.swift */; }; - 1DC669722B6CF0D700AA0645 /* TabSnapshotStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC6696F2B6CF0D700AA0645 /* TabSnapshotStore.swift */; }; 1DCFBC8A29ADF32B00313531 /* BurnerHomePageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DCFBC8929ADF32B00313531 /* BurnerHomePageView.swift */; }; 1DCFBC8B29ADF32B00313531 /* BurnerHomePageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DCFBC8929ADF32B00313531 /* BurnerHomePageView.swift */; }; 1DDC84F72B83558F00670238 /* PreferencesPrivateSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC84F62B83558F00670238 /* PreferencesPrivateSearchView.swift */; }; 1DDC84F82B83558F00670238 /* PreferencesPrivateSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC84F62B83558F00670238 /* PreferencesPrivateSearchView.swift */; }; - 1DDC84F92B83558F00670238 /* PreferencesPrivateSearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC84F62B83558F00670238 /* PreferencesPrivateSearchView.swift */; }; 1DDC84FB2B8356CE00670238 /* PreferencesDefaultBrowserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC84FA2B8356CE00670238 /* PreferencesDefaultBrowserView.swift */; }; 1DDC84FC2B8356CE00670238 /* PreferencesDefaultBrowserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC84FA2B8356CE00670238 /* PreferencesDefaultBrowserView.swift */; }; - 1DDC84FD2B8356CE00670238 /* PreferencesDefaultBrowserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC84FA2B8356CE00670238 /* PreferencesDefaultBrowserView.swift */; }; 1DDC84FF2B835BC000670238 /* SearchPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC84FE2B835BC000670238 /* SearchPreferences.swift */; }; 1DDC85002B835BC000670238 /* SearchPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC84FE2B835BC000670238 /* SearchPreferences.swift */; }; - 1DDC85012B835BC000670238 /* SearchPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC84FE2B835BC000670238 /* SearchPreferences.swift */; }; 1DDC85032B83903E00670238 /* PreferencesWebTrackingProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC85022B83903E00670238 /* PreferencesWebTrackingProtectionView.swift */; }; 1DDC85042B83903E00670238 /* PreferencesWebTrackingProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC85022B83903E00670238 /* PreferencesWebTrackingProtectionView.swift */; }; - 1DDC85052B83903E00670238 /* PreferencesWebTrackingProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDC85022B83903E00670238 /* PreferencesWebTrackingProtectionView.swift */; }; 1DDD3EBC2B84DCB9004CBF2B /* WebTrackingProtectionPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDD3EBB2B84DCB9004CBF2B /* WebTrackingProtectionPreferences.swift */; }; 1DDD3EBD2B84DCB9004CBF2B /* WebTrackingProtectionPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDD3EBB2B84DCB9004CBF2B /* WebTrackingProtectionPreferences.swift */; }; - 1DDD3EBE2B84DCB9004CBF2B /* WebTrackingProtectionPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDD3EBB2B84DCB9004CBF2B /* WebTrackingProtectionPreferences.swift */; }; 1DDD3EC02B84F5D5004CBF2B /* PreferencesCookiePopupProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDD3EBF2B84F5D5004CBF2B /* PreferencesCookiePopupProtectionView.swift */; }; 1DDD3EC12B84F5D5004CBF2B /* PreferencesCookiePopupProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDD3EBF2B84F5D5004CBF2B /* PreferencesCookiePopupProtectionView.swift */; }; - 1DDD3EC22B84F5D5004CBF2B /* PreferencesCookiePopupProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDD3EBF2B84F5D5004CBF2B /* PreferencesCookiePopupProtectionView.swift */; }; 1DDD3EC42B84F96B004CBF2B /* CookiePopupProtectionPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDD3EC32B84F96B004CBF2B /* CookiePopupProtectionPreferences.swift */; }; 1DDD3EC52B84F96B004CBF2B /* CookiePopupProtectionPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDD3EC32B84F96B004CBF2B /* CookiePopupProtectionPreferences.swift */; }; - 1DDD3EC62B84F96B004CBF2B /* CookiePopupProtectionPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDD3EC32B84F96B004CBF2B /* CookiePopupProtectionPreferences.swift */; }; 1DDF076328F815AD00EDFBE3 /* BWCommunicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF075D28F815AD00EDFBE3 /* BWCommunicator.swift */; }; 1DDF076428F815AD00EDFBE3 /* BWManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF075E28F815AD00EDFBE3 /* BWManager.swift */; }; 1DE03425298BC7F000CAB3D7 /* InternalUserDeciderStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D12F2E1298BC660009A65FD /* InternalUserDeciderStoreMock.swift */; }; + 1DEF3BAD2BD145A9004A2FBA /* AutoClearHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DEF3BAC2BD145A9004A2FBA /* AutoClearHandler.swift */; }; + 1DEF3BAE2BD145A9004A2FBA /* AutoClearHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DEF3BAC2BD145A9004A2FBA /* AutoClearHandler.swift */; }; 1DFAB51D2A8982A600A0F7F6 /* SetExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DFAB51C2A8982A600A0F7F6 /* SetExtension.swift */; }; 1DFAB51E2A8982A600A0F7F6 /* SetExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DFAB51C2A8982A600A0F7F6 /* SetExtension.swift */; }; 1DFAB5222A8983DE00A0F7F6 /* SetExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DFAB51F2A89830D00A0F7F6 /* SetExtensionTests.swift */; }; 1DFAB5232A8983E100A0F7F6 /* SetExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DFAB51F2A89830D00A0F7F6 /* SetExtensionTests.swift */; }; - 1E0068AD2B1673BB00BBF43B /* SubscriptionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 1E0068AC2B1673BB00BBF43B /* SubscriptionUI */; }; 1E0C72062ABC63BD00802009 /* SubscriptionPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0C72052ABC63BD00802009 /* SubscriptionPagesUserScript.swift */; }; 1E0C72072ABC63BD00802009 /* SubscriptionPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0C72052ABC63BD00802009 /* SubscriptionPagesUserScript.swift */; }; - 1E21F8E32B73E48600FB272E /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = 1E21F8E22B73E48600FB272E /* Subscription */; }; - 1E2AE4C72ACB215900684E0A /* NetworkProtectionRemoteMessaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCF15D62ABB8A110083F6DF /* NetworkProtectionRemoteMessaging.swift */; }; - 1E2AE4C82ACB216B00684E0A /* HoverTrackingArea.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B140872ABDBCC1004F8E85 /* HoverTrackingArea.swift */; }; - 1E2AE4CA2ACB21A000684E0A /* NetworkProtectionRemoteMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCF15D82ABB8A7F0083F6DF /* NetworkProtectionRemoteMessage.swift */; }; - 1E2AE4CB2ACB21C800684E0A /* HardwareModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9579202AC687170062CA31 /* HardwareModel.swift */; }; + 1E559BB12BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E559BB02BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift */; }; + 1E559BB22BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E559BB02BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift */; }; 1E7E2E9029029A2A00C01B54 /* ContentBlockingRulesUpdateObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7E2E8F29029A2A00C01B54 /* ContentBlockingRulesUpdateObserver.swift */; }; 1E7E2E942902AC0E00C01B54 /* PrivacyDashboardPermissionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7E2E932902AC0E00C01B54 /* PrivacyDashboardPermissionHandler.swift */; }; 1E950E3F2912A10D0051A99B /* ContentBlocking in Frameworks */ = {isa = PBXBuildFile; productRef = 1E950E3E2912A10D0051A99B /* ContentBlocking */; }; @@ -167,37 +152,32 @@ 1EA7B8D52B7E078C000330A4 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = 1EA7B8D42B7E078C000330A4 /* Subscription */; }; 1ED910D52B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED910D42B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift */; }; 1ED910D62B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED910D42B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift */; }; - 1ED910D72B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ED910D42B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift */; }; 310E79BF294A19A8007C49E8 /* FireproofingReferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 310E79BE294A19A8007C49E8 /* FireproofingReferenceTests.swift */; }; 311B262728E73E0A00FD181A /* TabShadowConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 311B262628E73E0A00FD181A /* TabShadowConfig.swift */; }; 31267C692B640C4200FEF811 /* DataBrokerProtectionFeatureVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C5FFB82AF64D120008A79F /* DataBrokerProtectionFeatureVisibility.swift */; }; 31267C6A2B640C4B00FEF811 /* DataBrokerProtectionFeatureDisabler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3199C6F82AF94F5B002A7BA1 /* DataBrokerProtectionFeatureDisabler.swift */; }; 31267C6B2B640C5200FEF811 /* DataBrokerProtectionAppEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3199C6FC2AF97367002A7BA1 /* DataBrokerProtectionAppEvents.swift */; }; 3129788A2B64131200B67619 /* DataBrokerProtection in Frameworks */ = {isa = PBXBuildFile; productRef = 312978892B64131200B67619 /* DataBrokerProtection */; }; - 3143C8792B0D1F3D00382627 /* DataBrokerProtection in Frameworks */ = {isa = PBXBuildFile; productRef = 3143C8782B0D1F3D00382627 /* DataBrokerProtection */; }; 3154FD1428E6011A00909769 /* TabShadowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3154FD1328E6011A00909769 /* TabShadowView.swift */; }; - 3158B1472B0BF72E00AF130C /* DBPHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3192EC872A4DCF21001E97A5 /* DBPHomeViewController.swift */; }; 3158B1492B0BF73000AF130C /* DBPHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3192EC872A4DCF21001E97A5 /* DBPHomeViewController.swift */; }; 3158B14A2B0BF74300AF130C /* DataBrokerProtectionDebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316850712AF3AD58009A2828 /* DataBrokerProtectionDebugMenu.swift */; }; - 3158B14C2B0BF74500AF130C /* DataBrokerProtectionDebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316850712AF3AD58009A2828 /* DataBrokerProtectionDebugMenu.swift */; }; 3158B14D2B0BF74D00AF130C /* DataBrokerProtectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3139A1512AA4B3C000969C7D /* DataBrokerProtectionManager.swift */; }; - 3158B14F2B0BF74F00AF130C /* DataBrokerProtectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3139A1512AA4B3C000969C7D /* DataBrokerProtectionManager.swift */; }; 3158B1502B0BF75200AF130C /* DataBrokerProtectionLoginItemScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */; }; - 3158B1522B0BF75400AF130C /* DataBrokerProtectionLoginItemScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */; }; 3158B1532B0BF75700AF130C /* LoginItem+DataBrokerProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D8FA00B2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift */; }; - 3158B1552B0BF75900AF130C /* LoginItem+DataBrokerProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D8FA00B2AC5BDCE005DD0D0 /* LoginItem+DataBrokerProtection.swift */; }; 3158B1562B0BF75D00AF130C /* DataBrokerProtectionFeatureVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C5FFB82AF64D120008A79F /* DataBrokerProtectionFeatureVisibility.swift */; }; - 3158B1582B0BF76000AF130C /* DataBrokerProtectionFeatureVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C5FFB82AF64D120008A79F /* DataBrokerProtectionFeatureVisibility.swift */; }; 3158B1592B0BF76400AF130C /* DataBrokerProtectionFeatureDisabler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3199C6F82AF94F5B002A7BA1 /* DataBrokerProtectionFeatureDisabler.swift */; }; - 3158B15B2B0BF76700AF130C /* DataBrokerProtectionFeatureDisabler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3199C6F82AF94F5B002A7BA1 /* DataBrokerProtectionFeatureDisabler.swift */; }; 3158B15C2B0BF76D00AF130C /* DataBrokerProtectionAppEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3199C6FC2AF97367002A7BA1 /* DataBrokerProtectionAppEvents.swift */; }; - 3158B15E2B0BF76F00AF130C /* DataBrokerProtectionAppEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3199C6FC2AF97367002A7BA1 /* DataBrokerProtectionAppEvents.swift */; }; 315A023D2B64216B00BFA577 /* IPCServiceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD01C182AD8319C0088B32E /* IPCServiceManager.swift */; }; 315A023F2B6421AE00BFA577 /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 315A023E2B6421AE00BFA577 /* Networking */; }; 315AA07028CA5CC800200030 /* YoutubePlayerNavigationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315AA06F28CA5CC800200030 /* YoutubePlayerNavigationHandler.swift */; }; 3168506D2AF3AD1D009A2828 /* WaitlistViewControllerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3168506C2AF3AD1C009A2828 /* WaitlistViewControllerPresenter.swift */; }; 3168506E2AF3AD1D009A2828 /* WaitlistViewControllerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3168506C2AF3AD1C009A2828 /* WaitlistViewControllerPresenter.swift */; }; - 316850702AF3AD1D009A2828 /* WaitlistViewControllerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3168506C2AF3AD1C009A2828 /* WaitlistViewControllerPresenter.swift */; }; + 316913232BD2B6250051B46D /* DataBrokerProtectionPixelsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316913222BD2B6250051B46D /* DataBrokerProtectionPixelsHandler.swift */; }; + 316913242BD2B6250051B46D /* DataBrokerProtectionPixelsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316913222BD2B6250051B46D /* DataBrokerProtectionPixelsHandler.swift */; }; + 316913262BD2B76F0051B46D /* DataBrokerPrerequisitesStatusVerifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316913252BD2B76F0051B46D /* DataBrokerPrerequisitesStatusVerifier.swift */; }; + 316913272BD2B76F0051B46D /* DataBrokerPrerequisitesStatusVerifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316913252BD2B76F0051B46D /* DataBrokerPrerequisitesStatusVerifier.swift */; }; + 316913292BD2C7570051B46D /* DataBrokerProtectionErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316913282BD2C7570051B46D /* DataBrokerProtectionErrorViewController.swift */; }; + 3169132A2BD2C7570051B46D /* DataBrokerProtectionErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 316913282BD2C7570051B46D /* DataBrokerProtectionErrorViewController.swift */; }; 3171D6B82889849F0068632A /* CookieManagedNotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3171D6B72889849F0068632A /* CookieManagedNotificationView.swift */; }; 3171D6BA288984D00068632A /* BadgeAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3171D6B9288984D00068632A /* BadgeAnimationView.swift */; }; 3171D6DB2889B64D0068632A /* CookieManagedNotificationContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3171D6DA2889B64D0068632A /* CookieManagedNotificationContainerView.swift */; }; @@ -210,16 +190,20 @@ 31A2FD172BAB41C500D0E741 /* DataBrokerProtectionVisibilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A2FD162BAB41C500D0E741 /* DataBrokerProtectionVisibilityTests.swift */; }; 31A2FD182BAB43BA00D0E741 /* DataBrokerProtectionVisibilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A2FD162BAB41C500D0E741 /* DataBrokerProtectionVisibilityTests.swift */; }; 31A3A4E32B0C115F0021063C /* DataBrokerProtection in Frameworks */ = {isa = PBXBuildFile; productRef = 31A3A4E22B0C115F0021063C /* DataBrokerProtection */; }; + 31A83FB52BE28D7D00F74E67 /* UserText+DBP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A83FB42BE28D7D00F74E67 /* UserText+DBP.swift */; }; + 31A83FB62BE28D7D00F74E67 /* UserText+DBP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A83FB42BE28D7D00F74E67 /* UserText+DBP.swift */; }; + 31A83FB72BE28D8A00F74E67 /* UserText+DBP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A83FB42BE28D7D00F74E67 /* UserText+DBP.swift */; }; + 31A83FB82BE28D8A00F74E67 /* UserText+DBP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A83FB42BE28D7D00F74E67 /* UserText+DBP.swift */; }; 31AA6B972B960B870025014E /* DataBrokerProtectionLoginItemPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31AA6B962B960B870025014E /* DataBrokerProtectionLoginItemPixels.swift */; }; 31AA6B982B960BA50025014E /* DataBrokerProtectionLoginItemPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31AA6B962B960B870025014E /* DataBrokerProtectionLoginItemPixels.swift */; }; - 31AA6B992B960BA60025014E /* DataBrokerProtectionLoginItemPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31AA6B962B960B870025014E /* DataBrokerProtectionLoginItemPixels.swift */; }; 31B4AF532901A4F20013585E /* NSEventExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31B4AF522901A4F20013585E /* NSEventExtension.swift */; }; 31C3CE0228EDC1E70002C24A /* CustomRoundedCornersShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C3CE0128EDC1E70002C24A /* CustomRoundedCornersShape.swift */; }; 31C9ADE52AF0564500CEF57D /* WaitlistFeatureSetupHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C9ADE42AF0564500CEF57D /* WaitlistFeatureSetupHandler.swift */; }; 31C9ADE62AF0564500CEF57D /* WaitlistFeatureSetupHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C9ADE42AF0564500CEF57D /* WaitlistFeatureSetupHandler.swift */; }; - 31C9ADE82AF0564500CEF57D /* WaitlistFeatureSetupHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C9ADE42AF0564500CEF57D /* WaitlistFeatureSetupHandler.swift */; }; 31CF3432288B0B1B0087244B /* NavigationBarBadgeAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31CF3431288B0B1B0087244B /* NavigationBarBadgeAnimator.swift */; }; 31D5375C291D944100407A95 /* PasswordManagementBitwardenItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D5375B291D944100407A95 /* PasswordManagementBitwardenItemView.swift */; }; + 31DC2F222BD6DE6C001354EF /* DataBrokerPrerequisitesStatusVerifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DC2F202BD6DE65001354EF /* DataBrokerPrerequisitesStatusVerifierTests.swift */; }; + 31DC2F232BD6E028001354EF /* DataBrokerPrerequisitesStatusVerifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DC2F202BD6DE65001354EF /* DataBrokerPrerequisitesStatusVerifierTests.swift */; }; 31E163BA293A56F400963C10 /* BrokenSiteReportingReferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31E163B9293A56F400963C10 /* BrokenSiteReportingReferenceTests.swift */; }; 31E163BD293A579E00963C10 /* PrivacyReferenceTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31E163BC293A579E00963C10 /* PrivacyReferenceTestHelper.swift */; }; 31E163C0293A581900963C10 /* privacy-reference-tests in Resources */ = {isa = PBXBuildFile; fileRef = 31E163BF293A581900963C10 /* privacy-reference-tests */; }; @@ -233,7 +217,6 @@ 31F28C5328C8EECA00119F70 /* DuckURLSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F28C5228C8EECA00119F70 /* DuckURLSchemeHandler.swift */; }; 31F2D1FF2AF026D800BF0144 /* WaitlistTermsAndConditionsActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F2D1FE2AF026D800BF0144 /* WaitlistTermsAndConditionsActionHandler.swift */; }; 31F2D2002AF026D800BF0144 /* WaitlistTermsAndConditionsActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F2D1FE2AF026D800BF0144 /* WaitlistTermsAndConditionsActionHandler.swift */; }; - 31F2D2022AF026D800BF0144 /* WaitlistTermsAndConditionsActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F2D1FE2AF026D800BF0144 /* WaitlistTermsAndConditionsActionHandler.swift */; }; 31F7F2A6288AD2CA001C0D64 /* NavigationBarBadgeAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F7F2A5288AD2CA001C0D64 /* NavigationBarBadgeAnimationView.swift */; }; 3701C9CE29BD040C00305B15 /* FirefoxBerkeleyDatabaseReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3701C9CD29BD040900305B15 /* FirefoxBerkeleyDatabaseReader.swift */; }; 3701C9CF29BD040C00305B15 /* FirefoxBerkeleyDatabaseReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3701C9CD29BD040900305B15 /* FirefoxBerkeleyDatabaseReader.swift */; }; @@ -285,7 +268,6 @@ 3706FAB2293F65D500E42796 /* TabInstrumentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB88B4F25B7BA2B006F6B06 /* TabInstrumentation.swift */; }; 3706FAB5293F65D500E42796 /* ConfigurationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D33F1125C82EB3002B91A6 /* ConfigurationManager.swift */; }; 3706FAB6293F65D500E42796 /* YoutubePlayerUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F28C4C28C8EEC500119F70 /* YoutubePlayerUserScript.swift */; }; - 3706FAB7293F65D500E42796 /* PixelParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E48326146AAB0067D1B9 /* PixelParameters.swift */; }; 3706FAB8293F65D500E42796 /* FaviconImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5FA696275F90C400DCE9C9 /* FaviconImageCache.swift */; }; 3706FAB9293F65D500E42796 /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1430DFF424D0580F00B8978C /* TabBarViewController.swift */; }; 3706FABA293F65D500E42796 /* BookmarkOutlineViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929126670D2A00AD2C21 /* BookmarkOutlineViewDataSource.swift */; }; @@ -423,7 +405,6 @@ 3706FB60293F65D500E42796 /* PasswordManagementIdentityItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE6546E271FCD40008D1D63 /* PasswordManagementIdentityItemView.swift */; }; 3706FB61293F65D500E42796 /* ProgressExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F41030264D2B23003DA42C /* ProgressExtension.swift */; }; 3706FB62293F65D500E42796 /* CSVParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DF626B0002B00E14D75 /* CSVParser.swift */; }; - 3706FB64293F65D500E42796 /* PixelDataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44062616B30600DD1EC2 /* PixelDataModel.xcdatamodeld */; }; 3706FB65293F65D500E42796 /* PrivacyDashboardWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63BDF7D27FDAA640072D75B /* PrivacyDashboardWebView.swift */; }; 3706FB66293F65D500E42796 /* AppearancePreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C727F2FDD100F1F7B9 /* AppearancePreferences.swift */; }; 3706FB67293F65D500E42796 /* DownloadListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E87A26D381710062C350 /* DownloadListCoordinator.swift */; }; @@ -505,7 +486,6 @@ 3706FBC7293F65D500E42796 /* EncryptedHistoryStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE7527B263B056C00B973F8 /* EncryptedHistoryStore.swift */; }; 3706FBC8293F65D500E42796 /* FirePopoverCollectionViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE246F12709EF3B00BEEAEE /* FirePopoverCollectionViewItem.swift */; }; 3706FBC9293F65D500E42796 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA61C0D12727F59B00E6B681 /* ArrayExtension.swift */; }; - 3706FBCA293F65D500E42796 /* CrashReportSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A2B268F1ECD00D2D9CD /* CrashReportSender.swift */; }; 3706FBCB293F65D500E42796 /* BookmarkHTMLImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A1AAF2842C4EA00586521 /* BookmarkHTMLImporter.swift */; }; 3706FBCC293F65D500E42796 /* CustomRoundedCornersShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C3CE0128EDC1E70002C24A /* CustomRoundedCornersShape.swift */; }; 3706FBCD293F65D500E42796 /* LocaleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8D9061276D1D880078DB17 /* LocaleExtension.swift */; }; @@ -542,9 +522,6 @@ 3706FBF0293F65D500E42796 /* PasswordManagementItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CC1D7C26A05F250062F04E /* PasswordManagementItemModel.swift */; }; 3706FBF2293F65D500E42796 /* FindInPageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A0118125AF60E700FA6A0C /* FindInPageModel.swift */; }; 3706FBF3293F65D500E42796 /* PseudoFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929826670D2A00AD2C21 /* PseudoFolder.swift */; }; - 3706FBF5293F65D500E42796 /* PixelDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */; }; - 3706FBF6293F65D500E42796 /* Pixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E45226142B070067D1B9 /* Pixel.swift */; }; - 3706FBF7293F65D500E42796 /* PixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E47626146A570067D1B9 /* PixelEvent.swift */; }; 3706FBF8293F65D500E42796 /* TabBarFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2CB1342587C29500AA6FBE /* TabBarFooter.swift */; }; 3706FBF9293F65D500E42796 /* BookmarksBarCollectionViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE5336A286912D40019DBFD /* BookmarksBarCollectionViewItem.swift */; }; 3706FBFA293F65D500E42796 /* FileDownloadError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0B23826E742610031CB7F /* FileDownloadError.swift */; }; @@ -610,7 +587,6 @@ 3706FC3F293F65D500E42796 /* ApplicationDockMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA97BF4525135DD30014931A /* ApplicationDockMenu.swift */; }; 3706FC40293F65D500E42796 /* SaveIdentityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8A4DFE27C83B29005F40E8 /* SaveIdentityViewController.swift */; }; 3706FC41293F65D500E42796 /* FileStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1A69A258B076900F6F690 /* FileStore.swift */; }; - 3706FC42293F65D500E42796 /* PixelArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E47E26146A800067D1B9 /* PixelArguments.swift */; }; 3706FC43293F65D500E42796 /* PinnedTabsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF3F1E286F0A7A00BD9014 /* PinnedTabsViewModel.swift */; }; 3706FC44293F65D500E42796 /* BookmarkList.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4CF25D6A709007F5990 /* BookmarkList.swift */; }; 3706FC45293F65D500E42796 /* BookmarkTableRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292C92667123700AD2C21 /* BookmarkTableRowView.swift */; }; @@ -652,9 +628,8 @@ 3706FC6F293F65D500E42796 /* FirePopoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA13DCB3271480B0006D48D3 /* FirePopoverViewModel.swift */; }; 3706FC71293F65D500E42796 /* NSColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F41D174025CB131900472416 /* NSColorExtension.swift */; }; 3706FC73293F65D500E42796 /* AddressBarButtonsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4F525D6BF2C007F5990 /* AddressBarButtonsViewController.swift */; }; - 3706FC76293F65D500E42796 /* PixelDataRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C92C32750EF76002AC6B0 /* PixelDataRecord.swift */; }; 3706FC77293F65D500E42796 /* PageObserverUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 853014D525E671A000FB8205 /* PageObserverUserScript.swift */; }; - 3706FC78293F65D500E42796 /* SecureVaultErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */; }; + 3706FC78293F65D500E42796 /* SecureVaultReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultReporter.swift */; }; 3706FC79293F65D500E42796 /* NSImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B139AFC26B60BD800894F82 /* NSImageExtensions.swift */; }; 3706FC7B293F65D500E42796 /* PasswordManagementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85625995269C953C00EE44BC /* PasswordManagementViewController.swift */; }; 3706FC7C293F65D500E42796 /* ImportedBookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CFA26FE191E001E4761 /* ImportedBookmarks.swift */; }; @@ -673,7 +648,6 @@ 3706FC8C293F65D500E42796 /* FirefoxDataImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FF67726B602B100D42879 /* FirefoxDataImporter.swift */; }; 3706FC8D293F65D500E42796 /* PreferencesGeneralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8A27DB69BC00471A10 /* PreferencesGeneralView.swift */; }; 3706FC8E293F65D500E42796 /* PinnedTabsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF3F1F286F0A7A00BD9014 /* PinnedTabsView.swift */; }; - 3706FC92293F65D500E42796 /* NSStoryboardExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE0DF0426781961006337B7 /* NSStoryboardExtension.swift */; }; 3706FC93293F65D500E42796 /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8027DA2CA600471A10 /* PreferencesViewController.swift */; }; 3706FC94293F65D500E42796 /* FireproofDomains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B02198125E05FAC00ED7DEA /* FireproofDomains.swift */; }; 3706FC95293F65D500E42796 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B677440255DBEEA00025BD8 /* Database.swift */; }; @@ -703,7 +677,6 @@ 3706FCB8293F65D500E42796 /* Onboarding.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 85B7184927677C2D00B4277F /* Onboarding.storyboard */; }; 3706FCB9293F65D500E42796 /* FireproofDomains.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B0511AD262CAA5A00F6079C /* FireproofDomains.storyboard */; }; 3706FCBA293F65D500E42796 /* clickToLoadConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = EA47767F272A21B700419EDA /* clickToLoadConfig.json */; }; - 3706FCBB293F65D500E42796 /* Downloads.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B6B1E88126D5DAC30062C350 /* Downloads.storyboard */; }; 3706FCBC293F65D500E42796 /* dark-shield.json in Resources */ = {isa = PBXBuildFile; fileRef = AA34396F2754D4E900B241FA /* dark-shield.json */; }; 3706FCBD293F65D500E42796 /* dark-shield-mouse-over.json in Resources */ = {isa = PBXBuildFile; fileRef = AA7EB6EA27E880AE00036718 /* dark-shield-mouse-over.json */; }; 3706FCBE293F65D500E42796 /* autoconsent-bundle.js in Resources */ = {isa = PBXBuildFile; fileRef = B31055C327A1BA1D001AC618 /* autoconsent-bundle.js */; }; @@ -756,7 +729,6 @@ 3706FDDF293F661700E42796 /* BookmarkSidebarTreeControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292B22667103000AD2C21 /* BookmarkSidebarTreeControllerTests.swift */; }; 3706FDE0293F661700E42796 /* TabIndexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D2377B287EBDA300BCE03B /* TabIndexTests.swift */; }; 3706FDE1293F661700E42796 /* AdjacentItemEnumeratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534CA42811987D002621E7 /* AdjacentItemEnumeratorTests.swift */; }; - 3706FDE2293F661700E42796 /* PixelArgumentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44222616CABC00DD1EC2 /* PixelArgumentsTests.swift */; }; 3706FDE4293F661700E42796 /* TabLazyLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534C9D28104D9B002621E7 /* TabLazyLoaderTests.swift */; }; 3706FDE5293F661700E42796 /* URLEventHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85F1B0C825EF9759004792B6 /* URLEventHandlerTests.swift */; }; 3706FDE6293F661700E42796 /* BookmarkOutlineViewDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292B32667103000AD2C21 /* BookmarkOutlineViewDataSourceTests.swift */; }; @@ -802,14 +774,12 @@ 3706FE10293F661700E42796 /* TestNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA06E02913AEDB00225DE2 /* TestNavigationDelegate.swift */; }; 3706FE11293F661700E42796 /* URLSuggestedFilenameTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8553FF51257523760029327F /* URLSuggestedFilenameTests.swift */; }; 3706FE13293F661700E42796 /* ConfigurationStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3B4825DAC9BD00C7D2AA /* ConfigurationStorageTests.swift */; }; - 3706FE14293F661700E42796 /* DownloadListStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693956026F1C1BC0015B914 /* DownloadListStoreMock.swift */; }; 3706FE15293F661700E42796 /* PrivacyIconViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA91F83827076F1900771A0D /* PrivacyIconViewModelTests.swift */; }; 3706FE16293F661700E42796 /* CSVImporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723E0126B0003E00E14D75 /* CSVImporterTests.swift */; }; 3706FE19293F661700E42796 /* DeviceAuthenticatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBC16A427C488C900E00A38 /* DeviceAuthenticatorTests.swift */; }; 3706FE1A293F661700E42796 /* BrowserProfileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3F641D27A8D3BD00E0C118 /* BrowserProfileTests.swift */; }; 3706FE1B293F661700E42796 /* PermissionManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106B9F26A7BE0B0013B453 /* PermissionManagerTests.swift */; }; 3706FE1C293F661700E42796 /* ConnectBitwardenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B59CC8B290083240058F2F6 /* ConnectBitwardenViewModelTests.swift */; }; - 3706FE1D293F661700E42796 /* PixelStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B662D3D82755D7AD0035D4D6 /* PixelStoreTests.swift */; }; 3706FE1E293F661700E42796 /* GeolocationProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106BB426A809E60013B453 /* GeolocationProviderTests.swift */; }; 3706FE1F293F661700E42796 /* AppStateChangePublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A5A29F25B96E8300AA7ADA /* AppStateChangePublisherTests.swift */; }; 3706FE20293F661700E42796 /* CLLocationManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63ED0E226B3E7FA00A9DAD1 /* CLLocationManagerMock.swift */; }; @@ -851,7 +821,6 @@ 3706FE45293F661700E42796 /* ProgressEstimationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AE74332609AFCE005B9B1A /* ProgressEstimationTests.swift */; }; 3706FE46293F661700E42796 /* EncryptedValueTransformerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1A6FD258C5C1300F6F690 /* EncryptedValueTransformerTests.swift */; }; 3706FE47293F661700E42796 /* URLExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85F69B3B25EDE81F00978E59 /* URLExtensionTests.swift */; }; - 3706FE48293F661700E42796 /* PixelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44102616C0FC00DD1EC2 /* PixelTests.swift */; }; 3706FE49293F661700E42796 /* BookmarkNodePathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292B02667103000AD2C21 /* BookmarkNodePathTests.swift */; }; 3706FE4A293F661700E42796 /* BookmarkManagedObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292B62667103000AD2C21 /* BookmarkManagedObjectTests.swift */; }; 3706FE4B293F661700E42796 /* BookmarksHTMLImporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A1AB128451ED400586521 /* BookmarksHTMLImporterTests.swift */; }; @@ -978,16 +947,13 @@ 371D00E129D8509400EC8598 /* OpenSSL in Frameworks */ = {isa = PBXBuildFile; productRef = 371D00E029D8509400EC8598 /* OpenSSL */; }; 372217802B3337FE00B8E9C2 /* TestUtils in Frameworks */ = {isa = PBXBuildFile; productRef = 3722177F2B3337FE00B8E9C2 /* TestUtils */; }; 372217822B33380700B8E9C2 /* TestUtils in Frameworks */ = {isa = PBXBuildFile; productRef = 372217812B33380700B8E9C2 /* TestUtils */; }; - 372217842B33380E00B8E9C2 /* TestUtils in Frameworks */ = {isa = PBXBuildFile; productRef = 372217832B33380E00B8E9C2 /* TestUtils */; }; 37269EFB2B332F9E005E8E46 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 37269EFA2B332F9E005E8E46 /* Common */; }; 37269EFD2B332FAC005E8E46 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 37269EFC2B332FAC005E8E46 /* Common */; }; 37269EFF2B332FBB005E8E46 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 37269EFE2B332FBB005E8E46 /* Common */; }; 37269F012B332FC8005E8E46 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 37269F002B332FC8005E8E46 /* Common */; }; - 37269F032B332FD8005E8E46 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 37269F022B332FD8005E8E46 /* Common */; }; 37269F052B3332C2005E8E46 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 37269F042B3332C2005E8E46 /* Common */; }; 372A0FEC2B2379310033BF7F /* SyncMetricsEventsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372A0FEB2B2379310033BF7F /* SyncMetricsEventsHandler.swift */; }; 372A0FED2B2379310033BF7F /* SyncMetricsEventsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372A0FEB2B2379310033BF7F /* SyncMetricsEventsHandler.swift */; }; - 372A0FEE2B2379310033BF7F /* SyncMetricsEventsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372A0FEB2B2379310033BF7F /* SyncMetricsEventsHandler.swift */; }; 372BC2A12A4AFA47001D8FD5 /* SyncCredentialsAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372BC2A02A4AFA47001D8FD5 /* SyncCredentialsAdapter.swift */; }; 372BC2A22A4AFA47001D8FD5 /* SyncCredentialsAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372BC2A02A4AFA47001D8FD5 /* SyncCredentialsAdapter.swift */; }; 3739326529AE4B39009346AE /* DDGSync in Frameworks */ = {isa = PBXBuildFile; productRef = 3739326429AE4B39009346AE /* DDGSync */; }; @@ -998,9 +964,7 @@ 373A1AB228451ED400586521 /* BookmarksHTMLImporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A1AB128451ED400586521 /* BookmarksHTMLImporterTests.swift */; }; 373D9B4829EEAC1B00381FDD /* SyncMetadataDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373D9B4729EEAC1B00381FDD /* SyncMetadataDatabase.swift */; }; 373D9B4929EEAC1B00381FDD /* SyncMetadataDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373D9B4729EEAC1B00381FDD /* SyncMetadataDatabase.swift */; }; - 373FB4B12B4D6C42004C88D6 /* PreferencesViews in Frameworks */ = {isa = PBXBuildFile; productRef = 373FB4B02B4D6C42004C88D6 /* PreferencesViews */; }; 373FB4B32B4D6C4B004C88D6 /* PreferencesViews in Frameworks */ = {isa = PBXBuildFile; productRef = 373FB4B22B4D6C4B004C88D6 /* PreferencesViews */; }; - 373FB4B52B4D6C57004C88D6 /* PreferencesViews in Frameworks */ = {isa = PBXBuildFile; productRef = 373FB4B42B4D6C57004C88D6 /* PreferencesViews */; }; 37445F992A1566420029F789 /* SyncDataProviders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37445F982A1566420029F789 /* SyncDataProviders.swift */; }; 37445F9A2A1566420029F789 /* SyncDataProviders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37445F982A1566420029F789 /* SyncDataProviders.swift */; }; 37445F9C2A1569F00029F789 /* SyncBookmarksAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37445F9B2A1569F00029F789 /* SyncBookmarksAdapter.swift */; }; @@ -1021,7 +985,6 @@ 376E2D2629428353001CD31B /* PrivacyReferenceTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31E163BC293A579E00963C10 /* PrivacyReferenceTestHelper.swift */; }; 376E2D2729428353001CD31B /* BrokenSiteReportingReferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31E163B9293A56F400963C10 /* BrokenSiteReportingReferenceTests.swift */; }; 376E2D282942843D001CD31B /* privacy-reference-tests in Resources */ = {isa = PBXBuildFile; fileRef = 31E163BF293A581900963C10 /* privacy-reference-tests */; }; - 376E2D29294286B8001CD31B /* PixelEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC2621C293996410087A482 /* PixelEventTests.swift */; }; 37716D8029707E5D00A9FC6D /* FireproofingReferenceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 310E79BE294A19A8007C49E8 /* FireproofingReferenceTests.swift */; }; 3775912D29AAC72700E26367 /* SyncPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3775912C29AAC72700E26367 /* SyncPreferences.swift */; }; 3775912E29AAC72700E26367 /* SyncPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3775912C29AAC72700E26367 /* SyncPreferences.swift */; }; @@ -1030,7 +993,6 @@ 3776582D27F71652009A6B35 /* WebsiteBreakageReportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3776582C27F71652009A6B35 /* WebsiteBreakageReportTests.swift */; }; 3776582F27F82E62009A6B35 /* AutofillPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3776582E27F82E62009A6B35 /* AutofillPreferences.swift */; }; 3776583127F8325B009A6B35 /* AutofillPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3776583027F8325B009A6B35 /* AutofillPreferencesTests.swift */; }; - 3778183D2AD6F86D00533759 /* FavoritesDisplayModeSyncHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377D801B2AB47FBB002AF251 /* FavoritesDisplayModeSyncHandler.swift */; }; 377D801C2AB47FBB002AF251 /* FavoritesDisplayModeSyncHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377D801B2AB47FBB002AF251 /* FavoritesDisplayModeSyncHandler.swift */; }; 377D801F2AB48191002AF251 /* FavoritesDisplayModeSyncHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 377D801B2AB47FBB002AF251 /* FavoritesDisplayModeSyncHandler.swift */; }; 378205F62837CBA800D1D4AA /* SavedStateMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378205F52837CBA800D1D4AA /* SavedStateMock.swift */; }; @@ -1049,10 +1011,8 @@ 37A5E2F0298AA1B20047046B /* Persistence in Frameworks */ = {isa = PBXBuildFile; productRef = 37A5E2EF298AA1B20047046B /* Persistence */; }; 37A6A8F12AFCC988008580A3 /* FaviconsFetcherOnboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A6A8F02AFCC988008580A3 /* FaviconsFetcherOnboarding.swift */; }; 37A6A8F22AFCC988008580A3 /* FaviconsFetcherOnboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A6A8F02AFCC988008580A3 /* FaviconsFetcherOnboarding.swift */; }; - 37A6A8F42AFCC988008580A3 /* FaviconsFetcherOnboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A6A8F02AFCC988008580A3 /* FaviconsFetcherOnboarding.swift */; }; 37A6A8F62AFCCA59008580A3 /* FaviconsFetcherOnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A6A8F52AFCCA59008580A3 /* FaviconsFetcherOnboardingViewController.swift */; }; 37A6A8F72AFCCA59008580A3 /* FaviconsFetcherOnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A6A8F52AFCCA59008580A3 /* FaviconsFetcherOnboardingViewController.swift */; }; - 37A6A8F92AFCCA59008580A3 /* FaviconsFetcherOnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A6A8F52AFCCA59008580A3 /* FaviconsFetcherOnboardingViewController.swift */; }; 37A803DB27FD69D300052F4C /* DataImportResources in Resources */ = {isa = PBXBuildFile; fileRef = 37A803DA27FD69D300052F4C /* DataImportResources */; }; 37AFCE8127DA2CA600471A10 /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8027DA2CA600471A10 /* PreferencesViewController.swift */; }; 37AFCE8527DA2D3900471A10 /* PreferencesSidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8427DA2D3900471A10 /* PreferencesSidebar.swift */; }; @@ -1109,11 +1069,8 @@ 4B0511E1262CAA8600F6079C /* NSOpenPanelExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0511DF262CAA8600F6079C /* NSOpenPanelExtensions.swift */; }; 4B0511E2262CAA8600F6079C /* NSViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0511E0262CAA8600F6079C /* NSViewControllerExtension.swift */; }; 4B05265E2B1AE5C70054955A /* VPNMetadataCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B05265D2B1AE5C70054955A /* VPNMetadataCollector.swift */; }; - 4B05265F2B1AEFDB0054955A /* VPNMetadataCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B05265D2B1AE5C70054955A /* VPNMetadataCollector.swift */; }; 4B0526612B1D55320054955A /* VPNFeedbackSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0526602B1D55320054955A /* VPNFeedbackSender.swift */; }; - 4B0526622B1D55320054955A /* VPNFeedbackSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0526602B1D55320054955A /* VPNFeedbackSender.swift */; }; 4B0526642B1D55D80054955A /* VPNFeedbackCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0526632B1D55D80054955A /* VPNFeedbackCategory.swift */; }; - 4B0526652B1D55D80054955A /* VPNFeedbackCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0526632B1D55D80054955A /* VPNFeedbackCategory.swift */; }; 4B0A63E8289DB58E00378EF7 /* FirefoxFaviconsReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A63E7289DB58E00378EF7 /* FirefoxFaviconsReader.swift */; }; 4B0AACAC28BC63ED001038AC /* ChromiumFaviconsReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0AACAB28BC63ED001038AC /* ChromiumFaviconsReader.swift */; }; 4B0AACAE28BC6FD0001038AC /* SafariFaviconsReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0AACAD28BC6FD0001038AC /* SafariFaviconsReader.swift */; }; @@ -1122,7 +1079,6 @@ 4B0DB5E528BD9D08007DD239 /* PinningManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0DB5E428BD9D08007DD239 /* PinningManager.swift */; }; 4B0EF7262B578095009D6481 /* AppVersionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA71ED92B4B81E80002EBCE /* AppVersionExtension.swift */; }; 4B0EF7272B578096009D6481 /* AppVersionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA71ED92B4B81E80002EBCE /* AppVersionExtension.swift */; }; - 4B0EF7282B5780AB009D6481 /* AppVersionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA71ED92B4B81E80002EBCE /* AppVersionExtension.swift */; }; 4B0EF7292B5780EB009D6481 /* VPNAppEventsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8DB3192B504D7500EC16DA /* VPNAppEventsHandler.swift */; }; 4B11060525903E570039B979 /* CoreDataEncryptionTesting.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4B11060325903E570039B979 /* CoreDataEncryptionTesting.xcdatamodeld */; }; 4B11060A25903EAC0039B979 /* CoreDataEncryptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B11060925903EAC0039B979 /* CoreDataEncryptionTests.swift */; }; @@ -1136,16 +1092,20 @@ 4B1E6EEE27AB5E5100F51793 /* PasswordManagementListSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E6EEC27AB5E5100F51793 /* PasswordManagementListSection.swift */; }; 4B1E6EF127AB5E5D00F51793 /* NSPopUpButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E6EEF27AB5E5D00F51793 /* NSPopUpButtonView.swift */; }; 4B1E6EF227AB5E5D00F51793 /* PasswordManagementItemList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E6EF027AB5E5D00F51793 /* PasswordManagementItemList.swift */; }; + 4B1EFF1C2BD71EEF007CC84F /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4B1EFF1B2BD71EEF007CC84F /* PixelKit */; }; + 4B1EFF1D2BD71FCA007CC84F /* UserDefaultsWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C6A29525CC1FFD00EEB5F1 /* UserDefaultsWrapper.swift */; }; + 4B1EFF1E2BD72034007CC84F /* BundleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106B9D26A565DA0013B453 /* BundleExtension.swift */; }; + 4B1EFF1F2BD72170007CC84F /* OptionalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B637273C26CCF0C200C8CB02 /* OptionalExtension.swift */; }; + 4B1EFF212BD72189007CC84F /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 4B1EFF202BD72189007CC84F /* Networking */; }; + 4B1EFF222BD7223D007CC84F /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; 4B25375B2A11BE7300610219 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B4D603E2A0B290200BCD287 /* NetworkExtension.framework */; }; 4B2537722A11BF8B00610219 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B25376F2A11BF8B00610219 /* main.swift */; }; - 4B2537772A11BFE100610219 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4B2537762A11BFE100610219 /* PixelKit */; }; 4B25377A2A11C01700610219 /* UserText+NetworkProtectionExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D607C2A0B29FA00BCD287 /* UserText+NetworkProtectionExtensions.swift */; }; 4B29759728281F0900187C4E /* FirefoxEncryptionKeyReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B29759628281F0900187C4E /* FirefoxEncryptionKeyReader.swift */; }; 4B2975992828285900187C4E /* FirefoxKeyReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2975982828285900187C4E /* FirefoxKeyReaderTests.swift */; }; 4B2D06292A11C0C900DE1F49 /* Bundle+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605E2A0B29FA00BCD287 /* Bundle+VPN.swift */; }; 4B2D062A2A11C0C900DE1F49 /* NetworkProtectionOptionKeyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605F2A0B29FA00BCD287 /* NetworkProtectionOptionKeyExtension.swift */; }; 4B2D062C2A11C0E100DE1F49 /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 4B2D062B2A11C0E100DE1F49 /* Networking */; }; - 4B2D062D2A11C12300DE1F49 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85799C1725DEBB3F0007EC87 /* Logging.swift */; }; 4B2D06322A11C1D300DE1F49 /* NSApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C8F622591021700748EB7 /* NSApplicationExtension.swift */; }; 4B2D06332A11C1E300DE1F49 /* OptionalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B637273C26CCF0C200C8CB02 /* OptionalExtension.swift */; }; 4B2D065B2A11D1FF00DE1F49 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4BEC322A11B509001D9AC5 /* Logging.swift */; }; @@ -1155,7 +1115,6 @@ 4B2D067F2A1334D700DE1F49 /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4B2D067E2A1334D700DE1F49 /* NetworkProtectionUI */; }; 4B2E7D6326FF9D6500D2DB17 /* PrintingUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E7D6226FF9D6500D2DB17 /* PrintingUserScript.swift */; }; 4B2F565C2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2F565B2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift */; }; - 4B2F565D2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2F565B2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift */; }; 4B379C1527BD91E3008A968E /* QuartzIdleStateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C1427BD91E3008A968E /* QuartzIdleStateProvider.swift */; }; 4B379C1E27BDB7FF008A968E /* DeviceAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C1D27BDB7FF008A968E /* DeviceAuthenticator.swift */; }; 4B379C2227BDBA29008A968E /* LocalAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C2127BDBA29008A968E /* LocalAuthenticationService.swift */; }; @@ -1171,11 +1130,6 @@ 4B37EE762B4CFF3300A89A61 /* DataBrokerProtectionRemoteMessaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE672B4CFC9500A89A61 /* DataBrokerProtectionRemoteMessaging.swift */; }; 4B37EE772B4CFF3900A89A61 /* DataBrokerProtectionRemoteMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE662B4CFC9500A89A61 /* DataBrokerProtectionRemoteMessage.swift */; }; 4B37EE782B4CFF3900A89A61 /* DataBrokerProtectionRemoteMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE662B4CFC9500A89A61 /* DataBrokerProtectionRemoteMessage.swift */; }; - 4B37EE792B4CFF6F00A89A61 /* DataBrokerProtectionRemoteMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE662B4CFC9500A89A61 /* DataBrokerProtectionRemoteMessage.swift */; }; - 4B37EE7A2B4CFF7200A89A61 /* DataBrokerProtectionRemoteMessaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE672B4CFC9500A89A61 /* DataBrokerProtectionRemoteMessaging.swift */; }; - 4B37EE7B2B4CFF7C00A89A61 /* HomePageRemoteMessagingStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE5C2B4CFC3C00A89A61 /* HomePageRemoteMessagingStorage.swift */; }; - 4B37EE7C2B4CFF8000A89A61 /* HomePageRemoteMessagingRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE5E2B4CFC3C00A89A61 /* HomePageRemoteMessagingRequest.swift */; }; - 4B37EE7D2B4CFF8300A89A61 /* SurveyURLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE5D2B4CFC3C00A89A61 /* SurveyURLBuilder.swift */; }; 4B39AAF627D9B2C700A73FD5 /* NSStackViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B39AAF527D9B2C700A73FD5 /* NSStackViewExtension.swift */; }; 4B3B8490297A0E1000A384BD /* EmailManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3B848F297A0E1000A384BD /* EmailManagerExtension.swift */; }; 4B3F641E27A8D3BD00E0C118 /* BrowserProfileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3F641D27A8D3BD00E0C118 /* BrowserProfileTests.swift */; }; @@ -1185,10 +1139,8 @@ 4B41EDA12B15437A001EEDF4 /* NetworkProtectionNotificationsPresenterFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41ED9F2B15437A001EEDF4 /* NetworkProtectionNotificationsPresenterFactory.swift */; }; 4B41EDA32B1543B9001EEDF4 /* VPNPreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDA22B1543B9001EEDF4 /* VPNPreferencesModel.swift */; }; 4B41EDA42B1543B9001EEDF4 /* VPNPreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDA22B1543B9001EEDF4 /* VPNPreferencesModel.swift */; }; - 4B41EDA52B1543B9001EEDF4 /* VPNPreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDA22B1543B9001EEDF4 /* VPNPreferencesModel.swift */; }; 4B41EDA72B1543C9001EEDF4 /* PreferencesVPNView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDA62B1543C9001EEDF4 /* PreferencesVPNView.swift */; }; 4B41EDA82B1543C9001EEDF4 /* PreferencesVPNView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDA62B1543C9001EEDF4 /* PreferencesVPNView.swift */; }; - 4B41EDA92B1543C9001EEDF4 /* PreferencesVPNView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDA62B1543C9001EEDF4 /* PreferencesVPNView.swift */; }; 4B41EDAB2B1544B2001EEDF4 /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 4B41EDAA2B1544B2001EEDF4 /* LoginItems */; }; 4B41EDAE2B168AFF001EEDF4 /* VPNFeedbackFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDAD2B168AFF001EEDF4 /* VPNFeedbackFormViewController.swift */; }; 4B41EDAF2B168AFF001EEDF4 /* VPNFeedbackFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDAD2B168AFF001EEDF4 /* VPNFeedbackFormViewController.swift */; }; @@ -1196,14 +1148,10 @@ 4B41EDB22B168B1E001EEDF4 /* VPNFeedbackFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDB02B168B1E001EEDF4 /* VPNFeedbackFormView.swift */; }; 4B41EDB42B168C55001EEDF4 /* VPNFeedbackFormViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDB32B168C55001EEDF4 /* VPNFeedbackFormViewModel.swift */; }; 4B41EDB52B168C55001EEDF4 /* VPNFeedbackFormViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDB32B168C55001EEDF4 /* VPNFeedbackFormViewModel.swift */; }; - 4B41EDB62B169883001EEDF4 /* VPNFeedbackFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDAD2B168AFF001EEDF4 /* VPNFeedbackFormViewController.swift */; }; - 4B41EDB72B169887001EEDF4 /* VPNFeedbackFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDB02B168B1E001EEDF4 /* VPNFeedbackFormView.swift */; }; - 4B41EDB82B169889001EEDF4 /* VPNFeedbackFormViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B41EDB32B168C55001EEDF4 /* VPNFeedbackFormViewModel.swift */; }; 4B434690285ED7A100177407 /* BookmarksBarViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B43468F285ED7A100177407 /* BookmarksBarViewModelTests.swift */; }; 4B43469528655D1400177407 /* FirefoxDataImporterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B43469428655D1400177407 /* FirefoxDataImporterTests.swift */; }; 4B44FEF32B1FEF5A000619D8 /* FocusableTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B44FEF22B1FEF5A000619D8 /* FocusableTextEditor.swift */; }; 4B44FEF42B1FEF5A000619D8 /* FocusableTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B44FEF22B1FEF5A000619D8 /* FocusableTextEditor.swift */; }; - 4B44FEF52B1FEF5A000619D8 /* FocusableTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B44FEF22B1FEF5A000619D8 /* FocusableTextEditor.swift */; }; 4B4BEC3D2A11B56B001D9AC5 /* DuckDuckGoNotificationsAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4BEC382A11B509001D9AC5 /* DuckDuckGoNotificationsAppDelegate.swift */; }; 4B4BEC3E2A11B56E001D9AC5 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4BEC322A11B509001D9AC5 /* Logging.swift */; }; 4B4BEC412A11B5BD001D9AC5 /* NetworkProtectionUNNotificationsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60762A0B29FA00BCD287 /* NetworkProtectionUNNotificationsPresenter.swift */; }; @@ -1213,7 +1161,6 @@ 4B4BEC482A11B61F001D9AC5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4B4BEC342A11B509001D9AC5 /* Assets.xcassets */; }; 4B4D603F2A0B290200BCD287 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B4D603E2A0B290200BCD287 /* NetworkExtension.framework */; }; 4B4D60892A0B2A1C00BCD287 /* NetworkProtectionUNNotificationsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60762A0B29FA00BCD287 /* NetworkProtectionUNNotificationsPresenter.swift */; }; - 4B4D60982A0B2A5C00BCD287 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4B4D60972A0B2A5C00BCD287 /* PixelKit */; }; 4B4D609F2A0B2C7300BCD287 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85799C1725DEBB3F0007EC87 /* Logging.swift */; }; 4B4D60A02A0B2D5B00BCD287 /* Bundle+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605E2A0B29FA00BCD287 /* Bundle+VPN.swift */; }; 4B4D60A12A0B2D6100BCD287 /* NetworkProtectionOptionKeyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605F2A0B29FA00BCD287 /* NetworkProtectionOptionKeyExtension.swift */; }; @@ -1230,11 +1177,6 @@ 4B4D60C12A0C848E00BCD287 /* NetworkProtectionControllerErrorStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606A2A0B29FA00BCD287 /* NetworkProtectionControllerErrorStore.swift */; }; 4B4D60C22A0C849000BCD287 /* EventMapping+NetworkProtectionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60722A0B29FA00BCD287 /* EventMapping+NetworkProtectionError.swift */; }; 4B4D60C32A0C849100BCD287 /* EventMapping+NetworkProtectionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60722A0B29FA00BCD287 /* EventMapping+NetworkProtectionError.swift */; }; - 4B4D60C42A0C849600BCD287 /* NetworkProtectionInvitePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606F2A0B29FA00BCD287 /* NetworkProtectionInvitePresenter.swift */; }; - 4B4D60C62A0C849600BCD287 /* NetworkProtectionInviteCodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60702A0B29FA00BCD287 /* NetworkProtectionInviteCodeViewModel.swift */; }; - 4B4D60CA2A0C849600BCD287 /* NetworkProtectionInvitePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606F2A0B29FA00BCD287 /* NetworkProtectionInvitePresenter.swift */; }; - 4B4D60CC2A0C849600BCD287 /* NetworkProtectionInviteCodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60702A0B29FA00BCD287 /* NetworkProtectionInviteCodeViewModel.swift */; }; - 4B4D60CF2A0C849600BCD287 /* NetworkProtectionInviteDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606C2A0B29FA00BCD287 /* NetworkProtectionInviteDialog.swift */; }; 4B4D60D32A0C84F700BCD287 /* UserText+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60D22A0C84F700BCD287 /* UserText+NetworkProtection.swift */; }; 4B4D60D42A0C84F700BCD287 /* UserText+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60D22A0C84F700BCD287 /* UserText+NetworkProtection.swift */; }; 4B4D60DD2A0C875E00BCD287 /* NetworkProtectionOptionKeyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605F2A0B29FA00BCD287 /* NetworkProtectionOptionKeyExtension.swift */; }; @@ -1245,7 +1187,6 @@ 4B4F72EC266B2ED300814C60 /* CollectionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4F72EB266B2ED300814C60 /* CollectionExtension.swift */; }; 4B520F632BA5573A006405C7 /* WaitlistThankYouView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B520F622BA5573A006405C7 /* WaitlistThankYouView.swift */; }; 4B520F642BA5573A006405C7 /* WaitlistThankYouView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B520F622BA5573A006405C7 /* WaitlistThankYouView.swift */; }; - 4B520F652BA5573A006405C7 /* WaitlistThankYouView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B520F622BA5573A006405C7 /* WaitlistThankYouView.swift */; }; 4B59023E26B35F3600489384 /* ChromiumLoginReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B59023926B35F3600489384 /* ChromiumLoginReader.swift */; }; 4B59024026B35F3600489384 /* ChromiumDataImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B59023B26B35F3600489384 /* ChromiumDataImporter.swift */; }; 4B59024826B3673600489384 /* ThirdPartyBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B59024726B3673600489384 /* ThirdPartyBrowser.swift */; }; @@ -1258,16 +1199,12 @@ 4B677433255DBEB800025BD8 /* httpsMobileV2Bloom.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B677428255DBEB800025BD8 /* httpsMobileV2Bloom.bin */; }; 4B677435255DBEB800025BD8 /* httpsMobileV2FalsePositives.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B67742A255DBEB800025BD8 /* httpsMobileV2FalsePositives.json */; }; 4B677442255DBEEA00025BD8 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B677440255DBEEA00025BD8 /* Database.swift */; }; - 4B67853F2AA7C726008A5004 /* DailyPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B67853E2AA7C726008A5004 /* DailyPixel.swift */; }; - 4B6785402AA7C726008A5004 /* DailyPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B67853E2AA7C726008A5004 /* DailyPixel.swift */; }; 4B6785472AA8DE68008A5004 /* NetworkProtectionFeatureDisabler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6785432AA8DE1F008A5004 /* NetworkProtectionFeatureDisabler.swift */; }; 4B6785482AA8DE69008A5004 /* NetworkProtectionFeatureDisabler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6785432AA8DE1F008A5004 /* NetworkProtectionFeatureDisabler.swift */; }; 4B67854A2AA8DE75008A5004 /* NetworkProtectionFeatureVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD8679A2A9E9E000063B9F7 /* NetworkProtectionFeatureVisibility.swift */; }; 4B67854B2AA8DE76008A5004 /* NetworkProtectionFeatureVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD8679A2A9E9E000063B9F7 /* NetworkProtectionFeatureVisibility.swift */; }; - 4B68DDFF2ACBA14100FB0973 /* FileLineError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B696AFFA2AC5924800C93203 /* FileLineError.swift */; }; 4B6B64842BA930420009FF9F /* WaitlistThankYouPromptPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6B64832BA930420009FF9F /* WaitlistThankYouPromptPresenter.swift */; }; 4B6B64852BA930420009FF9F /* WaitlistThankYouPromptPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6B64832BA930420009FF9F /* WaitlistThankYouPromptPresenter.swift */; }; - 4B6B64862BA930420009FF9F /* WaitlistThankYouPromptPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6B64832BA930420009FF9F /* WaitlistThankYouPromptPresenter.swift */; }; 4B70C00127B0793D000386ED /* DuckDuckGo-ExampleCrash.ips in Resources */ = {isa = PBXBuildFile; fileRef = 4B70BFFF27B0793D000386ED /* DuckDuckGo-ExampleCrash.ips */; }; 4B70C00227B0793D000386ED /* CrashReportTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B70C00027B0793D000386ED /* CrashReportTests.swift */; }; 4B723E0526B0003E00E14D75 /* DataImportMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DFF26B0003E00E14D75 /* DataImportMocks.swift */; }; @@ -1282,11 +1219,8 @@ 4B723E1226B0006E00E14D75 /* DataImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DEB26B0002B00E14D75 /* DataImport.swift */; }; 4B723E1326B0007A00E14D75 /* CSVLoginExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DFD26B0002B00E14D75 /* CSVLoginExporter.swift */; }; 4B723E1926B000DC00E14D75 /* TemporaryFileCreator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723E1726B000DC00E14D75 /* TemporaryFileCreator.swift */; }; - 4B7534CC2A1FD7EA00158A99 /* NetworkProtectionInviteDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606C2A0B29FA00BCD287 /* NetworkProtectionInviteDialog.swift */; }; 4B7A57CF279A4EF300B1C70E /* ChromiumPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7A57CE279A4EF300B1C70E /* ChromiumPreferences.swift */; }; 4B7A60A1273E0BE400BBDFEB /* WKWebsiteDataStoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7A60A0273E0BE400BBDFEB /* WKWebsiteDataStoreExtension.swift */; }; - 4B81AD352B29512B00706C96 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = 4B81AD342B29512B00706C96 /* PixelKitTestingUtilities */; }; - 4B81AD372B29513100706C96 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = 4B81AD362B29513100706C96 /* PixelKitTestingUtilities */; }; 4B85A48028821CC500FC4C39 /* NSPasteboardItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B85A47F28821CC500FC4C39 /* NSPasteboardItemExtension.swift */; }; 4B8A4DFF27C83B29005F40E8 /* SaveIdentityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8A4DFE27C83B29005F40E8 /* SaveIdentityViewController.swift */; }; 4B8A4E0127C8447E005F40E8 /* SaveIdentityPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8A4E0027C8447E005F40E8 /* SaveIdentityPopover.swift */; }; @@ -1331,692 +1265,6 @@ 4B9292DB2667125D00AD2C21 /* ContextualMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292DA2667125D00AD2C21 /* ContextualMenu.swift */; }; 4B9579212AC687170062CA31 /* HardwareModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9579202AC687170062CA31 /* HardwareModel.swift */; }; 4B9579222AC687170062CA31 /* HardwareModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9579202AC687170062CA31 /* HardwareModel.swift */; }; - 4B9579462AC7AE700062CA31 /* FaviconUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA0CC562539EBC90079BC96 /* FaviconUserScript.swift */; }; - 4B9579472AC7AE700062CA31 /* BWResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF076128F815AD00EDFBE3 /* BWResponse.swift */; }; - 4B9579482AC7AE700062CA31 /* LottieAnimationCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AADCBF3926F7C2CE00EF67A8 /* LottieAnimationCache.swift */; }; - 4B9579492AC7AE700062CA31 /* WaitlistDialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0182A983B24000927DB /* WaitlistDialogView.swift */; }; - 4B95794A2AC7AE700062CA31 /* TabIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D23779287EB8CA00BCE03B /* TabIndex.swift */; }; - 4B95794B2AC7AE700062CA31 /* SavePanelAccessoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60C6F8C29B200AB007BFAA8 /* SavePanelAccessoryView.swift */; }; - 4B95794C2AC7AE700062CA31 /* TabLazyLoaderDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534CA2281132CB002621E7 /* TabLazyLoaderDataSource.swift */; }; - 4B95794D2AC7AE700062CA31 /* LoginImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DF426B0002B00E14D75 /* LoginImport.swift */; }; - 4B95794E2AC7AE700062CA31 /* JoinWaitlistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0172A983B24000927DB /* JoinWaitlistView.swift */; }; - 4B95794F2AC7AE700062CA31 /* LazyLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534C9F28113101002621E7 /* LazyLoadable.swift */; }; - 4B9579502AC7AE700062CA31 /* ClickToLoadModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE427FF275D47FA00DAC26B /* ClickToLoadModel.swift */; }; - 4B9579512AC7AE700062CA31 /* KeyedCodingExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0230C0A2272080090018F728 /* KeyedCodingExtension.swift */; }; - 4B9579522AC7AE700062CA31 /* PrivacyDashboardTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BF5D842946FFDA006742B1 /* PrivacyDashboardTabExtension.swift */; }; - 4B9579542AC7AE700062CA31 /* DownloadListStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0B22F26E61D630031CB7F /* DownloadListStore.swift */; }; - 4B9579552AC7AE700062CA31 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85799C1725DEBB3F0007EC87 /* Logging.swift */; }; - 4B9579562AC7AE700062CA31 /* CrashReportPromptPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A2D268F1EE300D2D9CD /* CrashReportPromptPresenter.swift */; }; - 4B9579572AC7AE700062CA31 /* BWCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF075C28F815AD00EDFBE3 /* BWCredential.swift */; }; - 4B9579582AC7AE700062CA31 /* PreferencesRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8627DA334800471A10 /* PreferencesRootView.swift */; }; - 4B9579592AC7AE700062CA31 /* AppStateChangedPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B684590725C9027900DC17B6 /* AppStateChangedPublisher.swift */; }; - 4B95795A2AC7AE700062CA31 /* BookmarkTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92928926670D1700AD2C21 /* BookmarkTableCellView.swift */; }; - 4B95795B2AC7AE700062CA31 /* BookmarkManagementSidebarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292C72667123700AD2C21 /* BookmarkManagementSidebarViewController.swift */; }; - 4B95795C2AC7AE700062CA31 /* NSStackViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B39AAF527D9B2C700A73FD5 /* NSStackViewExtension.swift */; }; - 4B95795D2AC7AE700062CA31 /* OptionalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B637273C26CCF0C200C8CB02 /* OptionalExtension.swift */; }; - 4B95795E2AC7AE700062CA31 /* PasswordManagementLoginItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE65471271FCD40008D1D63 /* PasswordManagementLoginItemView.swift */; }; - 4B95795F2AC7AE700062CA31 /* UserText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA80EC53256BE3BC007083E7 /* UserText.swift */; }; - 4B9579602AC7AE700062CA31 /* WKWebView+Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = B61EF3EB266F91E700B4D78F /* WKWebView+Download.swift */; }; - 4B9579612AC7AE700062CA31 /* TabShadowConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 311B262628E73E0A00FD181A /* TabShadowConfig.swift */; }; - 4B9579622AC7AE700062CA31 /* URLSessionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DB3AEE278D5C370024C5C4 /* URLSessionExtension.swift */; }; - 4B9579632AC7AE700062CA31 /* WKWebsiteDataStoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7A60A0273E0BE400BBDFEB /* WKWebsiteDataStoreExtension.swift */; }; - 4B9579642AC7AE700062CA31 /* WindowDraggingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693954526F04BEA0015B914 /* WindowDraggingView.swift */; }; - 4B9579652AC7AE700062CA31 /* SecureVaultSorting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E6EEB27AB5E5100F51793 /* SecureVaultSorting.swift */; }; - 4B9579662AC7AE700062CA31 /* PreferencesSidebarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C627F2FDD100F1F7B9 /* PreferencesSidebarModel.swift */; }; - 4B9579672AC7AE700062CA31 /* DuckPlayerURLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3767190128E724B2003A2A15 /* DuckPlayerURLExtension.swift */; }; - 4B9579682AC7AE700062CA31 /* BWEncryptionOutput.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D43EB31292788C70065E5D6 /* BWEncryptionOutput.m */; }; - 4B9579692AC7AE700062CA31 /* PermissionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106BAC26A7BF390013B453 /* PermissionState.swift */; }; - 4B95796A2AC7AE700062CA31 /* FeedbackPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371C0A2827E33EDC0070591F /* FeedbackPresenter.swift */; }; - 4B95796B2AC7AE700062CA31 /* NavigationProtectionTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66260DC29AC5D4300E9E3EE /* NavigationProtectionTabExtension.swift */; }; - 4B95796C2AC7AE700062CA31 /* BurnerMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D1A33482A6FEB170080ACED /* BurnerMode.swift */; }; - 4B95796D2AC7AE700062CA31 /* UserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14505A07256084EF00272CC6 /* UserAgent.swift */; }; - 4B95796E2AC7AE700062CA31 /* LegacyBookmarkStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 987799EF2999993C005D8EB6 /* LegacyBookmarkStore.swift */; }; - 4B95796F2AC7AE700062CA31 /* NSAlert+DataImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8AC93426B3B2FD00879451 /* NSAlert+DataImport.swift */; }; - 4B9579702AC7AE700062CA31 /* MainWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7412BC24D2BEEE00D22FE0 /* MainWindow.swift */; }; - 4B9579712AC7AE700062CA31 /* CrashReportPromptViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD6D8862696DF6D002393B3 /* CrashReportPromptViewController.swift */; }; - 4B9579722AC7AE700062CA31 /* BookmarksCleanupErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379E877529E98729001C8BB0 /* BookmarksCleanupErrorHandling.swift */; }; - 4B9579732AC7AE700062CA31 /* ContextMenuManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA06E32913ECEE00225DE2 /* ContextMenuManager.swift */; }; - 4B9579742AC7AE700062CA31 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693954326F04BE90015B914 /* GradientView.swift */; }; - 4B9579752AC7AE700062CA31 /* PreferencesSidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8427DA2D3900471A10 /* PreferencesSidebar.swift */; }; - 4B9579762AC7AE700062CA31 /* HoveredLinkTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C00ED4292FB21E009C73A6 /* HoveredLinkTabExtension.swift */; }; - 4B9579772AC7AE700062CA31 /* NSPointExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C8F5D2590EEE800748EB7 /* NSPointExtension.swift */; }; - 4B9579782AC7AE700062CA31 /* WindowsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6EF9AC25066F42004754E6 /* WindowsManager.swift */; }; - 4B9579792AC7AE700062CA31 /* BWRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D43EB39292B63B00065E5D6 /* BWRequest.swift */; }; - 4B95797A2AC7AE700062CA31 /* WKWebViewConfigurationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68458CC25C7EB9000DC17B6 /* WKWebViewConfigurationExtensions.swift */; }; - 4B95797B2AC7AE700062CA31 /* HomePageDefaultBrowserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC7ADC27BEB6EE00FFB69B /* HomePageDefaultBrowserModel.swift */; }; - 4B95797C2AC7AE700062CA31 /* CrashReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A25268DFEE200D2D9CD /* CrashReporter.swift */; }; - 4B95797D2AC7AE700062CA31 /* AddressBarTextSelectionNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60D64482AAF1B7C00B26F50 /* AddressBarTextSelectionNavigation.swift */; }; - 4B95797E2AC7AE700062CA31 /* BadgeNotificationAnimationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3184AC6C288F29D800C35E4B /* BadgeNotificationAnimationModel.swift */; }; - 4B95797F2AC7AE700062CA31 /* HyperLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 857FFEBF27D239DC00415E7A /* HyperLink.swift */; }; - 4B9579802AC7AE700062CA31 /* SyncDataProviders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37445F982A1566420029F789 /* SyncDataProviders.swift */; }; - 4B9579812AC7AE700062CA31 /* PasteboardWriting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929A26670D2A00AD2C21 /* PasteboardWriting.swift */; }; - 4B9579822AC7AE700062CA31 /* BookmarkOutlineCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92928726670D1600AD2C21 /* BookmarkOutlineCellView.swift */; }; - 4B9579832AC7AE700062CA31 /* UnprotectedDomains.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B604085A274B8CA300680351 /* UnprotectedDomains.xcdatamodeld */; }; - 4B9579842AC7AE700062CA31 /* TabInstrumentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB88B4F25B7BA2B006F6B06 /* TabInstrumentation.swift */; }; - 4B9579872AC7AE700062CA31 /* ConfigurationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D33F1125C82EB3002B91A6 /* ConfigurationManager.swift */; }; - 4B9579882AC7AE700062CA31 /* YoutubePlayerUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F28C4C28C8EEC500119F70 /* YoutubePlayerUserScript.swift */; }; - 4B9579892AC7AE700062CA31 /* PixelParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E48326146AAB0067D1B9 /* PixelParameters.swift */; }; - 4B95798B2AC7AE700062CA31 /* FaviconImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5FA696275F90C400DCE9C9 /* FaviconImageCache.swift */; }; - 4B95798C2AC7AE700062CA31 /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1430DFF424D0580F00B8978C /* TabBarViewController.swift */; }; - 4B95798D2AC7AE700062CA31 /* BookmarkOutlineViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929126670D2A00AD2C21 /* BookmarkOutlineViewDataSource.swift */; }; - 4B95798E2AC7AE700062CA31 /* DataImportStatusProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56D145EA29E6C99B00E3488A /* DataImportStatusProviding.swift */; }; - 4B95798F2AC7AE700062CA31 /* PasswordManagementBitwardenItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D5375B291D944100407A95 /* PasswordManagementBitwardenItemView.swift */; }; - 4B9579912AC7AE700062CA31 /* NSNotificationName+PasswordManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D885AF26A590A90077C374 /* NSNotificationName+PasswordManager.swift */; }; - 4B9579922AC7AE700062CA31 /* RulesCompilationMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B610F2BA27A145C500FCEBE9 /* RulesCompilationMonitor.swift */; }; - 4B9579932AC7AE700062CA31 /* FBProtectionTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D574B329472253008ED1B6 /* FBProtectionTabExtension.swift */; }; - 4B9579942AC7AE700062CA31 /* CrashReportReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A27268E045400D2D9CD /* CrashReportReader.swift */; }; - 4B9579952AC7AE700062CA31 /* DataTaskProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3B3425DA82A600C7D2AA /* DataTaskProviding.swift */; }; - 4B9579962AC7AE700062CA31 /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = EECE10E429DD77E60044D027 /* FeatureFlag.swift */; }; - 4B9579972AC7AE700062CA31 /* FeedbackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA3D531627A1EEED00074EC1 /* FeedbackViewController.swift */; }; - 4B9579982AC7AE700062CA31 /* FaviconSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAEF6BC7276A081C0024DCF4 /* FaviconSelector.swift */; }; - 4B95799A2AC7AE700062CA31 /* PrintingUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E7D6226FF9D6500D2DB17 /* PrintingUserScript.swift */; }; - 4B95799B2AC7AE700062CA31 /* ConnectBitwardenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBDEE9028FC14760092FAA6 /* ConnectBitwardenViewController.swift */; }; - 4B95799C2AC7AE700062CA31 /* BWManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF075E28F815AD00EDFBE3 /* BWManager.swift */; }; - 4B95799D2AC7AE700062CA31 /* AppTrackerDataSetProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9833912E27AAA3CE00DAF119 /* AppTrackerDataSetProvider.swift */; }; - 4B95799E2AC7AE700062CA31 /* EncryptionKeyGeneration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1A6B2258B080A00F6F690 /* EncryptionKeyGeneration.swift */; }; - 4B95799F2AC7AE700062CA31 /* TabLazyLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B11B3828095E6600CBB621 /* TabLazyLoader.swift */; }; - 4B9579A02AC7AE700062CA31 /* InvitedToWaitlistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0162A983B24000927DB /* InvitedToWaitlistView.swift */; }; - 4B9579A22AC7AE700062CA31 /* SaveCredentialsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8589063B267BCDC000D23B0D /* SaveCredentialsViewController.swift */; }; - 4B9579A32AC7AE700062CA31 /* PopUpButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBE0AA627B9B027003B37A8 /* PopUpButton.swift */; }; - 4B9579A42AC7AE700062CA31 /* NetworkProtectionInviteDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606C2A0B29FA00BCD287 /* NetworkProtectionInviteDialog.swift */; }; - 4B9579A52AC7AE700062CA31 /* SuggestionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABEE6A424AA0A7F0043105B /* SuggestionViewController.swift */; }; - 4B9579A82AC7AE700062CA31 /* BWKeyStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6216B129069BBF00386B2C /* BWKeyStorage.swift */; }; - 4B9579A92AC7AE700062CA31 /* VisitViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7E919E287872EA00AB6B62 /* VisitViewModel.swift */; }; - 4B9579AA2AC7AE700062CA31 /* AddressBarTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6676BE02AA986A700525A21 /* AddressBarTextEditor.swift */; }; - 4B9579AB2AC7AE700062CA31 /* Atb.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50352726A11F00758A2B /* Atb.swift */; }; - 4B9579AC2AC7AE700062CA31 /* BrowserTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0BB6929AF1C7000AE8E3C /* BrowserTabView.swift */; }; - 4B9579AD2AC7AE700062CA31 /* DownloadsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E87F26D5DA9B0062C350 /* DownloadsViewController.swift */; }; - 4B9579AE2AC7AE700062CA31 /* DataExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3AF625D5DBFD00C7D2AA /* DataExtension.swift */; }; - 4B9579AF2AC7AE700062CA31 /* ConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85480FCE25D1AA22009424E3 /* ConfigurationStore.swift */; }; - 4B9579B02AC7AE700062CA31 /* Feedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA3D531A27A2F57E00074EC1 /* Feedback.swift */; }; - 4B9579B22AC7AE700062CA31 /* FirefoxFaviconsReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0A63E7289DB58E00378EF7 /* FirefoxFaviconsReader.swift */; }; - 4B9579B32AC7AE700062CA31 /* CopyHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858A798226A8B75F00A75A42 /* CopyHandler.swift */; }; - 4B9579B42AC7AE700062CA31 /* ContentBlockingRulesUpdateObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7E2E8F29029A2A00C01B54 /* ContentBlockingRulesUpdateObserver.swift */; }; - 4B9579B52AC7AE700062CA31 /* FirefoxLoginReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8AC93826B48A5100879451 /* FirefoxLoginReader.swift */; }; - 4B9579B62AC7AE700062CA31 /* AtbParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50382726A12400758A2B /* AtbParser.swift */; }; - 4B9579B72AC7AE700062CA31 /* PreferencesDuckPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F19A6428E1B3FB00740DC6 /* PreferencesDuckPlayerView.swift */; }; - 4B9579B92AC7AE700062CA31 /* BookmarkSidebarTreeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929426670D2A00AD2C21 /* BookmarkSidebarTreeController.swift */; }; - 4B9579BA2AC7AE700062CA31 /* HomePageFavoritesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E8627BBB8F20038AD11 /* HomePageFavoritesModel.swift */; }; - 4B9579BB2AC7AE700062CA31 /* SequenceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB88B4925B7B690006F6B06 /* SequenceExtensions.swift */; }; - 4B9579BC2AC7AE700062CA31 /* WKBackForwardListExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B602E7CE2A93A5FF00F12201 /* WKBackForwardListExtension.swift */; }; - 4B9579BD2AC7AE700062CA31 /* ChromiumDataImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B59023B26B35F3600489384 /* ChromiumDataImporter.swift */; }; - 4B9579BE2AC7AE700062CA31 /* BackForwardListItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA0CC3B25337FAB0079BC96 /* BackForwardListItemViewModel.swift */; }; - 4B9579BF2AC7AE700062CA31 /* BWNotRespondingAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D43EB3329297D760065E5D6 /* BWNotRespondingAlert.swift */; }; - 4B9579C02AC7AE700062CA31 /* DebugUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB88B4425B7B55C006F6B06 /* DebugUserScript.swift */; }; - 4B9579C12AC7AE700062CA31 /* RecentlyClosedTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC6881828626BF800D54247 /* RecentlyClosedTab.swift */; }; - 4B9579C22AC7AE700062CA31 /* PDFSearchTextMenuItemHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B688B4DE27420D290087BEAF /* PDFSearchTextMenuItemHandler.swift */; }; - 4B9579C42AC7AE700062CA31 /* HistoryMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7E919628746BCC00AB6B62 /* HistoryMenu.swift */; }; - 4B9579C52AC7AE700062CA31 /* ContentScopeFeatureFlagging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4A6198B283CFFBB007F2080 /* ContentScopeFeatureFlagging.swift */; }; - 4B9579C62AC7AE700062CA31 /* OnboardingButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85707F23276A332A00DC0649 /* OnboardingButtonStyles.swift */; }; - 4B9579C72AC7AE700062CA31 /* SaveIdentityPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8A4E0027C8447E005F40E8 /* SaveIdentityPopover.swift */; }; - 4B9579C82AC7AE700062CA31 /* AuthenticationAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = B637273A26CBC8AF00C8CB02 /* AuthenticationAlert.swift */; }; - 4B9579C92AC7AE700062CA31 /* SetExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DFAB51C2A8982A600A0F7F6 /* SetExtension.swift */; }; - 4B9579CA2AC7AE700062CA31 /* YoutubePlayerNavigationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315AA06F28CA5CC800200030 /* YoutubePlayerNavigationHandler.swift */; }; - 4B9579CB2AC7AE700062CA31 /* PreferencesAboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE9127DB8CAD00471A10 /* PreferencesAboutView.swift */; }; - 4B9579CC2AC7AE700062CA31 /* ContentBlocking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9826B09F2747DF3D0092F683 /* ContentBlocking.swift */; }; - 4B9579CD2AC7AE700062CA31 /* LocalAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C2127BDBA29008A968E /* LocalAuthenticationService.swift */; }; - 4B9579CE2AC7AE700062CA31 /* CredentialsCleanupErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CEFCA82A6737A2001EF741 /* CredentialsCleanupErrorHandling.swift */; }; - 4B9579CF2AC7AE700062CA31 /* SafariBookmarksReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CFC26FE191E001E4761 /* SafariBookmarksReader.swift */; }; - 4B9579D02AC7AE700062CA31 /* HTTPCookie.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA6D0FC2A1FF9A100540406 /* HTTPCookie.swift */; }; - 4B9579D12AC7AE700062CA31 /* SafariVersionReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = AACF6FD526BC366D00CF09F9 /* SafariVersionReader.swift */; }; - 4B9579D22AC7AE700062CA31 /* LoginFaviconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE65484271FCD7B008D1D63 /* LoginFaviconView.swift */; }; - 4B9579D32AC7AE700062CA31 /* FireproofDomainsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0511B4262CAA5A00F6079C /* FireproofDomainsViewController.swift */; }; - 4B9579D42AC7AE700062CA31 /* URLEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA4D700625545EF800C3411E /* URLEventHandler.swift */; }; - 4B9579D52AC7AE700062CA31 /* SupportedOsChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8057C72A83CAEE00F4FED6 /* SupportedOsChecker.swift */; }; - 4B9579D62AC7AE700062CA31 /* WKWebViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA92127625ADA07900600CD4 /* WKWebViewExtension.swift */; }; - 4B9579D72AC7AE700062CA31 /* CleanThisHistoryMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAAB9113288EB1D600A057A9 /* CleanThisHistoryMenuItem.swift */; }; - 4B9579D92AC7AE700062CA31 /* DownloadListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0B23526E732000031CB7F /* DownloadListItem.swift */; }; - 4B9579DA2AC7AE700062CA31 /* WaitlistRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB00A2A983B24000927DB /* WaitlistRequest.swift */; }; - 4B9579DB2AC7AE700062CA31 /* DownloadsPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E87D26D5DA0E0062C350 /* DownloadsPopover.swift */; }; - 4B9579DC2AC7AE700062CA31 /* BookmarksBarMenuFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85774AFE2A713D3B00DE0561 /* BookmarksBarMenuFactory.swift */; }; - 4B9579DD2AC7AE700062CA31 /* SpacerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929626670D2A00AD2C21 /* SpacerNode.swift */; }; - 4B9579DF2AC7AE700062CA31 /* SyncManagementDialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3775913529AB9A1C00E26367 /* SyncManagementDialogViewController.swift */; }; - 4B9579E02AC7AE700062CA31 /* BookmarkExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0BB6629AEFF8100AE8E3C /* BookmarkExtension.swift */; }; - 4B9579E12AC7AE700062CA31 /* PasswordManagementCreditCardModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE6547B271FCD4D008D1D63 /* PasswordManagementCreditCardModel.swift */; }; - 4B9579E22AC7AE700062CA31 /* NSEventExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31B4AF522901A4F20013585E /* NSEventExtension.swift */; }; - 4B9579E32AC7AE700062CA31 /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85707F25276A335700DC0649 /* Onboarding.swift */; }; - 4B9579E42AC7AE700062CA31 /* PopUpWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C92C0274E3EF4002AC6B0 /* PopUpWindow.swift */; }; - 4B9579E52AC7AE700062CA31 /* Favicons.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = AA5FA69E275F948900DCE9C9 /* Favicons.xcdatamodeld */; }; - 4B9579E62AC7AE700062CA31 /* Publisher.asVoid.swift in Sources */ = {isa = PBXBuildFile; fileRef = B684592125C93BE000DC17B6 /* Publisher.asVoid.swift */; }; - 4B9579E72AC7AE700062CA31 /* Waitlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0072A983B23000927DB /* Waitlist.swift */; }; - 4B9579E82AC7AE700062CA31 /* NavigationButtonMenuDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA0CC32252F181A0079BC96 /* NavigationButtonMenuDelegate.swift */; }; - 4B9579E92AC7AE700062CA31 /* CrashReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A29268E239100D2D9CD /* CrashReport.swift */; }; - 4B9579EA2AC7AE700062CA31 /* NSPopoverExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6A491F29CF7A490011DF74 /* NSPopoverExtension.swift */; }; - 4B9579EB2AC7AE700062CA31 /* NSPathControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CC53F327E8D4620028713D /* NSPathControlView.swift */; }; - 4B9579EC2AC7AE700062CA31 /* HTTPSUpgradeTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BF5D8829470BC4006742B1 /* HTTPSUpgradeTabExtension.swift */; }; - 4B9579ED2AC7AE700062CA31 /* AppIconChanger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D36E65A298ACD2900AA485D /* AppIconChanger.swift */; }; - 4B9579EE2AC7AE700062CA31 /* AppMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60E12A0C883A00BCD287 /* AppMain.swift */; }; - 4B9579EF2AC7AE700062CA31 /* ProductWaitlistRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0092A983B23000927DB /* ProductWaitlistRequest.swift */; }; - 4B9579F02AC7AE700062CA31 /* Bookmark.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 987799FC29999B64005D8EB6 /* Bookmark.xcdatamodeld */; }; - 4B9579F12AC7AE700062CA31 /* DefaultBrowserPromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E9D27BFE4500038AD11 /* DefaultBrowserPromptView.swift */; }; - 4B9579F22AC7AE700062CA31 /* WaitlistActivationDateStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4032832AAAC24400CCA602 /* WaitlistActivationDateStore.swift */; }; - 4B9579F42AC7AE700062CA31 /* FaviconManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA512D1324D99D9800230283 /* FaviconManager.swift */; }; - 4B9579F52AC7AE700062CA31 /* PFMoveApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BB108582A43375D000AB95F /* PFMoveApplication.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 4B9579F62AC7AE700062CA31 /* ChromiumFaviconsReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0AACAB28BC63ED001038AC /* ChromiumFaviconsReader.swift */; }; - 4B9579F72AC7AE700062CA31 /* SuggestionTableRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABEE6AA24ACA0F90043105B /* SuggestionTableRowView.swift */; }; - 4B9579F82AC7AE700062CA31 /* DownloadsPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C327F2FDD100F1F7B9 /* DownloadsPreferences.swift */; }; - 4B9579F92AC7AE700062CA31 /* PasswordManagementItemList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E6EF027AB5E5D00F51793 /* PasswordManagementItemList.swift */; }; - 4B9579FA2AC7AE700062CA31 /* Bookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4CD25D6A709007F5990 /* Bookmark.swift */; }; - 4B9579FB2AC7AE700062CA31 /* ConnectBitwardenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBDEE8F28FC14760092FAA6 /* ConnectBitwardenViewModel.swift */; }; - 4B9579FC2AC7AE700062CA31 /* NSNotificationName+DataImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5A4F4B27F3A5AA008FBD88 /* NSNotificationName+DataImport.swift */; }; - 4B9579FD2AC7AE700062CA31 /* StoredPermission.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64C853726944B880048FEBE /* StoredPermission.swift */; }; - 4B9579FE2AC7AE700062CA31 /* FirePopoverCollectionViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE246F7270A406200BEEAEE /* FirePopoverCollectionViewHeader.swift */; }; - 4B9579FF2AC7AE700062CA31 /* FireViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB7320826DD0CD9002FACF9 /* FireViewController.swift */; }; - 4B957A002AC7AE700062CA31 /* OutlineSeparatorViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92928626670D1600AD2C21 /* OutlineSeparatorViewCell.swift */; }; - 4B957A012AC7AE700062CA31 /* SafariDataImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CFD26FE191E001E4761 /* SafariDataImporter.swift */; }; - 4B957A022AC7AE700062CA31 /* WaitlistViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB00C2A983B24000927DB /* WaitlistViewModel.swift */; }; - 4B957A032AC7AE700062CA31 /* LocalBookmarkStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 987799F829999973005D8EB6 /* LocalBookmarkStore.swift */; }; - 4B957A042AC7AE700062CA31 /* BWEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D02633528D8A9A9005CBB41 /* BWEncryption.m */; settings = {COMPILER_FLAGS = "-Wno-deprecated -Wno-strict-prototypes"; }; }; - 4B957A052AC7AE700062CA31 /* StatisticsLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50342726A11F00758A2B /* StatisticsLoader.swift */; }; - 4B957A072AC7AE700062CA31 /* DataClearingPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C127F2FDD100F1F7B9 /* DataClearingPreferences.swift */; }; - 4B957A082AC7AE700062CA31 /* LocalUnprotectedDomains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 336B39E22726B4B700C417D3 /* LocalUnprotectedDomains.swift */; }; - 4B957A092AC7AE700062CA31 /* InternalUserDeciderStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D36E657298AA3BA00AA485D /* InternalUserDeciderStore.swift */; }; - 4B957A0A2AC7AE700062CA31 /* NewWindowPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B634DBE4293C944700C3C99E /* NewWindowPolicy.swift */; }; - 4B957A0B2AC7AE700062CA31 /* NavigationBarBadgeAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31CF3431288B0B1B0087244B /* NavigationBarBadgeAnimator.swift */; }; - 4B957A0C2AC7AE700062CA31 /* NSTextViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858A798426A8BB5D00A75A42 /* NSTextViewExtension.swift */; }; - 4B957A0D2AC7AE700062CA31 /* FutureExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B634DBE6293C98C500C3C99E /* FutureExtension.swift */; }; - 4B957A0E2AC7AE700062CA31 /* UserDialogRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B634DBE2293C8FFF00C3C99E /* UserDialogRequest.swift */; }; - 4B957A0F2AC7AE700062CA31 /* DownloadsCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E88326D5EB570062C350 /* DownloadsCellView.swift */; }; - 4B957A112AC7AE700062CA31 /* PublishedAfter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AAAC2C260330580029438D /* PublishedAfter.swift */; }; - 4B957A122AC7AE700062CA31 /* FirefoxBerkeleyDatabaseReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3701C9CD29BD040900305B15 /* FirefoxBerkeleyDatabaseReader.swift */; }; - 4B957A132AC7AE700062CA31 /* WebViewSnapshotView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37054FCD2876472D00033B6F /* WebViewSnapshotView.swift */; }; - 4B957A142AC7AE700062CA31 /* DeviceAuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBC169F27C4859400E00A38 /* DeviceAuthenticationService.swift */; }; - 4B957A152AC7AE700062CA31 /* AppConfigurationURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */; }; - 4B957A162AC7AE700062CA31 /* SyncSettingsAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CBCA992A8966E60050218F /* SyncSettingsAdapter.swift */; }; - 4B957A172AC7AE700062CA31 /* AutofillPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3776582E27F82E62009A6B35 /* AutofillPreferences.swift */; }; - 4B957A192AC7AE700062CA31 /* PasswordManagerCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D074B262909A433006E4AC3 /* PasswordManagerCoordinator.swift */; }; - 4B957A1A2AC7AE700062CA31 /* PasswordManagementIdentityModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE6547A271FCD4D008D1D63 /* PasswordManagementIdentityModel.swift */; }; - 4B957A1B2AC7AE700062CA31 /* UserDefaultsWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C6A29525CC1FFD00EEB5F1 /* UserDefaultsWrapper.swift */; }; - 4B957A1C2AC7AE700062CA31 /* PasswordManagementPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85625997269C9C5F00EE44BC /* PasswordManagementPopover.swift */; }; - 4B957A1D2AC7AE700062CA31 /* BWCommunicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF075D28F815AD00EDFBE3 /* BWCommunicator.swift */; }; - 4B957A1E2AC7AE700062CA31 /* HomePageRecentlyVisitedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E9027BFB9810038AD11 /* HomePageRecentlyVisitedModel.swift */; }; - 4B957A1F2AC7AE700062CA31 /* NavigationBarPopovers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85012B0129133F9F003D0DCC /* NavigationBarPopovers.swift */; }; - 4B957A202AC7AE700062CA31 /* CancellableExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B626A75F2992407C00053070 /* CancellableExtension.swift */; }; - 4B957A212AC7AE700062CA31 /* PinnedTabsHostingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D23783287F4D6A00BCE03B /* PinnedTabsHostingView.swift */; }; - 4B957A222AC7AE700062CA31 /* FirefoxBookmarksReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CF526FE191E001E4761 /* FirefoxBookmarksReader.swift */; }; - 4B957A232AC7AE700062CA31 /* DeviceIdleStateDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBC16A127C485BC00E00A38 /* DeviceIdleStateDetector.swift */; }; - 4B957A242AC7AE700062CA31 /* FlatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C2327BDE1B0008A968E /* FlatButton.swift */; }; - 4B957A252AC7AE700062CA31 /* PinnedTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37054FC82873301700033B6F /* PinnedTabView.swift */; }; - 4B957A262AC7AE700062CA31 /* DataEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1A69F258B079600F6F690 /* DataEncryption.swift */; }; - 4B957A272AC7AE700062CA31 /* PrivacyDashboardPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6FA8940269C425400588ECD /* PrivacyDashboardPopover.swift */; }; - 4B957A282AC7AE700062CA31 /* TestsClosureNavigationResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B626A76C29928B1600053070 /* TestsClosureNavigationResponder.swift */; }; - 4B957A292AC7AE700062CA31 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B7184D27677CBB00B4277F /* RootView.swift */; }; - 4B957A2A2AC7AE700062CA31 /* AddressBarTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABEE6AE24AD22B90043105B /* AddressBarTextField.swift */; }; - 4B957A2B2AC7AE700062CA31 /* FocusRingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693953E26F04BE70015B914 /* FocusRingView.swift */; }; - 4B957A2C2AC7AE700062CA31 /* BookmarksBarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE41A5D28446EAD00760399 /* BookmarksBarViewModel.swift */; }; - 4B957A2D2AC7AE700062CA31 /* NSPopUpButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E6EEF27AB5E5D00F51793 /* NSPopUpButtonView.swift */; }; - 4B957A2E2AC7AE700062CA31 /* BlockMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85774B022A71CDD000DE0561 /* BlockMenuItem.swift */; }; - 4B957A2F2AC7AE700062CA31 /* ContextualMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292DA2667125D00AD2C21 /* ContextualMenu.swift */; }; - 4B957A302AC7AE700062CA31 /* NavigationBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA68C3D22490ED62001B8783 /* NavigationBarViewController.swift */; }; - 4B957A312AC7AE700062CA31 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA585DAE2490E6E600E9A3E2 /* MainViewController.swift */; }; - 4B957A322AC7AE700062CA31 /* DuckPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F19A6928E2F2D000740DC6 /* DuckPlayer.swift */; }; - 4B957A332AC7AE700062CA31 /* Favicon.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5FA699275F91C700DCE9C9 /* Favicon.swift */; }; - 4B957A342AC7AE700062CA31 /* SuggestionContainerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABEE69924A902A90043105B /* SuggestionContainerViewModel.swift */; }; - 4B957A352AC7AE700062CA31 /* FirePopoverWrapperViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA840A9727319D1600E63CDD /* FirePopoverWrapperViewController.swift */; }; - 4B957A362AC7AE700062CA31 /* NSPasteboardItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B85A47F28821CC500FC4C39 /* NSPasteboardItemExtension.swift */; }; - 4B957A372AC7AE700062CA31 /* AutofillPreferencesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C227F2FDD100F1F7B9 /* AutofillPreferencesModel.swift */; }; - 4B957A382AC7AE700062CA31 /* NetworkProtectionDebugUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */; }; - 4B957A392AC7AE700062CA31 /* NSException+Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = B657841E25FA497600D8DB33 /* NSException+Catch.swift */; }; - 4B957A3A2AC7AE700062CA31 /* PasswordManagementNoteModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE6547D271FCD4D008D1D63 /* PasswordManagementNoteModel.swift */; }; - 4B957A3B2AC7AE700062CA31 /* CookieNotificationAnimationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3184AC6E288F2A1100C35E4B /* CookieNotificationAnimationModel.swift */; }; - 4B957A3C2AC7AE700062CA31 /* JoinedWaitlistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0152A983B24000927DB /* JoinedWaitlistView.swift */; }; - 4B957A3D2AC7AE700062CA31 /* SharingMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63ED0E426BB8FB900A9DAD1 /* SharingMenu.swift */; }; - 4B957A3E2AC7AE700062CA31 /* EnableWaitlistFeatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0132A983B24000927DB /* EnableWaitlistFeatureView.swift */; }; - 4B957A3F2AC7AE700062CA31 /* GrammarFeaturesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA4FF40B2624751A004E2377 /* GrammarFeaturesManager.swift */; }; - 4B957A402AC7AE700062CA31 /* WaitlistModalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0192A983B24000927DB /* WaitlistModalViewController.swift */; }; - 4B957A412AC7AE700062CA31 /* WKMenuItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA06E7291401D700225DE2 /* WKMenuItemIdentifier.swift */; }; - 4B957A422AC7AE700062CA31 /* SafariFaviconsReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0AACAD28BC6FD0001038AC /* SafariFaviconsReader.swift */; }; - 4B957A432AC7AE700062CA31 /* NSScreenExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B3E0DC2657E9CF0040E0A2 /* NSScreenExtension.swift */; }; - 4B957A442AC7AE700062CA31 /* NSBezierPathExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65E6B9F26D9F10600095F96 /* NSBezierPathExtension.swift */; }; - 4B957A452AC7AE700062CA31 /* Bundle+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605E2A0B29FA00BCD287 /* Bundle+VPN.swift */; }; - 4B957A462AC7AE700062CA31 /* WebsiteDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6820E325502F19005ED0D5 /* WebsiteDataStore.swift */; }; - 4B957A472AC7AE700062CA31 /* NetworkProtectionFeatureVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD8679A2A9E9E000063B9F7 /* NetworkProtectionFeatureVisibility.swift */; }; - 4B957A482AC7AE700062CA31 /* PermissionContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64C852926942AC90048FEBE /* PermissionContextMenu.swift */; }; - 4B957A492AC7AE700062CA31 /* ContextMenuUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D438B5256E7C9E00F3BAF8 /* ContextMenuUserScript.swift */; }; - 4B957A4A2AC7AE700062CA31 /* NSSavePanelExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693954726F04BEA0015B914 /* NSSavePanelExtension.swift */; }; - 4B957A4B2AC7AE700062CA31 /* AppPrivacyConfigurationDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9826B0A12747DFEB0092F683 /* AppPrivacyConfigurationDataProvider.swift */; }; - 4B957A4C2AC7AE700062CA31 /* LinkButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E88A26D774090062C350 /* LinkButton.swift */; }; - 4B957A4D2AC7AE700062CA31 /* TemporaryFileHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF0914282DD40100EE1418 /* TemporaryFileHandler.swift */; }; - 4B957A4E2AC7AE700062CA31 /* URL+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B602E8152A1E2570006D261F /* URL+NetworkProtection.swift */; }; - 4B957A4F2AC7AE700062CA31 /* PrivacyFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB6BCDF827C6BEFF00CC76DC /* PrivacyFeatures.swift */; }; - 4B957A512AC7AE700062CA31 /* ViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378F44EA29B4C73E00899924 /* ViewExtension.swift */; }; - 4B957A522AC7AE700062CA31 /* AVCaptureDevice+SwizzledAuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DB3CF826A00E2D00D459B7 /* AVCaptureDevice+SwizzledAuthState.swift */; }; - 4B957A532AC7AE700062CA31 /* SubscriptionPagesUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E0C72052ABC63BD00802009 /* SubscriptionPagesUserScript.swift */; }; - 4B957A542AC7AE700062CA31 /* VisitMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAAB9115288EB46B00A057A9 /* VisitMenuItem.swift */; }; - 4B957A552AC7AE700062CA31 /* EncryptionKeyStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1A6BC258B082300F6F690 /* EncryptionKeyStore.swift */; }; - 4B957A562AC7AE700062CA31 /* TabExtensionsBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C00ED6292FB4B4009C73A6 /* TabExtensionsBuilder.swift */; }; - 4B957A582AC7AE700062CA31 /* PasswordManagementIdentityItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE6546E271FCD40008D1D63 /* PasswordManagementIdentityItemView.swift */; }; - 4B957A592AC7AE700062CA31 /* ProgressExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F41030264D2B23003DA42C /* ProgressExtension.swift */; }; - 4B957A5A2AC7AE700062CA31 /* CSVParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DF626B0002B00E14D75 /* CSVParser.swift */; }; - 4B957A5B2AC7AE700062CA31 /* PixelDataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44062616B30600DD1EC2 /* PixelDataModel.xcdatamodeld */; }; - 4B957A5C2AC7AE700062CA31 /* PrivacyDashboardWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63BDF7D27FDAA640072D75B /* PrivacyDashboardWebView.swift */; }; - 4B957A5D2AC7AE700062CA31 /* AppearancePreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C727F2FDD100F1F7B9 /* AppearancePreferences.swift */; }; - 4B957A5E2AC7AE700062CA31 /* DownloadListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E87A26D381710062C350 /* DownloadListCoordinator.swift */; }; - 4B957A5F2AC7AE700062CA31 /* AdClickAttributionTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B647EFBA2922584B00BA628D /* AdClickAttributionTabExtension.swift */; }; - 4B957A602AC7AE700062CA31 /* NSNotificationName+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B980E202817604000282EE1 /* NSNotificationName+Debug.swift */; }; - 4B957A612AC7AE700062CA31 /* NavigationBarBadgeAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F7F2A5288AD2CA001C0D64 /* NavigationBarBadgeAnimationView.swift */; }; - 4B957A622AC7AE700062CA31 /* AddressBarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4F025D6BF10007F5990 /* AddressBarButton.swift */; }; - 4B957A642AC7AE700062CA31 /* FaviconStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5FA69C275F945C00DCE9C9 /* FaviconStore.swift */; }; - 4B957A652AC7AE700062CA31 /* WaitlistTermsAndConditionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0142A983B24000927DB /* WaitlistTermsAndConditionsView.swift */; }; - 4B957A662AC7AE700062CA31 /* SuggestionListCharacteristics.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB8203B26B2DE0D00788AC3 /* SuggestionListCharacteristics.swift */; }; - 4B957A672AC7AE700062CA31 /* TimeIntervalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAADFD05264AA282001555EA /* TimeIntervalExtension.swift */; }; - 4B957A682AC7AE700062CA31 /* NetworkProtectionFeatureDisabler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6785432AA8DE1F008A5004 /* NetworkProtectionFeatureDisabler.swift */; }; - 4B957A692AC7AE700062CA31 /* BookmarkListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292CC2667123700AD2C21 /* BookmarkListViewController.swift */; }; - 4B957A6A2AC7AE700062CA31 /* SecureVaultLoginImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DF326B0002B00E14D75 /* SecureVaultLoginImporter.swift */; }; - 4B957A6B2AC7AE700062CA31 /* WKProcessPoolExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B645D8F529FA95440024461F /* WKProcessPoolExtension.swift */; }; - 4B957A6D2AC7AE700062CA31 /* LoginItemsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE86A2AA76CF90026E7DC /* LoginItemsManager.swift */; }; - 4B957A6E2AC7AE700062CA31 /* PixelExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 857E5AF42A79045800FC0FB4 /* PixelExperiment.swift */; }; - 4B957A6F2AC7AE700062CA31 /* DuckPlayerTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C416A6294A4AE500C4F2E7 /* DuckPlayerTabExtension.swift */; }; - 4B957A702AC7AE700062CA31 /* RecentlyClosedCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C1DD4285C780C0089850C /* RecentlyClosedCoordinator.swift */; }; - 4B957A712AC7AE700062CA31 /* URLRequestExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA88D14A252A557100980B4E /* URLRequestExtension.swift */; }; - 4B957A722AC7AE700062CA31 /* FaviconHostReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6197C5276B3168008396F0 /* FaviconHostReference.swift */; }; - 4B957A732AC7AE700062CA31 /* DownloadsTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6685E4129A61C460043D2EE /* DownloadsTabExtension.swift */; }; - 4B957A752AC7AE700062CA31 /* ASN1Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8AC93A26B48ADF00879451 /* ASN1Parser.swift */; }; - 4B957A762AC7AE700062CA31 /* FileDownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 856C98DE257014BD00A22F1F /* FileDownloadManager.swift */; }; - 4B957A772AC7AE700062CA31 /* BookmarkImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CF626FE191E001E4761 /* BookmarkImport.swift */; }; - 4B957A782AC7AE700062CA31 /* KeySetDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68503A6279141CD00893A05 /* KeySetDictionary.swift */; }; - 4B957A792AC7AE700062CA31 /* HistoryTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66260DF29AC6EBD00E9E3EE /* HistoryTabExtension.swift */; }; - 4B957A7A2AC7AE700062CA31 /* FireCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAEEC6A827088ADB008445F7 /* FireCoordinator.swift */; }; - 4B957A7B2AC7AE700062CA31 /* GeolocationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B655369A268442EE00085A79 /* GeolocationProvider.swift */; }; - 4B957A7C2AC7AE700062CA31 /* NSAlert+ActiveDownloadsTermination.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0B23B26E87D900031CB7F /* NSAlert+ActiveDownloadsTermination.swift */; }; - 4B957A7D2AC7AE700062CA31 /* IndexPathExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAECA41F24EEA4AC00EFA63A /* IndexPathExtension.swift */; }; - 4B957A7E2AC7AE700062CA31 /* PasswordManagementNoteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE65472271FCD40008D1D63 /* PasswordManagementNoteItemView.swift */; }; - 4B957A7F2AC7AE700062CA31 /* NSApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C8F622591021700748EB7 /* NSApplicationExtension.swift */; }; - 4B957A802AC7AE700062CA31 /* NSWindowExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9E9A5525A3AE8400D1959D /* NSWindowExtension.swift */; }; - 4B957A812AC7AE700062CA31 /* KeychainType+ClientDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */; }; - 4B957A822AC7AE700062CA31 /* SyncDebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370A34B02AB24E3700C77F7C /* SyncDebugMenu.swift */; }; - 4B957A832AC7AE700062CA31 /* AddBookmarkPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4C425D6A6E8007F5990 /* AddBookmarkPopover.swift */; }; - 4B957A852AC7AE700062CA31 /* QRSharingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F7127D29F6779000594A45 /* QRSharingService.swift */; }; - 4B957A862AC7AE700062CA31 /* ProcessExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C2FB127706E6A00BF2C7D /* ProcessExtension.swift */; }; - 4B957A872AC7AE700062CA31 /* PermissionAuthorizationQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106BA526A7BEC80013B453 /* PermissionAuthorizationQuery.swift */; }; - 4B957A882AC7AE700062CA31 /* BadgeAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3171D6B9288984D00068632A /* BadgeAnimationView.swift */; }; - 4B957A892AC7AE700062CA31 /* BrowserTabSelectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292C62667123700AD2C21 /* BrowserTabSelectionDelegate.swift */; }; - 4B957A8A2AC7AE700062CA31 /* ContinueSetUpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56D6A3D529DB2BAB0055215A /* ContinueSetUpView.swift */; }; - 4B957A8B2AC7AE700062CA31 /* PasswordManagementListSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E6EEC27AB5E5100F51793 /* PasswordManagementListSection.swift */; }; - 4B957A8C2AC7AE700062CA31 /* FaviconReferenceCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA222CB82760F74E00321475 /* FaviconReferenceCache.swift */; }; - 4B957A8D2AC7AE700062CA31 /* BookmarkTreeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929726670D2A00AD2C21 /* BookmarkTreeController.swift */; }; - 4B957A8E2AC7AE700062CA31 /* FirefoxEncryptionKeyReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B29759628281F0900187C4E /* FirefoxEncryptionKeyReader.swift */; }; - 4B957A8F2AC7AE700062CA31 /* EventMapping+NetworkProtectionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60722A0B29FA00BCD287 /* EventMapping+NetworkProtectionError.swift */; }; - 4B957A902AC7AE700062CA31 /* BookmarkManagementSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292C82667123700AD2C21 /* BookmarkManagementSplitViewController.swift */; }; - 4B957A912AC7AE700062CA31 /* CookieManagedNotificationContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3171D6DA2889B64D0068632A /* CookieManagedNotificationContainerView.swift */; }; - 4B957A922AC7AE700062CA31 /* FileManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E61EE2263AC0C8004E11AB /* FileManagerExtension.swift */; }; - 4B957A932AC7AE700062CA31 /* PermissionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DB3CFA26A17CB800D459B7 /* PermissionModel.swift */; }; - 4B957A942AC7AE700062CA31 /* PasteboardFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929226670D2A00AD2C21 /* PasteboardFolder.swift */; }; - 4B957A952AC7AE700062CA31 /* CookieManagedNotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3171D6B72889849F0068632A /* CookieManagedNotificationView.swift */; }; - 4B957A962AC7AE700062CA31 /* PermissionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106BAA26A7BF1D0013B453 /* PermissionType.swift */; }; - 4B957A982AC7AE700062CA31 /* RecentlyClosedWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC6881A28626C1900D54247 /* RecentlyClosedWindow.swift */; }; - 4B957A992AC7AE700062CA31 /* ActionSpeech.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85707F29276A35FE00DC0649 /* ActionSpeech.swift */; }; - 4B957A9B2AC7AE700062CA31 /* ModalSheetCancellable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BE9FA9293F7955006363C6 /* ModalSheetCancellable.swift */; }; - 4B957A9C2AC7AE700062CA31 /* FireproofDomainsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6830962274CDEC7004B46BB /* FireproofDomainsStore.swift */; }; - 4B957A9D2AC7AE700062CA31 /* NetworkProtectionSimulateFailureMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */; }; - 4B957A9E2AC7AE700062CA31 /* PrivacyDashboardPermissionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7E2E932902AC0E00C01B54 /* PrivacyDashboardPermissionHandler.swift */; }; - 4B957A9F2AC7AE700062CA31 /* TabCollectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9FF95E24A1FB680039E328 /* TabCollectionViewModel.swift */; }; - 4B957AA02AC7AE700062CA31 /* BookmarkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4CE25D6A709007F5990 /* BookmarkManager.swift */; }; - 4B957AA12AC7AE700062CA31 /* AboutModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C527F2FDD100F1F7B9 /* AboutModel.swift */; }; - 4B957AA22AC7AE700062CA31 /* PasswordManagementCreditCardItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE65470271FCD40008D1D63 /* PasswordManagementCreditCardItemView.swift */; }; - 4B957AA32AC7AE700062CA31 /* NSTextFieldExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C8F58258FE21F00748EB7 /* NSTextFieldExtension.swift */; }; - 4B957AA42AC7AE700062CA31 /* BWManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3706FEC7293F6F7500E42796 /* BWManagement.swift */; }; - 4B957AA52AC7AE700062CA31 /* FireproofDomainsContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6830960274CDE99004B46BB /* FireproofDomainsContainer.swift */; }; - 4B957AA62AC7AE700062CA31 /* ExternalAppSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B687B7CB2947A1E9001DEA6F /* ExternalAppSchemeHandler.swift */; }; - 4B957AA72AC7AE700062CA31 /* GeolocationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65536AD2685E17100085A79 /* GeolocationService.swift */; }; - 4B957AA82AC7AE700062CA31 /* FireproofingURLExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B02197F25E05FAC00ED7DEA /* FireproofingURLExtensions.swift */; }; - 4B957AA92AC7AE700062CA31 /* ContentOverlayPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1E819B27C8874900FF0E60 /* ContentOverlayPopover.swift */; }; - 4B957AAA2AC7AE700062CA31 /* TabShadowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3154FD1328E6011A00909769 /* TabShadowView.swift */; }; - 4B957AAB2AC7AE700062CA31 /* BWMessageIdGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D43EB3B292B664A0065E5D6 /* BWMessageIdGenerator.swift */; }; - 4B957AAC2AC7AE700062CA31 /* EncryptedValueTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1A6A4258B07DF00F6F690 /* EncryptedValueTransformer.swift */; }; - 4B957AAD2AC7AE700062CA31 /* Tab+Dialogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = B634DBE0293C8FD500C3C99E /* Tab+Dialogs.swift */; }; - 4B957AAE2AC7AE700062CA31 /* PasteboardBookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929526670D2A00AD2C21 /* PasteboardBookmark.swift */; }; - 4B957AAF2AC7AE700062CA31 /* PinnedTabsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF3F13286D8A6500BD9014 /* PinnedTabsManager.swift */; }; - 4B957AB02AC7AE700062CA31 /* HoverUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 856CADEF271710F400E79BB0 /* HoverUserScript.swift */; }; - 4B957AB12AC7AE700062CA31 /* MainMenuActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6EF9B425081B4C004754E6 /* MainMenuActions.swift */; }; - 4B957AB22AC7AE700062CA31 /* WKWebView+SessionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63D466825BEB6C200874977 /* WKWebView+SessionState.swift */; }; - 4B957AB32AC7AE700062CA31 /* NetworkProtectionControllerErrorStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606A2A0B29FA00BCD287 /* NetworkProtectionControllerErrorStore.swift */; }; - 4B957AB42AC7AE700062CA31 /* DataImport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DEB26B0002B00E14D75 /* DataImport.swift */; }; - 4B957AB52AC7AE700062CA31 /* NetworkProtectionDebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BE146062A6A83C700C313B8 /* NetworkProtectionDebugMenu.swift */; }; - 4B957AB62AC7AE700062CA31 /* FireproofDomains.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B6085D072743993C00A9C456 /* FireproofDomains.xcdatamodeld */; }; - 4B957AB82AC7AE700062CA31 /* HomePageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E7C27BBB8630038AD11 /* HomePageView.swift */; }; - 4B957AB92AC7AE700062CA31 /* SerpHeadersNavigationResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BF5D922947199A006742B1 /* SerpHeadersNavigationResponder.swift */; }; - 4B957ABA2AC7AE700062CA31 /* HomePageContinueSetUpModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569277C029DDCBB500B633EF /* HomePageContinueSetUpModel.swift */; }; - 4B957ABB2AC7AE700062CA31 /* WebKitDownloadTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A924D82664C72D001A28CA /* WebKitDownloadTask.swift */; }; - 4B957ABC2AC7AE700062CA31 /* ChromiumLoginReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B59023926B35F3600489384 /* ChromiumLoginReader.swift */; }; - 4B957ABD2AC7AE700062CA31 /* NSAlert+PasswordManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D885B226A5A9DE0077C374 /* NSAlert+PasswordManager.swift */; }; - 4B957ABE2AC7AE700062CA31 /* UserContentUpdating.swift in Sources */ = {isa = PBXBuildFile; fileRef = 983DFB2428B67036006B7E34 /* UserContentUpdating.swift */; }; - 4B957ABF2AC7AE700062CA31 /* ChromiumPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7A57CE279A4EF300B1C70E /* ChromiumPreferences.swift */; }; - 4B957AC02AC7AE700062CA31 /* FirePopoverViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6AD95A2704B6DB00159F8A /* FirePopoverViewController.swift */; }; - 4B957AC12AC7AE700062CA31 /* SavePaymentMethodPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE4005227CF3DC3007D3161 /* SavePaymentMethodPopover.swift */; }; - 4B957AC22AC7AE700062CA31 /* FindInPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A0116825AF1D8900FA6A0C /* FindInPageViewController.swift */; }; - 4B957AC32AC7AE700062CA31 /* Cryptography.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB6CE5E26B77ED000EC5860 /* Cryptography.swift */; }; - 4B957AC42AC7AE700062CA31 /* BWVault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D69C552291302F200B75945 /* BWVault.swift */; }; - 4B957AC52AC7AE700062CA31 /* NSViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6FFB4324DC33320028F4D0 /* NSViewExtension.swift */; }; - 4B957AC72AC7AE700062CA31 /* DownloadListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0B23D26E8BF1F0031CB7F /* DownloadListViewModel.swift */; }; - 4B957AC82AC7AE700062CA31 /* BookmarkManagementDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292CD2667123700AD2C21 /* BookmarkManagementDetailViewController.swift */; }; - 4B957AC92AC7AE700062CA31 /* CSVImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DF726B0002B00E14D75 /* CSVImporter.swift */; }; - 4B957ACA2AC7AE700062CA31 /* StartupPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A4CEB9282E992F00D75B89 /* StartupPreferences.swift */; }; - 4B957ACB2AC7AE700062CA31 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */; }; - 4B957ACC2AC7AE700062CA31 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA4BBA3A25C58FA200C4FB0F /* MainMenu.swift */; }; - 4B957ACE2AC7AE700062CA31 /* BrowserTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA585D83248FD31100E9A3E2 /* BrowserTabViewController.swift */; }; - 4B957ACF2AC7AE700062CA31 /* CallToAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85707F21276A32B600DC0649 /* CallToAction.swift */; }; - 4B957AD02AC7AE700062CA31 /* MouseOverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693953D26F04BE70015B914 /* MouseOverView.swift */; }; - 4B957AD12AC7AE700062CA31 /* EncryptedHistoryStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE7527B263B056C00B973F8 /* EncryptedHistoryStore.swift */; }; - 4B957AD22AC7AE700062CA31 /* FirePopoverCollectionViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE246F12709EF3B00BEEAEE /* FirePopoverCollectionViewItem.swift */; }; - 4B957AD32AC7AE700062CA31 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA61C0D12727F59B00E6B681 /* ArrayExtension.swift */; }; - 4B957AD42AC7AE700062CA31 /* NetworkProtectionInviteCodeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60702A0B29FA00BCD287 /* NetworkProtectionInviteCodeViewModel.swift */; }; - 4B957AD52AC7AE700062CA31 /* CrashReportSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A2B268F1ECD00D2D9CD /* CrashReportSender.swift */; }; - 4B957AD62AC7AE700062CA31 /* BookmarkHTMLImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A1AAF2842C4EA00586521 /* BookmarkHTMLImporter.swift */; }; - 4B957AD72AC7AE700062CA31 /* CustomRoundedCornersShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C3CE0128EDC1E70002C24A /* CustomRoundedCornersShape.swift */; }; - 4B957AD82AC7AE700062CA31 /* LocaleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8D9061276D1D880078DB17 /* LocaleExtension.swift */; }; - 4B957AD92AC7AE700062CA31 /* SavePaymentMethodViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE4005427CF3F19007D3161 /* SavePaymentMethodViewController.swift */; }; - 4B957ADA2AC7AE700062CA31 /* BWStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF075F28F815AD00EDFBE3 /* BWStatus.swift */; }; - 4B957ADB2AC7AE700062CA31 /* WebKitVersionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAFE068226C7082D005434CC /* WebKitVersionProvider.swift */; }; - 4B957ADC2AC7AE700062CA31 /* NSCoderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63D467925BFC3E100874977 /* NSCoderExtensions.swift */; }; - 4B957ADD2AC7AE700062CA31 /* RunningApplicationCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D77921C28FFF27C00BE0210 /* RunningApplicationCheck.swift */; }; - 4B957ADE2AC7AE700062CA31 /* StatePersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A5A27025B9377300AA7ADA /* StatePersistenceService.swift */; }; - 4B957ADF2AC7AE700062CA31 /* WindowManager+StateRestoration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68458AF25C7E76A00DC17B6 /* WindowManager+StateRestoration.swift */; }; - 4B957AE02AC7AE700062CA31 /* TabCollection+NSSecureCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68458C425C7EA0C00DC17B6 /* TabCollection+NSSecureCoding.swift */; }; - 4B957AE12AC7AE700062CA31 /* Instruments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB88B5A25B7BA50006F6B06 /* Instruments.swift */; }; - 4B957AE22AC7AE700062CA31 /* ContentBlockerRulesLists.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9812D894276CEDA5004B6181 /* ContentBlockerRulesLists.swift */; }; - 4B957AE32AC7AE700062CA31 /* NSViewControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0511E0262CAA8600F6079C /* NSViewControllerExtension.swift */; }; - 4B957AE42AC7AE700062CA31 /* NSAppearanceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F44C130125C2DA0400426E3E /* NSAppearanceExtension.swift */; }; - 4B957AE52AC7AE700062CA31 /* EmailManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3B848F297A0E1000A384BD /* EmailManagerExtension.swift */; }; - 4B957AE62AC7AE700062CA31 /* PermissionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64C84F0269310120048FEBE /* PermissionManager.swift */; }; - 4B957AE72AC7AE700062CA31 /* DefaultBrowserPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C827F2FDD100F1F7B9 /* DefaultBrowserPreferences.swift */; }; - 4B957AE82AC7AE700062CA31 /* Permissions.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B64C852E26943BC10048FEBE /* Permissions.xcdatamodeld */; }; - 4B957AE92AC7AE700062CA31 /* JSAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE339227291BDEFD009F62C1 /* JSAlertController.swift */; }; - 4B957AEA2AC7AE700062CA31 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB01C2A983B24000927DB /* NotificationService.swift */; }; - 4B957AEB2AC7AE700062CA31 /* SyncPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3775912C29AAC72700E26367 /* SyncPreferences.swift */; }; - 4B957AEC2AC7AE700062CA31 /* FaviconNullStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB9617F29F67F3E00CF5568 /* FaviconNullStore.swift */; }; - 4B957AED2AC7AE700062CA31 /* PaddedImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693954126F04BE80015B914 /* PaddedImageButton.swift */; }; - 4B957AEE2AC7AE700062CA31 /* EncryptionKeyStoring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1A6B7258B081600F6F690 /* EncryptionKeyStoring.swift */; }; - 4B957AEF2AC7AE700062CA31 /* String+Punycode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65783E625F8AAFB00D8DB33 /* String+Punycode.swift */; }; - 4B957AF02AC7AE700062CA31 /* NSException+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = B657841925FA484B00D8DB33 /* NSException+Catch.m */; }; - 4B957AF12AC7AE700062CA31 /* AppStateRestorationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B684592E25C93FBF00DC17B6 /* AppStateRestorationManager.swift */; }; - 4B957AF22AC7AE700062CA31 /* DailyPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B67853E2AA7C726008A5004 /* DailyPixel.swift */; }; - 4B957AF32AC7AE700062CA31 /* NavigationHotkeyHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66260E529ACAE4B00E9E3EE /* NavigationHotkeyHandler.swift */; }; - 4B957AF42AC7AE700062CA31 /* ClickToLoadUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */; }; - 4B957AF52AC7AE700062CA31 /* WindowControllersManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA892E9250A4CEF005B37B2 /* WindowControllersManager.swift */; }; - 4B957AF62AC7AE700062CA31 /* FireAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C5991A27D10CF000E605B2 /* FireAnimationView.swift */; }; - 4B957AF72AC7AE700062CA31 /* FaviconUrlReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6197C3276B314D008396F0 /* FaviconUrlReference.swift */; }; - 4B957AF92AC7AE700062CA31 /* PasswordManagementItemListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CC1D7A26A05ECF0062F04E /* PasswordManagementItemListModel.swift */; }; - 4B957AFA2AC7AE700062CA31 /* SuggestionTableCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABEE6A824AB4B910043105B /* SuggestionTableCellView.swift */; }; - 4B957AFB2AC7AE700062CA31 /* FireViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6820F025503DA9005ED0D5 /* FireViewModel.swift */; }; - 4B957AFC2AC7AE700062CA31 /* SyncCredentialsAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372BC2A02A4AFA47001D8FD5 /* SyncCredentialsAdapter.swift */; }; - 4B957AFD2AC7AE700062CA31 /* WKUserContentControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA0CC69253CC43C0079BC96 /* WKUserContentControllerExtension.swift */; }; - 4B957AFE2AC7AE700062CA31 /* EditableTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE65473271FCD40008D1D63 /* EditableTextView.swift */; }; - 4B957AFF2AC7AE700062CA31 /* TabCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9FF95C24A1FA1C0039E328 /* TabCollection.swift */; }; - 4B957B002AC7AE700062CA31 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B688B4D9273E6D3B0087BEAF /* MainView.swift */; }; - 4B957B012AC7AE700062CA31 /* Tab+Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B61E2CD4294346C000773D8A /* Tab+Navigation.swift */; }; - 4B957B022AC7AE700062CA31 /* EmailUrlExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B65143D263924B5005B46EB /* EmailUrlExtensions.swift */; }; - 4B957B032AC7AE700062CA31 /* PasswordManagementItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CC1D7C26A05F250062F04E /* PasswordManagementItemModel.swift */; }; - 4B957B042AC7AE700062CA31 /* UpdateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD86E51267A0DFF005C11BE /* UpdateController.swift */; }; - 4B957B052AC7AE700062CA31 /* FindInPageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A0118125AF60E700FA6A0C /* FindInPageModel.swift */; }; - 4B957B062AC7AE700062CA31 /* PseudoFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929826670D2A00AD2C21 /* PseudoFolder.swift */; }; - 4B957B082AC7AE700062CA31 /* PixelDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */; }; - 4B957B092AC7AE700062CA31 /* WaitlistStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB00E2A983B24000927DB /* WaitlistStorage.swift */; }; - 4B957B0A2AC7AE700062CA31 /* Pixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E45226142B070067D1B9 /* Pixel.swift */; }; - 4B957B0B2AC7AE700062CA31 /* PixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E47626146A570067D1B9 /* PixelEvent.swift */; }; - 4B957B0C2AC7AE700062CA31 /* TabBarFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA2CB1342587C29500AA6FBE /* TabBarFooter.swift */; }; - 4B957B0D2AC7AE700062CA31 /* JSAlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC111E5294D06290086524F /* JSAlertViewModel.swift */; }; - 4B957B0E2AC7AE700062CA31 /* BookmarksBarCollectionViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE5336A286912D40019DBFD /* BookmarksBarCollectionViewItem.swift */; }; - 4B957B0F2AC7AE700062CA31 /* FileDownloadError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0B23826E742610031CB7F /* FileDownloadError.swift */; }; - 4B957B102AC7AE700062CA31 /* MoreOrLessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E9F27BFE60E0038AD11 /* MoreOrLessView.swift */; }; - 4B957B122AC7AE700062CA31 /* History.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = AAE75278263B046100B973F8 /* History.xcdatamodeld */; }; - 4B957B132AC7AE700062CA31 /* PermissionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64C853C26944B940048FEBE /* PermissionStore.swift */; }; - 4B957B142AC7AE700062CA31 /* PrivacyIconViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA75A0AD26F3500C0086B667 /* PrivacyIconViewModel.swift */; }; - 4B957B152AC7AE700062CA31 /* ChromiumBookmarksReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CF926FE191E001E4761 /* ChromiumBookmarksReader.swift */; }; - 4B957B162AC7AE700062CA31 /* Downloads.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B6C0B23226E71BCD0031CB7F /* Downloads.xcdatamodeld */; }; - 4B957B172AC7AE700062CA31 /* TabPreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE8B10F258A456C00E81239 /* TabPreviewViewController.swift */; }; - 4B957B182AC7AE700062CA31 /* PreferencesDataClearingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CC53EB27E8A4D10028713D /* PreferencesDataClearingView.swift */; }; - 4B957B192AC7AE700062CA31 /* NSPasteboardExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0135CD2729F1AA00D54834 /* NSPasteboardExtension.swift */; }; - 4B957B1A2AC7AE700062CA31 /* OnboardingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85707F30276A7DCA00DC0649 /* OnboardingViewModel.swift */; }; - 4B957B1B2AC7AE700062CA31 /* ScriptSourceProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3B0425D6B1D800C7D2AA /* ScriptSourceProviding.swift */; }; - 4B957B1C2AC7AE700062CA31 /* CoreDataBookmarkImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CF726FE191E001E4761 /* CoreDataBookmarkImporter.swift */; }; - 4B957B1D2AC7AE700062CA31 /* SuggestionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA3F895224C18AD500628DDE /* SuggestionViewModel.swift */; }; - 4B957B1E2AC7AE700062CA31 /* BookmarkManagedObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929926670D2A00AD2C21 /* BookmarkManagedObject.swift */; }; - 4B957B1F2AC7AE700062CA31 /* CSVLoginExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B723DFD26B0002B00E14D75 /* CSVLoginExporter.swift */; }; - 4B957B202AC7AE700062CA31 /* NSAttributedStringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C48CCB278D808F00D3263E /* NSAttributedStringExtension.swift */; }; - 4B957B212AC7AE700062CA31 /* AnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7EB6E427E7D6DC00036718 /* AnimationView.swift */; }; - 4B957B222AC7AE700062CA31 /* NSRectExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85625999269CA0A600EE44BC /* NSRectExtension.swift */; }; - 4B957B232AC7AE700062CA31 /* WaitlistRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB01A2A983B24000927DB /* WaitlistRootView.swift */; }; - 4B957B242AC7AE700062CA31 /* YoutubeOverlayUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F28C4E28C8EEC500119F70 /* YoutubeOverlayUserScript.swift */; }; - 4B957B252AC7AE700062CA31 /* DictionaryExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6040855274B830F00680351 /* DictionaryExtension.swift */; }; - 4B957B262AC7AE700062CA31 /* Publishers.NestedObjectChanges.swift in Sources */ = {isa = PBXBuildFile; fileRef = B684592625C93C0500DC17B6 /* Publishers.NestedObjectChanges.swift */; }; - 4B957B272AC7AE700062CA31 /* MenuItemSelectors.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA06E52913F39400225DE2 /* MenuItemSelectors.swift */; }; - 4B957B282AC7AE700062CA31 /* FaviconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E9927BFE3C30038AD11 /* FaviconView.swift */; }; - 4B957B292AC7AE700062CA31 /* OnboardingFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85707F2B276A364E00DC0649 /* OnboardingFlow.swift */; }; - 4B957B2A2AC7AE700062CA31 /* PasswordManagementLoginModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE6547C271FCD4D008D1D63 /* PasswordManagementLoginModel.swift */; }; - 4B957B2B2AC7AE700062CA31 /* TabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9FF95A24A1EFC20039E328 /* TabViewModel.swift */; }; - 4B957B2C2AC7AE700062CA31 /* TabDragAndDropManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9E9A5D25A4867200D1959D /* TabDragAndDropManager.swift */; }; - 4B957B2D2AC7AE700062CA31 /* NSNotificationName+Favicons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBD3BFF285ACE090047A89D /* NSNotificationName+Favicons.swift */; }; - 4B957B2E2AC7AE700062CA31 /* PinningManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0DB5E428BD9D08007DD239 /* PinningManager.swift */; }; - 4B957B2F2AC7AE700062CA31 /* SyncMetadataDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373D9B4729EEAC1B00381FDD /* SyncMetadataDatabase.swift */; }; - 4B957B302AC7AE700062CA31 /* TabCollectionViewModel+NSSecureCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68458BF25C7E9E000DC17B6 /* TabCollectionViewModel+NSSecureCoding.swift */; }; - 4B957B312AC7AE700062CA31 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA8EDF2624923EC70071C2E8 /* StringExtension.swift */; }; - 4B957B322AC7AE700062CA31 /* EmailManagerRequestDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85378DA1274E7F25007C5CBF /* EmailManagerRequestDelegate.swift */; }; - 4B957B332AC7AE700062CA31 /* ApplicationVersionReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D43EB35292ACE690065E5D6 /* ApplicationVersionReader.swift */; }; - 4B957B342AC7AE700062CA31 /* BookmarksBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD18EFF283F0BC500058124 /* BookmarksBarViewController.swift */; }; - 4B957B352AC7AE700062CA31 /* PreferencesAutofillView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 379DE4BC27EA31AC002CC3DE /* PreferencesAutofillView.swift */; }; - 4B957B362AC7AE700062CA31 /* BurnerHomePageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DCFBC8929ADF32B00313531 /* BurnerHomePageView.swift */; }; - 4B957B372AC7AE700062CA31 /* UserText+PasswordManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858A797E26A79EAA00A75A42 /* UserText+PasswordManager.swift */; }; - 4B957B382AC7AE700062CA31 /* LoadingProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693954026F04BE80015B914 /* LoadingProgressView.swift */; }; - 4B957B392AC7AE700062CA31 /* StatisticsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50362726A12000758A2B /* StatisticsStore.swift */; }; - 4B957B3A2AC7AE700062CA31 /* BWInstallationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBDEE8C28FC14760092FAA6 /* BWInstallationService.swift */; }; - 4B957B3B2AC7AE700062CA31 /* BookmarksBarPromptPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859F30632A72A7BB00C20372 /* BookmarksBarPromptPopover.swift */; }; - 4B957B3C2AC7AE700062CA31 /* NetworkProtectionInvitePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606F2A0B29FA00BCD287 /* NetworkProtectionInvitePresenter.swift */; }; - 4B957B3D2AC7AE700062CA31 /* ColorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693954626F04BEA0015B914 /* ColorView.swift */; }; - 4B957B3E2AC7AE700062CA31 /* RecentlyClosedCacheItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C1DD2285A217F0089850C /* RecentlyClosedCacheItem.swift */; }; - 4B957B3F2AC7AE700062CA31 /* PopupBlockedPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BBF17327475B15004F850E /* PopupBlockedPopover.swift */; }; - 4B957B402AC7AE700062CA31 /* SaveCredentialsPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85890639267BCD8E00D23B0D /* SaveCredentialsPopover.swift */; }; - 4B957B412AC7AE700062CA31 /* LegacyBookmarksStoreMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 987799F02999993C005D8EB6 /* LegacyBookmarksStoreMigration.swift */; }; - 4B957B422AC7AE700062CA31 /* QuartzIdleStateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C1427BD91E3008A968E /* QuartzIdleStateProvider.swift */; }; - 4B957B432AC7AE700062CA31 /* DuckPlayerPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37F19A6628E1B43200740DC6 /* DuckPlayerPreferences.swift */; }; - 4B957B442AC7AE700062CA31 /* DownloadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C0B22D26E61CE70031CB7F /* DownloadViewModel.swift */; }; - 4B957B452AC7AE700062CA31 /* BookmarkHTMLReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373A1AA7283ED1B900586521 /* BookmarkHTMLReader.swift */; }; - 4B957B462AC7AE700062CA31 /* Tab+NSSecureCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68458B725C7E8B200DC17B6 /* Tab+NSSecureCoding.swift */; }; - 4B957B472AC7AE700062CA31 /* NSNotificationName+EmailManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85378D9F274E6F42007C5CBF /* NSNotificationName+EmailManager.swift */; }; - 4B957B482AC7AE700062CA31 /* MouseOverButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693954926F04BEB0015B914 /* MouseOverButton.swift */; }; - 4B957B492AC7AE700062CA31 /* FireInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA61C0CF2722159B00E6B681 /* FireInfoViewController.swift */; }; - 4B957B4A2AC7AE700062CA31 /* LoginItem+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE8682AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift */; }; - 4B957B4B2AC7AE700062CA31 /* PermissionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64C85412694590B0048FEBE /* PermissionButton.swift */; }; - 4B957B4C2AC7AE700062CA31 /* MoreOptionsMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA0CC462533833C0079BC96 /* MoreOptionsMenu.swift */; }; - 4B957B4D2AC7AE700062CA31 /* PermissionAuthorizationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64C84E22692DC9F0048FEBE /* PermissionAuthorizationViewController.swift */; }; - 4B957B4E2AC7AE700062CA31 /* BookmarkNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92929326670D2A00AD2C21 /* BookmarkNode.swift */; }; - 4B957B4F2AC7AE700062CA31 /* LongPressButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693954426F04BE90015B914 /* LongPressButton.swift */; }; - 4B957B502AC7AE700062CA31 /* CoreDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6085D052743905F00A9C456 /* CoreDataStore.swift */; }; - 4B957B512AC7AE700062CA31 /* BundleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106B9D26A565DA0013B453 /* BundleExtension.swift */; }; - 4B957B522AC7AE700062CA31 /* NSOpenPanelExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0511DF262CAA8600F6079C /* NSOpenPanelExtensions.swift */; }; - 4B957B532AC7AE700062CA31 /* FirePopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE99B8827088A19008B6BD9 /* FirePopover.swift */; }; - 4B957B552AC7AE700062CA31 /* NetworkProtectionOnboardingMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B05829D2A812AC000AC3F7C /* NetworkProtectionOnboardingMenu.swift */; }; - 4B957B562AC7AE700062CA31 /* VariantManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50372726A12000758A2B /* VariantManager.swift */; }; - 4B957B572AC7AE700062CA31 /* ApplicationDockMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA97BF4525135DD30014931A /* ApplicationDockMenu.swift */; }; - 4B957B582AC7AE700062CA31 /* SaveIdentityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8A4DFE27C83B29005F40E8 /* SaveIdentityViewController.swift */; }; - 4B957B592AC7AE700062CA31 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; - 4B957B5A2AC7AE700062CA31 /* FileStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1A69A258B076900F6F690 /* FileStore.swift */; }; - 4B957B5B2AC7AE700062CA31 /* PixelArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E47E26146A800067D1B9 /* PixelArguments.swift */; }; - 4B957B5C2AC7AE700062CA31 /* PinnedTabsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF3F1E286F0A7A00BD9014 /* PinnedTabsViewModel.swift */; }; - 4B957B5D2AC7AE700062CA31 /* BookmarkList.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4CF25D6A709007F5990 /* BookmarkList.swift */; }; - 4B957B5E2AC7AE700062CA31 /* NEOnDemandRuleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B602E81C2A1E25B0006D261F /* NEOnDemandRuleExtension.swift */; }; - 4B957B5F2AC7AE700062CA31 /* BookmarkTableRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292C92667123700AD2C21 /* BookmarkTableRowView.swift */; }; - 4B957B602AC7AE700062CA31 /* FavoritesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E9327BFE1E70038AD11 /* FavoritesView.swift */; }; - 4B957B612AC7AE700062CA31 /* HomePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC7ADA27BD628400FFB69B /* HomePage.swift */; }; - 4B957B622AC7AE700062CA31 /* RoundedSelectionRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0511B3262CAA5A00F6079C /* RoundedSelectionRowView.swift */; }; - 4B957B632AC7AE700062CA31 /* LocalStatisticsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50392726A12500758A2B /* LocalStatisticsStore.swift */; }; - 4B957B642AC7AE700062CA31 /* BackForwardListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B689ECD426C247DB006FB0C5 /* BackForwardListItem.swift */; }; - 4B957B672AC7AE700062CA31 /* AtbAndVariantCleanup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50562727D16900758A2B /* AtbAndVariantCleanup.swift */; }; - 4B957B692AC7AE700062CA31 /* FeedbackWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA3D531427A1ED9300074EC1 /* FeedbackWindow.swift */; }; - 4B957B6A2AC7AE700062CA31 /* WorkspaceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6685E3E29A606190043D2EE /* WorkspaceProtocol.swift */; }; - 4B957B6B2AC7AE700062CA31 /* RecentlyVisitedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85F0FF1227CFAB04001C7C6E /* RecentlyVisitedView.swift */; }; - 4B957B6C2AC7AE700062CA31 /* MouseOverAnimationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7EB6DE27E7C57D00036718 /* MouseOverAnimationButton.swift */; }; - 4B957B6D2AC7AE700062CA31 /* TabBarScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7412B624D1687000D22FE0 /* TabBarScrollView.swift */; }; - 4B957B6E2AC7AE700062CA31 /* BookmarkListTreeControllerDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292D82667124B00AD2C21 /* BookmarkListTreeControllerDataSource.swift */; }; - 4B957B6F2AC7AE700062CA31 /* AddressBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14D9B8F924F7E089000D4D13 /* AddressBarViewController.swift */; }; - 4B957B702AC7AE700062CA31 /* Permissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65536A52685B82B00085A79 /* Permissions.swift */; }; - 4B957B712AC7AE700062CA31 /* TabPreviewWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC82C5F258B6CB5009B6B42 /* TabPreviewWindowController.swift */; }; - 4B957B722AC7AE700062CA31 /* NSSizeExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4E325D6BA9C007F5990 /* NSSizeExtension.swift */; }; - 4B957B732AC7AE700062CA31 /* Fire.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6820EA25503D6A005ED0D5 /* Fire.swift */; }; - 4B957B742AC7AE700062CA31 /* SyncBookmarksAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37445F9B2A1569F00029F789 /* SyncBookmarksAdapter.swift */; }; - 4B957B752AC7AE700062CA31 /* RandomAccessCollectionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AAAC3D26048F690029438D /* RandomAccessCollectionExtension.swift */; }; - 4B957B762AC7AE700062CA31 /* NSOutlineViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292AE26670F5300AD2C21 /* NSOutlineViewExtensions.swift */; }; - 4B957B772AC7AE700062CA31 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA585D81248FD31100E9A3E2 /* AppDelegate.swift */; }; - 4B957B782AC7AE700062CA31 /* ContentOverlayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1E819D27C8874900FF0E60 /* ContentOverlayViewController.swift */; }; - 4B957B792AC7AE700062CA31 /* ContentBlockingTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D574B12947224C008ED1B6 /* ContentBlockingTabExtension.swift */; }; - 4B957B7A2AC7AE700062CA31 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B7184B27677C6500B4277F /* OnboardingViewController.swift */; }; - 4B957B7B2AC7AE700062CA31 /* DeviceAuthenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B379C1D27BDB7FF008A968E /* DeviceAuthenticator.swift */; }; - 4B957B7C2AC7AE700062CA31 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95512A9DF1CE0081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift */; }; - 4B957B7D2AC7AE700062CA31 /* TabBarCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1456D6E024EFCBC300775049 /* TabBarCollectionView.swift */; }; - 4B957B7E2AC7AE700062CA31 /* NetworkProtection+ConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60692A0B29FA00BCD287 /* NetworkProtection+ConvenienceInitializers.swift */; }; - 4B957B7F2AC7AE700062CA31 /* NavigationActionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66B9C5B29A5EBAD0010E8F3 /* NavigationActionExtension.swift */; }; - 4B957B802AC7AE700062CA31 /* NSAlertExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85308E24267FC9F2001ABD76 /* NSAlertExtension.swift */; }; - 4B957B812AC7AE700062CA31 /* ThirdPartyBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B59024726B3673600489384 /* ThirdPartyBrowser.swift */; }; - 4B957B822AC7AE700062CA31 /* SearchNonexistentDomainNavigationResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60C6F7629B0E286007BFAA8 /* SearchNonexistentDomainNavigationResponder.swift */; }; - 4B957B832AC7AE700062CA31 /* CircularProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65E6B9D26D9EC0800095F96 /* CircularProgressView.swift */; }; - 4B957B842AC7AE700062CA31 /* SuggestionContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = AABEE69B24A902BB0043105B /* SuggestionContainer.swift */; }; - 4B957B852AC7AE700062CA31 /* FindInPageTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C00ECC292F89D9009C73A6 /* FindInPageTabExtension.swift */; }; - 4B957B862AC7AE700062CA31 /* HomePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85589E7D27BBB8630038AD11 /* HomePageViewController.swift */; }; - 4B957B882AC7AE700062CA31 /* OperatingSystemVersionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E46A2614618A0067D1B9 /* OperatingSystemVersionExtension.swift */; }; - 4B957B892AC7AE700062CA31 /* ToggleableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDFA4AD27BF19E500648192 /* ToggleableScrollView.swift */; }; - 4B957B8A2AC7AE700062CA31 /* TabCleanupPreparer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D36F4232A3B85C50052B527 /* TabCleanupPreparer.swift */; }; - 4B957B8B2AC7AE700062CA31 /* NetworkProtectionOptionKeyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605F2A0B29FA00BCD287 /* NetworkProtectionOptionKeyExtension.swift */; }; - 4B957B8C2AC7AE700062CA31 /* UserScripts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85AC3AEE25D5CE9800C7D2AA /* UserScripts.swift */; }; - 4B957B8D2AC7AE700062CA31 /* NSWorkspaceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B643BF1327ABF772000BACEC /* NSWorkspaceExtension.swift */; }; - 4B957B8E2AC7AE700062CA31 /* AutofillTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C00ECA292F839D009C73A6 /* AutofillTabExtension.swift */; }; - 4B957B8F2AC7AE700062CA31 /* Assertions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E319372953446000DD3BCF /* Assertions.swift */; }; - 4B957B902AC7AE700062CA31 /* BookmarkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB549DE25DAB8F80058460B /* BookmarkViewModel.swift */; }; - 4B957B912AC7AE700062CA31 /* DaxSpeech.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85707F27276A34D900DC0649 /* DaxSpeech.swift */; }; - 4B957B922AC7AE700062CA31 /* DuckURLSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31F28C5228C8EECA00119F70 /* DuckURLSchemeHandler.swift */; }; - 4B957B932AC7AE700062CA31 /* FirePopoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA13DCB3271480B0006D48D3 /* FirePopoverViewModel.swift */; }; - 4B957B942AC7AE700062CA31 /* BWCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D43EB37292B636E0065E5D6 /* BWCommand.swift */; }; - 4B957B952AC7AE700062CA31 /* NSColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F41D174025CB131900472416 /* NSColorExtension.swift */; }; - 4B957B972AC7AE700062CA31 /* AddressBarButtonsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4F525D6BF2C007F5990 /* AddressBarButtonsViewController.swift */; }; - 4B957B982AC7AE700062CA31 /* BWError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DDF076028F815AD00EDFBE3 /* BWError.swift */; }; - 4B957B9A2AC7AE700062CA31 /* PixelDataRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C92C32750EF76002AC6B0 /* PixelDataRecord.swift */; }; - 4B957B9B2AC7AE700062CA31 /* PageObserverUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 853014D525E671A000FB8205 /* PageObserverUserScript.swift */; }; - 4B957B9C2AC7AE700062CA31 /* SecureVaultErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */; }; - 4B957B9D2AC7AE700062CA31 /* NSImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B139AFC26B60BD800894F82 /* NSImageExtensions.swift */; }; - 4B957B9E2AC7AE700062CA31 /* WaitlistKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB00F2A983B24000927DB /* WaitlistKeychainStorage.swift */; }; - 4B957B9F2AC7AE700062CA31 /* PasswordManagementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85625995269C953C00EE44BC /* PasswordManagementViewController.swift */; }; - 4B957BA02AC7AE700062CA31 /* ImportedBookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB99CFA26FE191E001E4761 /* ImportedBookmarks.swift */; }; - 4B957BA12AC7AE700062CA31 /* UserDefaults+NetworkProtectionShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B934C402A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift */; }; - 4B957BA22AC7AE700062CA31 /* NavigationActionPolicyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B626A75929921FAA00053070 /* NavigationActionPolicyExtension.swift */; }; - 4B957BA32AC7AE700062CA31 /* CIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B603FD9D2A02712E00F3FCA9 /* CIImageExtension.swift */; }; - 4B957BA42AC7AE700062CA31 /* NSMenuExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6EF9B2250785D5004754E6 /* NSMenuExtension.swift */; }; - 4B957BA52AC7AE700062CA31 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7412B424D1536B00D22FE0 /* MainWindowController.swift */; }; - 4B957BA62AC7AE700062CA31 /* Tab.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA9FF95824A1ECF20039E328 /* Tab.swift */; }; - 4B957BA72AC7AE700062CA31 /* ConnectBitwardenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBDEE8E28FC14760092FAA6 /* ConnectBitwardenView.swift */; }; - 4B957BA82AC7AE700062CA31 /* DispatchQueueExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63D467025BFA6C100874977 /* DispatchQueueExtensions.swift */; }; - 4B957BA92AC7AE700062CA31 /* BookmarksBarAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850E8DFA2A6FEC5E00691187 /* BookmarksBarAppearance.swift */; }; - 4B957BAA2AC7AE700062CA31 /* PermissionAuthorizationPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64C84EA2692DD650048FEBE /* PermissionAuthorizationPopover.swift */; }; - 4B957BAB2AC7AE700062CA31 /* PopoverMessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85378D9D274E664C007C5CBF /* PopoverMessageViewController.swift */; }; - 4B957BAC2AC7AE700062CA31 /* WebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA6FFB4524DC3B5A0028F4D0 /* WebView.swift */; }; - 4B957BAD2AC7AE700062CA31 /* ShadowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693954226F04BE90015B914 /* ShadowView.swift */; }; - 4B957BAE2AC7AE700062CA31 /* FeedbackSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA3D531C27A2F58F00074EC1 /* FeedbackSender.swift */; }; - 4B957BAF2AC7AE700062CA31 /* TabExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BDDA002942389000F68088 /* TabExtensions.swift */; }; - 4B957BB02AC7AE700062CA31 /* TabBarViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA7412B024D0B3AC00D22FE0 /* TabBarViewItem.swift */; }; - 4B957BB12AC7AE700062CA31 /* NSWindow+Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 856C98D42570116900A22F1F /* NSWindow+Toast.swift */; }; - 4B957BB22AC7AE700062CA31 /* AutoconsentUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = B31055BC27A1BA1D001AC618 /* AutoconsentUserScript.swift */; }; - 4B957BB32AC7AE700062CA31 /* BookmarksExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859E7D6A27453BF3009C2B69 /* BookmarksExporter.swift */; }; - 4B957BB42AC7AE700062CA31 /* NetworkProtectionAppEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2DDCF72A93A8BB0039D884 /* NetworkProtectionAppEvents.swift */; }; - 4B957BB52AC7AE700062CA31 /* FirefoxDataImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FF67726B602B100D42879 /* FirefoxDataImporter.swift */; }; - 4B957BB62AC7AE700062CA31 /* PreferencesGeneralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8A27DB69BC00471A10 /* PreferencesGeneralView.swift */; }; - 4B957BB72AC7AE700062CA31 /* PinnedTabsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37BF3F1F286F0A7A00BD9014 /* PinnedTabsView.swift */; }; - 4B957BB92AC7AE700062CA31 /* SyncErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FD78102A29EBD100B36DB1 /* SyncErrorHandler.swift */; }; - 4B957BBA2AC7AE700062CA31 /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA8EDF2324923E980071C2E8 /* URLExtension.swift */; }; - 4B957BBB2AC7AE700062CA31 /* Tab+UIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B634DBDE293C8F7F00C3C99E /* Tab+UIDelegate.swift */; }; - 4B957BBD2AC7AE700062CA31 /* NSStoryboardExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE0DF0426781961006337B7 /* NSStoryboardExtension.swift */; }; - 4B957BBE2AC7AE700062CA31 /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37AFCE8027DA2CA600471A10 /* PreferencesViewController.swift */; }; - 4B957BBF2AC7AE700062CA31 /* FireproofDomains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B02198125E05FAC00ED7DEA /* FireproofDomains.swift */; }; - 4B957BC02AC7AE700062CA31 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B677440255DBEEA00025BD8 /* Database.swift */; }; - 4B957BC12AC7AE700062CA31 /* HorizontallyCenteredLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE5336D286915A10019DBFD /* HorizontallyCenteredLayout.swift */; }; - 4B957BC22AC7AE700062CA31 /* BookmarksOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92928526670D1600AD2C21 /* BookmarksOutlineView.swift */; }; - 4B957BC32AC7AE700062CA31 /* CountryList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE65482271FCD53008D1D63 /* CountryList.swift */; }; - 4B957BC42AC7AE700062CA31 /* PreferencesSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CD54C427F2FDD100F1F7B9 /* PreferencesSection.swift */; }; - 4B957BC52AC7AE700062CA31 /* NetworkProtectionNavBarButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60652A0B29FA00BCD287 /* NetworkProtectionNavBarButtonModel.swift */; }; - 4B957BC62AC7AE700062CA31 /* AutoconsentManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23FD2C2886A81D007F6985 /* AutoconsentManagement.swift */; }; - 4B957BC72AC7AE700062CA31 /* UserText+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D60D22A0C84F700BCD287 /* UserText+NetworkProtection.swift */; }; - 4B957BC82AC7AE700062CA31 /* WebViewContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B2400D28083B49001B8F3A /* WebViewContainerView.swift */; }; - 4B957BC92AC7AE700062CA31 /* BookmarkStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4D625D6A710007F5990 /* BookmarkStore.swift */; }; - 4B957BCA2AC7AE700062CA31 /* PrivacyDashboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6FA893E269C424500588ECD /* PrivacyDashboardViewController.swift */; }; - 4B957BCB2AC7AE700062CA31 /* PreferencesAppearanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D2771427E870D4003365FD /* PreferencesAppearanceView.swift */; }; - 4B957BCC2AC7AE700062CA31 /* NSMenuItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA72D5FD25FFF94E00C77619 /* NSMenuItemExtension.swift */; }; - 4B957BCD2AC7AE700062CA31 /* ContiguousBytesExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BA1A6C1258B0A1300F6F690 /* ContiguousBytesExtension.swift */; }; - 4B957BCE2AC7AE700062CA31 /* AdjacentItemEnumerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37534CA62811988E002621E7 /* AdjacentItemEnumerator.swift */; }; - 4B957BCF2AC7AE700062CA31 /* BookmarkDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 987799F52999996B005D8EB6 /* BookmarkDatabase.swift */; }; - 4B957BD02AC7AE700062CA31 /* ChromiumKeychainPrompt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE53373286E39F10019DBFD /* ChromiumKeychainPrompt.swift */; }; - 4B957BD12AC7AE700062CA31 /* WKProcessPool+GeolocationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6553691268440D700085A79 /* WKProcessPool+GeolocationProvider.swift */; }; - 4B957BD22AC7AE700062CA31 /* RecentlyClosedMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C1DD0285A154E0089850C /* RecentlyClosedMenu.swift */; }; - 4B957BD52AC7AE700062CA31 /* QuickLookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6F7128029F681EB00594A45 /* QuickLookUI.framework */; }; - 4B957BD62AC7AE700062CA31 /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 4B95793F2AC7AE700062CA31 /* LoginItems */; }; - 4B957BD72AC7AE700062CA31 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = 4B95793E2AC7AE700062CA31 /* NetworkProtection */; }; - 4B957BD82AC7AE700062CA31 /* BrowserServicesKit in Frameworks */ = {isa = PBXBuildFile; productRef = 4B95792B2AC7AE700062CA31 /* BrowserServicesKit */; }; - 4B957BDA2AC7AE700062CA31 /* Bookmarks in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579342AC7AE700062CA31 /* Bookmarks */; }; - 4B957BDB2AC7AE700062CA31 /* ContentBlocking in Frameworks */ = {isa = PBXBuildFile; productRef = 4B95792E2AC7AE700062CA31 /* ContentBlocking */; }; - 4B957BDC2AC7AE700062CA31 /* SwiftUIExtensions in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579372AC7AE700062CA31 /* SwiftUIExtensions */; }; - 4B957BDD2AC7AE700062CA31 /* UserScript in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579302AC7AE700062CA31 /* UserScript */; }; - 4B957BDE2AC7AE700062CA31 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579322AC7AE700062CA31 /* Configuration */; }; - 4B957BE22AC7AE700062CA31 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579292AC7AE700062CA31 /* Sparkle */; }; - 4B957BE32AC7AE700062CA31 /* Navigation in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579332AC7AE700062CA31 /* Navigation */; }; - 4B957BE42AC7AE700062CA31 /* DDGSync in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579352AC7AE700062CA31 /* DDGSync */; }; - 4B957BE52AC7AE700062CA31 /* OpenSSL in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579382AC7AE700062CA31 /* OpenSSL */; }; - 4B957BE62AC7AE700062CA31 /* PrivacyDashboard in Frameworks */ = {isa = PBXBuildFile; productRef = 4B95792F2AC7AE700062CA31 /* PrivacyDashboard */; }; - 4B957BE72AC7AE700062CA31 /* SyncDataProviders in Frameworks */ = {isa = PBXBuildFile; productRef = 4B95793C2AC7AE700062CA31 /* SyncDataProviders */; }; - 4B957BE82AC7AE700062CA31 /* SyncUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579362AC7AE700062CA31 /* SyncUI */; }; - 4B957BE92AC7AE700062CA31 /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4B95793D2AC7AE700062CA31 /* NetworkProtectionUI */; }; - 4B957BEB2AC7AE700062CA31 /* Persistence in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579312AC7AE700062CA31 /* Persistence */; }; - 4B957BEF2AC7AE700062CA31 /* CrashReports.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA693E5D2696E5B90007BB78 /* CrashReports.storyboard */; }; - 4B957BF02AC7AE700062CA31 /* trackerData.json in Resources */ = {isa = PBXBuildFile; fileRef = 9833913027AAA4B500DAF119 /* trackerData.json */; }; - 4B957BF12AC7AE700062CA31 /* dark-shield-dot-mouse-over.json in Resources */ = {isa = PBXBuildFile; fileRef = AA7EB6EC27E880B600036718 /* dark-shield-dot-mouse-over.json */; }; - 4B957BF22AC7AE700062CA31 /* 01_Fire_really_small.json in Resources */ = {isa = PBXBuildFile; fileRef = 8511E18325F82B34002F516B /* 01_Fire_really_small.json */; }; - 4B957BF32AC7AE700062CA31 /* Onboarding.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 85B7184927677C2D00B4277F /* Onboarding.storyboard */; }; - 4B957BF42AC7AE700062CA31 /* FireproofDomains.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B0511AD262CAA5A00F6079C /* FireproofDomains.storyboard */; }; - 4B957BF52AC7AE700062CA31 /* clickToLoadConfig.json in Resources */ = {isa = PBXBuildFile; fileRef = EA47767F272A21B700419EDA /* clickToLoadConfig.json */; }; - 4B957BF62AC7AE700062CA31 /* Downloads.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B6B1E88126D5DAC30062C350 /* Downloads.storyboard */; }; - 4B957BF72AC7AE700062CA31 /* dark-shield.json in Resources */ = {isa = PBXBuildFile; fileRef = AA34396F2754D4E900B241FA /* dark-shield.json */; }; - 4B957BF82AC7AE700062CA31 /* BookmarksBarPromptAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 859F30662A72B38500C20372 /* BookmarksBarPromptAssets.xcassets */; }; - 4B957BF92AC7AE700062CA31 /* dark-shield-mouse-over.json in Resources */ = {isa = PBXBuildFile; fileRef = AA7EB6EA27E880AE00036718 /* dark-shield-mouse-over.json */; }; - 4B957BFA2AC7AE700062CA31 /* autoconsent-bundle.js in Resources */ = {isa = PBXBuildFile; fileRef = B31055C327A1BA1D001AC618 /* autoconsent-bundle.js */; }; - 4B957BFB2AC7AE700062CA31 /* ContentOverlay.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7B1E819C27C8874900FF0E60 /* ContentOverlay.storyboard */; }; - 4B957BFC2AC7AE700062CA31 /* FindInPage.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 85A0117325AF2EDF00FA6A0C /* FindInPage.storyboard */; }; - 4B957BFD2AC7AE700062CA31 /* JSAlert.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EEC111E3294D06020086524F /* JSAlert.storyboard */; }; - 4B957C002AC7AE700062CA31 /* userscript.js in Resources */ = {isa = PBXBuildFile; fileRef = B31055BE27A1BA1D001AC618 /* userscript.js */; }; - 4B957C012AC7AE700062CA31 /* fb-tds.json in Resources */ = {isa = PBXBuildFile; fileRef = EA4617EF273A28A700F110A2 /* fb-tds.json */; }; - 4B957C032AC7AE700062CA31 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = AA68C3D62490F821001B8783 /* README.md */; }; - 4B957C042AC7AE700062CA31 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AA585D85248FD31400E9A3E2 /* Assets.xcassets */; }; - 4B957C052AC7AE700062CA31 /* NavigationBar.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 85589E8C27BBBB870038AD11 /* NavigationBar.storyboard */; }; - 4B957C062AC7AE700062CA31 /* FirePopoverCollectionViewHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = AAE246F5270A3D3000BEEAEE /* FirePopoverCollectionViewHeader.xib */; }; - 4B957C072AC7AE700062CA31 /* TabBar.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA80EC7B256C46AA007083E7 /* TabBar.storyboard */; }; - 4B957C082AC7AE700062CA31 /* shield-dot.json in Resources */ = {isa = PBXBuildFile; fileRef = AA34396B2754D4E300B241FA /* shield-dot.json */; }; - 4B957C0B2AC7AE700062CA31 /* BookmarksBarCollectionViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BE53369286912D40019DBFD /* BookmarksBarCollectionViewItem.xib */; }; - 4B957C0C2AC7AE700062CA31 /* PrivacyDashboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B6FA893C269C423100588ECD /* PrivacyDashboard.storyboard */; }; - 4B957C0D2AC7AE700062CA31 /* shield.json in Resources */ = {isa = PBXBuildFile; fileRef = AA34396A2754D4E200B241FA /* shield.json */; }; - 4B957C0E2AC7AE700062CA31 /* TabBarViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = AA7412B124D0B3AC00D22FE0 /* TabBarViewItem.xib */; }; - 4B957C102AC7AE700062CA31 /* httpsMobileV2FalsePositives.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B67742A255DBEB800025BD8 /* httpsMobileV2FalsePositives.json */; }; - 4B957C112AC7AE700062CA31 /* BookmarksBar.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4BD18F04283F151F00058124 /* BookmarksBar.storyboard */; }; - 4B957C122AC7AE700062CA31 /* trackers-1.json in Resources */ = {isa = PBXBuildFile; fileRef = AA3439732754D55100B241FA /* trackers-1.json */; }; - 4B957C132AC7AE700062CA31 /* dark-trackers-1.json in Resources */ = {isa = PBXBuildFile; fileRef = AA3439762754D55100B241FA /* dark-trackers-1.json */; }; - 4B957C142AC7AE700062CA31 /* Feedback.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA3863C427A1E28F00749AB5 /* Feedback.storyboard */; }; - 4B957C182AC7AE700062CA31 /* shield-mouse-over.json in Resources */ = {isa = PBXBuildFile; fileRef = AA7EB6E627E8809D00036718 /* shield-mouse-over.json */; }; - 4B957C1A2AC7AE700062CA31 /* PermissionAuthorization.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64C84DD2692D7400048FEBE /* PermissionAuthorization.storyboard */; }; - 4B957C1B2AC7AE700062CA31 /* dark-trackers-3.json in Resources */ = {isa = PBXBuildFile; fileRef = AA3439772754D55100B241FA /* dark-trackers-3.json */; }; - 4B957C1C2AC7AE700062CA31 /* dark-trackers-2.json in Resources */ = {isa = PBXBuildFile; fileRef = AA3439722754D55100B241FA /* dark-trackers-2.json */; }; - 4B957C1D2AC7AE700062CA31 /* Fire.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AAB7320626DD0C37002FACF9 /* Fire.storyboard */; }; - 4B957C1F2AC7AE700062CA31 /* social_images in Resources */ = {isa = PBXBuildFile; fileRef = EA18D1C9272F0DC8006DC101 /* social_images */; }; - 4B957C202AC7AE700062CA31 /* shield-dot-mouse-over.json in Resources */ = {isa = PBXBuildFile; fileRef = AA7EB6E827E880A600036718 /* shield-dot-mouse-over.json */; }; - 4B957C222AC7AE700062CA31 /* fb-sdk.js in Resources */ = {isa = PBXBuildFile; fileRef = EAC80DDF271F6C0100BBF02D /* fb-sdk.js */; }; - 4B957C232AC7AE700062CA31 /* PasswordManager.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 85625993269C8F9600EE44BC /* PasswordManager.storyboard */; }; - 4B957C242AC7AE700062CA31 /* dark-flame-mouse-over.json in Resources */ = {isa = PBXBuildFile; fileRef = AA7EB6E127E7D05500036718 /* dark-flame-mouse-over.json */; }; - 4B957C252AC7AE700062CA31 /* flame-mouse-over.json in Resources */ = {isa = PBXBuildFile; fileRef = AA7EB6E027E7D05500036718 /* flame-mouse-over.json */; }; - 4B957C262AC7AE700062CA31 /* httpsMobileV2Bloom.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B677428255DBEB800025BD8 /* httpsMobileV2Bloom.bin */; }; - 4B957C272AC7AE700062CA31 /* trackers-3.json in Resources */ = {isa = PBXBuildFile; fileRef = AA3439752754D55100B241FA /* trackers-3.json */; }; - 4B957C282AC7AE700062CA31 /* macos-config.json in Resources */ = {isa = PBXBuildFile; fileRef = 026ADE1326C3010C002518EE /* macos-config.json */; }; - 4B957C292AC7AE700062CA31 /* httpsMobileV2BloomSpec.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B677427255DBEB800025BD8 /* httpsMobileV2BloomSpec.json */; }; - 4B957C2A2AC7AE700062CA31 /* TabBarFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = AA2CB12C2587BB5600AA6FBE /* TabBarFooter.xib */; }; - 4B957C2C2AC7AE700062CA31 /* FirePopoverCollectionViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = AAE246F22709EF3B00BEEAEE /* FirePopoverCollectionViewItem.xib */; }; - 4B957C2D2AC7AE700062CA31 /* ProximaNova-Bold-webfont.woff2 in Resources */ = {isa = PBXBuildFile; fileRef = EAA29AE7278D2E43007070CF /* ProximaNova-Bold-webfont.woff2 */; }; - 4B957C2E2AC7AE700062CA31 /* dark-shield-dot.json in Resources */ = {isa = PBXBuildFile; fileRef = AA34396E2754D4E900B241FA /* dark-shield-dot.json */; }; - 4B957C2F2AC7AE700062CA31 /* trackers-2.json in Resources */ = {isa = PBXBuildFile; fileRef = AA3439742754D55100B241FA /* trackers-2.json */; }; - 4B957C302AC7AE700062CA31 /* ProximaNova-Reg-webfont.woff2 in Resources */ = {isa = PBXBuildFile; fileRef = EAA29AE8278D2E43007070CF /* ProximaNova-Reg-webfont.woff2 */; }; - 4B957C312AC7AE700062CA31 /* clickToLoad.js in Resources */ = {isa = PBXBuildFile; fileRef = EAFAD6C92728BD1200F9DF00 /* clickToLoad.js */; }; - 4B957C342AC7AE700062CA31 /* DuckDuckGo VPN.app in Embed Login Items */ = {isa = PBXBuildFile; fileRef = 4B2D06392A11CFBB00DE1F49 /* DuckDuckGo VPN.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 4B957C352AC7AE700062CA31 /* DuckDuckGo Notifications.app in Embed Login Items */ = {isa = PBXBuildFile; fileRef = 4B4BEC202A11B4E2001D9AC5 /* DuckDuckGo Notifications.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 4B9754EC2984300100D7B834 /* EmailManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3B848F297A0E1000A384BD /* EmailManagerExtension.swift */; }; 4B980E212817604000282EE1 /* NSNotificationName+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B980E202817604000282EE1 /* NSNotificationName+Debug.swift */; }; 4B98D27A28D95F1A003C2B6F /* ChromiumFaviconsReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98D27928D95F1A003C2B6F /* ChromiumFaviconsReaderTests.swift */; }; @@ -2033,8 +1281,6 @@ 4B9DB02A2A983B24000927DB /* WaitlistStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB00E2A983B24000927DB /* WaitlistStorage.swift */; }; 4B9DB02C2A983B24000927DB /* WaitlistKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB00F2A983B24000927DB /* WaitlistKeychainStorage.swift */; }; 4B9DB02D2A983B24000927DB /* WaitlistKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB00F2A983B24000927DB /* WaitlistKeychainStorage.swift */; }; - 4B9DB0322A983B24000927DB /* EnableWaitlistFeatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0132A983B24000927DB /* EnableWaitlistFeatureView.swift */; }; - 4B9DB0332A983B24000927DB /* EnableWaitlistFeatureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0132A983B24000927DB /* EnableWaitlistFeatureView.swift */; }; 4B9DB0352A983B24000927DB /* WaitlistTermsAndConditionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0142A983B24000927DB /* WaitlistTermsAndConditionsView.swift */; }; 4B9DB0362A983B24000927DB /* WaitlistTermsAndConditionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0142A983B24000927DB /* WaitlistTermsAndConditionsView.swift */; }; 4B9DB0382A983B24000927DB /* JoinedWaitlistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0152A983B24000927DB /* JoinedWaitlistView.swift */; }; @@ -2055,8 +1301,6 @@ 4B9DB0552A983B55000927DB /* MockWaitlistStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB04F2A983B55000927DB /* MockWaitlistStorage.swift */; }; 4B9DB0562A983B55000927DB /* MockNotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0502A983B55000927DB /* MockNotificationService.swift */; }; 4B9DB0572A983B55000927DB /* MockNotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0502A983B55000927DB /* MockNotificationService.swift */; }; - 4B9DB0582A983B55000927DB /* MockNetworkProtectionCodeRedeemer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0512A983B55000927DB /* MockNetworkProtectionCodeRedeemer.swift */; }; - 4B9DB0592A983B55000927DB /* MockNetworkProtectionCodeRedeemer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0512A983B55000927DB /* MockNetworkProtectionCodeRedeemer.swift */; }; 4B9DB05A2A983B55000927DB /* MockWaitlistRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0522A983B55000927DB /* MockWaitlistRequest.swift */; }; 4B9DB05B2A983B55000927DB /* MockWaitlistRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0522A983B55000927DB /* MockWaitlistRequest.swift */; }; 4B9DB05C2A983B55000927DB /* WaitlistViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9DB0532A983B55000927DB /* WaitlistViewModelTests.swift */; }; @@ -2106,7 +1350,6 @@ 4BBF0917282DD6EF00EE1418 /* TemporaryFileHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF0916282DD6EF00EE1418 /* TemporaryFileHandlerTests.swift */; }; 4BBF09232830812900EE1418 /* FileSystemDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF09222830812900EE1418 /* FileSystemDSL.swift */; }; 4BBF0925283083EC00EE1418 /* FileSystemDSLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBF0924283083EC00EE1418 /* FileSystemDSLTests.swift */; }; - 4BC2621D293996410087A482 /* PixelEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC2621C293996410087A482 /* PixelEventTests.swift */; }; 4BCBE4552BA7E16600FC75A1 /* NetworkProtectionSubscriptionEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2F565B2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift */; }; 4BCBE4562BA7E16900FC75A1 /* DataBrokerProtectionSubscriptionEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5789712B2CA70F0009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift */; }; 4BCBE4582BA7E17800FC75A1 /* SubscriptionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 4BCBE4572BA7E17800FC75A1 /* SubscriptionUI */; }; @@ -2123,7 +1366,6 @@ 4BD57C042AC112DF00B580EE /* NetworkProtectionRemoteMessagingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD57C032AC112DF00B580EE /* NetworkProtectionRemoteMessagingTests.swift */; }; 4BD57C052AC112DF00B580EE /* NetworkProtectionRemoteMessagingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD57C032AC112DF00B580EE /* NetworkProtectionRemoteMessagingTests.swift */; }; 4BDFA4AE27BF19E500648192 /* ToggleableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDFA4AD27BF19E500648192 /* ToggleableScrollView.swift */; }; - 4BE0DF06267819A1006337B7 /* NSStoryboardExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE0DF0426781961006337B7 /* NSStoryboardExtension.swift */; }; 4BE344EE2B2376DF003FC223 /* VPNFeedbackFormViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE344ED2B2376DF003FC223 /* VPNFeedbackFormViewModelTests.swift */; }; 4BE344EF2B23786F003FC223 /* VPNFeedbackFormViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE344ED2B2376DF003FC223 /* VPNFeedbackFormViewModelTests.swift */; }; 4BE4005327CF3DC3007D3161 /* SavePaymentMethodPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE4005227CF3DC3007D3161 /* SavePaymentMethodPopover.swift */; }; @@ -2148,14 +1390,12 @@ 4BF0E5062AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; 4BF0E5072AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; 4BF0E5082AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; - 4BF0E50A2AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; 4BF0E50B2AD2552200FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; 4BF0E50C2AD2552300FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */; }; 4BF0E5122AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5112AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift */; }; 4BF0E5132AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5112AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift */; }; 4BF0E5142AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5112AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift */; }; 4BF0E5152AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5112AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift */; }; - 4BF0E5172AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0E5112AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift */; }; 4BF4951826C08395000547B8 /* ThirdPartyBrowserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF4951726C08395000547B8 /* ThirdPartyBrowserTests.swift */; }; 4BF4EA5027C71F26004E57C4 /* PasswordManagementListSectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF4EA4F27C71F26004E57C4 /* PasswordManagementListSectionTests.swift */; }; 4BF6961D28BE911100D402D4 /* RecentlyVisitedSiteModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF6961C28BE911100D402D4 /* RecentlyVisitedSiteModelTests.swift */; }; @@ -2182,6 +1422,12 @@ 561D66682B95C45A008ACC5C /* Suggestion.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 561D66692B95C45A008ACC5C /* Suggestion.storyboard */; }; 562532A02BC069180034D316 /* ZoomPopoverViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5625329D2BC069100034D316 /* ZoomPopoverViewModelTests.swift */; }; 562532A12BC069190034D316 /* ZoomPopoverViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5625329D2BC069100034D316 /* ZoomPopoverViewModelTests.swift */; }; + 560C3FFC2BC9911000F589CE /* PermanentSurveyManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560C3FFB2BC9911000F589CE /* PermanentSurveyManagerTests.swift */; }; + 560C3FFD2BC9911000F589CE /* PermanentSurveyManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560C3FFB2BC9911000F589CE /* PermanentSurveyManagerTests.swift */; }; + 560C3FFF2BCD5A1E00F589CE /* PermanentSurveyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560C3FFE2BCD5A1E00F589CE /* PermanentSurveyManager.swift */; }; + 560C40002BCD5A1E00F589CE /* PermanentSurveyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560C3FFE2BCD5A1E00F589CE /* PermanentSurveyManager.swift */; }; + 561D66662B95C45A008ACC5C /* Suggestion.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 561D66692B95C45A008ACC5C /* Suggestion.storyboard */; }; + 561D66672B95C45A008ACC5C /* Suggestion.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 561D66692B95C45A008ACC5C /* Suggestion.storyboard */; }; 562984702AC4610100AC20EB /* SyncPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5629846E2AC4610100AC20EB /* SyncPreferencesTests.swift */; }; 562984712AC469E400AC20EB /* SyncPreferencesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5629846E2AC4610100AC20EB /* SyncPreferencesTests.swift */; }; 56534DED29DF252C00121467 /* CapturingDefaultBrowserProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56534DEC29DF252C00121467 /* CapturingDefaultBrowserProvider.swift */; }; @@ -2202,9 +1448,18 @@ 569277C529DEE09D00B633EF /* ContinueSetUpModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569277C329DEE09D00B633EF /* ContinueSetUpModelTests.swift */; }; 56B234BF2A84EFD200F2A1CC /* NavigationBarUrlExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56B234BE2A84EFD200F2A1CC /* NavigationBarUrlExtensionsTests.swift */; }; 56B234C02A84EFD800F2A1CC /* NavigationBarUrlExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56B234BE2A84EFD200F2A1CC /* NavigationBarUrlExtensionsTests.swift */; }; + 56BA1E752BAAF70F001CF69F /* SSLErrorPageTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E742BAAF70F001CF69F /* SSLErrorPageTabExtension.swift */; }; + 56BA1E762BAAF70F001CF69F /* SSLErrorPageTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E742BAAF70F001CF69F /* SSLErrorPageTabExtension.swift */; }; + 56BA1E7F2BAB2D29001CF69F /* ErrorPageTabExtensionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E7C2BAB290E001CF69F /* ErrorPageTabExtensionTest.swift */; }; + 56BA1E802BAB2E43001CF69F /* ErrorPageTabExtensionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E7C2BAB290E001CF69F /* ErrorPageTabExtensionTest.swift */; }; + 56BA1E822BAC506F001CF69F /* SSLErrorPageUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E812BAC506F001CF69F /* SSLErrorPageUserScript.swift */; }; + 56BA1E832BAC506F001CF69F /* SSLErrorPageUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E812BAC506F001CF69F /* SSLErrorPageUserScript.swift */; }; + 56BA1E872BAC8239001CF69F /* SSLErrorPageUserScriptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E862BAC8239001CF69F /* SSLErrorPageUserScriptTests.swift */; }; + 56BA1E882BAC8239001CF69F /* SSLErrorPageUserScriptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E862BAC8239001CF69F /* SSLErrorPageUserScriptTests.swift */; }; + 56BA1E8A2BB1CB5B001CF69F /* CertificateTrustEvaluator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E892BB1CB5B001CF69F /* CertificateTrustEvaluator.swift */; }; + 56BA1E8B2BB1CB5B001CF69F /* CertificateTrustEvaluator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BA1E892BB1CB5B001CF69F /* CertificateTrustEvaluator.swift */; }; 56CEE90E2B7A725B00CF10AA /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 56CEE90D2B7A6DE100CF10AA /* InfoPlist.xcstrings */; }; 56CEE90F2B7A725C00CF10AA /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 56CEE90D2B7A6DE100CF10AA /* InfoPlist.xcstrings */; }; - 56CEE9102B7A72FE00CF10AA /* InfoPlist.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 56CEE90D2B7A6DE100CF10AA /* InfoPlist.xcstrings */; }; 56D145E829E6BB6300E3488A /* CapturingDataImportProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56D145E729E6BB6300E3488A /* CapturingDataImportProvider.swift */; }; 56D145E929E6BB6300E3488A /* CapturingDataImportProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56D145E729E6BB6300E3488A /* CapturingDataImportProvider.swift */; }; 56D145EB29E6C99B00E3488A /* DataImportStatusProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56D145EA29E6C99B00E3488A /* DataImportStatusProviding.swift */; }; @@ -2235,33 +1490,28 @@ 7B2DDCFB2A93B25F0039D884 /* KeychainType+ClientDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */; }; 7B2E52252A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2E52242A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift */; }; 7B31FD8C2AD125620086AA24 /* NetworkProtectionIPC in Frameworks */ = {isa = PBXBuildFile; productRef = 7B31FD8B2AD125620086AA24 /* NetworkProtectionIPC */; }; - 7B31FD902AD1257B0086AA24 /* NetworkProtectionIPC in Frameworks */ = {isa = PBXBuildFile; productRef = 7B31FD8F2AD1257B0086AA24 /* NetworkProtectionIPC */; }; 7B3618C22ADE75C8000D6154 /* NetworkProtectionNavBarPopoverManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3618C12ADE75C8000D6154 /* NetworkProtectionNavBarPopoverManager.swift */; }; - 7B3618C52ADE77D3000D6154 /* NetworkProtectionNavBarPopoverManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3618C12ADE75C8000D6154 /* NetworkProtectionNavBarPopoverManager.swift */; }; 7B37C7A52BAA32A50062546A /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = 7B37C7A42BAA32A50062546A /* Subscription */; }; 7B430EA12A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */; }; 7B430EA22A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */; }; 7B4CE8E726F02135009134B1 /* TabBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4CE8E626F02134009134B1 /* TabBarTests.swift */; }; - 7B5DD69A2AE51FFA001DE99C /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B5DD6992AE51FFA001DE99C /* PixelKit */; }; - 7B5F9A752AE2BE4E002AEBC0 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B5F9A742AE2BE4E002AEBC0 /* PixelKit */; }; + 7B4D8A212BDA857300852966 /* VPNOperationErrorRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4D8A202BDA857300852966 /* VPNOperationErrorRecorder.swift */; }; + 7B4D8A222BDA857300852966 /* VPNOperationErrorRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4D8A202BDA857300852966 /* VPNOperationErrorRecorder.swift */; }; + 7B4D8A232BDA857300852966 /* VPNOperationErrorRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4D8A202BDA857300852966 /* VPNOperationErrorRecorder.swift */; }; + 7B4D8A242BDA857300852966 /* VPNOperationErrorRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4D8A202BDA857300852966 /* VPNOperationErrorRecorder.swift */; }; 7B624F172BA25C1F00A6C544 /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 7B624F162BA25C1F00A6C544 /* NetworkProtectionUI */; }; 7B7DFB202B7E736B009EA1A3 /* MacPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */; }; 7B7DFB222B7E7473009EA1A3 /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 7B7DFB212B7E7473009EA1A3 /* Networking */; }; 7B7FCD0F2BA33B2700C04FBE /* UserDefaults+vpnLegacyUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7FCD0E2BA33B2700C04FBE /* UserDefaults+vpnLegacyUser.swift */; }; 7B7FCD102BA33B2700C04FBE /* UserDefaults+vpnLegacyUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7FCD0E2BA33B2700C04FBE /* UserDefaults+vpnLegacyUser.swift */; }; - 7B7FCD112BA33B2700C04FBE /* UserDefaults+vpnLegacyUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7FCD0E2BA33B2700C04FBE /* UserDefaults+vpnLegacyUser.swift */; }; - 7B8C083C2AE1268E00F4C67F /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B8C083B2AE1268E00F4C67F /* PixelKit */; }; 7B8DB31A2B504D7500EC16DA /* VPNAppEventsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8DB3192B504D7500EC16DA /* VPNAppEventsHandler.swift */; }; 7B934C412A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B934C402A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift */; }; - 7B94E1652B7ED95100E32B96 /* NetworkProtectionProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 7B94E1642B7ED95100E32B96 /* NetworkProtectionProxy */; }; 7B97CD592B7E0B57004FEF43 /* NetworkProtectionProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 7B97CD582B7E0B57004FEF43 /* NetworkProtectionProxy */; }; 7B97CD5B2B7E0B85004FEF43 /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 7B97CD5A2B7E0B85004FEF43 /* Common */; }; 7B97CD5C2B7E0BBB004FEF43 /* UserDefaultsWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C6A29525CC1FFD00EEB5F1 /* UserDefaultsWrapper.swift */; }; 7B97CD5D2B7E0BCE004FEF43 /* BundleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106B9D26A565DA0013B453 /* BundleExtension.swift */; }; 7B97CD5E2B7E0BEA004FEF43 /* OptionalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B637273C26CCF0C200C8CB02 /* OptionalExtension.swift */; }; 7B97CD5F2B7E0BF7004FEF43 /* NSApplicationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5C8F622591021700748EB7 /* NSApplicationExtension.swift */; }; - 7B97CD602B7E0C2E004FEF43 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85799C1725DEBB3F0007EC87 /* Logging.swift */; }; - 7B97CD622B7E0C4B004FEF43 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B97CD612B7E0C4B004FEF43 /* PixelKit */; }; 7BA076BB2B65D61400D7FB72 /* NetworkProtectionProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA076BA2B65D61400D7FB72 /* NetworkProtectionProxy */; }; 7BA4727D26F01BC400EAA165 /* CoreDataTestUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B9292C42667104B00AD2C21 /* CoreDataTestUtilities.swift */; }; 7BA59C9B2AE18B49009A97B1 /* SystemExtensionManager in Frameworks */ = {isa = PBXBuildFile; productRef = 7BA59C9A2AE18B49009A97B1 /* SystemExtensionManager */; }; @@ -2281,7 +1531,6 @@ 7BA7CC4B2AD11EC60042E5CE /* NetworkProtectionControllerErrorStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606A2A0B29FA00BCD287 /* NetworkProtectionControllerErrorStore.swift */; }; 7BA7CC4C2AD11EC70042E5CE /* NetworkProtectionControllerErrorStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D606A2A0B29FA00BCD287 /* NetworkProtectionControllerErrorStore.swift */; }; 7BA7CC4E2AD11F6F0042E5CE /* NetworkProtectionIPCTunnelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA7CC4D2AD11F6F0042E5CE /* NetworkProtectionIPCTunnelController.swift */; }; - 7BA7CC502AD11F6F0042E5CE /* NetworkProtectionIPCTunnelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BA7CC4D2AD11F6F0042E5CE /* NetworkProtectionIPCTunnelController.swift */; }; 7BA7CC532AD11FCE0042E5CE /* Bundle+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605E2A0B29FA00BCD287 /* Bundle+VPN.swift */; }; 7BA7CC542AD11FCE0042E5CE /* Bundle+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605E2A0B29FA00BCD287 /* Bundle+VPN.swift */; }; 7BA7CC552AD11FFB0042E5CE /* NetworkProtectionOptionKeyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605F2A0B29FA00BCD287 /* NetworkProtectionOptionKeyExtension.swift */; }; @@ -2298,8 +1547,6 @@ 7BB108592A43375D000AB95F /* PFMoveApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BB108582A43375D000AB95F /* PFMoveApplication.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 7BBA7CE62BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBA7CE52BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift */; }; 7BBA7CE72BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBA7CE52BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift */; }; - 7BBA7CEA2BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBA7CE52BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift */; }; - 7BBD44282AD730A400D0A064 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7BBD44272AD730A400D0A064 /* PixelKit */; }; 7BBD45B12A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */; }; 7BBD45B22A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */; }; 7BBE2B7B2B61663C00697445 /* NetworkProtectionProxy in Frameworks */ = {isa = PBXBuildFile; productRef = 7BBE2B7A2B61663C00697445 /* NetworkProtectionProxy */; }; @@ -2313,23 +1560,16 @@ 7BEC182F2AD5D8DC00D30536 /* SystemExtensionManager in Frameworks */ = {isa = PBXBuildFile; productRef = 7BEC182E2AD5D8DC00D30536 /* SystemExtensionManager */; }; 7BEC20422B0F505F00243D3E /* AddBookmarkPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEC20402B0F505F00243D3E /* AddBookmarkPopoverView.swift */; }; 7BEC20432B0F505F00243D3E /* AddBookmarkPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEC20402B0F505F00243D3E /* AddBookmarkPopoverView.swift */; }; - 7BEC20442B0F505F00243D3E /* AddBookmarkPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEC20402B0F505F00243D3E /* AddBookmarkPopoverView.swift */; }; 7BEC20452B0F505F00243D3E /* AddBookmarkFolderPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEC20412B0F505F00243D3E /* AddBookmarkFolderPopoverView.swift */; }; 7BEC20462B0F505F00243D3E /* AddBookmarkFolderPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEC20412B0F505F00243D3E /* AddBookmarkFolderPopoverView.swift */; }; - 7BEC20472B0F505F00243D3E /* AddBookmarkFolderPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEC20412B0F505F00243D3E /* AddBookmarkFolderPopoverView.swift */; }; 7BEEA5122AD1235B00A9E72B /* NetworkProtectionIPC in Frameworks */ = {isa = PBXBuildFile; productRef = 7BEEA5112AD1235B00A9E72B /* NetworkProtectionIPC */; }; 7BEEA5142AD1236300A9E72B /* NetworkProtectionIPC in Frameworks */ = {isa = PBXBuildFile; productRef = 7BEEA5132AD1236300A9E72B /* NetworkProtectionIPC */; }; 7BEEA5162AD1236E00A9E72B /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 7BEEA5152AD1236E00A9E72B /* NetworkProtectionUI */; }; - 7BFCB74E2ADE7E1A00DA3EA7 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */; }; - 7BFCB7502ADE7E2300DA3EA7 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7BFCB74F2ADE7E2300DA3EA7 /* PixelKit */; }; - 7BFE95522A9DF1CE0081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95512A9DF1CE0081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift */; }; 7BFE95542A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */; }; 7BFE95552A9DF2990081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */; }; 7BFE95562A9DF29B0081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */; }; 7BFE95592A9DF2AF0081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */; }; - 7BFE955A2A9DF4550081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFE95512A9DF1CE0081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift */; }; 7BFF850F2B0C09DA00ECACA2 /* DuckDuckGo Personal Information Removal.app in Embed Login Items */ = {isa = PBXBuildFile; fileRef = 9D9AE8D12AAA39A70026E7DC /* DuckDuckGo Personal Information Removal.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 7BFF85102B0C09E300ECACA2 /* DuckDuckGo Personal Information Removal.app in Embed Login Items */ = {isa = PBXBuildFile; fileRef = 9D9AE8D12AAA39A70026E7DC /* DuckDuckGo Personal Information Removal.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 85012B0229133F9F003D0DCC /* NavigationBarPopovers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85012B0129133F9F003D0DCC /* NavigationBarPopovers.swift */; }; 850E8DFB2A6FEC5E00691187 /* BookmarksBarAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850E8DFA2A6FEC5E00691187 /* BookmarksBarAppearance.swift */; }; 8511E18425F82B34002F516B /* 01_Fire_really_small.json in Resources */ = {isa = PBXBuildFile; fileRef = 8511E18325F82B34002F516B /* 01_Fire_really_small.json */; }; @@ -2409,17 +1649,14 @@ 85CC1D7D26A05F250062F04E /* PasswordManagementItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CC1D7C26A05F250062F04E /* PasswordManagementItemModel.swift */; }; 85D0327B2B8E3D090041D1FB /* HistoryCoordinatorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D0327A2B8E3D090041D1FB /* HistoryCoordinatorExtension.swift */; }; 85D0327C2B8E3D090041D1FB /* HistoryCoordinatorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D0327A2B8E3D090041D1FB /* HistoryCoordinatorExtension.swift */; }; - 85D0327D2B8E3D090041D1FB /* HistoryCoordinatorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D0327A2B8E3D090041D1FB /* HistoryCoordinatorExtension.swift */; }; 85D33F1225C82EB3002B91A6 /* ConfigurationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D33F1125C82EB3002B91A6 /* ConfigurationManager.swift */; }; 85D438B6256E7C9E00F3BAF8 /* ContextMenuUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D438B5256E7C9E00F3BAF8 /* ContextMenuUserScript.swift */; }; 85D44B862BA08D29001B4AB5 /* Suggestions in Frameworks */ = {isa = PBXBuildFile; productRef = 85D44B852BA08D29001B4AB5 /* Suggestions */; }; 85D44B882BA08D30001B4AB5 /* Suggestions in Frameworks */ = {isa = PBXBuildFile; productRef = 85D44B872BA08D30001B4AB5 /* Suggestions */; }; - 85D44B8A2BA08D3B001B4AB5 /* Suggestions in Frameworks */ = {isa = PBXBuildFile; productRef = 85D44B892BA08D3B001B4AB5 /* Suggestions */; }; 85D885B026A590A90077C374 /* NSNotificationName+PasswordManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D885AF26A590A90077C374 /* NSNotificationName+PasswordManager.swift */; }; 85D885B326A5A9DE0077C374 /* NSAlert+PasswordManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85D885B226A5A9DE0077C374 /* NSAlert+PasswordManager.swift */; }; 85E2BBCE2B8F534000DBEC7A /* History in Frameworks */ = {isa = PBXBuildFile; productRef = 85E2BBCD2B8F534000DBEC7A /* History */; }; 85E2BBD02B8F534A00DBEC7A /* History in Frameworks */ = {isa = PBXBuildFile; productRef = 85E2BBCF2B8F534A00DBEC7A /* History */; }; - 85E2BBD22B8F536F00DBEC7A /* History in Frameworks */ = {isa = PBXBuildFile; productRef = 85E2BBD12B8F536F00DBEC7A /* History */; }; 85F0FF1327CFAB04001C7C6E /* RecentlyVisitedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85F0FF1227CFAB04001C7C6E /* RecentlyVisitedView.swift */; }; 85F1B0C925EF9759004792B6 /* URLEventHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85F1B0C825EF9759004792B6 /* URLEventHandlerTests.swift */; }; 85F487B5276A8F2E003CE668 /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85F487B4276A8F2E003CE668 /* OnboardingTests.swift */; }; @@ -2450,8 +1687,6 @@ 98A50964294B691800D10880 /* Persistence in Frameworks */ = {isa = PBXBuildFile; productRef = 98A50963294B691800D10880 /* Persistence */; }; 98A95D88299A2DF900B9B81A /* BookmarkMigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A95D87299A2DF900B9B81A /* BookmarkMigrationTests.swift */; }; 98EB5D1027516A4800681FE6 /* AppPrivacyConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98EB5D0F27516A4800681FE6 /* AppPrivacyConfigurationTests.swift */; }; - 9D6983F92AC773C3002C02FC /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9D6983F82AC773C3002C02FC /* PixelKit */; }; - 9D6983FB2AC773C8002C02FC /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9D6983FA2AC773C8002C02FC /* PixelKit */; }; 9D9AE8692AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE8682AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift */; }; 9D9AE86B2AA76CF90026E7DC /* LoginItemsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE86A2AA76CF90026E7DC /* LoginItemsManager.swift */; }; 9D9AE86C2AA76D1B0026E7DC /* LoginItemsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE86A2AA76CF90026E7DC /* LoginItemsManager.swift */; }; @@ -2468,11 +1703,18 @@ 9D9AE92A2AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE9282AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift */; }; 9D9AE92C2AAB84FF0026E7DC /* DBPMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */; }; 9D9AE92D2AAB84FF0026E7DC /* DBPMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */; }; - 9DB6E7242AA0DC5800A17F3C /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 9DB6E7232AA0DC5800A17F3C /* LoginItems */; }; 9DC70B1A2AA1FA5B005A844B /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = 9DC70B192AA1FA5B005A844B /* LoginItems */; }; 9DEF97E12B06C4EE00764F03 /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 9DEF97E02B06C4EE00764F03 /* Networking */; }; 9F0A2CF82B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0A2CF72B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift */; }; 9F0A2CF92B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0A2CF72B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift */; }; + 9F0FFFB42BCCAE37007C87DD /* BookmarkAllTabsDialogCoordinatorViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0FFFB32BCCAE37007C87DD /* BookmarkAllTabsDialogCoordinatorViewModelTests.swift */; }; + 9F0FFFB52BCCAE37007C87DD /* BookmarkAllTabsDialogCoordinatorViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0FFFB32BCCAE37007C87DD /* BookmarkAllTabsDialogCoordinatorViewModelTests.swift */; }; + 9F0FFFB82BCCAE9C007C87DD /* AddEditBookmarkDialogViewModelMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0FFFB72BCCAE9C007C87DD /* AddEditBookmarkDialogViewModelMock.swift */; }; + 9F0FFFB92BCCAE9C007C87DD /* AddEditBookmarkDialogViewModelMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0FFFB72BCCAE9C007C87DD /* AddEditBookmarkDialogViewModelMock.swift */; }; + 9F0FFFBB2BCCAEC2007C87DD /* AddEditBookmarkFolderDialogViewModelMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0FFFBA2BCCAEC2007C87DD /* AddEditBookmarkFolderDialogViewModelMock.swift */; }; + 9F0FFFBC2BCCAEC2007C87DD /* AddEditBookmarkFolderDialogViewModelMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0FFFBA2BCCAEC2007C87DD /* AddEditBookmarkFolderDialogViewModelMock.swift */; }; + 9F0FFFBE2BCCAF1F007C87DD /* BookmarkAllTabsDialogViewModelMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0FFFBD2BCCAF1F007C87DD /* BookmarkAllTabsDialogViewModelMock.swift */; }; + 9F0FFFBF2BCCAF1F007C87DD /* BookmarkAllTabsDialogViewModelMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0FFFBD2BCCAF1F007C87DD /* BookmarkAllTabsDialogViewModelMock.swift */; }; 9F180D0F2B69C553000D695F /* Tab+WKUIDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F180D0E2B69C553000D695F /* Tab+WKUIDelegateTests.swift */; }; 9F180D102B69C553000D695F /* Tab+WKUIDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F180D0E2B69C553000D695F /* Tab+WKUIDelegateTests.swift */; }; 9F180D122B69C665000D695F /* DownloadsTabExtensionMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F180D112B69C665000D695F /* DownloadsTabExtensionMock.swift */; }; @@ -2481,69 +1723,92 @@ 9F26060C2B85C20B00819292 /* AddEditBookmarkDialogViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2606092B85C20400819292 /* AddEditBookmarkDialogViewModelTests.swift */; }; 9F26060E2B85E17D00819292 /* AddEditBookmarkDialogCoordinatorViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F26060D2B85E17D00819292 /* AddEditBookmarkDialogCoordinatorViewModelTests.swift */; }; 9F26060F2B85E17D00819292 /* AddEditBookmarkDialogCoordinatorViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F26060D2B85E17D00819292 /* AddEditBookmarkDialogCoordinatorViewModelTests.swift */; }; + 9F33445E2BBFA77F0040CBEB /* BookmarksBarVisibilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F33445D2BBFA77F0040CBEB /* BookmarksBarVisibilityManager.swift */; }; + 9F33445F2BBFA77F0040CBEB /* BookmarksBarVisibilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F33445D2BBFA77F0040CBEB /* BookmarksBarVisibilityManager.swift */; }; + 9F3344622BBFBDA40040CBEB /* BookmarksBarVisibilityManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3344612BBFBDA40040CBEB /* BookmarksBarVisibilityManagerTests.swift */; }; + 9F3344632BBFBDA40040CBEB /* BookmarksBarVisibilityManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3344612BBFBDA40040CBEB /* BookmarksBarVisibilityManagerTests.swift */; }; 9F3910622B68C35600CB5112 /* DownloadsTabExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3910612B68C35600CB5112 /* DownloadsTabExtensionTests.swift */; }; 9F3910632B68C35600CB5112 /* DownloadsTabExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3910612B68C35600CB5112 /* DownloadsTabExtensionTests.swift */; }; 9F3910692B68D87B00CB5112 /* ProgressExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3910682B68D87B00CB5112 /* ProgressExtensionTests.swift */; }; 9F39106A2B68D87B00CB5112 /* ProgressExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3910682B68D87B00CB5112 /* ProgressExtensionTests.swift */; }; 9F514F912B7D88AD001832A9 /* AddEditBookmarkFolderDialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F514F902B7D88AD001832A9 /* AddEditBookmarkFolderDialogView.swift */; }; 9F514F922B7D88AD001832A9 /* AddEditBookmarkFolderDialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F514F902B7D88AD001832A9 /* AddEditBookmarkFolderDialogView.swift */; }; - 9F514F932B7D88AD001832A9 /* AddEditBookmarkFolderDialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F514F902B7D88AD001832A9 /* AddEditBookmarkFolderDialogView.swift */; }; 9F56CFA92B82DC4300BB7F11 /* AddEditBookmarkFolderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56CFA82B82DC4300BB7F11 /* AddEditBookmarkFolderView.swift */; }; 9F56CFAA2B82DC4300BB7F11 /* AddEditBookmarkFolderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56CFA82B82DC4300BB7F11 /* AddEditBookmarkFolderView.swift */; }; - 9F56CFAB2B82DC4300BB7F11 /* AddEditBookmarkFolderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56CFA82B82DC4300BB7F11 /* AddEditBookmarkFolderView.swift */; }; 9F56CFAD2B84326C00BB7F11 /* AddEditBookmarkDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56CFAC2B84326C00BB7F11 /* AddEditBookmarkDialogViewModel.swift */; }; 9F56CFAE2B84326C00BB7F11 /* AddEditBookmarkDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56CFAC2B84326C00BB7F11 /* AddEditBookmarkDialogViewModel.swift */; }; - 9F56CFAF2B84326C00BB7F11 /* AddEditBookmarkDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56CFAC2B84326C00BB7F11 /* AddEditBookmarkDialogViewModel.swift */; }; 9F56CFB12B843F6C00BB7F11 /* BookmarksDialogViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56CFB02B843F6C00BB7F11 /* BookmarksDialogViewFactory.swift */; }; 9F56CFB22B843F6C00BB7F11 /* BookmarksDialogViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56CFB02B843F6C00BB7F11 /* BookmarksDialogViewFactory.swift */; }; - 9F56CFB32B843F6C00BB7F11 /* BookmarksDialogViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F56CFB02B843F6C00BB7F11 /* BookmarksDialogViewFactory.swift */; }; 9F872D982B8DA9F800138637 /* Bookmarks+Tab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872D972B8DA9F800138637 /* Bookmarks+Tab.swift */; }; 9F872D992B8DA9F800138637 /* Bookmarks+Tab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872D972B8DA9F800138637 /* Bookmarks+Tab.swift */; }; - 9F872D9A2B8DA9F800138637 /* Bookmarks+Tab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872D972B8DA9F800138637 /* Bookmarks+Tab.swift */; }; 9F872D9D2B9058D000138637 /* Bookmarks+TabTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872D9C2B9058D000138637 /* Bookmarks+TabTests.swift */; }; 9F872D9E2B9058D000138637 /* Bookmarks+TabTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872D9C2B9058D000138637 /* Bookmarks+TabTests.swift */; }; 9F872DA02B90644800138637 /* ContextualMenuTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872D9F2B90644800138637 /* ContextualMenuTests.swift */; }; 9F872DA12B90644800138637 /* ContextualMenuTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872D9F2B90644800138637 /* ContextualMenuTests.swift */; }; 9F872DA32B90920F00138637 /* BookmarkFolderInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872DA22B90920F00138637 /* BookmarkFolderInfo.swift */; }; 9F872DA42B90920F00138637 /* BookmarkFolderInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872DA22B90920F00138637 /* BookmarkFolderInfo.swift */; }; - 9F872DA52B90920F00138637 /* BookmarkFolderInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F872DA22B90920F00138637 /* BookmarkFolderInfo.swift */; }; + 9F8D57322BCCCB9A00AEA660 /* UserDefaultsBookmarkFoldersStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8D57312BCCCB9A00AEA660 /* UserDefaultsBookmarkFoldersStoreTests.swift */; }; + 9F8D57332BCCCB9A00AEA660 /* UserDefaultsBookmarkFoldersStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8D57312BCCCB9A00AEA660 /* UserDefaultsBookmarkFoldersStoreTests.swift */; }; 9F982F0D2B8224BF00231028 /* AddEditBookmarkFolderDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F982F0C2B8224BE00231028 /* AddEditBookmarkFolderDialogViewModel.swift */; }; 9F982F0E2B8224BF00231028 /* AddEditBookmarkFolderDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F982F0C2B8224BE00231028 /* AddEditBookmarkFolderDialogViewModel.swift */; }; - 9F982F0F2B8224BF00231028 /* AddEditBookmarkFolderDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F982F0C2B8224BE00231028 /* AddEditBookmarkFolderDialogViewModel.swift */; }; 9F982F132B822B7B00231028 /* AddEditBookmarkFolderDialogViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F982F112B82268F00231028 /* AddEditBookmarkFolderDialogViewModelTests.swift */; }; 9F982F142B822C7400231028 /* AddEditBookmarkFolderDialogViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F982F112B82268F00231028 /* AddEditBookmarkFolderDialogViewModelTests.swift */; }; + 9F9C49F62BC786790099738D /* MoreOptionsMenu+BookmarksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9C49F52BC786790099738D /* MoreOptionsMenu+BookmarksTests.swift */; }; + 9F9C49F72BC786790099738D /* MoreOptionsMenu+BookmarksTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9C49F52BC786790099738D /* MoreOptionsMenu+BookmarksTests.swift */; }; + 9F9C49F92BC7BC970099738D /* BookmarkAllTabsDialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9C49F82BC7BC970099738D /* BookmarkAllTabsDialogView.swift */; }; + 9F9C49FA2BC7BC970099738D /* BookmarkAllTabsDialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9C49F82BC7BC970099738D /* BookmarkAllTabsDialogView.swift */; }; + 9F9C49FD2BC7E9830099738D /* BookmarkAllTabsDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9C49FC2BC7E9820099738D /* BookmarkAllTabsDialogViewModel.swift */; }; + 9F9C49FE2BC7E9830099738D /* BookmarkAllTabsDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9C49FC2BC7E9820099738D /* BookmarkAllTabsDialogViewModel.swift */; }; + 9F9C4A012BC7F36D0099738D /* BookmarkAllTabsDialogCoordinatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9C4A002BC7F36D0099738D /* BookmarkAllTabsDialogCoordinatorViewModel.swift */; }; + 9F9C4A022BC7F36D0099738D /* BookmarkAllTabsDialogCoordinatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9C4A002BC7F36D0099738D /* BookmarkAllTabsDialogCoordinatorViewModel.swift */; }; 9FA173DA2B79BD8A00EE4E6E /* BookmarkDialogContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173D92B79BD8A00EE4E6E /* BookmarkDialogContainerView.swift */; }; 9FA173DB2B79BD8A00EE4E6E /* BookmarkDialogContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173D92B79BD8A00EE4E6E /* BookmarkDialogContainerView.swift */; }; - 9FA173DC2B79BD8A00EE4E6E /* BookmarkDialogContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173D92B79BD8A00EE4E6E /* BookmarkDialogContainerView.swift */; }; 9FA173DF2B7A0EFE00EE4E6E /* BookmarkDialogButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173DE2B7A0EFE00EE4E6E /* BookmarkDialogButtonsView.swift */; }; 9FA173E02B7A0EFE00EE4E6E /* BookmarkDialogButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173DE2B7A0EFE00EE4E6E /* BookmarkDialogButtonsView.swift */; }; - 9FA173E12B7A0EFE00EE4E6E /* BookmarkDialogButtonsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173DE2B7A0EFE00EE4E6E /* BookmarkDialogButtonsView.swift */; }; 9FA173E32B7A12B600EE4E6E /* BookmarkDialogFolderManagementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173E22B7A12B600EE4E6E /* BookmarkDialogFolderManagementView.swift */; }; 9FA173E42B7A12B600EE4E6E /* BookmarkDialogFolderManagementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173E22B7A12B600EE4E6E /* BookmarkDialogFolderManagementView.swift */; }; - 9FA173E52B7A12B600EE4E6E /* BookmarkDialogFolderManagementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173E22B7A12B600EE4E6E /* BookmarkDialogFolderManagementView.swift */; }; 9FA173E72B7B122E00EE4E6E /* BookmarkDialogStackedContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173E62B7B122E00EE4E6E /* BookmarkDialogStackedContentView.swift */; }; 9FA173E82B7B122E00EE4E6E /* BookmarkDialogStackedContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173E62B7B122E00EE4E6E /* BookmarkDialogStackedContentView.swift */; }; - 9FA173E92B7B122E00EE4E6E /* BookmarkDialogStackedContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173E62B7B122E00EE4E6E /* BookmarkDialogStackedContentView.swift */; }; 9FA173EB2B7B232200EE4E6E /* AddEditBookmarkDialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173EA2B7B232200EE4E6E /* AddEditBookmarkDialogView.swift */; }; 9FA173EC2B7B232200EE4E6E /* AddEditBookmarkDialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173EA2B7B232200EE4E6E /* AddEditBookmarkDialogView.swift */; }; - 9FA173ED2B7B232200EE4E6E /* AddEditBookmarkDialogView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA173EA2B7B232200EE4E6E /* AddEditBookmarkDialogView.swift */; }; + 9FA5A0A52BC8F34900153786 /* UserDefaultsBookmarkFoldersStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA5A0A42BC8F34900153786 /* UserDefaultsBookmarkFoldersStore.swift */; }; + 9FA5A0A62BC8F34900153786 /* UserDefaultsBookmarkFoldersStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA5A0A42BC8F34900153786 /* UserDefaultsBookmarkFoldersStore.swift */; }; + 9FA5A0A92BC900FC00153786 /* BookmarkAllTabsDialogViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA5A0A82BC900FC00153786 /* BookmarkAllTabsDialogViewModelTests.swift */; }; + 9FA5A0AA2BC900FC00153786 /* BookmarkAllTabsDialogViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA5A0A82BC900FC00153786 /* BookmarkAllTabsDialogViewModelTests.swift */; }; + 9FA5A0B02BC9039200153786 /* BookmarkFolderStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA5A0AC2BC9037A00153786 /* BookmarkFolderStoreMock.swift */; }; + 9FA5A0B12BC9039300153786 /* BookmarkFolderStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA5A0AC2BC9037A00153786 /* BookmarkFolderStoreMock.swift */; }; 9FA75A3E2BA00E1400DA5FA6 /* BookmarksBarMenuFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA75A3D2BA00E1400DA5FA6 /* BookmarksBarMenuFactoryTests.swift */; }; 9FA75A3F2BA00E1400DA5FA6 /* BookmarksBarMenuFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA75A3D2BA00E1400DA5FA6 /* BookmarksBarMenuFactoryTests.swift */; }; + 9FAD623A2BCFDB32007F3A65 /* WebsiteInfoHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD62392BCFDB32007F3A65 /* WebsiteInfoHelpers.swift */; }; + 9FAD623B2BCFDB32007F3A65 /* WebsiteInfoHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD62392BCFDB32007F3A65 /* WebsiteInfoHelpers.swift */; }; + 9FAD623D2BD09DE5007F3A65 /* WebsiteInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD623C2BD09DE5007F3A65 /* WebsiteInfoTests.swift */; }; + 9FAD623E2BD09DE5007F3A65 /* WebsiteInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD623C2BD09DE5007F3A65 /* WebsiteInfoTests.swift */; }; + 9FBD84522BB3AACB00220859 /* AttributionOriginFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84512BB3AACB00220859 /* AttributionOriginFileProvider.swift */; }; + 9FBD84532BB3AACB00220859 /* AttributionOriginFileProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84512BB3AACB00220859 /* AttributionOriginFileProvider.swift */; }; + 9FBD84562BB3ACFD00220859 /* AttributionOriginFileProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84552BB3ACFD00220859 /* AttributionOriginFileProviderTests.swift */; }; + 9FBD84572BB3ACFD00220859 /* AttributionOriginFileProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84552BB3ACFD00220859 /* AttributionOriginFileProviderTests.swift */; }; + 9FBD845D2BB3B80300220859 /* Origin.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9FBD845C2BB3B80300220859 /* Origin.txt */; }; + 9FBD845E2BB3B80300220859 /* Origin.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9FBD845C2BB3B80300220859 /* Origin.txt */; }; + 9FBD84612BB3BC6400220859 /* Origin-empty.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9FBD84602BB3BC6400220859 /* Origin-empty.txt */; }; + 9FBD84622BB3BC6400220859 /* Origin-empty.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9FBD84602BB3BC6400220859 /* Origin-empty.txt */; }; + 9FBD84702BB3DD8400220859 /* MockAttributionsPixelHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD846F2BB3DD8400220859 /* MockAttributionsPixelHandler.swift */; }; + 9FBD84712BB3DD8400220859 /* MockAttributionsPixelHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD846F2BB3DD8400220859 /* MockAttributionsPixelHandler.swift */; }; + 9FBD84732BB3E15D00220859 /* InstallationAttributionPixelHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84722BB3E15D00220859 /* InstallationAttributionPixelHandler.swift */; }; + 9FBD84742BB3E15D00220859 /* InstallationAttributionPixelHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84722BB3E15D00220859 /* InstallationAttributionPixelHandler.swift */; }; + 9FBD84772BB3E54200220859 /* InstallationAttributionPixelHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84762BB3E54200220859 /* InstallationAttributionPixelHandlerTests.swift */; }; + 9FBD84782BB3E54200220859 /* InstallationAttributionPixelHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84762BB3E54200220859 /* InstallationAttributionPixelHandlerTests.swift */; }; + 9FBD847A2BB3EC3300220859 /* MockAttributionOriginProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84792BB3EC3300220859 /* MockAttributionOriginProvider.swift */; }; + 9FBD847B2BB3EC3300220859 /* MockAttributionOriginProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD84792BB3EC3300220859 /* MockAttributionOriginProvider.swift */; }; 9FDA6C212B79A59D00E099A9 /* BookmarkFavoriteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FDA6C202B79A59D00E099A9 /* BookmarkFavoriteView.swift */; }; 9FDA6C222B79A59D00E099A9 /* BookmarkFavoriteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FDA6C202B79A59D00E099A9 /* BookmarkFavoriteView.swift */; }; - 9FDA6C232B79A59D00E099A9 /* BookmarkFavoriteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FDA6C202B79A59D00E099A9 /* BookmarkFavoriteView.swift */; }; 9FEE98652B846870002E44E8 /* AddEditBookmarkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE98642B846870002E44E8 /* AddEditBookmarkView.swift */; }; 9FEE98662B846870002E44E8 /* AddEditBookmarkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE98642B846870002E44E8 /* AddEditBookmarkView.swift */; }; - 9FEE98672B846870002E44E8 /* AddEditBookmarkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE98642B846870002E44E8 /* AddEditBookmarkView.swift */; }; 9FEE98692B85B869002E44E8 /* BookmarksDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE98682B85B869002E44E8 /* BookmarksDialogViewModel.swift */; }; 9FEE986A2B85B869002E44E8 /* BookmarksDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE98682B85B869002E44E8 /* BookmarksDialogViewModel.swift */; }; - 9FEE986B2B85B869002E44E8 /* BookmarksDialogViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE98682B85B869002E44E8 /* BookmarksDialogViewModel.swift */; }; 9FEE986D2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE986C2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift */; }; 9FEE986E2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE986C2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift */; }; - 9FEE986F2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE986C2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift */; }; 9FF521462BAA908500B9819B /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 9FF521452BAA908500B9819B /* Lottie */; }; 9FF521482BAA909C00B9819B /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 9FF521472BAA909C00B9819B /* Lottie */; }; - 9FF5214A2BAA90C400B9819B /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 9FF521492BAA90C400B9819B /* Lottie */; }; AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = AA06B6B62672AF8100F541C5 /* Sparkle */; }; AA0877B826D5160D00B05660 /* SafariVersionReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0877B726D5160D00B05660 /* SafariVersionReaderTests.swift */; }; AA0877BA26D5161D00B05660 /* WebKitVersionProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0877B926D5161D00B05660 /* WebKitVersionProviderTests.swift */; }; @@ -2664,7 +1929,6 @@ AAC30A26268DFEE200D2D9CD /* CrashReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A25268DFEE200D2D9CD /* CrashReporter.swift */; }; AAC30A28268E045400D2D9CD /* CrashReportReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A27268E045400D2D9CD /* CrashReportReader.swift */; }; AAC30A2A268E239100D2D9CD /* CrashReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A29268E239100D2D9CD /* CrashReport.swift */; }; - AAC30A2C268F1ECD00D2D9CD /* CrashReportSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A2B268F1ECD00D2D9CD /* CrashReportSender.swift */; }; AAC30A2E268F1EE300D2D9CD /* CrashReportPromptPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC30A2D268F1EE300D2D9CD /* CrashReportPromptPresenter.swift */; }; AAC5E4C725D6A6E8007F5990 /* AddBookmarkPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4C425D6A6E8007F5990 /* AddBookmarkPopover.swift */; }; AAC5E4D025D6A709007F5990 /* Bookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4CD25D6A709007F5990 /* Bookmark.swift */; }; @@ -2707,7 +1971,6 @@ B31055CB27A1BA1D001AC618 /* autoconsent-bundle.js in Resources */ = {isa = PBXBuildFile; fileRef = B31055C327A1BA1D001AC618 /* autoconsent-bundle.js */; }; B60293E62BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60293E52BA19ECD0033186B /* NetPPopoverManagerMock.swift */; }; B60293E72BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60293E52BA19ECD0033186B /* NetPPopoverManagerMock.swift */; }; - B60293E82BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60293E52BA19ECD0033186B /* NetPPopoverManagerMock.swift */; }; B602E7CF2A93A5FF00F12201 /* WKBackForwardListExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B602E7CE2A93A5FF00F12201 /* WKBackForwardListExtension.swift */; }; B602E7D02A93A5FF00F12201 /* WKBackForwardListExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B602E7CE2A93A5FF00F12201 /* WKBackForwardListExtension.swift */; }; B602E8162A1E2570006D261F /* URL+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B602E8152A1E2570006D261F /* URL+NetworkProtection.swift */; }; @@ -2744,7 +2007,6 @@ B604085C274B8FBA00680351 /* UnprotectedDomains.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B604085A274B8CA300680351 /* UnprotectedDomains.xcdatamodeld */; }; B6080BC52B21E78100B418EF /* DataImportErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6080BC42B21E78100B418EF /* DataImportErrorView.swift */; }; B6080BC62B21E78100B418EF /* DataImportErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6080BC42B21E78100B418EF /* DataImportErrorView.swift */; }; - B6080BC82B21E78100B418EF /* DataImportErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6080BC42B21E78100B418EF /* DataImportErrorView.swift */; }; B6085D062743905F00A9C456 /* CoreDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6085D052743905F00A9C456 /* CoreDataStore.swift */; }; B6085D092743AAB600A9C456 /* FireproofDomains.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B6085D072743993C00A9C456 /* FireproofDomains.xcdatamodeld */; }; B60C6F7729B0E286007BFAA8 /* SearchNonexistentDomainNavigationResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60C6F7629B0E286007BFAA8 /* SearchNonexistentDomainNavigationResponder.swift */; }; @@ -2767,7 +2029,6 @@ B60D644A2AAF1B7C00B26F50 /* AddressBarTextSelectionNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60D64482AAF1B7C00B26F50 /* AddressBarTextSelectionNavigation.swift */; }; B6104E9B2BA9C173008636B2 /* DownloadResumeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6104E9A2BA9C173008636B2 /* DownloadResumeData.swift */; }; B6104E9C2BA9C173008636B2 /* DownloadResumeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6104E9A2BA9C173008636B2 /* DownloadResumeData.swift */; }; - B6104E9D2BA9C174008636B2 /* DownloadResumeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6104E9A2BA9C173008636B2 /* DownloadResumeData.swift */; }; B6106BA026A7BE0B0013B453 /* PermissionManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106B9F26A7BE0B0013B453 /* PermissionManagerTests.swift */; }; B6106BA726A7BECC0013B453 /* PermissionAuthorizationQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106BA526A7BEC80013B453 /* PermissionAuthorizationQuery.swift */; }; B6106BAB26A7BF1D0013B453 /* PermissionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106BAA26A7BF1D0013B453 /* PermissionType.swift */; }; @@ -2796,13 +2057,10 @@ B62A234129C41D4400D22475 /* HistoryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62A233F29C41D4400D22475 /* HistoryIntegrationTests.swift */; }; B62B48392ADE46FC000DECE5 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62B48382ADE46FC000DECE5 /* Application.swift */; }; B62B483A2ADE46FC000DECE5 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62B48382ADE46FC000DECE5 /* Application.swift */; }; - B62B483C2ADE46FC000DECE5 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62B48382ADE46FC000DECE5 /* Application.swift */; }; B62B483E2ADE48DE000DECE5 /* ArrayBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62B483D2ADE48DE000DECE5 /* ArrayBuilder.swift */; }; B62B483F2ADE48DE000DECE5 /* ArrayBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62B483D2ADE48DE000DECE5 /* ArrayBuilder.swift */; }; - B62B48412ADE48DE000DECE5 /* ArrayBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62B483D2ADE48DE000DECE5 /* ArrayBuilder.swift */; }; B62B48562ADE730D000DECE5 /* FileImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62B48552ADE730D000DECE5 /* FileImportView.swift */; }; B62B48572ADE730D000DECE5 /* FileImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62B48552ADE730D000DECE5 /* FileImportView.swift */; }; - B62B48592ADE730D000DECE5 /* FileImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62B48552ADE730D000DECE5 /* FileImportView.swift */; }; B62EB47C25BAD3BB005745C6 /* WKWebViewPrivateMethodsAvailabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62EB47B25BAD3BB005745C6 /* WKWebViewPrivateMethodsAvailabilityTests.swift */; }; B630793526731BC400DCEE41 /* URLSuggestedFilenameTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8553FF51257523760029327F /* URLSuggestedFilenameTests.swift */; }; B630793A26731F2600DCEE41 /* FileDownloadManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B630793926731F2600DCEE41 /* FileDownloadManagerTests.swift */; }; @@ -2829,7 +2087,7 @@ B63ED0E026AFE32F00A9DAD1 /* GeolocationProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63ED0DF26AFE32F00A9DAD1 /* GeolocationProviderMock.swift */; }; B63ED0E326B3E7FA00A9DAD1 /* CLLocationManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63ED0E226B3E7FA00A9DAD1 /* CLLocationManagerMock.swift */; }; B63ED0E526BB8FB900A9DAD1 /* SharingMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63ED0E426BB8FB900A9DAD1 /* SharingMenu.swift */; }; - B642738227B65BAC0005DFD1 /* SecureVaultErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */; }; + B642738227B65BAC0005DFD1 /* SecureVaultReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B642738127B65BAC0005DFD1 /* SecureVaultReporter.swift */; }; B643BF1427ABF772000BACEC /* NSWorkspaceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B643BF1327ABF772000BACEC /* NSWorkspaceExtension.swift */; }; B644B43D29D56829003FA9AB /* SearchNonexistentDomainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B644B43929D565DB003FA9AB /* SearchNonexistentDomainTests.swift */; }; B644B43E29D5682B003FA9AB /* SearchNonexistentDomainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B644B43929D565DB003FA9AB /* SearchNonexistentDomainTests.swift */; }; @@ -2854,7 +2112,6 @@ B64E42AC2B909DC9006C1346 /* test.pdf in Resources */ = {isa = PBXBuildFile; fileRef = B64E42AA2B909DC9006C1346 /* test.pdf */; }; B65211252B29A42C00B30633 /* BookmarkStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA652CDA25DDAB32009059CC /* BookmarkStoreMock.swift */; }; B65211262B29A42E00B30633 /* BookmarkStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA652CDA25DDAB32009059CC /* BookmarkStoreMock.swift */; }; - B65211272B29A43000B30633 /* BookmarkStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA652CDA25DDAB32009059CC /* BookmarkStoreMock.swift */; }; B65349AA265CF45000DCC645 /* DispatchQueueExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65349A9265CF45000DCC645 /* DispatchQueueExtensionsTests.swift */; }; B655124829A79465009BFE1C /* NavigationActionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66B9C5B29A5EBAD0010E8F3 /* NavigationActionExtension.swift */; }; B655124929A79465009BFE1C /* NavigationActionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66B9C5B29A5EBAD0010E8F3 /* NavigationActionExtension.swift */; }; @@ -2867,10 +2124,8 @@ B657841F25FA497600D8DB33 /* NSException+Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = B657841E25FA497600D8DB33 /* NSException+Catch.swift */; }; B658BAB62B0F845D00D1F2C7 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = B658BAB52B0F845D00D1F2C7 /* Localizable.xcstrings */; }; B658BAB72B0F848D00D1F2C7 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = B658BAB52B0F845D00D1F2C7 /* Localizable.xcstrings */; }; - B658BAB92B0F849100D1F2C7 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = B658BAB52B0F845D00D1F2C7 /* Localizable.xcstrings */; }; B65C7DFB2B886CF0001E2D5C /* WKPDFHUDViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65C7DFA2B886CF0001E2D5C /* WKPDFHUDViewWrapper.swift */; }; B65C7DFC2B886CF0001E2D5C /* WKPDFHUDViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65C7DFA2B886CF0001E2D5C /* WKPDFHUDViewWrapper.swift */; }; - B65C7DFD2B886CF0001E2D5C /* WKPDFHUDViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65C7DFA2B886CF0001E2D5C /* WKPDFHUDViewWrapper.swift */; }; B65CD8CB2B316DF100A595BB /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = B65CD8CA2B316DF100A595BB /* SnapshotTesting */; }; B65CD8CD2B316DFC00A595BB /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = B65CD8CC2B316DFC00A595BB /* SnapshotTesting */; }; B65CD8CF2B316E0200A595BB /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = B65CD8CE2B316E0200A595BB /* SnapshotTesting */; }; @@ -2886,14 +2141,12 @@ B65DA5F52A77D3FA00CBEE8D /* BundleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106B9D26A565DA0013B453 /* BundleExtension.swift */; }; B65E5DAF2B74DE6D00480415 /* TrackerNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65E5DAE2B74DE6D00480415 /* TrackerNetwork.swift */; }; B65E5DB02B74E6A900480415 /* TrackerNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65E5DAE2B74DE6D00480415 /* TrackerNetwork.swift */; }; - B65E5DB12B74E6AA00480415 /* TrackerNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65E5DAE2B74DE6D00480415 /* TrackerNetwork.swift */; }; B65E6B9E26D9EC0800095F96 /* CircularProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65E6B9D26D9EC0800095F96 /* CircularProgressView.swift */; }; B65E6BA026D9F10600095F96 /* NSBezierPathExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65E6B9F26D9F10600095F96 /* NSBezierPathExtension.swift */; }; B6619EF62B10DFF700CD9186 /* InstructionsFormatParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6619EF52B10DFF700CD9186 /* InstructionsFormatParserTests.swift */; }; B6619EF72B10DFF700CD9186 /* InstructionsFormatParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6619EF52B10DFF700CD9186 /* InstructionsFormatParserTests.swift */; }; B6619EFB2B111CC500CD9186 /* InstructionsFormatParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6619EF82B111CBE00CD9186 /* InstructionsFormatParser.swift */; }; B6619EFC2B111CC600CD9186 /* InstructionsFormatParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6619EF82B111CBE00CD9186 /* InstructionsFormatParser.swift */; }; - B6619EFE2B111CCC00CD9186 /* InstructionsFormatParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6619EF82B111CBE00CD9186 /* InstructionsFormatParser.swift */; }; B6619F032B17123200CD9186 /* DataImportViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6619F022B17123200CD9186 /* DataImportViewModelTests.swift */; }; B6619F042B17123200CD9186 /* DataImportViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6619F022B17123200CD9186 /* DataImportViewModelTests.swift */; }; B6619F062B17138D00CD9186 /* DataImportSourceViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6619F052B17138D00CD9186 /* DataImportSourceViewModelTests.swift */; }; @@ -2905,13 +2158,10 @@ B66260E629ACAE4B00E9E3EE /* NavigationHotkeyHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66260E529ACAE4B00E9E3EE /* NavigationHotkeyHandler.swift */; }; B66260E729ACAE4B00E9E3EE /* NavigationHotkeyHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66260E529ACAE4B00E9E3EE /* NavigationHotkeyHandler.swift */; }; B66260E829ACD0C900E9E3EE /* DuckPlayerTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C416A6294A4AE500C4F2E7 /* DuckPlayerTabExtension.swift */; }; - B662D3D92755D7AD0035D4D6 /* PixelStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B662D3D82755D7AD0035D4D6 /* PixelStoreTests.swift */; }; B662D3DE275613BB0035D4D6 /* EncryptionKeyStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B662D3DD275613BB0035D4D6 /* EncryptionKeyStoreMock.swift */; }; B662D3DF275616FF0035D4D6 /* EncryptionKeyStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B662D3DD275613BB0035D4D6 /* EncryptionKeyStoreMock.swift */; }; B6656E0D2B29C733008798A1 /* FileImportViewLocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6656E0C2B29C733008798A1 /* FileImportViewLocalizationTests.swift */; }; B6656E0E2B29C733008798A1 /* FileImportViewLocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6656E0C2B29C733008798A1 /* FileImportViewLocalizationTests.swift */; }; - B6656E122B29E3BE008798A1 /* DownloadListStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693956026F1C1BC0015B914 /* DownloadListStoreMock.swift */; }; - B6656E5B2B2ADB1C008798A1 /* RequestFilePermissionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B5F5832B03580A008DB58A /* RequestFilePermissionView.swift */; }; B6676BE12AA986A700525A21 /* AddressBarTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6676BE02AA986A700525A21 /* AddressBarTextEditor.swift */; }; B6676BE22AA986A700525A21 /* AddressBarTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6676BE02AA986A700525A21 /* AddressBarTextEditor.swift */; }; B6685E3D29A602D90043D2EE /* ExternalAppSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B687B7CB2947A1E9001DEA6F /* ExternalAppSchemeHandler.swift */; }; @@ -2921,13 +2171,10 @@ B6685E4329A61C470043D2EE /* DownloadsTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6685E4129A61C460043D2EE /* DownloadsTabExtension.swift */; }; B66CA41E2AD910B300447CF0 /* DataImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66CA41D2AD910B300447CF0 /* DataImportView.swift */; }; B66CA41F2AD910B300447CF0 /* DataImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66CA41D2AD910B300447CF0 /* DataImportView.swift */; }; - B66CA4212AD910B300447CF0 /* DataImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66CA41D2AD910B300447CF0 /* DataImportView.swift */; }; B677FC4F2B06376B0099EB04 /* ReportFeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B677FC4E2B06376B0099EB04 /* ReportFeedbackView.swift */; }; B677FC502B06376B0099EB04 /* ReportFeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B677FC4E2B06376B0099EB04 /* ReportFeedbackView.swift */; }; - B677FC522B06376B0099EB04 /* ReportFeedbackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B677FC4E2B06376B0099EB04 /* ReportFeedbackView.swift */; }; B677FC542B064A9C0099EB04 /* DataImportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B677FC532B064A9C0099EB04 /* DataImportViewModel.swift */; }; B677FC552B064A9C0099EB04 /* DataImportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B677FC532B064A9C0099EB04 /* DataImportViewModel.swift */; }; - B677FC572B064A9C0099EB04 /* DataImportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B677FC532B064A9C0099EB04 /* DataImportViewModel.swift */; }; B67C6C3D2654B897006C872E /* WebViewExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67C6C3C2654B897006C872E /* WebViewExtensionTests.swift */; }; B67C6C422654BF49006C872E /* DuckDuckGo-Symbol.jpg in Resources */ = {isa = PBXBuildFile; fileRef = B67C6C412654BF49006C872E /* DuckDuckGo-Symbol.jpg */; }; B67C6C472654C643006C872E /* FileManagerExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67C6C462654C643006C872E /* FileManagerExtensionTests.swift */; }; @@ -2936,15 +2183,12 @@ B6830963274CDEC7004B46BB /* FireproofDomainsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6830962274CDEC7004B46BB /* FireproofDomainsStore.swift */; }; B68412142B694BA10092F66A /* NSObject+performSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = B68412132B694BA10092F66A /* NSObject+performSelector.m */; }; B68412152B694BA10092F66A /* NSObject+performSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = B68412132B694BA10092F66A /* NSObject+performSelector.m */; }; - B68412162B694BA10092F66A /* NSObject+performSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = B68412132B694BA10092F66A /* NSObject+performSelector.m */; }; B684121C2B6A1D880092F66A /* ErrorPageHTMLTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B684121B2B6A1D880092F66A /* ErrorPageHTMLTemplate.swift */; }; B684121D2B6A1D880092F66A /* ErrorPageHTMLTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B684121B2B6A1D880092F66A /* ErrorPageHTMLTemplate.swift */; }; - B684121E2B6A1D880092F66A /* ErrorPageHTMLTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B684121B2B6A1D880092F66A /* ErrorPageHTMLTemplate.swift */; }; B68412202B6A30680092F66A /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B684121F2B6A30680092F66A /* StringExtensionTests.swift */; }; B68412212B6A30680092F66A /* StringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B684121F2B6A30680092F66A /* StringExtensionTests.swift */; }; B68412272B6A68C10092F66A /* WKBackForwardListItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68412242B6A67920092F66A /* WKBackForwardListItemExtension.swift */; }; B68412282B6A68C20092F66A /* WKBackForwardListItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68412242B6A67920092F66A /* WKBackForwardListItemExtension.swift */; }; - B68412292B6A68C90092F66A /* WKBackForwardListItemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68412242B6A67920092F66A /* WKBackForwardListItemExtension.swift */; }; B68458B025C7E76A00DC17B6 /* WindowManager+StateRestoration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68458AF25C7E76A00DC17B6 /* WindowManager+StateRestoration.swift */; }; B68458B825C7E8B200DC17B6 /* Tab+NSSecureCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68458B725C7E8B200DC17B6 /* Tab+NSSecureCoding.swift */; }; B68458C025C7E9E000DC17B6 /* TabCollectionViewModel+NSSecureCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68458BF25C7E9E000DC17B6 /* TabCollectionViewModel+NSSecureCoding.swift */; }; @@ -2962,19 +2206,14 @@ B689ECD526C247DB006FB0C5 /* BackForwardListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B689ECD426C247DB006FB0C5 /* BackForwardListItem.swift */; }; B68C2FB227706E6A00BF2C7D /* ProcessExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C2FB127706E6A00BF2C7D /* ProcessExtension.swift */; }; B68C92C1274E3EF4002AC6B0 /* PopUpWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C92C0274E3EF4002AC6B0 /* PopUpWindow.swift */; }; - B68C92C42750EF76002AC6B0 /* PixelDataRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C92C32750EF76002AC6B0 /* PixelDataRecord.swift */; }; B68D21C32ACBC916002DA3C2 /* ContentBlockingMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BDD9F429409DDD00F68088 /* ContentBlockingMock.swift */; }; B68D21C42ACBC917002DA3C2 /* ContentBlockingMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BDD9F429409DDD00F68088 /* ContentBlockingMock.swift */; }; B68D21C82ACBC96D002DA3C2 /* MockPrivacyConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B626A76F29928C4100053070 /* MockPrivacyConfiguration.swift */; }; B68D21C92ACBC96E002DA3C2 /* MockPrivacyConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B626A76F29928C4100053070 /* MockPrivacyConfiguration.swift */; }; - B68D21CA2ACBC971002DA3C2 /* MockPrivacyConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B626A76F29928C4100053070 /* MockPrivacyConfiguration.swift */; }; - B68D21CB2ACBC9A3002DA3C2 /* ContentBlockingMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BDD9F429409DDD00F68088 /* ContentBlockingMock.swift */; }; B68D21CF2ACBC9FC002DA3C2 /* ContentBlockerRulesManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B610F2E727AA397100FCEBE9 /* ContentBlockerRulesManagerMock.swift */; }; B68D21D02ACBC9FD002DA3C2 /* ContentBlockerRulesManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B610F2E727AA397100FCEBE9 /* ContentBlockerRulesManagerMock.swift */; }; - B68D21D22ACBCA01002DA3C2 /* ContentBlockerRulesManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B610F2E727AA397100FCEBE9 /* ContentBlockerRulesManagerMock.swift */; }; B690152C2ACBF4DA00AD0BAB /* MenuPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = B690152B2ACBF4DA00AD0BAB /* MenuPreview.swift */; }; B690152D2ACBF4DA00AD0BAB /* MenuPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = B690152B2ACBF4DA00AD0BAB /* MenuPreview.swift */; }; - B690152F2ACBF4DA00AD0BAB /* MenuPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = B690152B2ACBF4DA00AD0BAB /* MenuPreview.swift */; }; B693766E2B6B5F27005BD9D4 /* ErrorPageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693766D2B6B5F26005BD9D4 /* ErrorPageTests.swift */; }; B693766F2B6B5F27005BD9D4 /* ErrorPageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693766D2B6B5F26005BD9D4 /* ErrorPageTests.swift */; }; B693954B26F04BEB0015B914 /* MouseOverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693953D26F04BE70015B914 /* MouseOverView.swift */; }; @@ -2997,13 +2236,10 @@ B698E5042908011E00A746A8 /* AppKitPrivateMethodsAvailabilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B698E5032908011E00A746A8 /* AppKitPrivateMethodsAvailabilityTests.swift */; }; B69A14F22B4D6FE800B9417D /* AddBookmarkFolderPopoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69A14F12B4D6FE800B9417D /* AddBookmarkFolderPopoverViewModel.swift */; }; B69A14F32B4D6FE800B9417D /* AddBookmarkFolderPopoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69A14F12B4D6FE800B9417D /* AddBookmarkFolderPopoverViewModel.swift */; }; - B69A14F42B4D6FE800B9417D /* AddBookmarkFolderPopoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69A14F12B4D6FE800B9417D /* AddBookmarkFolderPopoverViewModel.swift */; }; B69A14F62B4D701F00B9417D /* AddBookmarkPopoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69A14F52B4D701F00B9417D /* AddBookmarkPopoverViewModel.swift */; }; B69A14F72B4D701F00B9417D /* AddBookmarkPopoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69A14F52B4D701F00B9417D /* AddBookmarkPopoverViewModel.swift */; }; - B69A14F82B4D701F00B9417D /* AddBookmarkPopoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69A14F52B4D701F00B9417D /* AddBookmarkPopoverViewModel.swift */; }; B69A14FA2B4D705D00B9417D /* BookmarkFolderPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69A14F92B4D705D00B9417D /* BookmarkFolderPicker.swift */; }; B69A14FB2B4D705D00B9417D /* BookmarkFolderPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69A14F92B4D705D00B9417D /* BookmarkFolderPicker.swift */; }; - B69A14FC2B4D705D00B9417D /* BookmarkFolderPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69A14F92B4D705D00B9417D /* BookmarkFolderPicker.swift */; }; B69B503A2726A12500758A2B /* StatisticsLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50342726A11F00758A2B /* StatisticsLoader.swift */; }; B69B503B2726A12500758A2B /* Atb.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50352726A11F00758A2B /* Atb.swift */; }; B69B503C2726A12500758A2B /* StatisticsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50362726A12000758A2B /* StatisticsStore.swift */; }; @@ -3023,25 +2259,23 @@ B69B50572727D16900758A2B /* AtbAndVariantCleanup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B69B50562727D16900758A2B /* AtbAndVariantCleanup.swift */; }; B6A22B622B1E29D000ECD2BA /* DataImportSummaryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A22B612B1E29D000ECD2BA /* DataImportSummaryViewModel.swift */; }; B6A22B632B1E29D000ECD2BA /* DataImportSummaryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A22B612B1E29D000ECD2BA /* DataImportSummaryViewModel.swift */; }; - B6A22B652B1E29D000ECD2BA /* DataImportSummaryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A22B612B1E29D000ECD2BA /* DataImportSummaryViewModel.swift */; }; B6A5A27125B9377300AA7ADA /* StatePersistenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A5A27025B9377300AA7ADA /* StatePersistenceService.swift */; }; B6A5A27925B93FFF00AA7ADA /* StateRestorationManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A5A27825B93FFE00AA7ADA /* StateRestorationManagerTests.swift */; }; B6A5A27E25B9403E00AA7ADA /* FileStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A5A27D25B9403E00AA7ADA /* FileStoreMock.swift */; }; B6A5A2A025B96E8300AA7ADA /* AppStateChangePublisherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A5A29F25B96E8300AA7ADA /* AppStateChangePublisherTests.swift */; }; B6A5A2A825BAA35500AA7ADA /* WindowManagerStateRestorationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A5A2A725BAA35500AA7ADA /* WindowManagerStateRestorationTests.swift */; }; B6A924D92664C72E001A28CA /* WebKitDownloadTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A924D82664C72D001A28CA /* WebKitDownloadTask.swift */; }; - B6A9E45326142B070067D1B9 /* Pixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E45226142B070067D1B9 /* Pixel.swift */; }; B6A9E46B2614618A0067D1B9 /* OperatingSystemVersionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E46A2614618A0067D1B9 /* OperatingSystemVersionExtension.swift */; }; - B6A9E47726146A570067D1B9 /* PixelEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E47626146A570067D1B9 /* PixelEvent.swift */; }; - B6A9E47F26146A800067D1B9 /* PixelArguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E47E26146A800067D1B9 /* PixelArguments.swift */; }; - B6A9E48426146AAB0067D1B9 /* PixelParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A9E48326146AAB0067D1B9 /* PixelParameters.swift */; }; B6AA64732994B43300D99CD6 /* FutureExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AA64722994B43300D99CD6 /* FutureExtensionTests.swift */; }; B6AA64742994B43300D99CD6 /* FutureExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AA64722994B43300D99CD6 /* FutureExtensionTests.swift */; }; B6AAAC2D260330580029438D /* PublishedAfter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AAAC2C260330580029438D /* PublishedAfter.swift */; }; B6AAAC3E26048F690029438D /* RandomAccessCollectionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AAAC3D26048F690029438D /* RandomAccessCollectionExtension.swift */; }; B6ABC5962B4861D4008343B9 /* FocusableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6ABC5952B4861D4008343B9 /* FocusableTextField.swift */; }; B6ABC5972B4861D4008343B9 /* FocusableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6ABC5952B4861D4008343B9 /* FocusableTextField.swift */; }; - B6ABC5982B4861D4008343B9 /* FocusableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6ABC5952B4861D4008343B9 /* FocusableTextField.swift */; }; + B6ABD0CA2BC03F610000EB69 /* SecurityScopedFileURLController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6ABD0C92BC03F610000EB69 /* SecurityScopedFileURLController.swift */; }; + B6ABD0CB2BC03F610000EB69 /* SecurityScopedFileURLController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6ABD0C92BC03F610000EB69 /* SecurityScopedFileURLController.swift */; }; + B6ABD0CE2BC042CE0000EB69 /* NSURL+sandboxExtensionRetainCount.m in Sources */ = {isa = PBXBuildFile; fileRef = B6ABD0CD2BC042CE0000EB69 /* NSURL+sandboxExtensionRetainCount.m */; }; + B6ABD0CF2BC042CE0000EB69 /* NSURL+sandboxExtensionRetainCount.m in Sources */ = {isa = PBXBuildFile; fileRef = B6ABD0CD2BC042CE0000EB69 /* NSURL+sandboxExtensionRetainCount.m */; }; B6AE39F129373AF200C37AA4 /* EmptyAttributionRulesProver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AE39F029373AF200C37AA4 /* EmptyAttributionRulesProver.swift */; }; B6AE39F329374AEC00C37AA4 /* OHHTTPStubs in Frameworks */ = {isa = PBXBuildFile; productRef = B6AE39F229374AEC00C37AA4 /* OHHTTPStubs */; }; B6AE39F529374AEC00C37AA4 /* OHHTTPStubsSwift in Frameworks */ = {isa = PBXBuildFile; productRef = B6AE39F429374AEC00C37AA4 /* OHHTTPStubsSwift */; }; @@ -3053,50 +2287,38 @@ B6B1E87B26D381710062C350 /* DownloadListCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E87A26D381710062C350 /* DownloadListCoordinator.swift */; }; B6B1E87E26D5DA0E0062C350 /* DownloadsPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E87D26D5DA0E0062C350 /* DownloadsPopover.swift */; }; B6B1E88026D5DA9B0062C350 /* DownloadsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E87F26D5DA9B0062C350 /* DownloadsViewController.swift */; }; - B6B1E88226D5DAC30062C350 /* Downloads.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B6B1E88126D5DAC30062C350 /* Downloads.storyboard */; }; B6B1E88426D5EB570062C350 /* DownloadsCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E88326D5EB570062C350 /* DownloadsCellView.swift */; }; B6B1E88B26D774090062C350 /* LinkButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B1E88A26D774090062C350 /* LinkButton.swift */; }; B6B2400E28083B49001B8F3A /* WebViewContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B2400D28083B49001B8F3A /* WebViewContainerView.swift */; }; B6B3E0E12657EA7A0040E0A2 /* NSScreenExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B3E0DC2657E9CF0040E0A2 /* NSScreenExtension.swift */; }; B6B4D1C52B0B3B5400C26286 /* DataImportReportModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4D1C42B0B3B5400C26286 /* DataImportReportModel.swift */; }; B6B4D1C62B0B3B5400C26286 /* DataImportReportModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4D1C42B0B3B5400C26286 /* DataImportReportModel.swift */; }; - B6B4D1C82B0B3B5400C26286 /* DataImportReportModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4D1C42B0B3B5400C26286 /* DataImportReportModel.swift */; }; B6B4D1CA2B0C8C9200C26286 /* FirefoxCompatibilityPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4D1C92B0C8C9200C26286 /* FirefoxCompatibilityPreferences.swift */; }; B6B4D1CB2B0C8C9200C26286 /* FirefoxCompatibilityPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4D1C92B0C8C9200C26286 /* FirefoxCompatibilityPreferences.swift */; }; - B6B4D1CD2B0C8C9200C26286 /* FirefoxCompatibilityPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4D1C92B0C8C9200C26286 /* FirefoxCompatibilityPreferences.swift */; }; B6B4D1CF2B0E0DD000C26286 /* DataImportNoDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4D1CE2B0E0DD000C26286 /* DataImportNoDataView.swift */; }; B6B4D1D02B0E0DD000C26286 /* DataImportNoDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4D1CE2B0E0DD000C26286 /* DataImportNoDataView.swift */; }; - B6B4D1D22B0E0DD000C26286 /* DataImportNoDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4D1CE2B0E0DD000C26286 /* DataImportNoDataView.swift */; }; B6B5F57F2B024105008DB58A /* DataImportSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B5F57E2B024105008DB58A /* DataImportSummaryView.swift */; }; B6B5F5802B024105008DB58A /* DataImportSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B5F57E2B024105008DB58A /* DataImportSummaryView.swift */; }; - B6B5F5822B024105008DB58A /* DataImportSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B5F57E2B024105008DB58A /* DataImportSummaryView.swift */; }; B6B5F5842B03580A008DB58A /* RequestFilePermissionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B5F5832B03580A008DB58A /* RequestFilePermissionView.swift */; }; B6B5F5852B03580A008DB58A /* RequestFilePermissionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B5F5832B03580A008DB58A /* RequestFilePermissionView.swift */; }; B6B5F5892B03673B008DB58A /* BrowserImportMoreInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B5F5882B03673B008DB58A /* BrowserImportMoreInfoView.swift */; }; B6B5F58A2B03673B008DB58A /* BrowserImportMoreInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B5F5882B03673B008DB58A /* BrowserImportMoreInfoView.swift */; }; - B6B5F58C2B03673B008DB58A /* BrowserImportMoreInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B5F5882B03673B008DB58A /* BrowserImportMoreInfoView.swift */; }; B6B71C582B23379600487131 /* NSLayoutConstraintExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B71C572B23379600487131 /* NSLayoutConstraintExtension.swift */; }; B6B71C592B23379600487131 /* NSLayoutConstraintExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B71C572B23379600487131 /* NSLayoutConstraintExtension.swift */; }; - B6B71C5A2B23379600487131 /* NSLayoutConstraintExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B71C572B23379600487131 /* NSLayoutConstraintExtension.swift */; }; B6B77BE8297973D4001E68A1 /* Navigation in Frameworks */ = {isa = PBXBuildFile; productRef = B6B77BE7297973D4001E68A1 /* Navigation */; }; B6BBF1702744CDE1004F850E /* CoreDataStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BBF16F2744CDE1004F850E /* CoreDataStoreTests.swift */; }; B6BBF1722744CE36004F850E /* FireproofDomainsStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BBF1712744CE36004F850E /* FireproofDomainsStoreMock.swift */; }; B6BBF17427475B15004F850E /* PopupBlockedPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BBF17327475B15004F850E /* PopupBlockedPopover.swift */; }; B6BCC51E2AFCD9ED002C5499 /* DataImportSourcePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC51D2AFCD9ED002C5499 /* DataImportSourcePicker.swift */; }; B6BCC51F2AFCD9ED002C5499 /* DataImportSourcePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC51D2AFCD9ED002C5499 /* DataImportSourcePicker.swift */; }; - B6BCC5212AFCD9ED002C5499 /* DataImportSourcePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC51D2AFCD9ED002C5499 /* DataImportSourcePicker.swift */; }; B6BCC5232AFCDABB002C5499 /* DataImportSourceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC5222AFCDABB002C5499 /* DataImportSourceViewModel.swift */; }; B6BCC5242AFCDABB002C5499 /* DataImportSourceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC5222AFCDABB002C5499 /* DataImportSourceViewModel.swift */; }; - B6BCC5262AFCDABB002C5499 /* DataImportSourceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC5222AFCDABB002C5499 /* DataImportSourceViewModel.swift */; }; B6BCC53B2AFD15DF002C5499 /* DataImportProfilePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC53A2AFD15DF002C5499 /* DataImportProfilePicker.swift */; }; B6BCC53C2AFD15DF002C5499 /* DataImportProfilePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC53A2AFD15DF002C5499 /* DataImportProfilePicker.swift */; }; - B6BCC53E2AFD15DF002C5499 /* DataImportProfilePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC53A2AFD15DF002C5499 /* DataImportProfilePicker.swift */; }; B6BCC54A2AFDF24B002C5499 /* TaskWithProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC5492AFDF24B002C5499 /* TaskWithProgress.swift */; }; B6BCC54B2AFDF24B002C5499 /* TaskWithProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC5492AFDF24B002C5499 /* TaskWithProgress.swift */; }; - B6BCC54D2AFDF24B002C5499 /* TaskWithProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC5492AFDF24B002C5499 /* TaskWithProgress.swift */; }; B6BCC54F2AFE4F7D002C5499 /* DataImportTypePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC54E2AFE4F7D002C5499 /* DataImportTypePicker.swift */; }; B6BCC5502AFE4F7D002C5499 /* DataImportTypePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC54E2AFE4F7D002C5499 /* DataImportTypePicker.swift */; }; - B6BCC5522AFE4F7D002C5499 /* DataImportTypePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BCC54E2AFE4F7D002C5499 /* DataImportTypePicker.swift */; }; B6BDDA012942389000F68088 /* TabExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BDDA002942389000F68088 /* TabExtensions.swift */; }; B6BE9FAA293F7955006363C6 /* ModalSheetCancellable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BE9FA9293F7955006363C6 /* ModalSheetCancellable.swift */; }; B6BF5D852946FFDA006742B1 /* PrivacyDashboardTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BF5D842946FFDA006742B1 /* PrivacyDashboardTabExtension.swift */; }; @@ -3125,15 +2347,12 @@ B6C843DB2BA1CAB6006FDEC3 /* FilePresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C843D92BA1CAB6006FDEC3 /* FilePresenterTests.swift */; }; B6C8CAA72AD010DD0060E1CD /* YandexDataImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C8CAA62AD010DD0060E1CD /* YandexDataImporter.swift */; }; B6C8CAA82AD010DD0060E1CD /* YandexDataImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C8CAA62AD010DD0060E1CD /* YandexDataImporter.swift */; }; - B6C8CAAA2AD010DD0060E1CD /* YandexDataImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C8CAA62AD010DD0060E1CD /* YandexDataImporter.swift */; }; B6CA4824298CDC2E0067ECCE /* AdClickAttributionTabExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CA4823298CDC2E0067ECCE /* AdClickAttributionTabExtensionTests.swift */; }; B6CA4825298CE4B70067ECCE /* AdClickAttributionTabExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CA4823298CDC2E0067ECCE /* AdClickAttributionTabExtensionTests.swift */; }; B6CC26682BAD959500F53F8D /* DownloadProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CC26672BAD959500F53F8D /* DownloadProgress.swift */; }; B6CC26692BAD959500F53F8D /* DownloadProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CC26672BAD959500F53F8D /* DownloadProgress.swift */; }; - B6CC266A2BAD959500F53F8D /* DownloadProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CC26672BAD959500F53F8D /* DownloadProgress.swift */; }; B6CC266C2BAD9CD800F53F8D /* FileProgressPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CC266B2BAD9CD800F53F8D /* FileProgressPresenter.swift */; }; B6CC266D2BAD9CD800F53F8D /* FileProgressPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CC266B2BAD9CD800F53F8D /* FileProgressPresenter.swift */; }; - B6CC266E2BAD9CD800F53F8D /* FileProgressPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6CC266B2BAD9CD800F53F8D /* FileProgressPresenter.swift */; }; B6D574B429472253008ED1B6 /* FBProtectionTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D574B329472253008ED1B6 /* FBProtectionTabExtension.swift */; }; B6D6A5DD2982A4CE001F5F11 /* Tab+Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B61E2CD4294346C000773D8A /* Tab+Navigation.swift */; }; B6DA06E12913AEDC00225DE2 /* TestNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA06E02913AEDB00225DE2 /* TestNavigationDelegate.swift */; }; @@ -3141,27 +2360,29 @@ B6DA06E42913ECEE00225DE2 /* ContextMenuManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA06E32913ECEE00225DE2 /* ContextMenuManager.swift */; }; B6DA06E62913F39400225DE2 /* MenuItemSelectors.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA06E52913F39400225DE2 /* MenuItemSelectors.swift */; }; B6DA06E8291401D700225DE2 /* WKMenuItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA06E7291401D700225DE2 /* WKMenuItemIdentifier.swift */; }; - B6DA44022616B28300DD1EC2 /* PixelDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */; }; - B6DA44082616B30600DD1EC2 /* PixelDataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44062616B30600DD1EC2 /* PixelDataModel.xcdatamodeld */; }; - B6DA44112616C0FC00DD1EC2 /* PixelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44102616C0FC00DD1EC2 /* PixelTests.swift */; }; B6DA44172616C13800DD1EC2 /* OHHTTPStubs in Frameworks */ = {isa = PBXBuildFile; productRef = B6DA44162616C13800DD1EC2 /* OHHTTPStubs */; }; B6DA44192616C13800DD1EC2 /* OHHTTPStubsSwift in Frameworks */ = {isa = PBXBuildFile; productRef = B6DA44182616C13800DD1EC2 /* OHHTTPStubsSwift */; }; B6DA441E2616C84600DD1EC2 /* PixelStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA441D2616C84600DD1EC2 /* PixelStoreMock.swift */; }; - B6DA44232616CABC00DD1EC2 /* PixelArgumentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44222616CABC00DD1EC2 /* PixelArgumentsTests.swift */; }; B6DB3AEF278D5C370024C5C4 /* URLSessionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DB3AEE278D5C370024C5C4 /* URLSessionExtension.swift */; }; B6DB3AF6278EA0130024C5C4 /* BundleExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6106B9D26A565DA0013B453 /* BundleExtension.swift */; }; B6DB3CF926A00E2D00D459B7 /* AVCaptureDevice+SwizzledAuthState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DB3CF826A00E2D00D459B7 /* AVCaptureDevice+SwizzledAuthState.swift */; }; B6DB3CFB26A17CB800D459B7 /* PermissionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DB3CFA26A17CB800D459B7 /* PermissionModel.swift */; }; B6DE57F62B05EA9000CD54B9 /* SheetHostingWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DE57F52B05EA9000CD54B9 /* SheetHostingWindow.swift */; }; B6DE57F72B05EA9000CD54B9 /* SheetHostingWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DE57F52B05EA9000CD54B9 /* SheetHostingWindow.swift */; }; - B6DE57F92B05EA9000CD54B9 /* SheetHostingWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DE57F52B05EA9000CD54B9 /* SheetHostingWindow.swift */; }; B6E1491029A5C30500AAFBE8 /* ContentBlockingTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D574B12947224C008ED1B6 /* ContentBlockingTabExtension.swift */; }; B6E1491129A5C30A00AAFBE8 /* FBProtectionTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6D574B329472253008ED1B6 /* FBProtectionTabExtension.swift */; }; B6E319382953446000DD3BCF /* Assertions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E319372953446000DD3BCF /* Assertions.swift */; }; + B6E3E5502BBFCDEE00A41922 /* OpenDownloadsCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E3E54F2BBFCDEE00A41922 /* OpenDownloadsCellView.swift */; }; + B6E3E5512BBFCDEE00A41922 /* OpenDownloadsCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E3E54F2BBFCDEE00A41922 /* OpenDownloadsCellView.swift */; }; + B6E3E5542BBFCEE300A41922 /* NoDownloadsCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E3E5532BBFCEE300A41922 /* NoDownloadsCellView.swift */; }; + B6E3E5552BBFCEE300A41922 /* NoDownloadsCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E3E5532BBFCEE300A41922 /* NoDownloadsCellView.swift */; }; + B6E3E5582BBFD51400A41922 /* PreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E3E5572BBFD51400A41922 /* PreviewViewController.swift */; }; + B6E3E5592BBFD51400A41922 /* PreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E3E5572BBFD51400A41922 /* PreviewViewController.swift */; }; + B6E3E55B2BC0041900A41922 /* DownloadListStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693956026F1C1BC0015B914 /* DownloadListStoreMock.swift */; }; + B6E3E55C2BC0041A00A41922 /* DownloadListStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B693956026F1C1BC0015B914 /* DownloadListStoreMock.swift */; }; B6E61EE3263AC0C8004E11AB /* FileManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E61EE2263AC0C8004E11AB /* FileManagerExtension.swift */; }; B6E6B9E32BA1F5F1008AA7E1 /* FilePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E6B9E22BA1F5F1008AA7E1 /* FilePresenter.swift */; }; B6E6B9E42BA1F5F1008AA7E1 /* FilePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E6B9E22BA1F5F1008AA7E1 /* FilePresenter.swift */; }; - B6E6B9E52BA1F5F1008AA7E1 /* FilePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E6B9E22BA1F5F1008AA7E1 /* FilePresenter.swift */; }; B6E6B9F62BA1FD90008AA7E1 /* SandboxTestTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E6B9F52BA1FD90008AA7E1 /* SandboxTestTool.swift */; }; B6E6BA042BA1FE05008AA7E1 /* FilePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E6B9E22BA1F5F1008AA7E1 /* FilePresenter.swift */; }; B6E6BA052BA1FE09008AA7E1 /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA8EDF2324923E980071C2E8 /* URLExtension.swift */; }; @@ -3182,8 +2403,19 @@ B6EC37FC29B83E99001ACE79 /* TestsURLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EC37FB29B83E99001ACE79 /* TestsURLExtension.swift */; }; B6EC37FD29B83E99001ACE79 /* TestsURLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EC37FB29B83E99001ACE79 /* TestsURLExtension.swift */; }; B6EC37FF29B8D915001ACE79 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = B6EC37FE29B8D915001ACE79 /* Configuration */; }; + B6EECB302BC3FA5A00B3CB77 /* SecurityScopedFileURLController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6ABD0C92BC03F610000EB69 /* SecurityScopedFileURLController.swift */; }; + B6EECB312BC3FAB100B3CB77 /* NSURL+sandboxExtensionRetainCount.m in Sources */ = {isa = PBXBuildFile; fileRef = B6ABD0CD2BC042CE0000EB69 /* NSURL+sandboxExtensionRetainCount.m */; }; + B6EECB322BC40A1400B3CB77 /* FileManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E61EE2263AC0C8004E11AB /* FileManagerExtension.swift */; }; B6EEDD7D2B8C69E900637EBC /* TabContentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EEDD7C2B8C69E900637EBC /* TabContentTests.swift */; }; B6EEDD7E2B8C69E900637EBC /* TabContentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6EEDD7C2B8C69E900637EBC /* TabContentTests.swift */; }; + B6F1B0222BCE5658005E863C /* BrokenSiteInfoTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F1B0212BCE5658005E863C /* BrokenSiteInfoTabExtension.swift */; }; + B6F1B0232BCE5658005E863C /* BrokenSiteInfoTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F1B0212BCE5658005E863C /* BrokenSiteInfoTabExtension.swift */; }; + B6F1B0262BCE5A50005E863C /* TabContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F1B0252BCE5A50005E863C /* TabContent.swift */; }; + B6F1B0272BCE5A50005E863C /* TabContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F1B0252BCE5A50005E863C /* TabContent.swift */; }; + B6F1B02A2BCE675C005E863C /* NetworkProtectionControllerTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F1B0292BCE675C005E863C /* NetworkProtectionControllerTabExtension.swift */; }; + B6F1B02B2BCE675C005E863C /* NetworkProtectionControllerTabExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F1B0292BCE675C005E863C /* NetworkProtectionControllerTabExtension.swift */; }; + B6F1B02E2BCE6B47005E863C /* TunnelControllerProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F1B02D2BCE6B47005E863C /* TunnelControllerProvider.swift */; }; + B6F1B02F2BCE6B47005E863C /* TunnelControllerProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F1B02D2BCE6B47005E863C /* TunnelControllerProvider.swift */; }; B6F1C80B2761C45400334924 /* LocalUnprotectedDomains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 336B39E22726B4B700C417D3 /* LocalUnprotectedDomains.swift */; }; B6F41031264D2B23003DA42C /* ProgressExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F41030264D2B23003DA42C /* ProgressExtension.swift */; }; B6F56567299A414300A04298 /* WKWebViewMockingExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F56566299A414300A04298 /* WKWebViewMockingExtension.swift */; }; @@ -3200,41 +2432,54 @@ B6F92BAD2A6937B5002ABA6B /* OptionalExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B637273C26CCF0C200C8CB02 /* OptionalExtension.swift */; }; B6F9BDDC2B45B7EE00677B33 /* WebsiteInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F9BDDB2B45B7EE00677B33 /* WebsiteInfo.swift */; }; B6F9BDDD2B45B7EE00677B33 /* WebsiteInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F9BDDB2B45B7EE00677B33 /* WebsiteInfo.swift */; }; - B6F9BDDE2B45B7EE00677B33 /* WebsiteInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F9BDDB2B45B7EE00677B33 /* WebsiteInfo.swift */; }; B6F9BDE42B45CD1900677B33 /* ModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F9BDE32B45CD1900677B33 /* ModalView.swift */; }; B6F9BDE52B45CD1900677B33 /* ModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F9BDE32B45CD1900677B33 /* ModalView.swift */; }; - B6F9BDE62B45CD1900677B33 /* ModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F9BDE32B45CD1900677B33 /* ModalView.swift */; }; B6FA893D269C423100588ECD /* PrivacyDashboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B6FA893C269C423100588ECD /* PrivacyDashboard.storyboard */; }; B6FA893F269C424500588ECD /* PrivacyDashboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6FA893E269C424500588ECD /* PrivacyDashboardViewController.swift */; }; B6FA8941269C425400588ECD /* PrivacyDashboardPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6FA8940269C425400588ECD /* PrivacyDashboardPopover.swift */; }; BB5789722B2CA70F0009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5789712B2CA70F0009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift */; }; - BB5789732B2CC0300009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5789712B2CA70F0009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift */; }; BBDFDC5A2B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBDFDC592B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift */; }; - BBDFDC5C2B2B8D7000F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBDFDC592B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift */; }; BBDFDC5D2B2B8E2100F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBDFDC592B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift */; }; + BD384AC92BBC821A00EF3735 /* vpn-dark-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */; }; + BD384ACA2BBC821A00EF3735 /* vpn-light-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC72BBC821100EF3735 /* vpn-light-mode.json */; }; + BD384ACB2BBC821B00EF3735 /* vpn-dark-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */; }; + BD384ACC2BBC821B00EF3735 /* vpn-light-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC72BBC821100EF3735 /* vpn-light-mode.json */; }; + BDA7647C2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA7647B2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift */; }; + BDA7647D2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA7647B2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift */; }; + BDA7647F2BC4998900D0400C /* DefaultVPNLocationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA7647B2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift */; }; + BDA764802BC4998A00D0400C /* DefaultVPNLocationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA7647B2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift */; }; + BDA764842BC49E3F00D0400C /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */; }; + BDA764852BC49E4000D0400C /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */; }; + BDA7648D2BC4E4EF00D0400C /* DefaultVPNLocationFormatterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA7648C2BC4E4EF00D0400C /* DefaultVPNLocationFormatterTests.swift */; }; + BDA7648E2BC4E4EF00D0400C /* DefaultVPNLocationFormatterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA7648C2BC4E4EF00D0400C /* DefaultVPNLocationFormatterTests.swift */; }; + BDA764912BC4E57200D0400C /* MockVPNLocationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA764902BC4E57200D0400C /* MockVPNLocationFormatter.swift */; }; + BDA764922BC4E57200D0400C /* MockVPNLocationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA764902BC4E57200D0400C /* MockVPNLocationFormatter.swift */; }; + BDADBDC92BD2BC2200421B9B /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = BDADBDC82BD2BC2200421B9B /* Lottie */; }; + BDADBDCB2BD2BC2800421B9B /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = BDADBDCA2BD2BC2800421B9B /* Lottie */; }; + BDADBDCC2BD2BC4D00421B9B /* vpn-dark-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */; }; + BDADBDCD2BD2BC5700421B9B /* vpn-light-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC72BBC821100EF3735 /* vpn-light-mode.json */; }; + BDE981D92BBD10D600645880 /* vpn-dark-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */; }; + BDE981DA2BBD10D600645880 /* vpn-light-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC72BBC821100EF3735 /* vpn-light-mode.json */; }; + C1372EF42BBC5BAD003F8793 /* SecureTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1372EF32BBC5BAD003F8793 /* SecureTextField.swift */; }; + C1372EF52BBC5BAD003F8793 /* SecureTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1372EF32BBC5BAD003F8793 /* SecureTextField.swift */; }; C13909EF2B85FD4E001626ED /* AutofillActionExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13909EE2B85FD4E001626ED /* AutofillActionExecutor.swift */; }; C13909F02B85FD4E001626ED /* AutofillActionExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13909EE2B85FD4E001626ED /* AutofillActionExecutor.swift */; }; - C13909F12B85FD4E001626ED /* AutofillActionExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13909EE2B85FD4E001626ED /* AutofillActionExecutor.swift */; }; C13909F42B85FD79001626ED /* AutofillDeleteAllPasswordsExecutorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13909F32B85FD79001626ED /* AutofillDeleteAllPasswordsExecutorTests.swift */; }; C13909F52B85FD79001626ED /* AutofillDeleteAllPasswordsExecutorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13909F32B85FD79001626ED /* AutofillDeleteAllPasswordsExecutorTests.swift */; }; C13909FB2B861039001626ED /* AutofillActionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13909FA2B861039001626ED /* AutofillActionPresenter.swift */; }; C13909FC2B861039001626ED /* AutofillActionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13909FA2B861039001626ED /* AutofillActionPresenter.swift */; }; - C13909FD2B861039001626ED /* AutofillActionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13909FA2B861039001626ED /* AutofillActionPresenter.swift */; }; C168B9AC2B31DC7E001AFAD9 /* AutofillNeverPromptWebsitesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C168B9AB2B31DC7E001AFAD9 /* AutofillNeverPromptWebsitesManager.swift */; }; C168B9AD2B31DC7F001AFAD9 /* AutofillNeverPromptWebsitesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C168B9AB2B31DC7E001AFAD9 /* AutofillNeverPromptWebsitesManager.swift */; }; - C168B9AE2B31DC7F001AFAD9 /* AutofillNeverPromptWebsitesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C168B9AB2B31DC7E001AFAD9 /* AutofillNeverPromptWebsitesManager.swift */; }; C17CA7AD2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17CA7AC2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift */; }; C17CA7AE2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17CA7AC2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift */; }; C17CA7B22B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17CA7B12B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift */; }; C17CA7B32B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17CA7B12B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift */; }; C1DAF3B52B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DAF3B42B9A44860059244F /* AutofillPopoverPresenter.swift */; }; C1DAF3B62B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DAF3B42B9A44860059244F /* AutofillPopoverPresenter.swift */; }; - C1DAF3B72B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DAF3B42B9A44860059244F /* AutofillPopoverPresenter.swift */; }; C1E961EB2B879E79001760E1 /* MockAutofillActionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961E72B879E4D001760E1 /* MockAutofillActionPresenter.swift */; }; C1E961ED2B879ED9001760E1 /* MockAutofillActionExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961EC2B879ED9001760E1 /* MockAutofillActionExecutor.swift */; }; C1E961EF2B87AA29001760E1 /* AutofillActionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961EE2B87AA29001760E1 /* AutofillActionBuilder.swift */; }; C1E961F02B87AA29001760E1 /* AutofillActionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961EE2B87AA29001760E1 /* AutofillActionBuilder.swift */; }; - C1E961F22B87AA29001760E1 /* AutofillActionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961EE2B87AA29001760E1 /* AutofillActionBuilder.swift */; }; C1E961F32B87B273001760E1 /* MockAutofillActionExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961EC2B879ED9001760E1 /* MockAutofillActionExecutor.swift */; }; C1E961F42B87B276001760E1 /* MockAutofillActionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961E72B879E4D001760E1 /* MockAutofillActionPresenter.swift */; }; CB24F70C29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */; }; @@ -3245,7 +2490,6 @@ CBDD5DE429A6800300832877 /* MockConfigurationStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDD5DE229A67F2700832877 /* MockConfigurationStore.swift */; }; D64A5FF82AEA5C2B00B6D6E7 /* HomeButtonMenuFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64A5FF72AEA5C2B00B6D6E7 /* HomeButtonMenuFactory.swift */; }; D64A5FF92AEA5C2B00B6D6E7 /* HomeButtonMenuFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64A5FF72AEA5C2B00B6D6E7 /* HomeButtonMenuFactory.swift */; }; - D64A5FFB2AEA5C2B00B6D6E7 /* HomeButtonMenuFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64A5FF72AEA5C2B00B6D6E7 /* HomeButtonMenuFactory.swift */; }; EA0BA3A9272217E6002A0B6C /* ClickToLoadUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0BA3A8272217E6002A0B6C /* ClickToLoadUserScript.swift */; }; EA18D1CA272F0DC8006DC101 /* social_images in Resources */ = {isa = PBXBuildFile; fileRef = EA18D1C9272F0DC8006DC101 /* social_images */; }; EA1E52B52798CF98002EC53C /* ClickToLoadModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1E52B42798CF98002EC53C /* ClickToLoadModelTests.swift */; }; @@ -3267,19 +2511,24 @@ EE339228291BDEFD009F62C1 /* JSAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE339227291BDEFD009F62C1 /* JSAlertController.swift */; }; EE3424602BA0853900173B1B /* VPNUninstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE34245D2BA0853900173B1B /* VPNUninstaller.swift */; }; EE3424612BA0853900173B1B /* VPNUninstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE34245D2BA0853900173B1B /* VPNUninstaller.swift */; }; + EE42CBCC2BC8004700AD411C /* PermissionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE42CBCB2BC8004700AD411C /* PermissionsTests.swift */; }; + EE54F7B32BBFEA49006218DB /* BookmarksAndFavoritesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE54F7B22BBFEA48006218DB /* BookmarksAndFavoritesTests.swift */; }; EE66418C2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */; }; EE66418D2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */; }; EE66666F2B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; EE6666702B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; - EE6666712B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */; }; EE7295E32A545B9A008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295E22A545B9A008C0991 /* NetworkProtection */; }; EE7295E72A545BBB008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295E62A545BBB008C0991 /* NetworkProtection */; }; EE7295E92A545BC4008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295E82A545BC4008C0991 /* NetworkProtection */; }; EE7295ED2A545C0A008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295EC2A545C0A008C0991 /* NetworkProtection */; }; EE7295EF2A545C12008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295EE2A545C12008C0991 /* NetworkProtection */; }; + EE7F74912BB5D76600CD9456 /* BookmarksBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE7F74902BB5D76600CD9456 /* BookmarksBarTests.swift */; }; + EE9D81C32BC57A3700338BE3 /* StateRestorationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9D81C22BC57A3700338BE3 /* StateRestorationTests.swift */; }; EEA3EEB12B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */; }; EEA3EEB32B24EC0600E8333A /* VPNLocationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */; }; EEAD7A7C2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; + EEBCA0C62BD7CE2C004DF19C /* VPNFailureRecoveryPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCA0C52BD7CE2C004DF19C /* VPNFailureRecoveryPixel.swift */; }; + EEBCA0C72BD7CE2C004DF19C /* VPNFailureRecoveryPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCA0C52BD7CE2C004DF19C /* VPNFailureRecoveryPixel.swift */; }; EEBCE6822BA444FA00B9DF00 /* XCUIElementExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEBCE6812BA444FA00B9DF00 /* XCUIElementExtension.swift */; }; EEBCE6832BA463DD00B9DF00 /* NSImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B139AFC26B60BD800894F82 /* NSImageExtensions.swift */; }; EEBCE6842BA4643200B9DF00 /* NSSizeExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC5E4E325D6BA9C007F5990 /* NSSizeExtension.swift */; }; @@ -3287,21 +2536,17 @@ EEC111E6294D06290086524F /* JSAlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC111E5294D06290086524F /* JSAlertViewModel.swift */; }; EEC4A65E2B277E8D00F7C0AA /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */; }; EEC4A65F2B277EE100F7C0AA /* VPNLocationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */; }; - EEC4A6602B277F0D00F7C0AA /* VPNLocationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */; }; - EEC4A6612B277F1100F7C0AA /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */; }; EEC4A6692B2C87D300F7C0AA /* VPNLocationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC4A6682B2C87D300F7C0AA /* VPNLocationView.swift */; }; EEC4A66A2B2C87D300F7C0AA /* VPNLocationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC4A6682B2C87D300F7C0AA /* VPNLocationView.swift */; }; - EEC4A66B2B2C87D300F7C0AA /* VPNLocationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC4A6682B2C87D300F7C0AA /* VPNLocationView.swift */; }; EEC4A66D2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC4A66C2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift */; }; EEC4A66E2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC4A66C2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift */; }; - EEC4A66F2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC4A66C2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift */; }; EEC4A6712B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC4A6702B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift */; }; EEC4A6722B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC4A6702B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift */; }; - EEC4A6732B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC4A6702B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift */; }; EEC589D92A4F1CE300BCD60C /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; EEC589DA2A4F1CE400BCD60C /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; EEC589DB2A4F1CE700BCD60C /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; EEC589DC2A4F1CE800BCD60C /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; + EEC7BE2E2BC6C09500F86835 /* AddressBarKeyboardShortcutsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC7BE2D2BC6C09400F86835 /* AddressBarKeyboardShortcutsTests.swift */; }; EEC8EB3E2982CA3B0065AA39 /* JSAlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC111E5294D06290086524F /* JSAlertViewModel.swift */; }; EEC8EB3F2982CA440065AA39 /* JSAlert.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EEC111E3294D06020086524F /* JSAlert.storyboard */; }; EEC8EB402982CD550065AA39 /* JSAlertViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */; }; @@ -3312,18 +2557,41 @@ EEDE50122BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDE50102BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift */; }; EEF12E6F2A2111880023E6BF /* MacPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */; }; EEF53E182950CED5002D78F4 /* JSAlertViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */; }; + F116A7C32BD1924B00F3FCF7 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = F116A7C22BD1924B00F3FCF7 /* PixelKitTestingUtilities */; }; + F116A7C72BD1925500F3FCF7 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = F116A7C62BD1925500F3FCF7 /* PixelKitTestingUtilities */; }; + F116A7C92BD1929000F3FCF7 /* PixelKitTestingUtilities in Frameworks */ = {isa = PBXBuildFile; productRef = F116A7C82BD1929000F3FCF7 /* PixelKitTestingUtilities */; }; + F188267C2BBEB3AA00D9AC4F /* GeneralPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F188267B2BBEB3AA00D9AC4F /* GeneralPixel.swift */; }; + F188267D2BBEB3AA00D9AC4F /* GeneralPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F188267B2BBEB3AA00D9AC4F /* GeneralPixel.swift */; }; + F18826802BBEB58100D9AC4F /* PrivacyProPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F188267F2BBEB58100D9AC4F /* PrivacyProPixel.swift */; }; + F18826812BBEB58100D9AC4F /* PrivacyProPixel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F188267F2BBEB58100D9AC4F /* PrivacyProPixel.swift */; }; + F18826842BBEE31700D9AC4F /* PixelKit+Assertion.swift in Sources */ = {isa = PBXBuildFile; fileRef = F18826832BBEE31700D9AC4F /* PixelKit+Assertion.swift */; }; + F18826852BBEE31700D9AC4F /* PixelKit+Assertion.swift in Sources */ = {isa = PBXBuildFile; fileRef = F18826832BBEE31700D9AC4F /* PixelKit+Assertion.swift */; }; + F188268D2BBF01C300D9AC4F /* PixelDataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44062616B30600DD1EC2 /* PixelDataModel.xcdatamodeld */; }; + F188268E2BBF01C400D9AC4F /* PixelDataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44062616B30600DD1EC2 /* PixelDataModel.xcdatamodeld */; }; + F18826902BC0105800D9AC4F /* PixelDataRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C92C32750EF76002AC6B0 /* PixelDataRecord.swift */; }; + F18826912BC0105800D9AC4F /* PixelDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */; }; + F18826922BC0105900D9AC4F /* PixelDataRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = B68C92C32750EF76002AC6B0 /* PixelDataRecord.swift */; }; + F18826932BC0105900D9AC4F /* PixelDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */; }; + F198C7122BD18A28000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7112BD18A28000BF24D /* PixelKit */; }; + F198C7142BD18A30000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7132BD18A30000BF24D /* PixelKit */; }; + F198C7162BD18A44000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7152BD18A44000BF24D /* PixelKit */; }; + F198C7182BD18A4C000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7172BD18A4C000BF24D /* PixelKit */; }; + F198C71A2BD18A5B000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C7192BD18A5B000BF24D /* PixelKit */; }; + F198C71C2BD18A61000BF24D /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = F198C71B2BD18A61000BF24D /* PixelKit */; }; + F198C71E2BD18D88000BF24D /* SwiftLintTool in Frameworks */ = {isa = PBXBuildFile; productRef = F198C71D2BD18D88000BF24D /* SwiftLintTool */; }; + F198C7202BD18D92000BF24D /* SwiftLintTool in Frameworks */ = {isa = PBXBuildFile; productRef = F198C71F2BD18D92000BF24D /* SwiftLintTool */; }; F1B33DF22BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */; }; F1B33DF32BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */; }; - F1B33DF42BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */; }; F1B33DF62BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */; }; F1B33DF72BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */; }; - F1B33DF82BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */; }; F1D43AEE2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */; }; F1D43AEF2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */; }; - F1D43AF02B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */; }; F1D43AF32B98E47800BAB743 /* BareBonesBrowserKit in Frameworks */ = {isa = PBXBuildFile; productRef = F1D43AF22B98E47800BAB743 /* BareBonesBrowserKit */; }; F1D43AF52B98E48900BAB743 /* BareBonesBrowserKit in Frameworks */ = {isa = PBXBuildFile; productRef = F1D43AF42B98E48900BAB743 /* BareBonesBrowserKit */; }; - F1D43AF72B98E48F00BAB743 /* BareBonesBrowserKit in Frameworks */ = {isa = PBXBuildFile; productRef = F1D43AF62B98E48F00BAB743 /* BareBonesBrowserKit */; }; + F1DF95E32BD1807C0045E591 /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 08D4923DC968236E22E373E2 /* Crashes */; }; + F1DF95E42BD1807C0045E591 /* Crashes in Frameworks */ = {isa = PBXBuildFile; productRef = 537FC71EA5115A983FAF3170 /* Crashes */; }; + F1DF95E52BD1807C0045E591 /* Subscription in Frameworks */ = {isa = PBXBuildFile; productRef = DC3F73D49B2D44464AFEFCD8 /* Subscription */; }; + F1DF95E72BD188B60045E591 /* LoginItems in Frameworks */ = {isa = PBXBuildFile; productRef = F1DF95E62BD188B60045E591 /* LoginItems */; }; F41D174125CB131900472416 /* NSColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F41D174025CB131900472416 /* NSColorExtension.swift */; }; F44C130225C2DA0400426E3E /* NSAppearanceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F44C130125C2DA0400426E3E /* NSAppearanceExtension.swift */; }; F4A6198C283CFFBB007F2080 /* ContentScopeFeatureFlagging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4A6198B283CFFBB007F2080 /* ContentScopeFeatureFlagging.swift */; }; @@ -3332,13 +2600,6 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 31C6E9AA2B0C07A30086DC30 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = AA585D76248FD31100E9A3E2 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9D9AE8B22AAA39A70026E7DC; - remoteInfo = DuckDuckGoDBPBackgroundAgent; - }; 31C6E9AC2B0C07BA0086DC30 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = AA585D76248FD31100E9A3E2 /* Project object */; @@ -3474,19 +2735,6 @@ name = "Embed Login Items"; runOnlyForDeploymentPostprocessing = 0; }; - 4B957C332AC7AE700062CA31 /* Embed Login Items */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = Contents/Library/LoginItems; - dstSubfolderSpec = 1; - files = ( - 7BFF85102B0C09E300ECACA2 /* DuckDuckGo Personal Information Removal.app in Embed Login Items */, - 4B957C342AC7AE700062CA31 /* DuckDuckGo VPN.app in Embed Login Items */, - 4B957C352AC7AE700062CA31 /* DuckDuckGo Notifications.app in Embed Login Items */, - ); - name = "Embed Login Items"; - runOnlyForDeploymentPostprocessing = 0; - }; 4BA7C4E02B3F6F7500AFE511 /* Embed Network Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -3510,9 +2758,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 021EA07F2BD2A9D500772C9A /* TabsPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsPreferences.swift; sourceTree = ""; }; + 021EA0822BD6DF1B00772C9A /* TabsPreferencesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsPreferencesTests.swift; sourceTree = ""; }; 0230C0A2272080090018F728 /* KeyedCodingExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyedCodingExtension.swift; sourceTree = ""; }; 026ADE1326C3010C002518EE /* macos-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "macos-config.json"; sourceTree = ""; }; 0289041E2A7B23CE0028369C /* AppConfigurationURLProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfigurationURLProviderTests.swift; sourceTree = ""; }; + 02C0737C2BE5B7E000BFE2F5 /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = ""; }; 142879D924CE1179005419BB /* SuggestionViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionViewModelTests.swift; sourceTree = ""; }; 142879DB24CE1185005419BB /* SuggestionContainerViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionContainerViewModelTests.swift; sourceTree = ""; }; 1430DFF424D0580F00B8978C /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.swift; sourceTree = ""; }; @@ -3588,9 +2839,11 @@ 1DDF075F28F815AD00EDFBE3 /* BWStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BWStatus.swift; sourceTree = ""; }; 1DDF076028F815AD00EDFBE3 /* BWError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BWError.swift; sourceTree = ""; }; 1DDF076128F815AD00EDFBE3 /* BWResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BWResponse.swift; sourceTree = ""; }; + 1DEF3BAC2BD145A9004A2FBA /* AutoClearHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoClearHandler.swift; sourceTree = ""; }; 1DFAB51C2A8982A600A0F7F6 /* SetExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetExtension.swift; sourceTree = ""; }; 1DFAB51F2A89830D00A0F7F6 /* SetExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetExtensionTests.swift; sourceTree = ""; }; 1E0C72052ABC63BD00802009 /* SubscriptionPagesUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionPagesUserScript.swift; sourceTree = ""; }; + 1E559BB02BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedirectNavigationResponder.swift; sourceTree = ""; }; 1E7E2E8F29029A2A00C01B54 /* ContentBlockingRulesUpdateObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentBlockingRulesUpdateObserver.swift; sourceTree = ""; }; 1E7E2E932902AC0E00C01B54 /* PrivacyDashboardPermissionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardPermissionHandler.swift; sourceTree = ""; }; 1E862A882A9FC01200F84D4B /* SubscriptionUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = SubscriptionUI; sourceTree = ""; }; @@ -3602,6 +2855,9 @@ 315AA06F28CA5CC800200030 /* YoutubePlayerNavigationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubePlayerNavigationHandler.swift; sourceTree = ""; }; 3168506C2AF3AD1C009A2828 /* WaitlistViewControllerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WaitlistViewControllerPresenter.swift; sourceTree = ""; }; 316850712AF3AD58009A2828 /* DataBrokerProtectionDebugMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionDebugMenu.swift; sourceTree = ""; }; + 316913222BD2B6250051B46D /* DataBrokerProtectionPixelsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionPixelsHandler.swift; sourceTree = ""; }; + 316913252BD2B76F0051B46D /* DataBrokerPrerequisitesStatusVerifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerPrerequisitesStatusVerifier.swift; sourceTree = ""; }; + 316913282BD2C7570051B46D /* DataBrokerProtectionErrorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionErrorViewController.swift; sourceTree = ""; }; 3171D6B72889849F0068632A /* CookieManagedNotificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CookieManagedNotificationView.swift; sourceTree = ""; }; 3171D6B9288984D00068632A /* BadgeAnimationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeAnimationView.swift; sourceTree = ""; }; 3171D6DA2889B64D0068632A /* CookieManagedNotificationContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CookieManagedNotificationContainerView.swift; sourceTree = ""; }; @@ -3614,6 +2870,7 @@ 3199C6F82AF94F5B002A7BA1 /* DataBrokerProtectionFeatureDisabler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionFeatureDisabler.swift; sourceTree = ""; }; 3199C6FC2AF97367002A7BA1 /* DataBrokerProtectionAppEvents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionAppEvents.swift; sourceTree = ""; }; 31A2FD162BAB41C500D0E741 /* DataBrokerProtectionVisibilityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionVisibilityTests.swift; sourceTree = ""; }; + 31A83FB42BE28D7D00F74E67 /* UserText+DBP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserText+DBP.swift"; sourceTree = ""; }; 31AA6B962B960B870025014E /* DataBrokerProtectionLoginItemPixels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionLoginItemPixels.swift; sourceTree = ""; }; 31B4AF522901A4F20013585E /* NSEventExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEventExtension.swift; sourceTree = ""; }; 31C3CE0128EDC1E70002C24A /* CustomRoundedCornersShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomRoundedCornersShape.swift; sourceTree = ""; }; @@ -3621,6 +2878,7 @@ 31C9ADE42AF0564500CEF57D /* WaitlistFeatureSetupHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistFeatureSetupHandler.swift; sourceTree = ""; }; 31CF3431288B0B1B0087244B /* NavigationBarBadgeAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarBadgeAnimator.swift; sourceTree = ""; }; 31D5375B291D944100407A95 /* PasswordManagementBitwardenItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordManagementBitwardenItemView.swift; sourceTree = ""; }; + 31DC2F202BD6DE65001354EF /* DataBrokerPrerequisitesStatusVerifierTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerPrerequisitesStatusVerifierTests.swift; sourceTree = ""; }; 31E163B9293A56F400963C10 /* BrokenSiteReportingReferenceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrokenSiteReportingReferenceTests.swift; sourceTree = ""; }; 31E163BC293A579E00963C10 /* PrivacyReferenceTestHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyReferenceTestHelper.swift; sourceTree = ""; }; 31E163BF293A581900963C10 /* privacy-reference-tests */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "privacy-reference-tests"; path = "Submodules/privacy-reference-tests"; sourceTree = SOURCE_ROOT; }; @@ -3666,6 +2924,7 @@ 376C4DB828A1A48A00CC0F5B /* FirePopoverViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirePopoverViewModelTests.swift; sourceTree = ""; }; 376CC8B4296EB630006B63A7 /* AppStore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppStore.xcconfig; sourceTree = ""; }; 376CC8B5296EBA8F006B63A7 /* BuildNumber.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = BuildNumber.xcconfig; sourceTree = ""; }; + 376E708D2BD686260082B7EB /* UI Tests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = "UI Tests.xctestplan"; sourceTree = ""; }; 37717E66296B5A20002FAEDF /* Global.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Global.xcconfig; sourceTree = ""; }; 3775912C29AAC72700E26367 /* SyncPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPreferences.swift; sourceTree = ""; }; 3775913529AB9A1C00E26367 /* SyncManagementDialogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncManagementDialogViewController.swift; sourceTree = ""; }; @@ -3816,9 +3075,6 @@ 4B4D60652A0B29FA00BCD287 /* NetworkProtectionNavBarButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionNavBarButtonModel.swift; sourceTree = ""; }; 4B4D60692A0B29FA00BCD287 /* NetworkProtection+ConvenienceInitializers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkProtection+ConvenienceInitializers.swift"; sourceTree = ""; }; 4B4D606A2A0B29FA00BCD287 /* NetworkProtectionControllerErrorStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionControllerErrorStore.swift; sourceTree = ""; }; - 4B4D606C2A0B29FA00BCD287 /* NetworkProtectionInviteDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionInviteDialog.swift; sourceTree = ""; }; - 4B4D606F2A0B29FA00BCD287 /* NetworkProtectionInvitePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionInvitePresenter.swift; sourceTree = ""; }; - 4B4D60702A0B29FA00BCD287 /* NetworkProtectionInviteCodeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionInviteCodeViewModel.swift; sourceTree = ""; }; 4B4D60722A0B29FA00BCD287 /* EventMapping+NetworkProtectionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EventMapping+NetworkProtectionError.swift"; sourceTree = ""; }; 4B4D60762A0B29FA00BCD287 /* NetworkProtectionUNNotificationsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionUNNotificationsPresenter.swift; sourceTree = ""; }; 4B4D607C2A0B29FA00BCD287 /* UserText+NetworkProtectionExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserText+NetworkProtectionExtensions.swift"; sourceTree = ""; }; @@ -3842,7 +3098,6 @@ 4B67742A255DBEB800025BD8 /* httpsMobileV2FalsePositives.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = httpsMobileV2FalsePositives.json; sourceTree = ""; }; 4B677440255DBEEA00025BD8 /* Database.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = ""; }; 4B677454255DC18000025BD8 /* Bridging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bridging.h; sourceTree = ""; }; - 4B67853E2AA7C726008A5004 /* DailyPixel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyPixel.swift; sourceTree = ""; }; 4B6785432AA8DE1F008A5004 /* NetworkProtectionFeatureDisabler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionFeatureDisabler.swift; sourceTree = ""; }; 4B6B64832BA930420009FF9F /* WaitlistThankYouPromptPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitlistThankYouPromptPresenter.swift; sourceTree = ""; }; 4B70BFFF27B0793D000386ED /* DuckDuckGo-ExampleCrash.ips */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "DuckDuckGo-ExampleCrash.ips"; sourceTree = ""; }; @@ -3905,8 +3160,6 @@ 4B9292D82667124B00AD2C21 /* BookmarkListTreeControllerDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkListTreeControllerDataSource.swift; sourceTree = ""; }; 4B9292DA2667125D00AD2C21 /* ContextualMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContextualMenu.swift; sourceTree = ""; }; 4B9579202AC687170062CA31 /* HardwareModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HardwareModel.swift; sourceTree = ""; }; - 4B957C412AC7AE700062CA31 /* DuckDuckGo Privacy Pro.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DuckDuckGo Privacy Pro.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 4B957C432AC7AF190062CA31 /* DuckDuckGoPrivacyPro.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DuckDuckGoPrivacyPro.xcconfig; sourceTree = ""; }; 4B980E202817604000282EE1 /* NSNotificationName+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSNotificationName+Debug.swift"; sourceTree = ""; }; 4B98D27928D95F1A003C2B6F /* ChromiumFaviconsReaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChromiumFaviconsReaderTests.swift; sourceTree = ""; }; 4B98D27B28D960DD003C2B6F /* FirefoxFaviconsReaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirefoxFaviconsReaderTests.swift; sourceTree = ""; }; @@ -3916,7 +3169,6 @@ 4B9DB00C2A983B24000927DB /* WaitlistViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WaitlistViewModel.swift; sourceTree = ""; }; 4B9DB00E2A983B24000927DB /* WaitlistStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WaitlistStorage.swift; sourceTree = ""; }; 4B9DB00F2A983B24000927DB /* WaitlistKeychainStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WaitlistKeychainStorage.swift; sourceTree = ""; }; - 4B9DB0132A983B24000927DB /* EnableWaitlistFeatureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableWaitlistFeatureView.swift; sourceTree = ""; }; 4B9DB0142A983B24000927DB /* WaitlistTermsAndConditionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WaitlistTermsAndConditionsView.swift; sourceTree = ""; }; 4B9DB0152A983B24000927DB /* JoinedWaitlistView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JoinedWaitlistView.swift; sourceTree = ""; }; 4B9DB0162A983B24000927DB /* InvitedToWaitlistView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InvitedToWaitlistView.swift; sourceTree = ""; }; @@ -3927,7 +3179,6 @@ 4B9DB01C2A983B24000927DB /* NotificationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; 4B9DB04F2A983B55000927DB /* MockWaitlistStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockWaitlistStorage.swift; sourceTree = ""; }; 4B9DB0502A983B55000927DB /* MockNotificationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockNotificationService.swift; sourceTree = ""; }; - 4B9DB0512A983B55000927DB /* MockNetworkProtectionCodeRedeemer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockNetworkProtectionCodeRedeemer.swift; sourceTree = ""; }; 4B9DB0522A983B55000927DB /* MockWaitlistRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockWaitlistRequest.swift; sourceTree = ""; }; 4B9DB0532A983B55000927DB /* WaitlistViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WaitlistViewModelTests.swift; sourceTree = ""; }; 4BA1A69A258B076900F6F690 /* FileStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileStore.swift; sourceTree = ""; }; @@ -3972,7 +3223,6 @@ 4BBF0916282DD6EF00EE1418 /* TemporaryFileHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemporaryFileHandlerTests.swift; sourceTree = ""; }; 4BBF09222830812900EE1418 /* FileSystemDSL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSystemDSL.swift; sourceTree = ""; }; 4BBF0924283083EC00EE1418 /* FileSystemDSLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileSystemDSLTests.swift; sourceTree = ""; }; - 4BC2621C293996410087A482 /* PixelEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelEventTests.swift; sourceTree = ""; }; 4BCF15D62ABB8A110083F6DF /* NetworkProtectionRemoteMessaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRemoteMessaging.swift; sourceTree = ""; }; 4BCF15D82ABB8A7F0083F6DF /* NetworkProtectionRemoteMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRemoteMessage.swift; sourceTree = ""; }; 4BCF15E42ABB98990083F6DF /* NetworkProtectionRemoteMessageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRemoteMessageTests.swift; sourceTree = ""; }; @@ -3981,8 +3231,6 @@ 4BD18F04283F151F00058124 /* BookmarksBar.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = BookmarksBar.storyboard; sourceTree = ""; }; 4BD57C032AC112DF00B580EE /* NetworkProtectionRemoteMessagingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionRemoteMessagingTests.swift; sourceTree = ""; }; 4BDFA4AD27BF19E500648192 /* ToggleableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleableScrollView.swift; sourceTree = ""; }; - 4BE0DF0426781961006337B7 /* NSStoryboardExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSStoryboardExtension.swift; sourceTree = ""; }; - 4BE15DB12A0B0DD500898243 /* PixelKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = PixelKit; sourceTree = ""; }; 4BE344ED2B2376DF003FC223 /* VPNFeedbackFormViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNFeedbackFormViewModelTests.swift; sourceTree = ""; }; 4BE4005227CF3DC3007D3161 /* SavePaymentMethodPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePaymentMethodPopover.swift; sourceTree = ""; }; 4BE4005427CF3F19007D3161 /* SavePaymentMethodViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePaymentMethodViewController.swift; sourceTree = ""; }; @@ -4011,6 +3259,8 @@ 5601FECC29B7973D00068905 /* TabBarViewItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewItemTests.swift; sourceTree = ""; }; 5603D90529B7B746007F9F01 /* MockTabViewItemDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTabViewItemDelegate.swift; sourceTree = ""; }; 5614B3A02BBD639D009B5031 /* ZoomPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZoomPopover.swift; sourceTree = ""; }; + 560C3FFB2BC9911000F589CE /* PermanentSurveyManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermanentSurveyManagerTests.swift; sourceTree = ""; }; + 560C3FFE2BCD5A1E00F589CE /* PermanentSurveyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermanentSurveyManager.swift; sourceTree = ""; }; 561D66692B95C45A008ACC5C /* Suggestion.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Suggestion.storyboard; sourceTree = ""; }; 5625329D2BC069100034D316 /* ZoomPopoverViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZoomPopoverViewModelTests.swift; sourceTree = ""; }; 5629846E2AC4610100AC20EB /* SyncPreferencesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncPreferencesTests.swift; sourceTree = ""; }; @@ -4024,6 +3274,11 @@ 569277C029DDCBB500B633EF /* HomePageContinueSetUpModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomePageContinueSetUpModel.swift; sourceTree = ""; }; 569277C329DEE09D00B633EF /* ContinueSetUpModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContinueSetUpModelTests.swift; sourceTree = ""; }; 56B234BE2A84EFD200F2A1CC /* NavigationBarUrlExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarUrlExtensionsTests.swift; sourceTree = ""; }; + 56BA1E742BAAF70F001CF69F /* SSLErrorPageTabExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSLErrorPageTabExtension.swift; sourceTree = ""; }; + 56BA1E7C2BAB290E001CF69F /* ErrorPageTabExtensionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorPageTabExtensionTest.swift; sourceTree = ""; }; + 56BA1E812BAC506F001CF69F /* SSLErrorPageUserScript.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSLErrorPageUserScript.swift; sourceTree = ""; }; + 56BA1E862BAC8239001CF69F /* SSLErrorPageUserScriptTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSLErrorPageUserScriptTests.swift; sourceTree = ""; }; + 56BA1E892BB1CB5B001CF69F /* CertificateTrustEvaluator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CertificateTrustEvaluator.swift; sourceTree = ""; }; 56CEE9092B7A66C500CF10AA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56CEE90D2B7A6DE100CF10AA /* InfoPlist.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = InfoPlist.xcstrings; sourceTree = ""; }; 56D145E729E6BB6300E3488A /* CapturingDataImportProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapturingDataImportProvider.swift; sourceTree = ""; }; @@ -4046,6 +3301,7 @@ 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionSimulateFailureMenu.swift; sourceTree = ""; }; 7B4CE8DA26F02108009134B1 /* UI Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UI Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 7B4CE8E626F02134009134B1 /* TabBarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarTests.swift; sourceTree = ""; }; + 7B4D8A202BDA857300852966 /* VPNOperationErrorRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNOperationErrorRecorder.swift; sourceTree = ""; }; 7B5291882A1697680022E406 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 7B5291892A169BC90022E406 /* DeveloperID.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DeveloperID.xcconfig; sourceTree = ""; }; 7B6D98662ADEB4B000CD35FE /* DataBrokerProtectionLoginItemScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionLoginItemScheduler.swift; sourceTree = ""; }; @@ -4087,7 +3343,6 @@ 7BEC20402B0F505F00243D3E /* AddBookmarkPopoverView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddBookmarkPopoverView.swift; sourceTree = ""; }; 7BEC20412B0F505F00243D3E /* AddBookmarkFolderPopoverView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddBookmarkFolderPopoverView.swift; sourceTree = ""; }; 7BF1A9D72AE054D300FCA683 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 7BFE95512A9DF1CE0081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift; sourceTree = ""; }; 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserDefaults+NetworkProtectionWaitlist.swift"; sourceTree = ""; }; 85012B0129133F9F003D0DCC /* NavigationBarPopovers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarPopovers.swift; sourceTree = ""; }; 850E8DFA2A6FEC5E00691187 /* BookmarksBarAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksBarAppearance.swift; sourceTree = ""; }; @@ -4204,10 +3459,16 @@ 9D9AE92B2AAB84FF0026E7DC /* DBPMocks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBPMocks.swift; sourceTree = ""; }; 9DB6E7222AA0DA7A00A17F3C /* LoginItems */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = LoginItems; sourceTree = ""; }; 9F0A2CF72B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseBookmarkEntityTests.swift; sourceTree = ""; }; + 9F0FFFB32BCCAE37007C87DD /* BookmarkAllTabsDialogCoordinatorViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkAllTabsDialogCoordinatorViewModelTests.swift; sourceTree = ""; }; + 9F0FFFB72BCCAE9C007C87DD /* AddEditBookmarkDialogViewModelMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditBookmarkDialogViewModelMock.swift; sourceTree = ""; }; + 9F0FFFBA2BCCAEC2007C87DD /* AddEditBookmarkFolderDialogViewModelMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditBookmarkFolderDialogViewModelMock.swift; sourceTree = ""; }; + 9F0FFFBD2BCCAF1F007C87DD /* BookmarkAllTabsDialogViewModelMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkAllTabsDialogViewModelMock.swift; sourceTree = ""; }; 9F180D0E2B69C553000D695F /* Tab+WKUIDelegateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tab+WKUIDelegateTests.swift"; sourceTree = ""; }; 9F180D112B69C665000D695F /* DownloadsTabExtensionMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsTabExtensionMock.swift; sourceTree = ""; }; 9F2606092B85C20400819292 /* AddEditBookmarkDialogViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditBookmarkDialogViewModelTests.swift; sourceTree = ""; }; 9F26060D2B85E17D00819292 /* AddEditBookmarkDialogCoordinatorViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditBookmarkDialogCoordinatorViewModelTests.swift; sourceTree = ""; }; + 9F33445D2BBFA77F0040CBEB /* BookmarksBarVisibilityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksBarVisibilityManager.swift; sourceTree = ""; }; + 9F3344612BBFBDA40040CBEB /* BookmarksBarVisibilityManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksBarVisibilityManagerTests.swift; sourceTree = ""; }; 9F3910612B68C35600CB5112 /* DownloadsTabExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsTabExtensionTests.swift; sourceTree = ""; }; 9F3910682B68D87B00CB5112 /* ProgressExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressExtensionTests.swift; sourceTree = ""; }; 9F514F902B7D88AD001832A9 /* AddEditBookmarkFolderDialogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditBookmarkFolderDialogView.swift; sourceTree = ""; }; @@ -4218,14 +3479,32 @@ 9F872D9C2B9058D000138637 /* Bookmarks+TabTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bookmarks+TabTests.swift"; sourceTree = ""; }; 9F872D9F2B90644800138637 /* ContextualMenuTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextualMenuTests.swift; sourceTree = ""; }; 9F872DA22B90920F00138637 /* BookmarkFolderInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkFolderInfo.swift; sourceTree = ""; }; + 9F8D57312BCCCB9A00AEA660 /* UserDefaultsBookmarkFoldersStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsBookmarkFoldersStoreTests.swift; sourceTree = ""; }; 9F982F0C2B8224BE00231028 /* AddEditBookmarkFolderDialogViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditBookmarkFolderDialogViewModel.swift; sourceTree = ""; }; 9F982F112B82268F00231028 /* AddEditBookmarkFolderDialogViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditBookmarkFolderDialogViewModelTests.swift; sourceTree = ""; }; + 9F9C49F52BC786790099738D /* MoreOptionsMenu+BookmarksTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MoreOptionsMenu+BookmarksTests.swift"; sourceTree = ""; }; + 9F9C49F82BC7BC970099738D /* BookmarkAllTabsDialogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkAllTabsDialogView.swift; sourceTree = ""; }; + 9F9C49FC2BC7E9820099738D /* BookmarkAllTabsDialogViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkAllTabsDialogViewModel.swift; sourceTree = ""; }; + 9F9C4A002BC7F36D0099738D /* BookmarkAllTabsDialogCoordinatorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkAllTabsDialogCoordinatorViewModel.swift; sourceTree = ""; }; 9FA173D92B79BD8A00EE4E6E /* BookmarkDialogContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkDialogContainerView.swift; sourceTree = ""; }; 9FA173DE2B7A0EFE00EE4E6E /* BookmarkDialogButtonsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkDialogButtonsView.swift; sourceTree = ""; }; 9FA173E22B7A12B600EE4E6E /* BookmarkDialogFolderManagementView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkDialogFolderManagementView.swift; sourceTree = ""; }; 9FA173E62B7B122E00EE4E6E /* BookmarkDialogStackedContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkDialogStackedContentView.swift; sourceTree = ""; }; 9FA173EA2B7B232200EE4E6E /* AddEditBookmarkDialogView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditBookmarkDialogView.swift; sourceTree = ""; }; + 9FA5A0A42BC8F34900153786 /* UserDefaultsBookmarkFoldersStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsBookmarkFoldersStore.swift; sourceTree = ""; }; + 9FA5A0A82BC900FC00153786 /* BookmarkAllTabsDialogViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkAllTabsDialogViewModelTests.swift; sourceTree = ""; }; + 9FA5A0AC2BC9037A00153786 /* BookmarkFolderStoreMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkFolderStoreMock.swift; sourceTree = ""; }; 9FA75A3D2BA00E1400DA5FA6 /* BookmarksBarMenuFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksBarMenuFactoryTests.swift; sourceTree = ""; }; + 9FAD62392BCFDB32007F3A65 /* WebsiteInfoHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebsiteInfoHelpers.swift; sourceTree = ""; }; + 9FAD623C2BD09DE5007F3A65 /* WebsiteInfoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebsiteInfoTests.swift; sourceTree = ""; }; + 9FBD84512BB3AACB00220859 /* AttributionOriginFileProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributionOriginFileProvider.swift; sourceTree = ""; }; + 9FBD84552BB3ACFD00220859 /* AttributionOriginFileProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributionOriginFileProviderTests.swift; sourceTree = ""; }; + 9FBD845C2BB3B80300220859 /* Origin.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Origin.txt; sourceTree = ""; }; + 9FBD84602BB3BC6400220859 /* Origin-empty.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Origin-empty.txt"; sourceTree = ""; }; + 9FBD846F2BB3DD8400220859 /* MockAttributionsPixelHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAttributionsPixelHandler.swift; sourceTree = ""; }; + 9FBD84722BB3E15D00220859 /* InstallationAttributionPixelHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationAttributionPixelHandler.swift; sourceTree = ""; }; + 9FBD84762BB3E54200220859 /* InstallationAttributionPixelHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallationAttributionPixelHandlerTests.swift; sourceTree = ""; }; + 9FBD84792BB3EC3300220859 /* MockAttributionOriginProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAttributionOriginProvider.swift; sourceTree = ""; }; 9FDA6C202B79A59D00E099A9 /* BookmarkFavoriteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkFavoriteView.swift; sourceTree = ""; }; 9FEE98642B846870002E44E8 /* AddEditBookmarkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddEditBookmarkView.swift; sourceTree = ""; }; 9FEE98682B85B869002E44E8 /* BookmarksDialogViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksDialogViewModel.swift; sourceTree = ""; }; @@ -4356,7 +3635,6 @@ AAC30A25268DFEE200D2D9CD /* CrashReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReporter.swift; sourceTree = ""; }; AAC30A27268E045400D2D9CD /* CrashReportReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportReader.swift; sourceTree = ""; }; AAC30A29268E239100D2D9CD /* CrashReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReport.swift; sourceTree = ""; }; - AAC30A2B268F1ECD00D2D9CD /* CrashReportSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportSender.swift; sourceTree = ""; }; AAC30A2D268F1EE300D2D9CD /* CrashReportPromptPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportPromptPresenter.swift; sourceTree = ""; }; AAC5E4C425D6A6E8007F5990 /* AddBookmarkPopover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddBookmarkPopover.swift; sourceTree = ""; }; AAC5E4CD25D6A709007F5990 /* Bookmark.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bookmark.swift; sourceTree = ""; }; @@ -4471,7 +3749,7 @@ B63ED0DF26AFE32F00A9DAD1 /* GeolocationProviderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeolocationProviderMock.swift; sourceTree = ""; }; B63ED0E226B3E7FA00A9DAD1 /* CLLocationManagerMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLLocationManagerMock.swift; sourceTree = ""; }; B63ED0E426BB8FB900A9DAD1 /* SharingMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingMenu.swift; sourceTree = ""; }; - B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureVaultErrorReporter.swift; sourceTree = ""; }; + B642738127B65BAC0005DFD1 /* SecureVaultReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureVaultReporter.swift; sourceTree = ""; }; B643BF1327ABF772000BACEC /* NSWorkspaceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSWorkspaceExtension.swift; sourceTree = ""; }; B644B43929D565DB003FA9AB /* SearchNonexistentDomainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchNonexistentDomainTests.swift; sourceTree = ""; }; B645D8F529FA95440024461F /* WKProcessPoolExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKProcessPoolExtension.swift; sourceTree = ""; }; @@ -4511,7 +3789,6 @@ B66260DC29AC5D4300E9E3EE /* NavigationProtectionTabExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationProtectionTabExtension.swift; sourceTree = ""; }; B66260DF29AC6EBD00E9E3EE /* HistoryTabExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryTabExtension.swift; sourceTree = ""; }; B66260E529ACAE4B00E9E3EE /* NavigationHotkeyHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationHotkeyHandler.swift; sourceTree = ""; }; - B662D3D82755D7AD0035D4D6 /* PixelStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelStoreTests.swift; sourceTree = ""; }; B662D3DD275613BB0035D4D6 /* EncryptionKeyStoreMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionKeyStoreMock.swift; sourceTree = ""; }; B6656E0C2B29C733008798A1 /* FileImportViewLocalizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileImportViewLocalizationTests.swift; sourceTree = ""; }; B6676BE02AA986A700525A21 /* AddressBarTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddressBarTextEditor.swift; sourceTree = ""; }; @@ -4600,15 +3877,13 @@ B6A60E4F2B73C3B800FD4968 /* WKURLSchemeTask+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WKURLSchemeTask+Private.h"; sourceTree = ""; }; B6A60E502B73C46B00FD4968 /* IntegrationTestsBridging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntegrationTestsBridging.h; sourceTree = ""; }; B6A924D82664C72D001A28CA /* WebKitDownloadTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebKitDownloadTask.swift; sourceTree = ""; }; - B6A9E45226142B070067D1B9 /* Pixel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pixel.swift; sourceTree = ""; }; B6A9E46A2614618A0067D1B9 /* OperatingSystemVersionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatingSystemVersionExtension.swift; sourceTree = ""; }; - B6A9E47626146A570067D1B9 /* PixelEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelEvent.swift; sourceTree = ""; }; - B6A9E47E26146A800067D1B9 /* PixelArguments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelArguments.swift; sourceTree = ""; }; - B6A9E48326146AAB0067D1B9 /* PixelParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelParameters.swift; sourceTree = ""; }; B6AA64722994B43300D99CD6 /* FutureExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FutureExtensionTests.swift; sourceTree = ""; }; B6AAAC2C260330580029438D /* PublishedAfter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishedAfter.swift; sourceTree = ""; }; B6AAAC3D26048F690029438D /* RandomAccessCollectionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandomAccessCollectionExtension.swift; sourceTree = ""; }; B6ABC5952B4861D4008343B9 /* FocusableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusableTextField.swift; sourceTree = ""; }; + B6ABD0C92BC03F610000EB69 /* SecurityScopedFileURLController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityScopedFileURLController.swift; sourceTree = ""; }; + B6ABD0CD2BC042CE0000EB69 /* NSURL+sandboxExtensionRetainCount.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSURL+sandboxExtensionRetainCount.m"; sourceTree = ""; }; B6AE39F029373AF200C37AA4 /* EmptyAttributionRulesProver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyAttributionRulesProver.swift; sourceTree = ""; }; B6AE74332609AFCE005B9B1A /* ProgressEstimationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressEstimationTests.swift; sourceTree = ""; }; B6B040072B95C4C80085279D /* Downloads 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Downloads 2.xcdatamodel"; sourceTree = ""; }; @@ -4616,7 +3891,6 @@ B6B1E87A26D381710062C350 /* DownloadListCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadListCoordinator.swift; sourceTree = ""; }; B6B1E87D26D5DA0E0062C350 /* DownloadsPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsPopover.swift; sourceTree = ""; }; B6B1E87F26D5DA9B0062C350 /* DownloadsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsViewController.swift; sourceTree = ""; }; - B6B1E88126D5DAC30062C350 /* Downloads.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Downloads.storyboard; sourceTree = ""; }; B6B1E88326D5EB570062C350 /* DownloadsCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsCellView.swift; sourceTree = ""; }; B6B1E88A26D774090062C350 /* LinkButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkButton.swift; sourceTree = ""; }; B6B2400D28083B49001B8F3A /* WebViewContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewContainerView.swift; sourceTree = ""; }; @@ -4672,14 +3946,15 @@ B6DA06E7291401D700225DE2 /* WKMenuItemIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKMenuItemIdentifier.swift; sourceTree = ""; }; B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelDataStore.swift; sourceTree = ""; }; B6DA44072616B30600DD1EC2 /* PixelDataModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = PixelDataModel.xcdatamodel; sourceTree = ""; }; - B6DA44102616C0FC00DD1EC2 /* PixelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PixelTests.swift; sourceTree = ""; }; B6DA441D2616C84600DD1EC2 /* PixelStoreMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelStoreMock.swift; sourceTree = ""; }; - B6DA44222616CABC00DD1EC2 /* PixelArgumentsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelArgumentsTests.swift; sourceTree = ""; }; B6DB3AEE278D5C370024C5C4 /* URLSessionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionExtension.swift; sourceTree = ""; }; B6DB3CF826A00E2D00D459B7 /* AVCaptureDevice+SwizzledAuthState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVCaptureDevice+SwizzledAuthState.swift"; sourceTree = ""; }; B6DB3CFA26A17CB800D459B7 /* PermissionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionModel.swift; sourceTree = ""; }; B6DE57F52B05EA9000CD54B9 /* SheetHostingWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetHostingWindow.swift; sourceTree = ""; }; B6E319372953446000DD3BCF /* Assertions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Assertions.swift; sourceTree = ""; }; + B6E3E54F2BBFCDEE00A41922 /* OpenDownloadsCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenDownloadsCellView.swift; sourceTree = ""; }; + B6E3E5532BBFCEE300A41922 /* NoDownloadsCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoDownloadsCellView.swift; sourceTree = ""; }; + B6E3E5572BBFD51400A41922 /* PreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewViewController.swift; sourceTree = ""; }; B6E61EE2263AC0C8004E11AB /* FileManagerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerExtension.swift; sourceTree = ""; }; B6E6B9E22BA1F5F1008AA7E1 /* FilePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePresenter.swift; sourceTree = ""; }; B6E6B9E82BA1FA1C008AA7E1 /* SandboxTestTool.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = SandboxTestTool.xcconfig; sourceTree = ""; }; @@ -4696,6 +3971,10 @@ B6EC37FA29B6447F001ACE79 /* TestsServer.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = TestsServer.xcconfig; sourceTree = ""; }; B6EC37FB29B83E99001ACE79 /* TestsURLExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestsURLExtension.swift; sourceTree = ""; }; B6EEDD7C2B8C69E900637EBC /* TabContentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabContentTests.swift; sourceTree = ""; }; + B6F1B0212BCE5658005E863C /* BrokenSiteInfoTabExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrokenSiteInfoTabExtension.swift; sourceTree = ""; }; + B6F1B0252BCE5A50005E863C /* TabContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabContent.swift; sourceTree = ""; }; + B6F1B0292BCE675C005E863C /* NetworkProtectionControllerTabExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionControllerTabExtension.swift; sourceTree = ""; }; + B6F1B02D2BCE6B47005E863C /* TunnelControllerProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelControllerProvider.swift; sourceTree = ""; }; B6F41030264D2B23003DA42C /* ProgressExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressExtension.swift; sourceTree = ""; }; B6F56566299A414300A04298 /* WKWebViewMockingExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WKWebViewMockingExtension.swift; sourceTree = ""; }; B6F7127D29F6779000594A45 /* QRSharingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRSharingService.swift; sourceTree = ""; }; @@ -4707,6 +3986,12 @@ B6FA8940269C425400588ECD /* PrivacyDashboardPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyDashboardPopover.swift; sourceTree = ""; }; BB5789712B2CA70F0009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionSubscriptionEventHandler.swift; sourceTree = ""; }; BBDFDC592B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataBrokerProtectionExternalWaitlistPixels.swift; sourceTree = ""; }; + BD384AC72BBC821100EF3735 /* vpn-light-mode.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "vpn-light-mode.json"; sourceTree = ""; }; + BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "vpn-dark-mode.json"; sourceTree = ""; }; + BDA7647B2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultVPNLocationFormatter.swift; sourceTree = ""; }; + BDA7648C2BC4E4EF00D0400C /* DefaultVPNLocationFormatterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultVPNLocationFormatterTests.swift; sourceTree = ""; }; + BDA764902BC4E57200D0400C /* MockVPNLocationFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockVPNLocationFormatter.swift; sourceTree = ""; }; + C1372EF32BBC5BAD003F8793 /* SecureTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureTextField.swift; sourceTree = ""; }; C13909EE2B85FD4E001626ED /* AutofillActionExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillActionExecutor.swift; sourceTree = ""; }; C13909F32B85FD79001626ED /* AutofillDeleteAllPasswordsExecutorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillDeleteAllPasswordsExecutorTests.swift; sourceTree = ""; }; C13909FA2B861039001626ED /* AutofillActionPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillActionPresenter.swift; sourceTree = ""; }; @@ -4737,22 +4022,31 @@ EE0429DF2BA31D2F009EB20F /* FindInPageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindInPageTests.swift; sourceTree = ""; }; EE339227291BDEFD009F62C1 /* JSAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSAlertController.swift; sourceTree = ""; }; EE34245D2BA0853900173B1B /* VPNUninstaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNUninstaller.swift; sourceTree = ""; }; + EE42CBCB2BC8004700AD411C /* PermissionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermissionsTests.swift; sourceTree = ""; }; + EE54F7B22BBFEA48006218DB /* BookmarksAndFavoritesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksAndFavoritesTests.swift; sourceTree = ""; }; EE66418B2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift"; sourceTree = ""; }; EE66666E2B56EDE4001D898D /* VPNLocationsHostingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationsHostingViewController.swift; sourceTree = ""; }; + EE7F74902BB5D76600CD9456 /* BookmarksBarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksBarTests.swift; sourceTree = ""; }; + EE9D81C22BC57A3700338BE3 /* StateRestorationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateRestorationTests.swift; sourceTree = ""; }; EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionVPNCountryLabelsModel.swift; sourceTree = ""; }; EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNLocationViewModel.swift; sourceTree = ""; }; EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppLauncher.swift; sourceTree = ""; }; + EEBCA0C52BD7CE2C004DF19C /* VPNFailureRecoveryPixel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VPNFailureRecoveryPixel.swift; sourceTree = ""; }; EEBCE6812BA444FA00B9DF00 /* XCUIElementExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XCUIElementExtension.swift; sourceTree = ""; }; EEC111E3294D06020086524F /* JSAlert.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = JSAlert.storyboard; sourceTree = ""; }; EEC111E5294D06290086524F /* JSAlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSAlertViewModel.swift; sourceTree = ""; }; EEC4A6682B2C87D300F7C0AA /* VPNLocationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationView.swift; sourceTree = ""; }; EEC4A66C2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationPreferenceItemModel.swift; sourceTree = ""; }; EEC4A6702B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNLocationPreferenceItem.swift; sourceTree = ""; }; + EEC7BE2D2BC6C09400F86835 /* AddressBarKeyboardShortcutsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressBarKeyboardShortcutsTests.swift; sourceTree = ""; }; EECE10E429DD77E60044D027 /* FeatureFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlag.swift; sourceTree = ""; }; EED735352BB46B6000F173D6 /* AutocompleteTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutocompleteTests.swift; sourceTree = ""; }; EEDE50102BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkProtection+VPNAgentConvenienceInitializers.swift"; sourceTree = ""; }; EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacPacketTunnelProvider.swift; sourceTree = ""; }; EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSAlertViewModelTests.swift; sourceTree = ""; }; + F188267B2BBEB3AA00D9AC4F /* GeneralPixel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralPixel.swift; sourceTree = ""; }; + F188267F2BBEB58100D9AC4F /* PrivacyProPixel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyProPixel.swift; sourceTree = ""; }; + F18826832BBEE31700D9AC4F /* PixelKit+Assertion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PixelKit+Assertion.swift"; sourceTree = ""; }; F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionAppStoreRestorer.swift; sourceTree = ""; }; F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionErrorReporter.swift; sourceTree = ""; }; F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MainMenuActions+VanillaBrowser.swift"; sourceTree = ""; }; @@ -4768,8 +4062,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F1DF95E42BD1807C0045E591 /* Crashes in Frameworks */, 373FB4B32B4D6C4B004C88D6 /* PreferencesViews in Frameworks */, - 7B5F9A752AE2BE4E002AEBC0 /* PixelKit in Frameworks */, 4BF97AD32B43C43F00EB4240 /* NetworkProtectionUI in Frameworks */, 7B1459572B7D43E500047F2C /* NetworkProtectionProxy in Frameworks */, B6F7128229F6820A00594A45 /* QuickLookUI.framework in Frameworks */, @@ -4778,10 +4072,12 @@ 37A5E2F0298AA1B20047046B /* Persistence in Frameworks */, 9DC70B1A2AA1FA5B005A844B /* LoginItems in Frameworks */, 37269EFD2B332FAC005E8E46 /* Common in Frameworks */, + F198C7142BD18A30000BF24D /* PixelKit in Frameworks */, F1D43AF52B98E48900BAB743 /* BareBonesBrowserKit in Frameworks */, 378F44E629B4BDEE00899924 /* SwiftUIExtensions in Frameworks */, 3706FCA7293F65D500E42796 /* BrowserServicesKit in Frameworks */, 3129788A2B64131200B67619 /* DataBrokerProtection in Frameworks */, + F198C7202BD18D92000BF24D /* SwiftLintTool in Frameworks */, 4BCBE4582BA7E17800FC75A1 /* SubscriptionUI in Frameworks */, 3706FCA9293F65D500E42796 /* ContentBlocking in Frameworks */, 85D44B882BA08D30001B4AB5 /* Suggestions in Frameworks */, @@ -4806,9 +4102,9 @@ buildActionMask = 2147483647; files = ( 3706FE88293F661700E42796 /* OHHTTPStubs in Frameworks */, + F116A7C72BD1925500F3FCF7 /* PixelKitTestingUtilities in Frameworks */, B65CD8CF2B316E0200A595BB /* SnapshotTesting in Frameworks */, 3706FE89293F661700E42796 /* OHHTTPStubsSwift in Frameworks */, - 4B81AD372B29513100706C96 /* PixelKitTestingUtilities in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4831,6 +4127,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F116A7C92BD1929000F3FCF7 /* PixelKitTestingUtilities in Frameworks */, B65CD8CD2B316DFC00A595BB /* SnapshotTesting in Frameworks */, B6AE39F329374AEC00C37AA4 /* OHHTTPStubs in Frameworks */, B6AE39F529374AEC00C37AA4 /* OHHTTPStubsSwift in Frameworks */, @@ -4843,8 +4140,8 @@ files = ( 37269F012B332FC8005E8E46 /* Common in Frameworks */, EE7295E92A545BC4008C0991 /* NetworkProtection in Frameworks */, - 4B2537772A11BFE100610219 /* PixelKit in Frameworks */, 7B37C7A52BAA32A50062546A /* Subscription in Frameworks */, + F198C7182BD18A4C000BF24D /* PixelKit in Frameworks */, 7BBE2B7B2B61663C00697445 /* NetworkProtectionProxy in Frameworks */, 4B2D062C2A11C0E100DE1F49 /* Networking in Frameworks */, 4B25375B2A11BE7300610219 /* NetworkExtension.framework in Frameworks */, @@ -4855,12 +4152,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F198C71A2BD18A5B000BF24D /* PixelKit in Frameworks */, 4B41EDAB2B1544B2001EEDF4 /* LoginItems in Frameworks */, 7B00997D2B6508B700FE7C31 /* NetworkProtectionProxy in Frameworks */, 7BEEA5122AD1235B00A9E72B /* NetworkProtectionIPC in Frameworks */, 7BA7CC5F2AD1210C0042E5CE /* Networking in Frameworks */, 7BEEA5162AD1236E00A9E72B /* NetworkProtectionUI in Frameworks */, - 7BFCB74E2ADE7E1A00DA3EA7 /* PixelKit in Frameworks */, + BDADBDC92BD2BC2200421B9B /* Lottie in Frameworks */, EE7295ED2A545C0A008C0991 /* NetworkProtection in Frameworks */, EE2F9C5B2B90F2FF00D45FC9 /* Subscription in Frameworks */, 7BEC182F2AD5D8DC00D30536 /* SystemExtensionManager in Frameworks */, @@ -4871,10 +4169,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7BFCB7502ADE7E2300DA3EA7 /* PixelKit in Frameworks */, 4BCBE45C2BA7E18500FC75A1 /* Subscription in Frameworks */, 7BA7CC612AD1211C0042E5CE /* Networking in Frameworks */, + F198C71C2BD18A61000BF24D /* PixelKit in Frameworks */, 7BEEA5142AD1236300A9E72B /* NetworkProtectionIPC in Frameworks */, + BDADBDCB2BD2BC2800421B9B /* Lottie in Frameworks */, 7B00997F2B6508C200FE7C31 /* NetworkProtectionProxy in Frameworks */, EE7295EF2A545C12008C0991 /* NetworkProtection in Frameworks */, 4B2D067F2A1334D700DE1F49 /* NetworkProtectionUI in Frameworks */, @@ -4886,7 +4185,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4B1EFF1C2BD71EEF007CC84F /* PixelKit in Frameworks */, 7B624F172BA25C1F00A6C544 /* NetworkProtectionUI in Frameworks */, + 4B1EFF212BD72189007CC84F /* Networking in Frameworks */, 37269F052B3332C2005E8E46 /* Common in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4895,54 +4196,16 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F1DF95E52BD1807C0045E591 /* Subscription in Frameworks */, 37269EFF2B332FBB005E8E46 /* Common in Frameworks */, EE7295E72A545BBB008C0991 /* NetworkProtection in Frameworks */, - 4B4D60982A0B2A5C00BCD287 /* PixelKit in Frameworks */, + F198C7162BD18A44000BF24D /* PixelKit in Frameworks */, 4B4D60AF2A0C837F00BCD287 /* Networking in Frameworks */, 7B25856E2BA2F2ED00D49F79 /* NetworkProtectionUI in Frameworks */, 4B4D603F2A0B290200BCD287 /* NetworkExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 4B957BD42AC7AE700062CA31 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 4B957BD52AC7AE700062CA31 /* QuickLookUI.framework in Frameworks */, - 3143C8792B0D1F3D00382627 /* DataBrokerProtection in Frameworks */, - 372217842B33380E00B8E9C2 /* TestUtils in Frameworks */, - 4B957BD62AC7AE700062CA31 /* LoginItems in Frameworks */, - 7B94E1652B7ED95100E32B96 /* NetworkProtectionProxy in Frameworks */, - 4B957BD72AC7AE700062CA31 /* NetworkProtection in Frameworks */, - 4B957BD82AC7AE700062CA31 /* BrowserServicesKit in Frameworks */, - 4B957BDA2AC7AE700062CA31 /* Bookmarks in Frameworks */, - 4B957BDB2AC7AE700062CA31 /* ContentBlocking in Frameworks */, - 4B957BDC2AC7AE700062CA31 /* SwiftUIExtensions in Frameworks */, - 4B957BDD2AC7AE700062CA31 /* UserScript in Frameworks */, - 7BBD44282AD730A400D0A064 /* PixelKit in Frameworks */, - F1D43AF72B98E48F00BAB743 /* BareBonesBrowserKit in Frameworks */, - 7B31FD902AD1257B0086AA24 /* NetworkProtectionIPC in Frameworks */, - 4B957BDE2AC7AE700062CA31 /* Configuration in Frameworks */, - 4B957BE22AC7AE700062CA31 /* Sparkle in Frameworks */, - 373FB4B52B4D6C57004C88D6 /* PreferencesViews in Frameworks */, - 4B957BE32AC7AE700062CA31 /* Navigation in Frameworks */, - 1E21F8E32B73E48600FB272E /* Subscription in Frameworks */, - 4B957BE42AC7AE700062CA31 /* DDGSync in Frameworks */, - 4B957BE52AC7AE700062CA31 /* OpenSSL in Frameworks */, - 85E2BBD22B8F536F00DBEC7A /* History in Frameworks */, - 4B957BE62AC7AE700062CA31 /* PrivacyDashboard in Frameworks */, - 9FF5214A2BAA90C400B9819B /* Lottie in Frameworks */, - 7B8C083C2AE1268E00F4C67F /* PixelKit in Frameworks */, - 85D44B8A2BA08D3B001B4AB5 /* Suggestions in Frameworks */, - 4B957BE72AC7AE700062CA31 /* SyncDataProviders in Frameworks */, - 37269F032B332FD8005E8E46 /* Common in Frameworks */, - 4B957BE82AC7AE700062CA31 /* SyncUI in Frameworks */, - 4B957BE92AC7AE700062CA31 /* NetworkProtectionUI in Frameworks */, - 1E0068AD2B1673BB00BBF43B /* SubscriptionUI in Frameworks */, - 4B957BEB2AC7AE700062CA31 /* Persistence in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 565E46DA2B2725DC0013AC2A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -4965,7 +4228,6 @@ files = ( 7BDA36E62B7E037100AD5388 /* NetworkExtension.framework in Frameworks */, 7B97CD592B7E0B57004FEF43 /* NetworkProtectionProxy in Frameworks */, - 7B97CD622B7E0C4B004FEF43 /* PixelKit in Frameworks */, 7B7DFB222B7E7473009EA1A3 /* Networking in Frameworks */, 7B97CD5B2B7E0B85004FEF43 /* Common in Frameworks */, ); @@ -4976,7 +4238,6 @@ buildActionMask = 2147483647; files = ( 9DEF97E12B06C4EE00764F03 /* Networking in Frameworks */, - 9D6983F92AC773C3002C02FC /* PixelKit in Frameworks */, 9D9AE8F92AAA3AD00026E7DC /* DataBrokerProtection in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4985,7 +4246,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9D6983FB2AC773C8002C02FC /* PixelKit in Frameworks */, 315A023F2B6421AE00BFA577 /* Networking in Frameworks */, 9D9AE8FB2AAA3AD90026E7DC /* DataBrokerProtection in Frameworks */, ); @@ -4995,15 +4255,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 373FB4B12B4D6C42004C88D6 /* PreferencesViews in Frameworks */, + F1DF95E32BD1807C0045E591 /* Crashes in Frameworks */, 85E2BBCE2B8F534000DBEC7A /* History in Frameworks */, 1EA7B8D32B7E078C000330A4 /* SubscriptionUI in Frameworks */, B6F7128129F681EB00594A45 /* QuickLookUI.framework in Frameworks */, - 9DB6E7242AA0DC5800A17F3C /* LoginItems in Frameworks */, EE7295E32A545B9A008C0991 /* NetworkProtection in Frameworks */, 9807F645278CA16F00E1547B /* BrowserServicesKit in Frameworks */, 987799ED299998B1005D8EB6 /* Bookmarks in Frameworks */, - 7B5DD69A2AE51FFA001DE99C /* PixelKit in Frameworks */, 1E950E3F2912A10D0051A99B /* ContentBlocking in Frameworks */, 31A3A4E32B0C115F0021063C /* DataBrokerProtection in Frameworks */, 378F44E429B4BDE900899924 /* SwiftUIExtensions in Frameworks */, @@ -5013,8 +4271,10 @@ 7B31FD8C2AD125620086AA24 /* NetworkProtectionIPC in Frameworks */, 37269EFB2B332F9E005E8E46 /* Common in Frameworks */, AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */, + F198C71E2BD18D88000BF24D /* SwiftLintTool in Frameworks */, 1EA7B8D52B7E078C000330A4 /* Subscription in Frameworks */, B6B77BE8297973D4001E68A1 /* Navigation in Frameworks */, + F198C7122BD18A28000BF24D /* PixelKit in Frameworks */, 3739326729AE4B42009346AE /* DDGSync in Frameworks */, 7BA59C9B2AE18B49009A97B1 /* SystemExtensionManager in Frameworks */, 371D00E129D8509400EC8598 /* OpenSSL in Frameworks */, @@ -5023,6 +4283,7 @@ 85D44B862BA08D29001B4AB5 /* Suggestions in Frameworks */, 37DF000529F9C056002B7D3E /* SyncDataProviders in Frameworks */, 37BA812D29B3CD690053F1A3 /* SyncUI in Frameworks */, + F1DF95E72BD188B60045E591 /* LoginItems in Frameworks */, 372217802B3337FE00B8E9C2 /* TestUtils in Frameworks */, 7BA076BB2B65D61400D7FB72 /* NetworkProtectionProxy in Frameworks */, 4B4D60B12A0C83B900BCD287 /* NetworkProtectionUI in Frameworks */, @@ -5035,9 +4296,9 @@ buildActionMask = 2147483647; files = ( B6DA44172616C13800DD1EC2 /* OHHTTPStubs in Frameworks */, + F116A7C32BD1924B00F3FCF7 /* PixelKitTestingUtilities in Frameworks */, B65CD8CB2B316DF100A595BB /* SnapshotTesting in Frameworks */, B6DA44192616C13800DD1EC2 /* OHHTTPStubsSwift in Frameworks */, - 4B81AD352B29512B00706C96 /* PixelKitTestingUtilities in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5242,6 +4503,14 @@ path = Subscription; sourceTree = ""; }; + 3169132B2BD2C7960051B46D /* ErrorView */ = { + isa = PBXGroup; + children = ( + 316913282BD2C7570051B46D /* DataBrokerProtectionErrorViewController.swift */, + ); + path = ErrorView; + sourceTree = ""; + }; 3171D6DC2889B6700068632A /* CookieManaged */ = { isa = PBXGroup; children = ( @@ -5264,6 +4533,8 @@ 3192EC862A4DCF0E001E97A5 /* DBP */ = { isa = PBXGroup; children = ( + 3169132B2BD2C7960051B46D /* ErrorView */, + 316913222BD2B6250051B46D /* DataBrokerProtectionPixelsHandler.swift */, 316850712AF3AD58009A2828 /* DataBrokerProtectionDebugMenu.swift */, 3192EC872A4DCF21001E97A5 /* DBPHomeViewController.swift */, 3139A1512AA4B3C000969C7D /* DataBrokerProtectionManager.swift */, @@ -5276,6 +4547,7 @@ BBDFDC592B2B8A0900F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift */, BB5789712B2CA70F0009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift */, 4B37EE652B4CFC9500A89A61 /* RemoteMessaging */, + 316913252BD2B76F0051B46D /* DataBrokerPrerequisitesStatusVerifier.swift */, ); path = DBP; sourceTree = ""; @@ -5284,6 +4556,7 @@ isa = PBXGroup; children = ( 31A2FD162BAB41C500D0E741 /* DataBrokerProtectionVisibilityTests.swift */, + 31DC2F202BD6DE65001354EF /* DataBrokerPrerequisitesStatusVerifierTests.swift */, ); path = DBP; sourceTree = ""; @@ -5403,6 +4676,7 @@ 566B195F29CDB7A9007E38F4 /* Mocks */, 378205FA283C277800D1D4AA /* MainMenuTests.swift */, 566B195C29CDB692007E38F4 /* MoreOptionsMenuTests.swift */, + 9F9C49F52BC786790099738D /* MoreOptionsMenu+BookmarksTests.swift */, ); path = Menus; sourceTree = ""; @@ -5430,7 +4704,6 @@ 378B588B295CF3B9002C0CC0 /* AppTargetsBase.xcconfig */, 378B58CD295ECA75002C0CC0 /* DuckDuckGo.xcconfig */, 37DD516C296EAEDC00837F27 /* DuckDuckGoAppStore.xcconfig */, - 4B957C432AC7AF190062CA31 /* DuckDuckGoPrivacyPro.xcconfig */, 378E2799296F6FDE00FCADA2 /* ManualAppStoreRelease.xcconfig */, 7B6EC5E32AE2D88C004FE6DF /* DBP */, 4B18E3222A1D31E4005D0AAA /* NetworkProtection */, @@ -5469,7 +4742,6 @@ 3192A2702A4C4E330084EA89 /* DataBrokerProtection */, 9DB6E7222AA0DA7A00A17F3C /* LoginItems */, 7B25FE322AD12C990012AFAB /* NetworkProtectionMac */, - 4BE15DB12A0B0DD500898243 /* PixelKit */, 378F44E229B4B7B600899924 /* SwiftUIExtensions */, 37BA812B29B3CB8A0053F1A3 /* SyncUI */, 1E862A882A9FC01200F84D4B /* SubscriptionUI */, @@ -5519,6 +4791,7 @@ 37F19A6628E1B43200740DC6 /* DuckPlayerPreferences.swift */, 37CD54C527F2FDD100F1F7B9 /* AboutModel.swift */, 1D220BFB2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift */, + 021EA07F2BD2A9D500772C9A /* TabsPreferences.swift */, ); path = Model; sourceTree = ""; @@ -5630,6 +4903,7 @@ 1D9FDEC22B9B63C90040B78C /* DataClearingPreferencesTests.swift */, 3714B1E628EDB7FA0056C57A /* DuckPlayerPreferencesTests.swift */, 1D9FDEC52B9B64DB0040B78C /* PrivacyProtectionStatusTests.swift */, + 021EA0822BD6DF1B00772C9A /* TabsPreferencesTests.swift */, ); path = Preferences; sourceTree = ""; @@ -5732,6 +5006,7 @@ isa = PBXGroup; children = ( 4B43468E285ED6CB00177407 /* ViewModel */, + 9F3344612BBFBDA40040CBEB /* BookmarksBarVisibilityManagerTests.swift */, ); path = BookmarksBar; sourceTree = ""; @@ -5816,38 +5091,28 @@ 4B4D60632A0B29FA00BCD287 /* BothAppTargets */ = { isa = PBXGroup; children = ( - EEA3EEAF2B24EB5100E8333A /* VPNLocation */, + 4B4D60722A0B29FA00BCD287 /* EventMapping+NetworkProtectionError.swift */, + BDE981DB2BBD110800645880 /* Assets */, + 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */, 9D9AE8682AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift */, + B602E81C2A1E25B0006D261F /* NEOnDemandRuleExtension.swift */, + 4B4D60692A0B29FA00BCD287 /* NetworkProtection+ConvenienceInitializers.swift */, + 7B2DDCF72A93A8BB0039D884 /* NetworkProtectionAppEvents.swift */, + 4B4D606A2A0B29FA00BCD287 /* NetworkProtectionControllerErrorStore.swift */, 7BE146062A6A83C700C313B8 /* NetworkProtectionDebugMenu.swift */, - 7B05829D2A812AC000AC3F7C /* NetworkProtectionOnboardingMenu.swift */, - 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */, 7BBD45B02A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift */, - 7B934C3D2A866CFF00FC8F9C /* NetworkProtectionOnboardingMenu.swift */, - 7BFE95512A9DF1CE0081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift */, - B602E81C2A1E25B0006D261F /* NEOnDemandRuleExtension.swift */, 4B4D60652A0B29FA00BCD287 /* NetworkProtectionNavBarButtonModel.swift */, 7B3618C12ADE75C8000D6154 /* NetworkProtectionNavBarPopoverManager.swift */, + 7B05829D2A812AC000AC3F7C /* NetworkProtectionOnboardingMenu.swift */, + 7B430EA02A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift */, 4B8F52402A18326600BE7131 /* NetworkProtectionTunnelController.swift */, - 4B4D60692A0B29FA00BCD287 /* NetworkProtection+ConvenienceInitializers.swift */, - 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */, - 4B4D606A2A0B29FA00BCD287 /* NetworkProtectionControllerErrorStore.swift */, - 4B4D606B2A0B29FA00BCD287 /* Invite */, - 4B4D60722A0B29FA00BCD287 /* EventMapping+NetworkProtectionError.swift */, - 7B2DDCF72A93A8BB0039D884 /* NetworkProtectionAppEvents.swift */, + EEA3EEAF2B24EB5100E8333A /* VPNLocation */, + 7B934C3D2A866CFF00FC8F9C /* NetworkProtectionOnboardingMenu.swift */, + B6F1B02D2BCE6B47005E863C /* TunnelControllerProvider.swift */, ); path = BothAppTargets; sourceTree = ""; }; - 4B4D606B2A0B29FA00BCD287 /* Invite */ = { - isa = PBXGroup; - children = ( - 4B4D606C2A0B29FA00BCD287 /* NetworkProtectionInviteDialog.swift */, - 4B4D606F2A0B29FA00BCD287 /* NetworkProtectionInvitePresenter.swift */, - 4B4D60702A0B29FA00BCD287 /* NetworkProtectionInviteCodeViewModel.swift */, - ); - path = Invite; - sourceTree = ""; - }; 4B4D60742A0B29FA00BCD287 /* NetworkExtensionTargets */ = { isa = PBXGroup; children = ( @@ -5886,6 +5151,7 @@ 4B4D607D2A0B29FA00BCD287 /* NetworkExtensionTargets */ = { isa = PBXGroup; children = ( + EEBCA0C12BD7CDDA004DF19C /* Pixels */, 4B41ED9F2B15437A001EEDF4 /* NetworkProtectionNotificationsPresenterFactory.swift */, EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */, 7B0099802B65C6B300FE7C31 /* MacTransparentProxyProvider.swift */, @@ -5967,8 +5233,8 @@ 4B67743D255DBEEA00025BD8 /* Database */ = { isa = PBXGroup; children = ( - 4B677440255DBEEA00025BD8 /* Database.swift */, B6085D052743905F00A9C456 /* CoreDataStore.swift */, + 4B677440255DBEEA00025BD8 /* Database.swift */, ); path = Database; sourceTree = ""; @@ -6201,7 +5467,6 @@ 4B9DB0122A983B24000927DB /* WaitlistSteps */ = { isa = PBXGroup; children = ( - 4B9DB0132A983B24000927DB /* EnableWaitlistFeatureView.swift */, 4B9DB0142A983B24000927DB /* WaitlistTermsAndConditionsView.swift */, 4B9DB0152A983B24000927DB /* JoinedWaitlistView.swift */, 4B9DB0162A983B24000927DB /* InvitedToWaitlistView.swift */, @@ -6234,7 +5499,6 @@ 317295D02AF058D3002C3206 /* MockWaitlistTermsAndConditionsActionHandler.swift */, 4B9DB04F2A983B55000927DB /* MockWaitlistStorage.swift */, 4B9DB0502A983B55000927DB /* MockNotificationService.swift */, - 4B9DB0512A983B55000927DB /* MockNetworkProtectionCodeRedeemer.swift */, 4B9DB0522A983B55000927DB /* MockWaitlistRequest.swift */, ); path = Mocks; @@ -6294,6 +5558,7 @@ 4BB88B4F25B7BA2B006F6B06 /* TabInstrumentation.swift */, 85C6A29525CC1FFD00EEB5F1 /* UserDefaultsWrapper.swift */, 4B9579202AC687170062CA31 /* HardwareModel.swift */, + 56BA1E892BB1CB5B001CF69F /* CertificateTrustEvaluator.swift */, ); path = Utilities; sourceTree = ""; @@ -6388,10 +5653,12 @@ 4BCF15E32ABB987F0083F6DF /* NetworkProtection */ = { isa = PBXGroup; children = ( + BDA7648F2BC4E56200D0400C /* Mocks */, 4BCF15E62ABB98A20083F6DF /* Resources */, 4BCF15E42ABB98990083F6DF /* NetworkProtectionRemoteMessageTests.swift */, 4BD57C032AC112DF00B580EE /* NetworkProtectionRemoteMessagingTests.swift */, 7B09CBA72BA4BE7000CF245B /* NetworkProtectionPixelEventTests.swift */, + BDA7648C2BC4E4EF00D0400C /* DefaultVPNLocationFormatterTests.swift */, ); path = NetworkProtection; sourceTree = ""; @@ -6435,6 +5702,7 @@ 4BF6961C28BE911100D402D4 /* RecentlyVisitedSiteModelTests.swift */, 569277C329DEE09D00B633EF /* ContinueSetUpModelTests.swift */, 56D145ED29E6DAD900E3488A /* DataImportProviderTests.swift */, + 560C3FFB2BC9911000F589CE /* PermanentSurveyManagerTests.swift */, ); path = HomePage; sourceTree = ""; @@ -6452,6 +5720,7 @@ children = ( 4BD18F02283F0F1000058124 /* View */, 850E8DFA2A6FEC5E00691187 /* BookmarksBarAppearance.swift */, + 9F33445D2BBFA77F0040CBEB /* BookmarksBarVisibilityManager.swift */, ); path = BookmarksBar; sourceTree = ""; @@ -6500,6 +5769,14 @@ path = Mocks; sourceTree = ""; }; + 56BA1E852BAC820D001CF69F /* UserScripts */ = { + isa = PBXGroup; + children = ( + 56BA1E862BAC8239001CF69F /* SSLErrorPageUserScriptTests.swift */, + ); + path = UserScripts; + sourceTree = ""; + }; 7B1E819A27C8874900FF0E60 /* Autofill */ = { isa = PBXGroup; children = ( @@ -6516,10 +5793,16 @@ 7B4CE8DB26F02108009134B1 /* UITests */ = { isa = PBXGroup; children = ( + 376E708D2BD686260082B7EB /* UI Tests.xctestplan */, EEBCE6802BA444FA00B9DF00 /* Common */, + EEC7BE2D2BC6C09400F86835 /* AddressBarKeyboardShortcutsTests.swift */, EED735352BB46B6000F173D6 /* AutocompleteTests.swift */, + EE54F7B22BBFEA48006218DB /* BookmarksAndFavoritesTests.swift */, + EE7F74902BB5D76600CD9456 /* BookmarksBarTests.swift */, EE02D41B2BB460A600DBE6B3 /* BrowsingHistoryTests.swift */, EE0429DF2BA31D2F009EB20F /* FindInPageTests.swift */, + EE42CBCB2BC8004700AD411C /* PermissionsTests.swift */, + EE9D81C22BC57A3700338BE3 /* StateRestorationTests.swift */, 7B4CE8E626F02134009134B1 /* TabBarTests.swift */, ); path = UITests; @@ -6638,6 +5921,7 @@ isa = PBXGroup; children = ( B6C0B23526E732000031CB7F /* DownloadListItem.swift */, + B693956026F1C1BC0015B914 /* DownloadListStoreMock.swift */, B6C0B23D26E8BF1F0031CB7F /* DownloadListViewModel.swift */, B6CC26672BAD959500F53F8D /* DownloadProgress.swift */, B6104E9A2BA9C173008636B2 /* DownloadResumeData.swift */, @@ -6645,8 +5929,10 @@ B6C0B23826E742610031CB7F /* FileDownloadError.swift */, 856C98DE257014BD00A22F1F /* FileDownloadManager.swift */, B6E6B9E22BA1F5F1008AA7E1 /* FilePresenter.swift */, - B6A924D82664C72D001A28CA /* WebKitDownloadTask.swift */, B6CC266B2BAD9CD800F53F8D /* FileProgressPresenter.swift */, + B6ABD0CD2BC042CE0000EB69 /* NSURL+sandboxExtensionRetainCount.m */, + B6ABD0C92BC03F610000EB69 /* SecurityScopedFileURLController.swift */, + B6A924D82664C72D001A28CA /* WebKitDownloadTask.swift */, ); path = Model; sourceTree = ""; @@ -6659,6 +5945,7 @@ 85589E9027BFB9810038AD11 /* HomePageRecentlyVisitedModel.swift */, 569277C029DDCBB500B633EF /* HomePageContinueSetUpModel.swift */, 56D145EA29E6C99B00E3488A /* DataImportStatusProviding.swift */, + 560C3FFE2BCD5A1E00F589CE /* PermanentSurveyManager.swift */, ); path = Model; sourceTree = ""; @@ -6702,6 +5989,7 @@ 4B44FEF22B1FEF5A000619D8 /* FocusableTextEditor.swift */, B6ABC5952B4861D4008343B9 /* FocusableTextField.swift */, B6F9BDE32B45CD1900677B33 /* ModalView.swift */, + C1372EF32BBC5BAD003F8793 /* SecureTextField.swift */, ); path = SwiftUI; sourceTree = ""; @@ -6709,26 +5997,27 @@ 8585B63626D6E61500C1416F /* AppKit */ = { isa = PBXGroup; children = ( + 85774B022A71CDD000DE0561 /* BlockMenuItem.swift */, B65E6B9D26D9EC0800095F96 /* CircularProgressView.swift */, B693954626F04BEA0015B914 /* ColorView.swift */, + 4B379C2327BDE1B0008A968E /* FlatButton.swift */, B693953E26F04BE70015B914 /* FocusRingView.swift */, B693954326F04BE90015B914 /* GradientView.swift */, - B6B1E88A26D774090062C350 /* LinkButton.swift */, B6B140872ABDBCC1004F8E85 /* HoverTrackingArea.swift */, + B6B1E88A26D774090062C350 /* LinkButton.swift */, + B693954026F04BE80015B914 /* LoadingProgressView.swift */, B693954426F04BE90015B914 /* LongPressButton.swift */, - B693954926F04BEB0015B914 /* MouseOverButton.swift */, AA7EB6DE27E7C57D00036718 /* MouseOverAnimationButton.swift */, + B693954926F04BEB0015B914 /* MouseOverButton.swift */, B693953D26F04BE70015B914 /* MouseOverView.swift */, - 4B379C2327BDE1B0008A968E /* FlatButton.swift */, + 1D26EBAB2B74BECB0002A93F /* NSImageSendable.swift */, B693954726F04BEA0015B914 /* NSSavePanelExtension.swift */, B693954126F04BE80015B914 /* PaddedImageButton.swift */, - B693954026F04BE80015B914 /* LoadingProgressView.swift */, + B6E3E5572BBFD51400A41922 /* PreviewViewController.swift */, B60C6F8C29B200AB007BFAA8 /* SavePanelAccessoryView.swift */, B693954226F04BE90015B914 /* ShadowView.swift */, - B693954526F04BEA0015B914 /* WindowDraggingView.swift */, 4BDFA4AD27BF19E500648192 /* ToggleableScrollView.swift */, - 85774B022A71CDD000DE0561 /* BlockMenuItem.swift */, - 1D26EBAB2B74BECB0002A93F /* NSImageSendable.swift */, + B693954526F04BEA0015B914 /* WindowDraggingView.swift */, ); path = AppKit; sourceTree = ""; @@ -6740,7 +6029,7 @@ 85CC1D7826A05E790062F04E /* Model */, 85CC1D7F26A05F6C0062F04E /* Services */, 85CC1D7926A05E820062F04E /* View */, - B642738127B65BAC0005DFD1 /* SecureVaultErrorReporter.swift */, + B642738127B65BAC0005DFD1 /* SecureVaultReporter.swift */, ); path = SecureVault; sourceTree = ""; @@ -6973,6 +6262,16 @@ path = DuckDuckGoDBPBackgroundAgent; sourceTree = ""; }; + 9F0FFFB62BCCAE80007C87DD /* Mocks */ = { + isa = PBXGroup; + children = ( + 9F0FFFB72BCCAE9C007C87DD /* AddEditBookmarkDialogViewModelMock.swift */, + 9F0FFFBA2BCCAEC2007C87DD /* AddEditBookmarkFolderDialogViewModelMock.swift */, + 9F0FFFBD2BCCAF1F007C87DD /* BookmarkAllTabsDialogViewModelMock.swift */, + ); + path = Mocks; + sourceTree = ""; + }; 9F872D9B2B9058B000138637 /* Extensions */ = { isa = PBXGroup; children = ( @@ -6984,9 +6283,12 @@ 9F982F102B82264400231028 /* ViewModels */ = { isa = PBXGroup; children = ( + 9F0FFFB62BCCAE80007C87DD /* Mocks */, 9F982F112B82268F00231028 /* AddEditBookmarkFolderDialogViewModelTests.swift */, 9F2606092B85C20400819292 /* AddEditBookmarkDialogViewModelTests.swift */, 9F26060D2B85E17D00819292 /* AddEditBookmarkDialogCoordinatorViewModelTests.swift */, + 9F0FFFB32BCCAE37007C87DD /* BookmarkAllTabsDialogCoordinatorViewModelTests.swift */, + 9FA5A0A82BC900FC00153786 /* BookmarkAllTabsDialogViewModelTests.swift */, ); path = ViewModels; sourceTree = ""; @@ -7004,6 +6306,7 @@ 9F56CFA82B82DC4300BB7F11 /* AddEditBookmarkFolderView.swift */, 9FEE98642B846870002E44E8 /* AddEditBookmarkView.swift */, 9F56CFB02B843F6C00BB7F11 /* BookmarksDialogViewFactory.swift */, + 9F9C49F82BC7BC970099738D /* BookmarkAllTabsDialogView.swift */, ); path = Dialog; sourceTree = ""; @@ -7016,6 +6319,14 @@ path = Factory; sourceTree = ""; }; + 9FAD62382BCFDB1D007F3A65 /* Helpers */ = { + isa = PBXGroup; + children = ( + 9FAD62392BCFDB32007F3A65 /* WebsiteInfoHelpers.swift */, + ); + path = Helpers; + sourceTree = ""; + }; AA0877B626D515EE00B05660 /* UserAgent */ = { isa = PBXGroup; children = ( @@ -7101,6 +6412,7 @@ 858A798226A8B75F00A75A42 /* CopyHandler.swift */, 1D36E65A298ACD2900AA485D /* AppIconChanger.swift */, CB24F70B29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift */, + 1DEF3BAC2BD145A9004A2FBA /* AutoClearHandler.swift */, ); path = Application; sourceTree = ""; @@ -7136,7 +6448,6 @@ 565E46DE2B2725DD0013AC2A /* SyncE2EUITests */, AA585D7F248FD31100E9A3E2 /* Products */, 85AE2FF024A33A2D002D507F /* Frameworks */, - EE0629702B90EE3500D868B4 /* Recovered References */, ); sourceTree = ""; }; @@ -7158,7 +6469,6 @@ 4B2D06692A13318400DE1F49 /* DuckDuckGo VPN App Store.app */, 9D9AE8D12AAA39A70026E7DC /* DuckDuckGo Personal Information Removal.app */, 9D9AE8F22AAA39D30026E7DC /* DuckDuckGo Personal Information Removal App Store.app */, - 4B957C412AC7AE700062CA31 /* DuckDuckGo Privacy Pro.app */, 565E46DD2B2725DC0013AC2A /* SyncE2EUITests.xctest */, 376113D42B29CD5B00E794BB /* SyncE2EUITests App Store.xctest */, 7BDA36E52B7E037100AD5388 /* VPNProxyExtension.appex */, @@ -7245,6 +6555,7 @@ AA585D93248FD31400E9A3E2 /* UnitTests */ = { isa = PBXGroup; children = ( + 56BA1E852BAC820D001CF69F /* UserScripts */, C13909F22B85FD60001626ED /* Autofill */, 5629846D2AC460DF00AC20EB /* Sync */, B6A5A28C25B962CB00AA7ADA /* App */, @@ -7366,6 +6677,7 @@ AA652CAB25DD820D009059CC /* Bookmarks */ = { isa = PBXGroup; children = ( + 9FAD62382BCFDB1D007F3A65 /* Helpers */, 9F872D9B2B9058B000138637 /* Extensions */, 9FA75A3C2BA00DF500DA5FA6 /* Factory */, 9F982F102B82264400231028 /* ViewModels */, @@ -7392,6 +6704,7 @@ 98A95D87299A2DF900B9B81A /* BookmarkMigrationTests.swift */, 9F872D9F2B90644800138637 /* ContextualMenuTests.swift */, 9F0A2CF72B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift */, + 9FAD623C2BD09DE5007F3A65 /* WebsiteInfoTests.swift */, ); path = Model; sourceTree = ""; @@ -7401,6 +6714,8 @@ children = ( AA652CB025DD825B009059CC /* LocalBookmarkStoreTests.swift */, 986189E52A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift */, + 9FA5A0AC2BC9037A00153786 /* BookmarkFolderStoreMock.swift */, + 9F8D57312BCCCB9A00AEA660 /* UserDefaultsBookmarkFoldersStoreTests.swift */, ); path = Services; sourceTree = ""; @@ -7508,6 +6823,7 @@ children = ( AA80EC53256BE3BC007083E7 /* UserText.swift */, 4B4D60D22A0C84F700BCD287 /* UserText+NetworkProtection.swift */, + 31A83FB42BE28D7D00F74E67 /* UserText+DBP.swift */, ); path = Localizables; sourceTree = ""; @@ -7646,6 +6962,7 @@ B626A75929921FAA00053070 /* NavigationActionPolicyExtension.swift */, B634DBE4293C944700C3C99E /* NewWindowPolicy.swift */, AA9FF95824A1ECF20039E328 /* Tab.swift */, + B6F1B0252BCE5A50005E863C /* TabContent.swift */, B634DBE0293C8FD500C3C99E /* Tab+Dialogs.swift */, B61E2CD4294346C000773D8A /* Tab+Navigation.swift */, B634DBDE293C8F7F00C3C99E /* Tab+UIDelegate.swift */, @@ -7786,6 +7103,8 @@ 9F56CFAC2B84326C00BB7F11 /* AddEditBookmarkDialogViewModel.swift */, 9FEE98682B85B869002E44E8 /* BookmarksDialogViewModel.swift */, 9FEE986C2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift */, + 9F9C4A002BC7F36D0099738D /* BookmarkAllTabsDialogCoordinatorViewModel.swift */, + 9F9C49FC2BC7E9820099738D /* BookmarkAllTabsDialogViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -7833,7 +7152,6 @@ children = ( AAC30A25268DFEE200D2D9CD /* CrashReporter.swift */, AAC30A27268E045400D2D9CD /* CrashReportReader.swift */, - AAC30A2B268F1ECD00D2D9CD /* CrashReportSender.swift */, AAC30A2D268F1EE300D2D9CD /* CrashReportPromptPresenter.swift */, AAC30A29268E239100D2D9CD /* CrashReport.swift */, ); @@ -7909,6 +7227,7 @@ B6DA06E52913F39400225DE2 /* MenuItemSelectors.swift */, AAC5E4D625D6A710007F5990 /* BookmarkStore.swift */, 987799F829999973005D8EB6 /* LocalBookmarkStore.swift */, + 9FA5A0A42BC8F34900153786 /* UserDefaultsBookmarkFoldersStore.swift */, ); path = Services; sourceTree = ""; @@ -8050,7 +7369,6 @@ B6B3E0DC2657E9CF0040E0A2 /* NSScreenExtension.swift */, AAC5E4E325D6BA9C007F5990 /* NSSizeExtension.swift */, 4B39AAF527D9B2C700A73FD5 /* NSStackViewExtension.swift */, - 4BE0DF0426781961006337B7 /* NSStoryboardExtension.swift */, AA5C8F58258FE21F00748EB7 /* NSTextFieldExtension.swift */, 858A798426A8BB5D00A75A42 /* NSTextViewExtension.swift */, 4B0511E0262CAA8600F6079C /* NSViewControllerExtension.swift */, @@ -8323,22 +7641,25 @@ B647EFB32922539400BA628D /* TabExtensions */ = { isa = PBXGroup; children = ( - B6BDDA002942389000F68088 /* TabExtensions.swift */, - 1D9A4E592B43213B00F449E2 /* TabSnapshotExtension.swift */, B647EFBA2922584B00BA628D /* AdClickAttributionTabExtension.swift */, B6C00ECA292F839D009C73A6 /* AutofillTabExtension.swift */, + B6F1B0212BCE5658005E863C /* BrokenSiteInfoTabExtension.swift */, B6D574B12947224C008ED1B6 /* ContentBlockingTabExtension.swift */, B6DA06E32913ECEE00225DE2 /* ContextMenuManager.swift */, + B6685E4129A61C460043D2EE /* DownloadsTabExtension.swift */, B6C416A6294A4AE500C4F2E7 /* DuckPlayerTabExtension.swift */, B6D574B329472253008ED1B6 /* FBProtectionTabExtension.swift */, - B6685E4129A61C460043D2EE /* DownloadsTabExtension.swift */, B6C00ECC292F89D9009C73A6 /* FindInPageTabExtension.swift */, B66260DF29AC6EBD00E9E3EE /* HistoryTabExtension.swift */, B6C00ED4292FB21E009C73A6 /* HoveredLinkTabExtension.swift */, B6BF5D8829470BC4006742B1 /* HTTPSUpgradeTabExtension.swift */, - B6BF5D842946FFDA006742B1 /* PrivacyDashboardTabExtension.swift */, B66260E529ACAE4B00E9E3EE /* NavigationHotkeyHandler.swift */, B66260DC29AC5D4300E9E3EE /* NavigationProtectionTabExtension.swift */, + B6F1B0292BCE675C005E863C /* NetworkProtectionControllerTabExtension.swift */, + B6BF5D842946FFDA006742B1 /* PrivacyDashboardTabExtension.swift */, + 56BA1E742BAAF70F001CF69F /* SSLErrorPageTabExtension.swift */, + B6BDDA002942389000F68088 /* TabExtensions.swift */, + 1D9A4E592B43213B00F449E2 /* TabSnapshotExtension.swift */, B626A76C29928B1600053070 /* TestsClosureNavigationResponder.swift */, ); path = TabExtensions; @@ -8417,6 +7738,7 @@ isa = PBXGroup; children = ( B684121B2B6A1D880092F66A /* ErrorPageHTMLTemplate.swift */, + 56BA1E812BAC506F001CF69F /* SSLErrorPageUserScript.swift */, ); path = ErrorPage; sourceTree = ""; @@ -8455,6 +7777,11 @@ B69B50392726A12500758A2B /* LocalStatisticsStore.swift */, B69B50372726A12000758A2B /* VariantManager.swift */, B69B50562727D16900758A2B /* AtbAndVariantCleanup.swift */, + B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */, + B68C92C32750EF76002AC6B0 /* PixelDataRecord.swift */, + B6DA44062616B30600DD1EC2 /* PixelDataModel.xcdatamodeld */, + 9FBD84512BB3AACB00220859 /* AttributionOriginFileProvider.swift */, + 9FBD84722BB3E15D00220859 /* InstallationAttributionPixelHandler.swift */, ); path = ATB; sourceTree = ""; @@ -8468,6 +7795,8 @@ B69B50442726C5C200758A2B /* StatisticsLoaderTests.swift */, B69B50432726C5C100758A2B /* VariantManagerTests.swift */, 857E44612A9F6F3500ED77A7 /* CampaignVariantTests.swift */, + 9FBD84552BB3ACFD00220859 /* AttributionOriginFileProviderTests.swift */, + 9FBD84762BB3E54200220859 /* InstallationAttributionPixelHandlerTests.swift */, ); path = ATB; sourceTree = ""; @@ -8481,6 +7810,10 @@ B69B504E2726CD7E00758A2B /* atb.json */, B69B504F2726CD7F00758A2B /* empty */, B69B50512726CD8000758A2B /* invalid.json */, + 9FBD845C2BB3B80300220859 /* Origin.txt */, + 9FBD84602BB3BC6400220859 /* Origin-empty.txt */, + 9FBD846F2BB3DD8400220859 /* MockAttributionsPixelHandler.swift */, + 9FBD84792BB3EC3300220859 /* MockAttributionOriginProvider.swift */, ); path = Mock; sourceTree = ""; @@ -8498,17 +7831,12 @@ B6A9E44E26142AF90067D1B9 /* Statistics */ = { isa = PBXGroup; children = ( - 857E5AF32A79044900FC0FB4 /* Experiment */, B69B50332726A10700758A2B /* ATB */, - B6A9E45226142B070067D1B9 /* Pixel.swift */, - 4B67853E2AA7C726008A5004 /* DailyPixel.swift */, - B6A9E47626146A570067D1B9 /* PixelEvent.swift */, - B6A9E47E26146A800067D1B9 /* PixelArguments.swift */, - B6A9E48326146AAB0067D1B9 /* PixelParameters.swift */, + 857E5AF32A79044900FC0FB4 /* Experiment */, B610F2BA27A145C500FCEBE9 /* RulesCompilationMonitor.swift */, - B6DA44012616B28300DD1EC2 /* PixelDataStore.swift */, - B68C92C32750EF76002AC6B0 /* PixelDataRecord.swift */, - B6DA44062616B30600DD1EC2 /* PixelDataModel.xcdatamodeld */, + F188267B2BBEB3AA00D9AC4F /* GeneralPixel.swift */, + F18826832BBEE31700D9AC4F /* PixelKit+Assertion.swift */, + F188267F2BBEB58100D9AC4F /* PrivacyProPixel.swift */, ); path = Statistics; sourceTree = ""; @@ -8524,11 +7852,12 @@ B6B1E87C26D5DA020062C350 /* View */ = { isa = PBXGroup; children = ( + B6B1E88326D5EB570062C350 /* DownloadsCellView.swift */, B6B1E87D26D5DA0E0062C350 /* DownloadsPopover.swift */, B6B1E87F26D5DA9B0062C350 /* DownloadsViewController.swift */, - B6B1E88126D5DAC30062C350 /* Downloads.storyboard */, - B6B1E88326D5EB570062C350 /* DownloadsCellView.swift */, + B6E3E5532BBFCEE300A41922 /* NoDownloadsCellView.swift */, B6C0B23B26E87D900031CB7F /* NSAlert+ActiveDownloadsTermination.swift */, + B6E3E54F2BBFCDEE00A41922 /* OpenDownloadsCellView.swift */, ); path = View; sourceTree = ""; @@ -8563,6 +7892,7 @@ isa = PBXGroup; children = ( B6BF5D922947199A006742B1 /* SerpHeadersNavigationResponder.swift */, + 1E559BB02BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift */, B60C6F7629B0E286007BFAA8 /* SearchNonexistentDomainNavigationResponder.swift */, B687B7CB2947A1E9001DEA6F /* ExternalAppSchemeHandler.swift */, ); @@ -8572,9 +7902,9 @@ B6C0B23126E71A800031CB7F /* Services */ = { isa = PBXGroup; children = ( - B6C0B23226E71BCD0031CB7F /* Downloads.xcdatamodeld */, - B6C0B22F26E61D630031CB7F /* DownloadListStore.swift */, B6B1E87A26D381710062C350 /* DownloadListCoordinator.swift */, + B6C0B22F26E61D630031CB7F /* DownloadListStore.swift */, + B6C0B23226E71BCD0031CB7F /* Downloads.xcdatamodeld */, ); path = Services; sourceTree = ""; @@ -8586,6 +7916,7 @@ B626A7632992506A00053070 /* SerpHeadersNavigationResponderTests.swift */, 1D1C36E529FB019C001FA40C /* HistoryTabExtensionTests.swift */, 1D8C2FE42B70F4C4005E4BBD /* TabSnapshotExtensionTests.swift */, + 56BA1E7C2BAB290E001CF69F /* ErrorPageTabExtensionTest.swift */, ); path = TabExtensionsTests; sourceTree = ""; @@ -8595,10 +7926,6 @@ children = ( 857E5AF72A79617100FC0FB4 /* PixelExperiment */, B69B50402726C3F400758A2B /* ATB */, - B6DA44102616C0FC00DD1EC2 /* PixelTests.swift */, - 4BC2621C293996410087A482 /* PixelEventTests.swift */, - B662D3D82755D7AD0035D4D6 /* PixelStoreTests.swift */, - B6DA44222616CABC00DD1EC2 /* PixelArgumentsTests.swift */, B6DA441D2616C84600DD1EC2 /* PixelStoreMock.swift */, 4B117F7C276C0CB5002F3D8C /* LocalStatisticsStoreTests.swift */, B610F2E327A8F37A00FCEBE9 /* CBRCompileTimeReporterTests.swift */, @@ -8609,6 +7936,7 @@ B6E6B9F42BA1FD90008AA7E1 /* sandbox-test-tool */ = { isa = PBXGroup; children = ( + 02C0737C2BE5B7E000BFE2F5 /* InfoPlist.xcstrings */, B6E6BA212BA2E4FB008AA7E1 /* Info.plist */, B6E6B9F52BA1FD90008AA7E1 /* SandboxTestTool.swift */, B6E6BA222BA2EDDE008AA7E1 /* FileReadResult.swift */, @@ -8632,7 +7960,6 @@ B693956726F352DB0015B914 /* DownloadsWebViewMock.h */, B693956826F352DB0015B914 /* DownloadsWebViewMock.m */, B630794126731F5400DCEE41 /* WKDownloadMock.swift */, - B693956026F1C1BC0015B914 /* DownloadListStoreMock.swift */, B693956226F1C2A40015B914 /* FileDownloadManagerMock.swift */, 9F180D112B69C665000D695F /* DownloadsTabExtensionMock.swift */, ); @@ -8677,6 +8004,23 @@ path = View; sourceTree = ""; }; + BDA7648F2BC4E56200D0400C /* Mocks */ = { + isa = PBXGroup; + children = ( + BDA764902BC4E57200D0400C /* MockVPNLocationFormatter.swift */, + ); + path = Mocks; + sourceTree = ""; + }; + BDE981DB2BBD110800645880 /* Assets */ = { + isa = PBXGroup; + children = ( + BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */, + BD384AC72BBC821100EF3735 /* vpn-light-mode.json */, + ); + path = Assets; + sourceTree = ""; + }; C13909F22B85FD60001626ED /* Autofill */ = { isa = PBXGroup; children = ( @@ -8738,16 +8082,10 @@ path = fonts; sourceTree = ""; }; - EE0629702B90EE3500D868B4 /* Recovered References */ = { - isa = PBXGroup; - children = ( - ); - name = "Recovered References"; - sourceTree = ""; - }; EEA3EEAF2B24EB5100E8333A /* VPNLocation */ = { isa = PBXGroup; children = ( + BDA7647B2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift */, EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */, EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */, EEC4A6682B2C87D300F7C0AA /* VPNLocationView.swift */, @@ -8768,6 +8106,14 @@ path = JSAlert; sourceTree = ""; }; + EEBCA0C12BD7CDDA004DF19C /* Pixels */ = { + isa = PBXGroup; + children = ( + EEBCA0C52BD7CE2C004DF19C /* VPNFailureRecoveryPixel.swift */, + ); + path = Pixels; + sourceTree = ""; + }; EEBCE6802BA444FA00B9DF00 /* Common */ = { isa = PBXGroup; children = ( @@ -8784,6 +8130,7 @@ 4BF0E5042AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift */, 7B934C402A866DD400FC8F9C /* UserDefaults+NetworkProtectionShared.swift */, 7BFE95532A9DF2930081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift */, + 7B4D8A202BDA857300852966 /* VPNOperationErrorRecorder.swift */, ); path = AppAndExtensionAndAgentTargets; sourceTree = ""; @@ -8820,13 +8167,13 @@ 3706FCA6293F65D500E42796 /* Frameworks */, 3706FCB1293F65D500E42796 /* Resources */, 4BBA2D272B6AC09D00F6A470 /* Embed Login Items */, + 6A8856B31B2BC5078B61ED81 /* Run swiftlint */, ); buildRules = ( ); dependencies = ( 4BBA2D2B2B6AD01E00F6A470 /* PBXTargetDependency */, 4BBA2D292B6ACD4D00F6A470 /* PBXTargetDependency */, - B69D061C2A4C0BC10032D14D /* PBXTargetDependency */, 4B5F14FE2A1529230060320F /* PBXTargetDependency */, ); name = "DuckDuckGo Privacy Browser App Store"; @@ -8845,7 +8192,6 @@ B6EC37FE29B8D915001ACE79 /* Configuration */, 37DF000629F9C061002B7D3E /* SyncDataProviders */, 9DC70B192AA1FA5B005A844B /* LoginItems */, - 7B5F9A742AE2BE4E002AEBC0 /* PixelKit */, 37269EFC2B332FAC005E8E46 /* Common */, 372217812B33380700B8E9C2 /* TestUtils */, 4BF97AD02B43C43F00EB4240 /* NetworkProtectionIPC */, @@ -8860,6 +8206,9 @@ 85D44B872BA08D30001B4AB5 /* Suggestions */, 4BCBE4592BA7E17800FC75A1 /* Subscription */, 9FF521472BAA909C00B9819B /* Lottie */, + 537FC71EA5115A983FAF3170 /* Crashes */, + F198C7132BD18A30000BF24D /* PixelKit */, + F198C71F2BD18D92000BF24D /* SwiftLintTool */, ); productName = DuckDuckGo; productReference = 3706FD05293F65D500E42796 /* DuckDuckGo App Store.app */; @@ -8883,8 +8232,8 @@ packageProductDependencies = ( 3706FDD6293F661700E42796 /* OHHTTPStubs */, 3706FDD8293F661700E42796 /* OHHTTPStubsSwift */, - 4B81AD362B29513100706C96 /* PixelKitTestingUtilities */, B65CD8CE2B316E0200A595BB /* SnapshotTesting */, + F116A7C62BD1925500F3FCF7 /* PixelKitTestingUtilities */, ); productName = DuckDuckGoTests; productReference = 3706FE99293F661700E42796 /* Unit Tests App Store.xctest */; @@ -8901,7 +8250,6 @@ buildRules = ( ); dependencies = ( - B69D061A2A4C0AD80032D14D /* PBXTargetDependency */, B6EC37F429B5DA94001ACE79 /* PBXTargetDependency */, 37079A95294236FA0031BB3C /* PBXTargetDependency */, ); @@ -8924,12 +8272,9 @@ buildRules = ( ); dependencies = ( - B6F997C12B8F35F800476735 /* PBXTargetDependency */, 376113D62B29CD6800E794BB /* PBXTargetDependency */, ); name = "SyncE2EUITests App Store"; - packageProductDependencies = ( - ); productName = DuckDuckGoSyncUITests; productReference = 376113D42B29CD5B00E794BB /* SyncE2EUITests App Store.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; @@ -8946,7 +8291,6 @@ ); dependencies = ( B6CAC23F2B8F0ECA006CD402 /* PBXTargetDependency */, - B69D06162A4C0ACD0032D14D /* PBXTargetDependency */, B6EC37F229B5DA8F001ACE79 /* PBXTargetDependency */, ); name = "Integration Tests"; @@ -8954,6 +8298,7 @@ B6AE39F229374AEC00C37AA4 /* OHHTTPStubs */, B6AE39F429374AEC00C37AA4 /* OHHTTPStubsSwift */, B65CD8CC2B316DFC00A595BB /* SnapshotTesting */, + F116A7C82BD1929000F3FCF7 /* PixelKitTestingUtilities */, ); productName = "Integration Tests"; productReference = 4B1AD89D25FC27E200261379 /* Integration Tests.xctest */; @@ -8971,16 +8316,15 @@ buildRules = ( ); dependencies = ( - B6080B9F2B20AF7B00B418EF /* PBXTargetDependency */, ); name = NetworkProtectionSystemExtension; packageProductDependencies = ( - 4B2537762A11BFE100610219 /* PixelKit */, 4B2D062B2A11C0E100DE1F49 /* Networking */, EE7295E82A545BC4008C0991 /* NetworkProtection */, 37269F002B332FC8005E8E46 /* Common */, 7BBE2B7A2B61663C00697445 /* NetworkProtectionProxy */, 7B37C7A42BAA32A50062546A /* Subscription */, + F198C7172BD18A4C000BF24D /* PixelKit */, ); productName = NetworkProtectionSystemExtension; productReference = 4B25375A2A11BE7300610219 /* com.duckduckgo.macos.vpn.network-extension.debug.systemextension */; @@ -8999,7 +8343,6 @@ buildRules = ( ); dependencies = ( - B6080BA32B20AF8300B418EF /* PBXTargetDependency */, 7BEC18312AD5DA3300D30536 /* PBXTargetDependency */, ); name = DuckDuckGoVPN; @@ -9009,10 +8352,11 @@ 7BEEA5112AD1235B00A9E72B /* NetworkProtectionIPC */, 7BEEA5152AD1236E00A9E72B /* NetworkProtectionUI */, 7BEC182E2AD5D8DC00D30536 /* SystemExtensionManager */, - 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */, 4B41EDAA2B1544B2001EEDF4 /* LoginItems */, 7B00997C2B6508B700FE7C31 /* NetworkProtectionProxy */, EE2F9C5A2B90F2FF00D45FC9 /* Subscription */, + F198C7192BD18A5B000BF24D /* PixelKit */, + BDADBDC82BD2BC2200421B9B /* Lottie */, ); productName = DuckDuckGoAgent; productReference = 4B2D06392A11CFBB00DE1F49 /* DuckDuckGo VPN.app */; @@ -9034,7 +8378,6 @@ dependencies = ( 7BDA36F82B7E082100AD5388 /* PBXTargetDependency */, 4BA7C4DF2B3F6F4900AFE511 /* PBXTargetDependency */, - B6080BA52B20AF8800B418EF /* PBXTargetDependency */, ); name = DuckDuckGoVPNAppStore; packageProductDependencies = ( @@ -9042,10 +8385,11 @@ EE7295EE2A545C12008C0991 /* NetworkProtection */, 7BA7CC602AD1211C0042E5CE /* Networking */, 7BEEA5132AD1236300A9E72B /* NetworkProtectionIPC */, - 7BFCB74F2ADE7E2300DA3EA7 /* PixelKit */, 7B00997E2B6508C200FE7C31 /* NetworkProtectionProxy */, 4BA7C4DC2B3F64E500AFE511 /* LoginItems */, 4BCBE45B2BA7E18500FC75A1 /* Subscription */, + F198C71B2BD18A61000BF24D /* PixelKit */, + BDADBDCA2BD2BC2800421B9B /* Lottie */, ); productName = DuckDuckGoAgentAppStore; productReference = 4B2D06692A13318400DE1F49 /* DuckDuckGo VPN App Store.app */; @@ -9062,13 +8406,14 @@ buildRules = ( ); dependencies = ( - B6080BA12B20AF7F00B418EF /* PBXTargetDependency */, 4B4BEC4A2A11B627001D9AC5 /* PBXTargetDependency */, ); name = DuckDuckGoNotifications; packageProductDependencies = ( 37269F042B3332C2005E8E46 /* Common */, 7B624F162BA25C1F00A6C544 /* NetworkProtectionUI */, + 4B1EFF1B2BD71EEF007CC84F /* PixelKit */, + 4B1EFF202BD72189007CC84F /* Networking */, ); productName = DuckDuckGoNotifications; productReference = 4B4BEC202A11B4E2001D9AC5 /* DuckDuckGo Notifications.app */; @@ -9085,76 +8430,21 @@ buildRules = ( ); dependencies = ( - B6080B9D2B20AF7700B418EF /* PBXTargetDependency */, 4B4D60532A0B29CB00BCD287 /* PBXTargetDependency */, ); name = NetworkProtectionAppExtension; packageProductDependencies = ( - 4B4D60972A0B2A5C00BCD287 /* PixelKit */, 4B4D60AE2A0C837F00BCD287 /* Networking */, EE7295E62A545BBB008C0991 /* NetworkProtection */, 37269EFE2B332FBB005E8E46 /* Common */, 7B25856D2BA2F2ED00D49F79 /* NetworkProtectionUI */, + DC3F73D49B2D44464AFEFCD8 /* Subscription */, + F198C7152BD18A44000BF24D /* PixelKit */, ); productName = NetworkProtectionAppExtension; productReference = 4B4D603D2A0B290200BCD287 /* NetworkProtectionAppExtension.appex */; productType = "com.apple.product-type.app-extension"; }; - 4B9579252AC7AE700062CA31 /* DuckDuckGo Privacy Pro */ = { - isa = PBXNativeTarget; - buildConfigurationList = 4B957C3C2AC7AE700062CA31 /* Build configuration list for PBXNativeTarget "DuckDuckGo Privacy Pro" */; - buildPhases = ( - 4B9579432AC7AE700062CA31 /* Assert Xcode version */, - 4B9579442AC7AE700062CA31 /* Check Embedded Config URLs */, - 4B9579452AC7AE700062CA31 /* Sources */, - 4B957BD42AC7AE700062CA31 /* Frameworks */, - 4B957BEC2AC7AE700062CA31 /* Resources */, - 4B957C322AC7AE700062CA31 /* Make /Applications symlink, remove app on Clean build */, - 4B957C332AC7AE700062CA31 /* Embed Login Items */, - 7B31FD942AD126FA0086AA24 /* Embed System Network Extension */, - ); - buildRules = ( - ); - dependencies = ( - 4B9579262AC7AE700062CA31 /* PBXTargetDependency */, - 31C6E9AB2B0C07A30086DC30 /* PBXTargetDependency */, - ); - name = "DuckDuckGo Privacy Pro"; - packageProductDependencies = ( - 4B9579292AC7AE700062CA31 /* Sparkle */, - 4B95792B2AC7AE700062CA31 /* BrowserServicesKit */, - 4B95792E2AC7AE700062CA31 /* ContentBlocking */, - 4B95792F2AC7AE700062CA31 /* PrivacyDashboard */, - 4B9579302AC7AE700062CA31 /* UserScript */, - 4B9579312AC7AE700062CA31 /* Persistence */, - 4B9579322AC7AE700062CA31 /* Configuration */, - 4B9579332AC7AE700062CA31 /* Navigation */, - 4B9579342AC7AE700062CA31 /* Bookmarks */, - 4B9579352AC7AE700062CA31 /* DDGSync */, - 4B9579362AC7AE700062CA31 /* SyncUI */, - 4B9579372AC7AE700062CA31 /* SwiftUIExtensions */, - 4B9579382AC7AE700062CA31 /* OpenSSL */, - 4B95793C2AC7AE700062CA31 /* SyncDataProviders */, - 4B95793D2AC7AE700062CA31 /* NetworkProtectionUI */, - 4B95793E2AC7AE700062CA31 /* NetworkProtection */, - 4B95793F2AC7AE700062CA31 /* LoginItems */, - 7B31FD8F2AD1257B0086AA24 /* NetworkProtectionIPC */, - 3143C8782B0D1F3D00382627 /* DataBrokerProtection */, - 1E0068AC2B1673BB00BBF43B /* SubscriptionUI */, - 37269F022B332FD8005E8E46 /* Common */, - 372217832B33380E00B8E9C2 /* TestUtils */, - 373FB4B42B4D6C57004C88D6 /* PreferencesViews */, - 1E21F8E22B73E48600FB272E /* Subscription */, - 7B94E1642B7ED95100E32B96 /* NetworkProtectionProxy */, - 85E2BBD12B8F536F00DBEC7A /* History */, - F1D43AF62B98E48F00BAB743 /* BareBonesBrowserKit */, - 85D44B892BA08D3B001B4AB5 /* Suggestions */, - 9FF521492BAA90C400B9819B /* Lottie */, - ); - productName = DuckDuckGo; - productReference = 4B957C412AC7AE700062CA31 /* DuckDuckGo Privacy Pro.app */; - productType = "com.apple.product-type.application"; - }; 565E46DC2B2725DC0013AC2A /* SyncE2EUITests */ = { isa = PBXNativeTarget; buildConfigurationList = 565E46E52B2725DD0013AC2A /* Build configuration list for PBXNativeTarget "SyncE2EUITests" */; @@ -9166,11 +8456,8 @@ buildRules = ( ); dependencies = ( - B6F997BF2B8F35F400476735 /* PBXTargetDependency */, ); name = SyncE2EUITests; - packageProductDependencies = ( - ); productName = DuckDuckGoSyncUITests; productReference = 565E46DD2B2725DC0013AC2A /* SyncE2EUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; @@ -9187,7 +8474,6 @@ ); dependencies = ( EE02D41E2BB460B500DBE6B3 /* PBXTargetDependency */, - B6F997BD2B8F35EF00476735 /* PBXTargetDependency */, ); name = "UI Tests"; packageProductDependencies = ( @@ -9214,7 +8500,6 @@ packageProductDependencies = ( 7B97CD582B7E0B57004FEF43 /* NetworkProtectionProxy */, 7B97CD5A2B7E0B85004FEF43 /* Common */, - 7B97CD612B7E0C4B004FEF43 /* PixelKit */, 7B7DFB212B7E7473009EA1A3 /* Networking */, ); productName = VPNProxyExtension; @@ -9233,12 +8518,10 @@ buildRules = ( ); dependencies = ( - B6080BA92B20AF8F00B418EF /* PBXTargetDependency */, ); name = DuckDuckGoDBPBackgroundAgent; packageProductDependencies = ( 9D9AE8F82AAA3AD00026E7DC /* DataBrokerProtection */, - 9D6983F82AC773C3002C02FC /* PixelKit */, 9DEF97E02B06C4EE00764F03 /* Networking */, ); productName = DuckDuckGoAgent; @@ -9257,12 +8540,10 @@ buildRules = ( ); dependencies = ( - B6080BAB2B20AF9200B418EF /* PBXTargetDependency */, ); name = DuckDuckGoDBPBackgroundAgentAppStore; packageProductDependencies = ( 9D9AE8FA2AAA3AD90026E7DC /* DataBrokerProtection */, - 9D6983FA2AC773C8002C02FC /* PixelKit */, 315A023E2B6421AE00BFA577 /* Networking */, ); productName = DuckDuckGoAgent; @@ -9280,12 +8561,12 @@ AA585D7C248FD31100E9A3E2 /* Resources */, B6F2C8722A7A4C7D000498CF /* Make /Applications symlink, remove app on Clean build */, 4B2D065D2A11D2AE00DE1F49 /* Embed Login Items */, + 28003FDBDB96625F1630CFF2 /* Run swiftlint */, ); buildRules = ( ); dependencies = ( 7B4627742B9AF2C8004ACE0B /* PBXTargetDependency */, - B6F997BB2B8F353F00476735 /* PBXTargetDependency */, 4B5F14FC2A15291D0060320F /* PBXTargetDependency */, 31C6E9AD2B0C07BA0086DC30 /* PBXTargetDependency */, ); @@ -9307,14 +8588,11 @@ 37DF000429F9C056002B7D3E /* SyncDataProviders */, 4B4D60B02A0C83B900BCD287 /* NetworkProtectionUI */, EE7295E22A545B9A008C0991 /* NetworkProtection */, - 9DB6E7232AA0DC5800A17F3C /* LoginItems */, 7B31FD8B2AD125620086AA24 /* NetworkProtectionIPC */, 7BA59C9A2AE18B49009A97B1 /* SystemExtensionManager */, - 7B5DD6992AE51FFA001DE99C /* PixelKit */, 31A3A4E22B0C115F0021063C /* DataBrokerProtection */, 37269EFA2B332F9E005E8E46 /* Common */, 3722177F2B3337FE00B8E9C2 /* TestUtils */, - 373FB4B02B4D6C42004C88D6 /* PreferencesViews */, 7BA076BA2B65D61400D7FB72 /* NetworkProtectionProxy */, 85E2BBCD2B8F534000DBEC7A /* History */, 1EA7B8D22B7E078C000330A4 /* SubscriptionUI */, @@ -9322,6 +8600,10 @@ F1D43AF22B98E47800BAB743 /* BareBonesBrowserKit */, 85D44B852BA08D29001B4AB5 /* Suggestions */, 9FF521452BAA908500B9819B /* Lottie */, + 08D4923DC968236E22E373E2 /* Crashes */, + F1DF95E62BD188B60045E591 /* LoginItems */, + F198C7112BD18A28000BF24D /* PixelKit */, + F198C71D2BD18D88000BF24D /* SwiftLintTool */, ); productName = DuckDuckGo; productReference = AA585D7E248FD31100E9A3E2 /* DuckDuckGo.app */; @@ -9340,14 +8622,13 @@ dependencies = ( B6E6BA1D2BA2E049008AA7E1 /* PBXTargetDependency */, B6CAC23D2B8F0EC6006CD402 /* PBXTargetDependency */, - B69D06142A4C0AC50032D14D /* PBXTargetDependency */, ); name = "Unit Tests"; packageProductDependencies = ( B6DA44162616C13800DD1EC2 /* OHHTTPStubs */, B6DA44182616C13800DD1EC2 /* OHHTTPStubsSwift */, - 4B81AD342B29512B00706C96 /* PixelKitTestingUtilities */, B65CD8CA2B316DF100A595BB /* SnapshotTesting */, + F116A7C22BD1924B00F3FCF7 /* PixelKitTestingUtilities */, ); productName = DuckDuckGoTests; productReference = AA585D90248FD31400E9A3E2 /* Unit Tests.xctest */; @@ -9360,6 +8641,7 @@ B6E6B9EF2BA1FD90008AA7E1 /* Sources */, B6E6B9F02BA1FD90008AA7E1 /* Frameworks */, B6AEB5532BA3029B00781A09 /* Cleanup entitlements */, + 02C0737E2BE5B7E000BFE2F5 /* Resources */, ); buildRules = ( ); @@ -9510,13 +8792,20 @@ 4B2D06682A13318400DE1F49 /* DuckDuckGoVPNAppStore */, 9D9AE8B22AAA39A70026E7DC /* DuckDuckGoDBPBackgroundAgent */, 9D9AE8D32AAA39D30026E7DC /* DuckDuckGoDBPBackgroundAgentAppStore */, - 4B9579252AC7AE700062CA31 /* DuckDuckGo Privacy Pro */, B6E6B9F22BA1FD90008AA7E1 /* sandbox-test-tool */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 02C0737E2BE5B7E000BFE2F5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 02C0737D2BE5B7E000BFE2F5 /* InfoPlist.xcstrings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 3706FCB1293F65D500E42796 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -9530,7 +8819,6 @@ 56CEE90F2B7A725C00CF10AA /* InfoPlist.xcstrings in Resources */, 3706FCB9293F65D500E42796 /* FireproofDomains.storyboard in Resources */, 3706FCBA293F65D500E42796 /* clickToLoadConfig.json in Resources */, - 3706FCBB293F65D500E42796 /* Downloads.storyboard in Resources */, 3706FCBC293F65D500E42796 /* dark-shield.json in Resources */, 854DAAAE2A72B613001E2E24 /* BookmarksBarPromptAssets.xcassets in Resources */, 3706FCBD293F65D500E42796 /* dark-shield-mouse-over.json in Resources */, @@ -9564,7 +8852,9 @@ 3706FCE6293F65D500E42796 /* social_images in Resources */, 3706FCE7293F65D500E42796 /* shield-dot-mouse-over.json in Resources */, 3706FCE9293F65D500E42796 /* fb-sdk.js in Resources */, + BD384ACB2BBC821B00EF3735 /* vpn-dark-mode.json in Resources */, 3706FCEA293F65D500E42796 /* PasswordManager.storyboard in Resources */, + BD384ACC2BBC821B00EF3735 /* vpn-light-mode.json in Resources */, 3706FCEB293F65D500E42796 /* dark-flame-mouse-over.json in Resources */, 3706FCEC293F65D500E42796 /* flame-mouse-over.json in Resources */, 3706FCED293F65D500E42796 /* httpsMobileV2Bloom.bin in Resources */, @@ -9589,8 +8879,10 @@ 3706FE8B293F661700E42796 /* empty in Resources */, 376E2D282942843D001CD31B /* privacy-reference-tests in Resources */, 3706FE8C293F661700E42796 /* atb-with-update.json in Resources */, + 9FBD84622BB3BC6400220859 /* Origin-empty.txt in Resources */, 3706FE8D293F661700E42796 /* DataImportResources in Resources */, 3706FE8E293F661700E42796 /* atb.json in Resources */, + 9FBD845E2BB3B80300220859 /* Origin.txt in Resources */, 3706FE8F293F661700E42796 /* DuckDuckGo-ExampleCrash.ips in Resources */, 3706FE90293F661700E42796 /* DuckDuckGo-Symbol.jpg in Resources */, 3706FE91293F661700E42796 /* invalid.json in Resources */, @@ -9624,7 +8916,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + BDE981DA2BBD10D600645880 /* vpn-light-mode.json in Resources */, 7BA7CC482AD11E5C0042E5CE /* Assets.xcassets in Resources */, + BDE981D92BBD10D600645880 /* vpn-dark-mode.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -9632,7 +8926,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + BDADBDCD2BD2BC5700421B9B /* vpn-light-mode.json in Resources */, 7BA7CC472AD11E5C0042E5CE /* Assets.xcassets in Resources */, + BDADBDCC2BD2BC4D00421B9B /* vpn-dark-mode.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -9644,70 +8940,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 4B957BEC2AC7AE700062CA31 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 561D66682B95C45A008ACC5C /* Suggestion.storyboard in Resources */, - 4B957BEF2AC7AE700062CA31 /* CrashReports.storyboard in Resources */, - 4B957BF02AC7AE700062CA31 /* trackerData.json in Resources */, - 4B957BF12AC7AE700062CA31 /* dark-shield-dot-mouse-over.json in Resources */, - 4B957BF22AC7AE700062CA31 /* 01_Fire_really_small.json in Resources */, - 4B957BF32AC7AE700062CA31 /* Onboarding.storyboard in Resources */, - 56CEE9102B7A72FE00CF10AA /* InfoPlist.xcstrings in Resources */, - 4B957BF42AC7AE700062CA31 /* FireproofDomains.storyboard in Resources */, - 4B957BF52AC7AE700062CA31 /* clickToLoadConfig.json in Resources */, - 4B957BF62AC7AE700062CA31 /* Downloads.storyboard in Resources */, - 4B957BF72AC7AE700062CA31 /* dark-shield.json in Resources */, - 4B957BF82AC7AE700062CA31 /* BookmarksBarPromptAssets.xcassets in Resources */, - 4B957BF92AC7AE700062CA31 /* dark-shield-mouse-over.json in Resources */, - 4B957BFA2AC7AE700062CA31 /* autoconsent-bundle.js in Resources */, - 4B957BFB2AC7AE700062CA31 /* ContentOverlay.storyboard in Resources */, - 4B957BFC2AC7AE700062CA31 /* FindInPage.storyboard in Resources */, - 4B957BFD2AC7AE700062CA31 /* JSAlert.storyboard in Resources */, - 4B957C002AC7AE700062CA31 /* userscript.js in Resources */, - 4B957C012AC7AE700062CA31 /* fb-tds.json in Resources */, - 4B957C032AC7AE700062CA31 /* README.md in Resources */, - 4B957C042AC7AE700062CA31 /* Assets.xcassets in Resources */, - 4B957C052AC7AE700062CA31 /* NavigationBar.storyboard in Resources */, - 4B957C062AC7AE700062CA31 /* FirePopoverCollectionViewHeader.xib in Resources */, - 4B957C072AC7AE700062CA31 /* TabBar.storyboard in Resources */, - 4B957C082AC7AE700062CA31 /* shield-dot.json in Resources */, - 4B957C0B2AC7AE700062CA31 /* BookmarksBarCollectionViewItem.xib in Resources */, - 4B957C0C2AC7AE700062CA31 /* PrivacyDashboard.storyboard in Resources */, - 4B957C0D2AC7AE700062CA31 /* shield.json in Resources */, - 4B957C0E2AC7AE700062CA31 /* TabBarViewItem.xib in Resources */, - 4B957C102AC7AE700062CA31 /* httpsMobileV2FalsePositives.json in Resources */, - 4B957C112AC7AE700062CA31 /* BookmarksBar.storyboard in Resources */, - 4B957C122AC7AE700062CA31 /* trackers-1.json in Resources */, - 4B957C132AC7AE700062CA31 /* dark-trackers-1.json in Resources */, - 4B957C142AC7AE700062CA31 /* Feedback.storyboard in Resources */, - B658BAB92B0F849100D1F2C7 /* Localizable.xcstrings in Resources */, - 4B957C182AC7AE700062CA31 /* shield-mouse-over.json in Resources */, - 4B957C1A2AC7AE700062CA31 /* PermissionAuthorization.storyboard in Resources */, - 4B957C1B2AC7AE700062CA31 /* dark-trackers-3.json in Resources */, - 4B957C1C2AC7AE700062CA31 /* dark-trackers-2.json in Resources */, - 4B957C1D2AC7AE700062CA31 /* Fire.storyboard in Resources */, - 4B957C1F2AC7AE700062CA31 /* social_images in Resources */, - 4B957C202AC7AE700062CA31 /* shield-dot-mouse-over.json in Resources */, - 4B957C222AC7AE700062CA31 /* fb-sdk.js in Resources */, - 4B957C232AC7AE700062CA31 /* PasswordManager.storyboard in Resources */, - 4B957C242AC7AE700062CA31 /* dark-flame-mouse-over.json in Resources */, - 4B957C252AC7AE700062CA31 /* flame-mouse-over.json in Resources */, - 4B957C262AC7AE700062CA31 /* httpsMobileV2Bloom.bin in Resources */, - 4B957C272AC7AE700062CA31 /* trackers-3.json in Resources */, - 4B957C282AC7AE700062CA31 /* macos-config.json in Resources */, - 4B957C292AC7AE700062CA31 /* httpsMobileV2BloomSpec.json in Resources */, - 4B957C2A2AC7AE700062CA31 /* TabBarFooter.xib in Resources */, - 4B957C2C2AC7AE700062CA31 /* FirePopoverCollectionViewItem.xib in Resources */, - 4B957C2D2AC7AE700062CA31 /* ProximaNova-Bold-webfont.woff2 in Resources */, - 4B957C2E2AC7AE700062CA31 /* dark-shield-dot.json in Resources */, - 4B957C2F2AC7AE700062CA31 /* trackers-2.json in Resources */, - 4B957C302AC7AE700062CA31 /* ProximaNova-Reg-webfont.woff2 in Resources */, - 4B957C312AC7AE700062CA31 /* clickToLoad.js in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 565E46DB2B2725DC0013AC2A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -9773,7 +9005,6 @@ 56CEE90E2B7A725B00CF10AA /* InfoPlist.xcstrings in Resources */, 4B0511C3262CAA5A00F6079C /* FireproofDomains.storyboard in Resources */, EA477680272A21B700419EDA /* clickToLoadConfig.json in Resources */, - B6B1E88226D5DAC30062C350 /* Downloads.storyboard in Resources */, AA3439712754D4E900B241FA /* dark-shield.json in Resources */, 859F30672A72B38500C20372 /* BookmarksBarPromptAssets.xcassets in Resources */, AA7EB6EB27E880AE00036718 /* dark-shield-mouse-over.json in Resources */, @@ -9807,7 +9038,9 @@ EA18D1CA272F0DC8006DC101 /* social_images in Resources */, AA7EB6E927E880A600036718 /* shield-dot-mouse-over.json in Resources */, EAC80DE0271F6C0100BBF02D /* fb-sdk.js in Resources */, + BD384AC92BBC821A00EF3735 /* vpn-dark-mode.json in Resources */, 85625994269C8F9600EE44BC /* PasswordManager.storyboard in Resources */, + BD384ACA2BBC821A00EF3735 /* vpn-light-mode.json in Resources */, AA7EB6E327E7D05500036718 /* dark-flame-mouse-over.json in Resources */, AA7EB6E227E7D05500036718 /* flame-mouse-over.json in Resources */, 4B677433255DBEB800025BD8 /* httpsMobileV2Bloom.bin in Resources */, @@ -9828,6 +9061,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9FBD845D2BB3B80300220859 /* Origin.txt in Resources */, B69B50532726CD8100758A2B /* empty in Resources */, 31E163C0293A581900963C10 /* privacy-reference-tests in Resources */, B69B50542726CD8100758A2B /* atb-with-update.json in Resources */, @@ -9839,13 +9073,14 @@ 4BCF15ED2ABB9B180083F6DF /* network-protection-messages.json in Resources */, B67C6C422654BF49006C872E /* DuckDuckGo-Symbol.jpg in Resources */, B69B50552726CD8100758A2B /* invalid.json in Resources */, + 9FBD84612BB3BC6400220859 /* Origin-empty.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 3121F62B2B64266A002F706A /* Copy Swift Package resources */ = { + 28003FDBDB96625F1630CFF2 /* Run swiftlint */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9855,16 +9090,16 @@ ); inputPaths = ( ); - name = "Copy Swift Package resources"; + name = "Run swiftlint"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n# We had issues where the Swift Package resources were not being added to the Agent Apps,\n# so we're manually coping them here.\n# It seems to be a known issue: https://forums.swift.org/t/swift-packages-resource-bundle-not-present-in-xcarchive-when-framework-using-said-package-is-archived/50084/2\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/ContentScopeScripts_ContentScopeScripts.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/DataBrokerProtection_DataBrokerProtection.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\n"; + shellScript = "if [ \"$CONFIGURATION\" != \"Debug\" ] || [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\n${BUILT_PRODUCTS_DIR}/SwiftLintTool\n"; }; - 3705272528992C8A000C06A2 /* Check Embedded Config URLs */ = { + 3121F62B2B64266A002F706A /* Copy Swift Package resources */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9874,16 +9109,16 @@ ); inputPaths = ( ); - name = "Check Embedded Config URLs"; + name = "Copy Swift Package resources"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\nif [ \"$CONFIGURATION\" == \"Release\" ]; then\n \"${SRCROOT}/scripts/update_embedded.sh\" -c\nfi\n"; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n# We had issues where the Swift Package resources were not being added to the Agent Apps,\n# so we're manually coping them here.\n# It seems to be a known issue: https://forums.swift.org/t/swift-packages-resource-bundle-not-present-in-xcarchive-when-framework-using-said-package-is-archived/50084/2\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/ContentScopeScripts_ContentScopeScripts.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/DataBrokerProtection_DataBrokerProtection.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\n"; }; - 3706FA79293F65D500E42796 /* Check Embedded Config URLs */ = { + 3705272528992C8A000C06A2 /* Check Embedded Config URLs */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9902,7 +9137,7 @@ shellPath = /bin/sh; shellScript = "if [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\nif [ \"$CONFIGURATION\" == \"Release\" ]; then\n \"${SRCROOT}/scripts/update_embedded.sh\" -c\nfi\n"; }; - 378E2798296F6D1D00FCADA2 /* Validate PRODUCT_NAME */ = { + 3706FA79293F65D500E42796 /* Check Embedded Config URLs */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9912,16 +9147,16 @@ ); inputPaths = ( ); - name = "Validate PRODUCT_NAME"; + name = "Check Embedded Config URLs"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [[ \"${CONFIGURATION}\" == \"Release\" && \"${PRODUCT_NAME}\" != \"DuckDuckGo\" ]]; then\n echo \"PRODUCT_NAME must be equal to \\\"DuckDuckGo\\\" (is \\\"${PRODUCT_NAME}\\\")\"\n echo \"See ManualAppStoreRelease.xcconfig for instructions.\"\n exit 1\nfi\n"; + shellScript = "if [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\nif [ \"$CONFIGURATION\" == \"Release\" ]; then\n \"${SRCROOT}/scripts/update_embedded.sh\" -c\nfi\n"; }; - 4B2D065C2A11D23600DE1F49 /* Copy Assets */ = { + 378E2798296F6D1D00FCADA2 /* Validate PRODUCT_NAME */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9931,16 +9166,16 @@ ); inputPaths = ( ); - name = "Copy Assets"; + name = "Validate PRODUCT_NAME"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# We had issues where the Swift Package resources were not being added to the Agent Apps,\n# so we're manually coping them here.\n# It seems to be a known issue: https://forums.swift.org/t/swift-packages-resource-bundle-not-present-in-xcarchive-when-framework-using-said-package-is-archived/50084/2\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/NetworkProtectionMac_NetworkProtectionUI.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\n"; + shellScript = "if [[ \"${CONFIGURATION}\" == \"Release\" && \"${PRODUCT_NAME}\" != \"DuckDuckGo\" ]]; then\n echo \"PRODUCT_NAME must be equal to \\\"DuckDuckGo\\\" (is \\\"${PRODUCT_NAME}\\\")\"\n echo \"See ManualAppStoreRelease.xcconfig for instructions.\"\n exit 1\nfi\n"; }; - 4B2D067D2A13341200DE1F49 /* ShellScript */ = { + 4B2D065C2A11D23600DE1F49 /* Copy Assets */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9950,6 +9185,7 @@ ); inputPaths = ( ); + name = "Copy Assets"; outputFileListPaths = ( ); outputPaths = ( @@ -9958,26 +9194,7 @@ shellPath = /bin/sh; shellScript = "# We had issues where the Swift Package resources were not being added to the Agent Apps,\n# so we're manually coping them here.\n# It seems to be a known issue: https://forums.swift.org/t/swift-packages-resource-bundle-not-present-in-xcarchive-when-framework-using-said-package-is-archived/50084/2\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/NetworkProtectionMac_NetworkProtectionUI.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\n"; }; - 4B9579432AC7AE700062CA31 /* Assert Xcode version */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Assert Xcode version"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/scripts/assert_xcode_version.sh\"\n"; - }; - 4B9579442AC7AE700062CA31 /* Check Embedded Config URLs */ = { + 4B2D067D2A13341200DE1F49 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -9987,33 +9204,13 @@ ); inputPaths = ( ); - name = "Check Embedded Config URLs"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ \"$CONFIGURATION\" == \"Release\" ]; then\n \"${SRCROOT}/scripts/update_embedded.sh\" -c\nfi\n"; - }; - 4B957C322AC7AE700062CA31 /* Make /Applications symlink, remove app on Clean build */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Make /Applications symlink, remove app on Clean build"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if [[ \"${CONFIGURATION}\" != \"Debug\" ]]; then\n # run only for Debug builds\n exit 0\nfi\n\n# if Xcode created real Applications directory inside BUILT_PRODUCTS_DIR \nif [[ ! -L ${BUILT_PRODUCTS_DIR}/Applications ]]; then\n # we only get here on clean build, remove an existing app in /Applications/DEBUG on clean build\n echo \"rm -rf /${INSTALL_PATH}/${PRODUCT_NAME}.app\"\n rm -rf \"/${INSTALL_PATH}/${PRODUCT_NAME}.app\"\n\n # create /Applications/DEBUG dir\n echo \"mkdir -p /${INSTALL_PATH}\"\n mkdir -p \"/${INSTALL_PATH}\"\n\n # move the app bundle to /Applications/DEBUG\n echo \"mv ${DSTROOT}/${INSTALL_PATH}/${PRODUCT_NAME}.app /${INSTALL_PATH}/${PRODUCT_NAME}.app\"\n mv \"${DSTROOT}/${INSTALL_PATH}/${PRODUCT_NAME}.app\" \"/${INSTALL_PATH}/${PRODUCT_NAME}.app\"\n\n # rm ${BUILT_PRODUCTS_DIR}/Applications directory created by Xcode\n echo \"rm -rf ${BUILT_PRODUCTS_DIR}/Applications\" \n rm -rf \"${BUILT_PRODUCTS_DIR}/Applications\"\n # create ${BUILT_PRODUCTS_DIR}/Applications symlink to /Applications\n echo \"ln -s /Applications ${BUILT_PRODUCTS_DIR}/Applications\"\n ln -s /Applications \"${BUILT_PRODUCTS_DIR}/Applications\"\nfi\n"; + shellScript = "# We had issues where the Swift Package resources were not being added to the Agent Apps,\n# so we're manually coping them here.\n# It seems to be a known issue: https://forums.swift.org/t/swift-packages-resource-bundle-not-present-in-xcarchive-when-framework-using-said-package-is-archived/50084/2\ncp -RL \"${BUILT_PRODUCTS_DIR}\"/NetworkProtectionMac_NetworkProtectionUI.bundle \"${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/\"\n"; }; 4BBA2D272B6AC09D00F6A470 /* Embed Login Items */ = { isa = PBXShellScriptBuildPhase; @@ -10034,7 +9231,7 @@ shellPath = /bin/sh; shellScript = "# Embeds login items for the App Store build.\n\n# Skip login item embedding for release builds until they're ready to go live.\nif [ \"${CONFIGURATION}\" = \"Release\" ]; then\n VPN_AGENT_NAME=\"${AGENT_RELEASE_PRODUCT_NAME}\"\n PIR_AGENT_NAME=\"${DBP_BACKGROUND_AGENT_RELEASE_PRODUCT_NAME}\"\nelse\n VPN_AGENT_NAME=\"${AGENT_PRODUCT_NAME}\"\n PIR_AGENT_NAME=\"${DBP_BACKGROUND_AGENT_PRODUCT_NAME}\"\nfi\n\nVPN_AGENT_ORIGIN=$(readlink -f \"${CONFIGURATION_BUILD_DIR}/${VPN_AGENT_NAME}.app\")\nPIR_AGENT_ORIGIN=$(readlink -f \"${CONFIGURATION_BUILD_DIR}/${PIR_AGENT_NAME}.app\")\nAGENT_DESTINATION=\"${CONFIGURATION_BUILD_DIR}/${CONTENTS_FOLDER_PATH}/Library/LoginItems\"\n \n# Make sure that Library/LoginItems exists before copying\nmkdir -p \"$AGENT_DESTINATION\"\n \necho \"Copying VPN agent from $VPN_AGENT_ORIGIN to $AGENT_DESTINATION\"\nrsync -r --links \"$VPN_AGENT_ORIGIN\" \"$AGENT_DESTINATION\"\n \necho \"Copying Personal Information Removal agent from $PIR_AGENT_ORIGIN to $AGENT_DESTINATION\"\nrsync -r --links \"$PIR_AGENT_ORIGIN\" \"$AGENT_DESTINATION\"\n"; }; - 7B31FD922AD126C40086AA24 /* Embed System Network Extension */ = { + 6A8856B31B2BC5078B61ED81 /* Run swiftlint */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -10044,16 +9241,16 @@ ); inputPaths = ( ); - name = "Embed System Network Extension"; + name = "Run swiftlint"; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [[ -z \"${SYSEX_BUNDLE_ID}\" ]]; then\n echo \"Required build settings are not defined, please check xcconfig files\"\n exit 1\nfi\n\n\necho \"ditto ${BUILT_PRODUCTS_DIR}/${SYSEX_BUNDLE_ID}.systemextension $BUILT_PRODUCTS_DIR/${CONTENTS_FOLDER_PATH}/Library/SystemExtensions/${SYSEX_BUNDLE_ID}.systemextension\"\n\nditto \"${BUILT_PRODUCTS_DIR}/${SYSEX_BUNDLE_ID}.systemextension\" \"$BUILT_PRODUCTS_DIR/${CONTENTS_FOLDER_PATH}/Library/SystemExtensions/${SYSEX_BUNDLE_ID}.systemextension\" || exit 1\n"; + shellScript = "if [ \"$CONFIGURATION\" != \"Debug\" ] || [ \"$ENABLE_PREVIEWS\" = \"YES\" ]; then exit 0; fi\n${BUILT_PRODUCTS_DIR}/SwiftLintTool\n"; }; - 7B31FD942AD126FA0086AA24 /* Embed System Network Extension */ = { + 7B31FD922AD126C40086AA24 /* Embed System Network Extension */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; @@ -10220,6 +9417,7 @@ 4B520F642BA5573A006405C7 /* WaitlistThankYouView.swift in Sources */, 3706FA80293F65D500E42796 /* TabLazyLoaderDataSource.swift in Sources */, 3706FA81293F65D500E42796 /* LoginImport.swift in Sources */, + 560C40002BCD5A1E00F589CE /* PermanentSurveyManager.swift in Sources */, C13909FC2B861039001626ED /* AutofillActionPresenter.swift in Sources */, 4BF97AD72B43C53D00EB4240 /* NetworkProtectionIPCTunnelController.swift in Sources */, EEC4A66E2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift in Sources */, @@ -10270,6 +9468,7 @@ 3706FAAD293F65D500E42796 /* BadgeNotificationAnimationModel.swift in Sources */, 3706FAAE293F65D500E42796 /* HyperLink.swift in Sources */, 3706FAAF293F65D500E42796 /* PasteboardWriting.swift in Sources */, + B6E3E5512BBFCDEE00A41922 /* OpenDownloadsCellView.swift in Sources */, 3706FAB0293F65D500E42796 /* BookmarkOutlineCellView.swift in Sources */, 3706FAB1293F65D500E42796 /* UnprotectedDomains.xcdatamodeld in Sources */, 5614B3A22BBD639D009B5031 /* ZoomPopover.swift in Sources */, @@ -10279,10 +9478,8 @@ 3706FAB6293F65D500E42796 /* YoutubePlayerUserScript.swift in Sources */, 1D8057C92A83CB3C00F4FED6 /* SupportedOsChecker.swift in Sources */, 373D9B4929EEAC1B00381FDD /* SyncMetadataDatabase.swift in Sources */, - 3706FAB7293F65D500E42796 /* PixelParameters.swift in Sources */, 3706FAB8293F65D500E42796 /* FaviconImageCache.swift in Sources */, 3706FAB9293F65D500E42796 /* TabBarViewController.swift in Sources */, - 4B9DB0332A983B24000927DB /* EnableWaitlistFeatureView.swift in Sources */, 3706FABA293F65D500E42796 /* BookmarkOutlineViewDataSource.swift in Sources */, 3706FABB293F65D500E42796 /* PasswordManagementBitwardenItemView.swift in Sources */, 1D220BF92B86192200F8BBC6 /* PreferencesEmailProtectionView.swift in Sources */, @@ -10296,6 +9493,7 @@ 3706FAC2293F65D500E42796 /* FaviconSelector.swift in Sources */, B696AFFC2AC5924800C93203 /* FileLineError.swift in Sources */, F1D43AEF2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */, + 56BA1E8B2BB1CB5B001CF69F /* CertificateTrustEvaluator.swift in Sources */, B6E1491129A5C30A00AAFBE8 /* FBProtectionTabExtension.swift in Sources */, 3706FAC4293F65D500E42796 /* PrintingUserScript.swift in Sources */, 1D01A3D92B88DF8B00FE8150 /* PreferencesSyncView.swift in Sources */, @@ -10333,6 +9531,7 @@ 1DDD3EC52B84F96B004CBF2B /* CookiePopupProtectionPreferences.swift in Sources */, 3706FAE0293F65D500E42796 /* BookmarkSidebarTreeController.swift in Sources */, 3706FAE1293F65D500E42796 /* HomePageFavoritesModel.swift in Sources */, + 7B4D8A222BDA857300852966 /* VPNOperationErrorRecorder.swift in Sources */, 3706FAE2293F65D500E42796 /* SequenceExtensions.swift in Sources */, 3706FAE3293F65D500E42796 /* ChromiumDataImporter.swift in Sources */, 3706FAE5293F65D500E42796 /* BackForwardListItemViewModel.swift in Sources */, @@ -10356,6 +9555,7 @@ 3706FAF3293F65D500E42796 /* LocalAuthenticationService.swift in Sources */, 1D36E659298AA3BA00AA485D /* InternalUserDeciderStore.swift in Sources */, B6BCC5242AFCDABB002C5499 /* DataImportSourceViewModel.swift in Sources */, + B6F1B02B2BCE675C005E863C /* NetworkProtectionControllerTabExtension.swift in Sources */, 3706FEBC293F6EFF00E42796 /* BWResponse.swift in Sources */, B65C7DFC2B886CF0001E2D5C /* WKPDFHUDViewWrapper.swift in Sources */, 3706FAF4293F65D500E42796 /* SafariBookmarksReader.swift in Sources */, @@ -10366,8 +9566,10 @@ F1B33DF72BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */, 3706FEC0293F6EFF00E42796 /* BWRequest.swift in Sources */, 3706FAF7293F65D500E42796 /* FireproofDomainsViewController.swift in Sources */, + F18826852BBEE31700D9AC4F /* PixelKit+Assertion.swift in Sources */, 4BF0E5062AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, 3706FAF8293F65D500E42796 /* URLEventHandler.swift in Sources */, + 9FBD84742BB3E15D00220859 /* InstallationAttributionPixelHandler.swift in Sources */, 37197EA72942443D00394917 /* AuthenticationAlert.swift in Sources */, 3706FEC3293F6F0600E42796 /* BWCommunicator.swift in Sources */, 3706FAFA293F65D500E42796 /* CleanThisHistoryMenuItem.swift in Sources */, @@ -10409,12 +9611,14 @@ 3706FB17293F65D500E42796 /* FirePopoverCollectionViewHeader.swift in Sources */, 85774B042A71CDD000DE0561 /* BlockMenuItem.swift in Sources */, 3706FB19293F65D500E42796 /* FireViewController.swift in Sources */, + B6E3E55C2BC0041A00A41922 /* DownloadListStoreMock.swift in Sources */, 4B4D60D42A0C84F700BCD287 /* UserText+NetworkProtection.swift in Sources */, 3707C71F294B5D2900682A9F /* WKUserContentControllerExtension.swift in Sources */, 3706FB1A293F65D500E42796 /* OutlineSeparatorViewCell.swift in Sources */, 3706FB1B293F65D500E42796 /* SafariDataImporter.swift in Sources */, 3706FB1D293F65D500E42796 /* StatisticsLoader.swift in Sources */, 3793FDD829535EBA00A2E28F /* Assertions.swift in Sources */, + F188267D2BBEB3AA00D9AC4F /* GeneralPixel.swift in Sources */, B62B48572ADE730D000DECE5 /* FileImportView.swift in Sources */, B6676BE22AA986A700525A21 /* AddressBarTextEditor.swift in Sources */, 3706FB1F293F65D500E42796 /* DataClearingPreferences.swift in Sources */, @@ -10446,6 +9650,7 @@ 3706FB35293F65D500E42796 /* FlatButton.swift in Sources */, 3706FB36293F65D500E42796 /* PinnedTabView.swift in Sources */, 3706FB37293F65D500E42796 /* DataEncryption.swift in Sources */, + 56BA1E762BAAF70F001CF69F /* SSLErrorPageTabExtension.swift in Sources */, 4B9DB0362A983B24000927DB /* WaitlistTermsAndConditionsView.swift in Sources */, 37197EA82942443D00394917 /* BrowserTabViewController.swift in Sources */, 3706FB39293F65D500E42796 /* PrivacyDashboardPopover.swift in Sources */, @@ -10457,7 +9662,6 @@ 1ED910D62B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift in Sources */, 3706FB40293F65D500E42796 /* ContextualMenu.swift in Sources */, 3706FB41293F65D500E42796 /* NavigationBarViewController.swift in Sources */, - 4B7534CC2A1FD7EA00158A99 /* NetworkProtectionInviteDialog.swift in Sources */, 3707C71C294B5D1900682A9F /* TabExtensionsBuilder.swift in Sources */, 3706FB42293F65D500E42796 /* MainViewController.swift in Sources */, 3706FB43293F65D500E42796 /* DuckPlayer.swift in Sources */, @@ -10466,6 +9670,7 @@ 3706FB46293F65D500E42796 /* FirePopoverWrapperViewController.swift in Sources */, 3706FB47293F65D500E42796 /* NSPasteboardItemExtension.swift in Sources */, 3706FB48293F65D500E42796 /* AutofillPreferencesModel.swift in Sources */, + B6F1B0272BCE5A50005E863C /* TabContent.swift in Sources */, 3168506E2AF3AD1D009A2828 /* WaitlistViewControllerPresenter.swift in Sources */, 3706FB49293F65D500E42796 /* NSException+Catch.swift in Sources */, B6B71C592B23379600487131 /* NSLayoutConstraintExtension.swift in Sources */, @@ -10486,6 +9691,7 @@ 4B9DB0422A983B24000927DB /* WaitlistDialogView.swift in Sources */, 3706FB57293F65D500E42796 /* AppPrivacyConfigurationDataProvider.swift in Sources */, 857E5AF62A790B7000FC0FB4 /* PixelExperiment.swift in Sources */, + 9F33445F2BBFA77F0040CBEB /* BookmarksBarVisibilityManager.swift in Sources */, 3706FB58293F65D500E42796 /* LinkButton.swift in Sources */, 4B0EF7272B578096009D6481 /* AppVersionExtension.swift in Sources */, 3706FB59293F65D500E42796 /* TemporaryFileHandler.swift in Sources */, @@ -10498,7 +9704,6 @@ 3706FB60293F65D500E42796 /* PasswordManagementIdentityItemView.swift in Sources */, 3706FB61293F65D500E42796 /* ProgressExtension.swift in Sources */, 3706FB62293F65D500E42796 /* CSVParser.swift in Sources */, - 3706FB64293F65D500E42796 /* PixelDataModel.xcdatamodeld in Sources */, B626A75B29921FAA00053070 /* NavigationActionPolicyExtension.swift in Sources */, 4B9DB02A2A983B24000927DB /* WaitlistStorage.swift in Sources */, 3706FB65293F65D500E42796 /* PrivacyDashboardWebView.swift in Sources */, @@ -10512,11 +9717,11 @@ 9FEE986A2B85B869002E44E8 /* BookmarksDialogViewModel.swift in Sources */, 3706FB6A293F65D500E42796 /* AddressBarButton.swift in Sources */, 4B41EDA42B1543B9001EEDF4 /* VPNPreferencesModel.swift in Sources */, + 1E559BB22BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift in Sources */, 7B7FCD102BA33B2700C04FBE /* UserDefaults+vpnLegacyUser.swift in Sources */, 3706FB6C293F65D500E42796 /* FaviconStore.swift in Sources */, 3706FB6D293F65D500E42796 /* SuggestionListCharacteristics.swift in Sources */, 377D801F2AB48191002AF251 /* FavoritesDisplayModeSyncHandler.swift in Sources */, - 4B4D60C62A0C849600BCD287 /* NetworkProtectionInviteCodeViewModel.swift in Sources */, 3706FB6F293F65D500E42796 /* BookmarkListViewController.swift in Sources */, 3706FB70293F65D500E42796 /* SecureVaultLoginImporter.swift in Sources */, 3706FB72293F65D500E42796 /* RecentlyClosedCoordinator.swift in Sources */, @@ -10556,8 +9761,11 @@ 37197EA42942441D00394917 /* NewWindowPolicy.swift in Sources */, 3706FB84293F65D500E42796 /* NSWindowExtension.swift in Sources */, 3706FB85293F65D500E42796 /* AddBookmarkPopover.swift in Sources */, + F18826922BC0105900D9AC4F /* PixelDataRecord.swift in Sources */, + F18826932BC0105900D9AC4F /* PixelDataStore.swift in Sources */, 7BBD45B22A691AB500C83CA9 /* NetworkProtectionDebugUtilities.swift in Sources */, 3706FB87293F65D500E42796 /* ProcessExtension.swift in Sources */, + F18826812BBEB58100D9AC4F /* PrivacyProPixel.swift in Sources */, 3706FB88293F65D500E42796 /* PermissionAuthorizationQuery.swift in Sources */, 3706FB89293F65D500E42796 /* BadgeAnimationView.swift in Sources */, 4B4D60C32A0C849100BCD287 /* EventMapping+NetworkProtectionError.swift in Sources */, @@ -10568,6 +9776,7 @@ B66260E129AC6EBD00E9E3EE /* HistoryTabExtension.swift in Sources */, 3706FB8E293F65D500E42796 /* FirefoxEncryptionKeyReader.swift in Sources */, 3706FB8F293F65D500E42796 /* BookmarkManagementSplitViewController.swift in Sources */, + 316913272BD2B76F0051B46D /* DataBrokerPrerequisitesStatusVerifier.swift in Sources */, 3706FB90293F65D500E42796 /* CookieManagedNotificationContainerView.swift in Sources */, 3706FB91293F65D500E42796 /* FileManagerExtension.swift in Sources */, 3706FB92293F65D500E42796 /* PermissionModel.swift in Sources */, @@ -10596,12 +9805,13 @@ 98779A0129999B64005D8EB6 /* Bookmark.xcdatamodeld in Sources */, 3706FB9E293F65D500E42796 /* AboutModel.swift in Sources */, 3706FB9F293F65D500E42796 /* PasswordManagementCreditCardItemView.swift in Sources */, + 9F9C4A022BC7F36D0099738D /* BookmarkAllTabsDialogCoordinatorViewModel.swift in Sources */, 3706FBA0293F65D500E42796 /* NSTextFieldExtension.swift in Sources */, 9FA173E82B7B122E00EE4E6E /* BookmarkDialogStackedContentView.swift in Sources */, 3706FBA1293F65D500E42796 /* FireproofDomainsContainer.swift in Sources */, 3706FBA2293F65D500E42796 /* GeolocationService.swift in Sources */, - 4B4D60C42A0C849600BCD287 /* NetworkProtectionInvitePresenter.swift in Sources */, 3706FBA3293F65D500E42796 /* FireproofingURLExtensions.swift in Sources */, + 3169132A2BD2C7570051B46D /* DataBrokerProtectionErrorViewController.swift in Sources */, 1DDD3EC12B84F5D5004CBF2B /* PreferencesCookiePopupProtectionView.swift in Sources */, 3706FBA4293F65D500E42796 /* ContentOverlayPopover.swift in Sources */, 3706FBA5293F65D500E42796 /* TabShadowView.swift in Sources */, @@ -10613,6 +9823,7 @@ B66260E829ACD0C900E9E3EE /* DuckPlayerTabExtension.swift in Sources */, 3706FBAA293F65D500E42796 /* HoverUserScript.swift in Sources */, 3706FBAC293F65D500E42796 /* MainMenuActions.swift in Sources */, + 9FBD84532BB3AACB00220859 /* AttributionOriginFileProvider.swift in Sources */, 4BF97AD92B43C5C000EB4240 /* Bundle+VPN.swift in Sources */, 3706FBAE293F65D500E42796 /* DataImport.swift in Sources */, 3706FBAF293F65D500E42796 /* FireproofDomains.xcdatamodeld in Sources */, @@ -10636,6 +9847,7 @@ 3706FBBE293F65D500E42796 /* DownloadListViewModel.swift in Sources */, 3706FBBF293F65D500E42796 /* BookmarkManagementDetailViewController.swift in Sources */, B6B4D1CB2B0C8C9200C26286 /* FirefoxCompatibilityPreferences.swift in Sources */, + F188268E2BBF01C400D9AC4F /* PixelDataModel.xcdatamodeld in Sources */, 3706FBC0293F65D500E42796 /* CSVImporter.swift in Sources */, 3706FBC1293F65D500E42796 /* StartupPreferences.swift in Sources */, 3706FBC2293F65D500E42796 /* MainMenu.swift in Sources */, @@ -10648,13 +9860,14 @@ 3706FBC7293F65D500E42796 /* EncryptedHistoryStore.swift in Sources */, 3706FBC8293F65D500E42796 /* FirePopoverCollectionViewItem.swift in Sources */, 3706FBC9293F65D500E42796 /* ArrayExtension.swift in Sources */, - 3706FBCA293F65D500E42796 /* CrashReportSender.swift in Sources */, 3706FBCB293F65D500E42796 /* BookmarkHTMLImporter.swift in Sources */, 4BF97ADC2B43C5E200EB4240 /* VPNFeedbackSender.swift in Sources */, 987799F72999996B005D8EB6 /* BookmarkDatabase.swift in Sources */, + BDA7647D2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift in Sources */, 3706FBCC293F65D500E42796 /* CustomRoundedCornersShape.swift in Sources */, 3706FBCD293F65D500E42796 /* LocaleExtension.swift in Sources */, 3706FBCE293F65D500E42796 /* SavePaymentMethodViewController.swift in Sources */, + 9FA5A0A62BC8F34900153786 /* UserDefaultsBookmarkFoldersStore.swift in Sources */, 1DDC85002B835BC000670238 /* SearchPreferences.swift in Sources */, 3706FBD0293F65D500E42796 /* WebKitVersionProvider.swift in Sources */, 3706FBD1293F65D500E42796 /* NSCoderExtensions.swift in Sources */, @@ -10667,6 +9880,7 @@ 7B430EA22A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */, 3706FBD5293F65D500E42796 /* TabCollection+NSSecureCoding.swift in Sources */, 3706FBD6293F65D500E42796 /* Instruments.swift in Sources */, + B6ABD0CF2BC042CE0000EB69 /* NSURL+sandboxExtensionRetainCount.m in Sources */, B62B483F2ADE48DE000DECE5 /* ArrayBuilder.swift in Sources */, 569277C229DDCBB500B633EF /* HomePageContinueSetUpModel.swift in Sources */, 3706FBD7293F65D500E42796 /* ContentBlockerRulesLists.swift in Sources */, @@ -10714,10 +9928,7 @@ 9F56CFAE2B84326C00BB7F11 /* AddEditBookmarkDialogViewModel.swift in Sources */, 3706FBF3293F65D500E42796 /* PseudoFolder.swift in Sources */, 1D26EBAD2B74BECB0002A93F /* NSImageSendable.swift in Sources */, - 3706FBF5293F65D500E42796 /* PixelDataStore.swift in Sources */, 1D220BFD2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift in Sources */, - 3706FBF6293F65D500E42796 /* Pixel.swift in Sources */, - 3706FBF7293F65D500E42796 /* PixelEvent.swift in Sources */, 3706FBF8293F65D500E42796 /* TabBarFooter.swift in Sources */, B626A7612992407D00053070 /* CancellableExtension.swift in Sources */, 3706FBF9293F65D500E42796 /* BookmarksBarCollectionViewItem.swift in Sources */, @@ -10743,8 +9954,8 @@ 1DCFBC8B29ADF32B00313531 /* BurnerHomePageView.swift in Sources */, 3706FC06293F65D500E42796 /* OnboardingViewModel.swift in Sources */, 3706FC07293F65D500E42796 /* ScriptSourceProviding.swift in Sources */, - 4B6785402AA7C726008A5004 /* DailyPixel.swift in Sources */, 31EF1E832B63FFCA00E6DB17 /* LoginItem+DataBrokerProtection.swift in Sources */, + 021EA0812BD2A9D500772C9A /* TabsPreferences.swift in Sources */, B6619EFC2B111CC600CD9186 /* InstructionsFormatParser.swift in Sources */, 3706FC08293F65D500E42796 /* CoreDataBookmarkImporter.swift in Sources */, 3706FC09293F65D500E42796 /* SuggestionViewModel.swift in Sources */, @@ -10769,6 +9980,7 @@ 3706FC13293F65D500E42796 /* FaviconView.swift in Sources */, B69A14F72B4D701F00B9417D /* AddBookmarkPopoverViewModel.swift in Sources */, 3706FC14293F65D500E42796 /* OnboardingFlow.swift in Sources */, + B6E3E5592BBFD51400A41922 /* PreviewViewController.swift in Sources */, EEC8EB3E2982CA3B0065AA39 /* JSAlertViewModel.swift in Sources */, 3706FC16293F65D500E42796 /* PasswordManagementLoginModel.swift in Sources */, 3706FC17293F65D500E42796 /* TabViewModel.swift in Sources */, @@ -10808,10 +10020,14 @@ B6685E4029A606190043D2EE /* WorkspaceProtocol.swift in Sources */, 3706FC2F293F65D500E42796 /* MouseOverButton.swift in Sources */, 3706FC30293F65D500E42796 /* FireInfoViewController.swift in Sources */, + B6F1B02F2BCE6B47005E863C /* TunnelControllerProvider.swift in Sources */, + 31A83FB62BE28D7D00F74E67 /* UserText+DBP.swift in Sources */, + 56BA1E832BAC506F001CF69F /* SSLErrorPageUserScript.swift in Sources */, 3706FC31293F65D500E42796 /* PermissionButton.swift in Sources */, 3706FC32293F65D500E42796 /* MoreOptionsMenu.swift in Sources */, 3706FC34293F65D500E42796 /* PermissionAuthorizationViewController.swift in Sources */, 3706FC35293F65D500E42796 /* BookmarkNode.swift in Sources */, + B6ABD0CB2BC03F610000EB69 /* SecurityScopedFileURLController.swift in Sources */, 31EF1E822B63FFC200E6DB17 /* DataBrokerProtectionLoginItemScheduler.swift in Sources */, B6B140892ABDBCC1004F8E85 /* HoverTrackingArea.swift in Sources */, 3706FC36293F65D500E42796 /* LongPressButton.swift in Sources */, @@ -10828,7 +10044,6 @@ 3706FC40293F65D500E42796 /* SaveIdentityViewController.swift in Sources */, 3706FC41293F65D500E42796 /* FileStore.swift in Sources */, 1DB67F2E2B6FEFDB003DF243 /* ViewSnapshotRenderer.swift in Sources */, - 3706FC42293F65D500E42796 /* PixelArguments.swift in Sources */, 3706FC43293F65D500E42796 /* PinnedTabsViewModel.swift in Sources */, 85D0327C2B8E3D090041D1FB /* HistoryCoordinatorExtension.swift in Sources */, B6685E4329A61C470043D2EE /* DownloadsTabExtension.swift in Sources */, @@ -10848,7 +10063,9 @@ 3706FC4E293F65D500E42796 /* AtbAndVariantCleanup.swift in Sources */, 3706FC50293F65D500E42796 /* FeedbackWindow.swift in Sources */, 3706FC51293F65D500E42796 /* RecentlyVisitedView.swift in Sources */, + B6E3E5552BBFCEE300A41922 /* NoDownloadsCellView.swift in Sources */, B645D8F729FA95440024461F /* WKProcessPoolExtension.swift in Sources */, + 9F9C49FE2BC7E9830099738D /* BookmarkAllTabsDialogViewModel.swift in Sources */, 9F514F922B7D88AD001832A9 /* AddEditBookmarkFolderDialogView.swift in Sources */, 3706FC52293F65D500E42796 /* MouseOverAnimationButton.swift in Sources */, B60293E72BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */, @@ -10898,12 +10115,12 @@ 3706FC71293F65D500E42796 /* NSColorExtension.swift in Sources */, 1DB9618229F67F6100CF5568 /* FaviconNullStore.swift in Sources */, 3706FC73293F65D500E42796 /* AddressBarButtonsViewController.swift in Sources */, - 3706FC76293F65D500E42796 /* PixelDataRecord.swift in Sources */, - 7BFE955A2A9DF4550081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift in Sources */, 9FDA6C222B79A59D00E099A9 /* BookmarkFavoriteView.swift in Sources */, + C1372EF52BBC5BAD003F8793 /* SecureTextField.swift in Sources */, + 316913242BD2B6250051B46D /* DataBrokerProtectionPixelsHandler.swift in Sources */, 3706FC77293F65D500E42796 /* PageObserverUserScript.swift in Sources */, 4BF0E5132AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, - 3706FC78293F65D500E42796 /* SecureVaultErrorReporter.swift in Sources */, + 3706FC78293F65D500E42796 /* SecureVaultReporter.swift in Sources */, 3706FC79293F65D500E42796 /* NSImageExtensions.swift in Sources */, 3706FEBD293F6EFF00E42796 /* BWCommand.swift in Sources */, 3706FC7B293F65D500E42796 /* PasswordManagementViewController.swift in Sources */, @@ -10923,6 +10140,7 @@ 3707C721294B5D2900682A9F /* WKMenuItemIdentifier.swift in Sources */, 3706FEBE293F6EFF00E42796 /* BWMessageIdGenerator.swift in Sources */, C1E961F02B87AA29001760E1 /* AutofillActionBuilder.swift in Sources */, + B6F1B0232BCE5658005E863C /* BrokenSiteInfoTabExtension.swift in Sources */, 3706FC85293F65D500E42796 /* ShadowView.swift in Sources */, 3706FC86293F65D500E42796 /* FeedbackSender.swift in Sources */, 3706FC88293F65D500E42796 /* TabBarViewItem.swift in Sources */, @@ -10935,7 +10153,6 @@ 3706FC8D293F65D500E42796 /* PreferencesGeneralView.swift in Sources */, 37197EA92942443D00394917 /* WebView.swift in Sources */, 3706FC8E293F65D500E42796 /* PinnedTabsView.swift in Sources */, - 3706FC92293F65D500E42796 /* NSStoryboardExtension.swift in Sources */, B6B5F58A2B03673B008DB58A /* BrowserImportMoreInfoView.swift in Sources */, 3706FC93293F65D500E42796 /* PreferencesViewController.swift in Sources */, 3706FC94293F65D500E42796 /* FireproofDomains.swift in Sources */, @@ -10944,6 +10161,7 @@ 3706FC96293F65D500E42796 /* HorizontallyCenteredLayout.swift in Sources */, 3706FC97293F65D500E42796 /* BookmarksOutlineView.swift in Sources */, 3706FC98293F65D500E42796 /* CountryList.swift in Sources */, + 1DEF3BAE2BD145A9004A2FBA /* AutoClearHandler.swift in Sources */, 4B37EE732B4CFF0800A89A61 /* HomePageRemoteMessagingStorage.swift in Sources */, 3706FC99293F65D500E42796 /* PreferencesSection.swift in Sources */, B6C8CAA82AD010DD0060E1CD /* YandexDataImporter.swift in Sources */, @@ -10957,6 +10175,7 @@ 3706FCA0293F65D500E42796 /* ContiguousBytesExtension.swift in Sources */, B602E8172A1E2570006D261F /* URL+NetworkProtection.swift in Sources */, 3706FCA1293F65D500E42796 /* AdjacentItemEnumerator.swift in Sources */, + 9F9C49FA2BC7BC970099738D /* BookmarkAllTabsDialogView.swift in Sources */, 3706FCA2293F65D500E42796 /* ChromiumKeychainPrompt.swift in Sources */, 3707C71E294B5D2900682A9F /* URLRequestExtension.swift in Sources */, 3706FCA3293F65D500E42796 /* WKProcessPool+GeolocationProvider.swift in Sources */, @@ -10971,6 +10190,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9F0FFFB92BCCAE9C007C87DD /* AddEditBookmarkDialogViewModelMock.swift in Sources */, 3706FDDA293F661700E42796 /* EmbeddedTrackerDataTests.swift in Sources */, 3706FDDB293F661700E42796 /* AutofillPreferencesTests.swift in Sources */, 3706FDDC293F661700E42796 /* FileManagerExtensionTests.swift in Sources */, @@ -10980,7 +10200,6 @@ 3706FDE0293F661700E42796 /* TabIndexTests.swift in Sources */, 9F26060F2B85E17D00819292 /* AddEditBookmarkDialogCoordinatorViewModelTests.swift in Sources */, 3706FDE1293F661700E42796 /* AdjacentItemEnumeratorTests.swift in Sources */, - 3706FDE2293F661700E42796 /* PixelArgumentsTests.swift in Sources */, 4B9DB0572A983B55000927DB /* MockNotificationService.swift in Sources */, 3706FDE4293F661700E42796 /* TabLazyLoaderTests.swift in Sources */, 3706FDE5293F661700E42796 /* URLEventHandlerTests.swift in Sources */, @@ -11004,12 +10223,14 @@ 3706FDF5293F661700E42796 /* StartupPreferencesTests.swift in Sources */, 3706FDF6293F661700E42796 /* DuckPlayerTests.swift in Sources */, 3706FDF7293F661700E42796 /* WebViewExtensionTests.swift in Sources */, + 9FA5A0AA2BC900FC00153786 /* BookmarkAllTabsDialogViewModelTests.swift in Sources */, 56534DEE29DF252C00121467 /* CapturingDefaultBrowserProvider.swift in Sources */, 3706FDF8293F661700E42796 /* FileStoreTests.swift in Sources */, 5603D90729B7B746007F9F01 /* MockTabViewItemDelegate.swift in Sources */, 3706FDF9293F661700E42796 /* TabViewModelTests.swift in Sources */, 9F872DA12B90644800138637 /* ContextualMenuTests.swift in Sources */, 3706FDFA293F661700E42796 /* DefaultBrowserPreferencesTests.swift in Sources */, + 9FBD84782BB3E54200220859 /* InstallationAttributionPixelHandlerTests.swift in Sources */, 3706FDFB293F661700E42796 /* DispatchQueueExtensionsTests.swift in Sources */, 9F180D102B69C553000D695F /* Tab+WKUIDelegateTests.swift in Sources */, 981E20B6299A39B8002B68CD /* BookmarkMigrationTests.swift in Sources */, @@ -11026,11 +10247,13 @@ 3706FE04293F661700E42796 /* TreeControllerTests.swift in Sources */, 3706FE05293F661700E42796 /* DownloadsWebViewMock.m in Sources */, 3706FE06293F661700E42796 /* CoreDataEncryptionTesting.xcdatamodeld in Sources */, + 56BA1E7F2BAB2D29001CF69F /* ErrorPageTabExtensionTest.swift in Sources */, 3706FE07293F661700E42796 /* PasswordManagementItemListModelTests.swift in Sources */, 3706FE08293F661700E42796 /* WKWebsiteDataStoreExtensionTests.swift in Sources */, 3706FE09293F661700E42796 /* VariantManagerTests.swift in Sources */, 3706FE0A293F661700E42796 /* UserAgentTests.swift in Sources */, 3706FE0B293F661700E42796 /* AVCaptureDeviceMock.swift in Sources */, + 9FBD84572BB3ACFD00220859 /* AttributionOriginFileProviderTests.swift in Sources */, 3706FE0C293F661700E42796 /* GeolocationProviderMock.swift in Sources */, CBDD5DE429A6800300832877 /* MockConfigurationStore.swift in Sources */, 3706FE0D293F661700E42796 /* MainMenuTests.swift in Sources */, @@ -11042,7 +10265,6 @@ 4BE344EF2B23786F003FC223 /* VPNFeedbackFormViewModelTests.swift in Sources */, B6F56569299A414300A04298 /* WKWebViewMockingExtension.swift in Sources */, 3706FE13293F661700E42796 /* ConfigurationStorageTests.swift in Sources */, - 3706FE14293F661700E42796 /* DownloadListStoreMock.swift in Sources */, 3706FE15293F661700E42796 /* PrivacyIconViewModelTests.swift in Sources */, B68412212B6A30680092F66A /* StringExtensionTests.swift in Sources */, 1D8C2FEE2B70F5D0005E4BBD /* MockViewSnapshotRenderer.swift in Sources */, @@ -11054,13 +10276,14 @@ 3706FE1B293F661700E42796 /* PermissionManagerTests.swift in Sources */, 3706FE1C293F661700E42796 /* ConnectBitwardenViewModelTests.swift in Sources */, 4B9DB0552A983B55000927DB /* MockWaitlistStorage.swift in Sources */, - 3706FE1D293F661700E42796 /* PixelStoreTests.swift in Sources */, 1D9FDEC72B9B64DB0040B78C /* PrivacyProtectionStatusTests.swift in Sources */, C13909F52B85FD79001626ED /* AutofillDeleteAllPasswordsExecutorTests.swift in Sources */, 857E44642A9F70F200ED77A7 /* CampaignVariantTests.swift in Sources */, 3706FE1E293F661700E42796 /* GeolocationProviderTests.swift in Sources */, 9F39106A2B68D87B00CB5112 /* ProgressExtensionTests.swift in Sources */, + 9FAD623B2BCFDB32007F3A65 /* WebsiteInfoHelpers.swift in Sources */, 3706FE1F293F661700E42796 /* AppStateChangePublisherTests.swift in Sources */, + 9FA5A0B12BC9039300153786 /* BookmarkFolderStoreMock.swift in Sources */, 3706FE20293F661700E42796 /* CLLocationManagerMock.swift in Sources */, B6656E0E2B29C733008798A1 /* FileImportViewLocalizationTests.swift in Sources */, B6C843DB2BA1CAB6006FDEC3 /* FilePresenterTests.swift in Sources */, @@ -11092,10 +10315,12 @@ B630E80129C887ED00363609 /* NSErrorAdditionalInfo.swift in Sources */, 3706FE31293F661700E42796 /* TabCollectionViewModelDelegateMock.swift in Sources */, 3706FE32293F661700E42796 /* BookmarksHTMLReaderTests.swift in Sources */, + 9F0FFFBC2BCCAEC2007C87DD /* AddEditBookmarkFolderDialogViewModelMock.swift in Sources */, 3706FE33293F661700E42796 /* FireTests.swift in Sources */, B60C6F8229B1B4AD007BFAA8 /* TestRunHelper.swift in Sources */, 567DA94029E8045D008AC5EE /* MockEmailStorage.swift in Sources */, 317295D32AF058D3002C3206 /* MockWaitlistTermsAndConditionsActionHandler.swift in Sources */, + 9F0FFFB52BCCAE37007C87DD /* BookmarkAllTabsDialogCoordinatorViewModelTests.swift in Sources */, 3706FE34293F661700E42796 /* PermissionStoreTests.swift in Sources */, 3706FE35293F661700E42796 /* ThirdPartyBrowserTests.swift in Sources */, 1DFAB5232A8983E100A0F7F6 /* SetExtensionTests.swift in Sources */, @@ -11103,6 +10328,7 @@ 3706FE37293F661700E42796 /* TabCollectionViewModelTests+WithoutPinnedTabsManager.swift in Sources */, 3706FE38293F661700E42796 /* SuggestionContainerTests.swift in Sources */, 3706FE39293F661700E42796 /* TabTests.swift in Sources */, + 9FAD623E2BD09DE5007F3A65 /* WebsiteInfoTests.swift in Sources */, 3706FE3A293F661700E42796 /* MockVariantManager.swift in Sources */, 3706FE3C293F661700E42796 /* FireproofDomainsStoreMock.swift in Sources */, 3706FE3D293F661700E42796 /* DataEncryptionTests.swift in Sources */, @@ -11125,13 +10351,14 @@ 3706FE46293F661700E42796 /* EncryptedValueTransformerTests.swift in Sources */, 9F3910632B68C35600CB5112 /* DownloadsTabExtensionTests.swift in Sources */, 3706FE47293F661700E42796 /* URLExtensionTests.swift in Sources */, + 9F8D57332BCCCB9A00AEA660 /* UserDefaultsBookmarkFoldersStoreTests.swift in Sources */, 1DB9617B29F1D06D00CF5568 /* InternalUserDeciderMock.swift in Sources */, 317295D52AF058D3002C3206 /* MockWaitlistFeatureSetupHandler.swift in Sources */, - 3706FE48293F661700E42796 /* PixelTests.swift in Sources */, 3706FE49293F661700E42796 /* BookmarkNodePathTests.swift in Sources */, 1DE03425298BC7F000CAB3D7 /* InternalUserDeciderStoreMock.swift in Sources */, 3706FE4A293F661700E42796 /* BookmarkManagedObjectTests.swift in Sources */, EEC8EB402982CD550065AA39 /* JSAlertViewModelTests.swift in Sources */, + BDA764922BC4E57200D0400C /* MockVPNLocationFormatter.swift in Sources */, 3706FE4B293F661700E42796 /* BookmarksHTMLImporterTests.swift in Sources */, 9FA75A3F2BA00E1400DA5FA6 /* BookmarksBarMenuFactoryTests.swift in Sources */, 56D145E929E6BB6300E3488A /* CapturingDataImportProvider.swift in Sources */, @@ -11150,22 +10377,23 @@ 566B196429CDB824007E38F4 /* MoreOptionsMenuTests.swift in Sources */, 9F0A2CF92B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift in Sources */, 3706FE56293F661700E42796 /* FaviconManagerMock.swift in Sources */, + 9F9C49F72BC786790099738D /* MoreOptionsMenu+BookmarksTests.swift in Sources */, 3706FE57293F661700E42796 /* LocalPinningManagerTests.swift in Sources */, 3706FE58293F661700E42796 /* HistoryStoreTests.swift in Sources */, 3706FE59293F661700E42796 /* EncryptionKeyGeneratorTests.swift in Sources */, 3706FE5A293F661700E42796 /* GeolocationServiceMock.swift in Sources */, 3706FE5B293F661700E42796 /* FirefoxLoginReaderTests.swift in Sources */, 1D1C36E429FAE8DA001FA40C /* FaviconManagerTests.swift in Sources */, - 376E2D29294286B8001CD31B /* PixelEventTests.swift in Sources */, 37716D8029707E5D00A9FC6D /* FireproofingReferenceTests.swift in Sources */, B6AA64742994B43300D99CD6 /* FutureExtensionTests.swift in Sources */, 3706FE5C293F661700E42796 /* DuckPlayerPreferencesTests.swift in Sources */, 1D9FDEB82B9B5D150040B78C /* SearchPreferencesTests.swift in Sources */, + 560C3FFD2BC9911000F589CE /* PermanentSurveyManagerTests.swift in Sources */, 3706FE5D293F661700E42796 /* FileSystemDSL.swift in Sources */, 3706FE5E293F661700E42796 /* DataImportMocks.swift in Sources */, 3706FE5F293F661700E42796 /* CrashReportTests.swift in Sources */, B60C6F7F29B1B41D007BFAA8 /* TestRunHelperInitializer.m in Sources */, - 4B9DB0592A983B55000927DB /* MockNetworkProtectionCodeRedeemer.swift in Sources */, + 9F0FFFBF2BCCAF1F007C87DD /* BookmarkAllTabsDialogViewModelMock.swift in Sources */, 3706FE61293F661700E42796 /* PinnedTabsViewModelTests.swift in Sources */, 3706FE62293F661700E42796 /* PasswordManagementListSectionTests.swift in Sources */, 3706FE63293F661700E42796 /* RecentlyClosedCoordinatorMock.swift in Sources */, @@ -11184,7 +10412,9 @@ 1D9FDEBE2B9B5F0F0040B78C /* CookiePopupProtectionPreferencesTests.swift in Sources */, 028904212A7B25770028369C /* AppConfigurationURLProviderTests.swift in Sources */, 3706FE6F293F661700E42796 /* LocalStatisticsStoreTests.swift in Sources */, + 31DC2F232BD6E028001354EF /* DataBrokerPrerequisitesStatusVerifierTests.swift in Sources */, 3706FE70293F661700E42796 /* HistoryCoordinatorTests.swift in Sources */, + 9F3344632BBFBDA40040CBEB /* BookmarksBarVisibilityManagerTests.swift in Sources */, 3706FE71293F661700E42796 /* SavedStateMock.swift in Sources */, 3706FE72293F661700E42796 /* ClickToLoadTDSTests.swift in Sources */, 3706FE73293F661700E42796 /* PermissionManagerMock.swift in Sources */, @@ -11197,12 +10427,14 @@ C1E961F32B87B273001760E1 /* MockAutofillActionExecutor.swift in Sources */, 376E2D2729428353001CD31B /* BrokenSiteReportingReferenceTests.swift in Sources */, 3707C72F294B5D4F00682A9F /* WebViewTests.swift in Sources */, + 021EA0852BD6E0EB00772C9A /* TabsPreferencesTests.swift in Sources */, 5682C69429B79B57004DE3C8 /* TabBarViewItemTests.swift in Sources */, 3706FE77293F661700E42796 /* PreferencesSidebarModelTests.swift in Sources */, 3706FE78293F661700E42796 /* HistoryCoordinatingMock.swift in Sources */, 3706FE79293F661700E42796 /* AppearancePreferencesTests.swift in Sources */, 3706FE7A293F661700E42796 /* FirePopoverViewModelTests.swift in Sources */, 7B09CBAA2BA4BE8200CF245B /* NetworkProtectionPixelEventTests.swift in Sources */, + 56BA1E882BAC8239001CF69F /* SSLErrorPageUserScriptTests.swift in Sources */, 3706FE7B293F661700E42796 /* HistoryStoringMock.swift in Sources */, 562984702AC4610100AC20EB /* SyncPreferencesTests.swift in Sources */, 3706FE7C293F661700E42796 /* LocalBookmarkStoreTests.swift in Sources */, @@ -11218,12 +10450,15 @@ 3706FE81293F661700E42796 /* PermissionModelTests.swift in Sources */, B60C6F8529B1BAD3007BFAA8 /* FileManagerTempDirReplacement.swift in Sources */, 567DA94629E95C3F008AC5EE /* YoutubeOverlayUserScriptTests.swift in Sources */, + 9FBD847B2BB3EC3300220859 /* MockAttributionOriginProvider.swift in Sources */, 3706FE82293F661700E42796 /* MockStatisticsStore.swift in Sources */, + 9FBD84712BB3DD8400220859 /* MockAttributionsPixelHandler.swift in Sources */, 3706FE83293F661700E42796 /* AutofillPreferencesModelTests.swift in Sources */, 3706FE84293F661700E42796 /* TabCollectionViewModelTests+PinnedTabs.swift in Sources */, B603975229C1FFAD00902A34 /* ExpectedNavigationExtension.swift in Sources */, 3706FE85293F661700E42796 /* BWRequestTests.swift in Sources */, 3706FE86293F661700E42796 /* FileDownloadManagerTests.swift in Sources */, + BDA7648E2BC4E4EF00D0400C /* DefaultVPNLocationFormatterTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -11310,7 +10545,7 @@ 4B25377A2A11C01700610219 /* UserText+NetworkProtectionExtensions.swift in Sources */, B65DA5F42A77D3FA00CBEE8D /* BundleExtension.swift in Sources */, EE66418D2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */, - 4B2D062D2A11C12300DE1F49 /* Logging.swift in Sources */, + EEBCA0C72BD7CE2C004DF19C /* VPNFailureRecoveryPixel.swift in Sources */, 7B2E52252A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift in Sources */, B602E8232A1E260E006D261F /* Bundle+NetworkProtectionExtensions.swift in Sources */, 4B2D062A2A11C0C900DE1F49 /* NetworkProtectionOptionKeyExtension.swift in Sources */, @@ -11347,12 +10582,15 @@ 7BA7CC5D2AD120C30042E5CE /* EventMapping+NetworkProtectionError.swift in Sources */, 7BA7CC4A2AD11EA00042E5CE /* NetworkProtectionTunnelController.swift in Sources */, EE3424602BA0853900173B1B /* VPNUninstaller.swift in Sources */, + 7B4D8A232BDA857300852966 /* VPNOperationErrorRecorder.swift in Sources */, 7BD1688E2AD4A4C400D24876 /* NetworkExtensionController.swift in Sources */, 7BA7CC3E2AD11E380042E5CE /* TunnelControllerIPCService.swift in Sources */, 7BA7CC402AD11E3D0042E5CE /* AppLauncher+DefaultInitializer.swift in Sources */, 7B0694982B6E980F00FA4DBA /* VPNProxyLauncher.swift in Sources */, + BDA764842BC49E3F00D0400C /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */, EEC589DB2A4F1CE700BCD60C /* AppLauncher.swift in Sources */, B65DA5EF2A77CC3A00CBEE8D /* Bundle+NetworkProtectionExtensions.swift in Sources */, + BDA7647F2BC4998900D0400C /* DefaultVPNLocationFormatter.swift in Sources */, 4BF0E5072AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, 7BA7CC442AD11E490042E5CE /* UserText.swift in Sources */, 4BF0E5142AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, @@ -11381,12 +10619,15 @@ 7BA7CC582AD1203A0042E5CE /* UserText+NetworkProtection.swift in Sources */, 7BA7CC4B2AD11EC60042E5CE /* NetworkProtectionControllerErrorStore.swift in Sources */, EE3424612BA0853900173B1B /* VPNUninstaller.swift in Sources */, + 7B4D8A242BDA857300852966 /* VPNOperationErrorRecorder.swift in Sources */, 4BF0E5152AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, 7BFE95592A9DF2AF0081ABE9 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */, 7BA7CC5C2AD120C30042E5CE /* EventMapping+NetworkProtectionError.swift in Sources */, B65DA5F02A77CC3C00CBEE8D /* Bundle+NetworkProtectionExtensions.swift in Sources */, + BDA764852BC49E4000D0400C /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */, 7BAF9E4D2A8A3CCB002D3B6E /* UserDefaults+NetworkProtectionShared.swift in Sources */, 7BA7CC392AD11E2D0042E5CE /* DuckDuckGoVPNAppDelegate.swift in Sources */, + BDA764802BC4998A00D0400C /* DefaultVPNLocationFormatter.swift in Sources */, 7BA7CC552AD11FFB0042E5CE /* NetworkProtectionOptionKeyExtension.swift in Sources */, 7BA7CC3D2AD11E380042E5CE /* TunnelControllerIPCService.swift in Sources */, 4BA7C4DA2B3F639800AFE511 /* NetworkProtectionTunnelController.swift in Sources */, @@ -11405,9 +10646,13 @@ 4B4BEC432A11B5C7001D9AC5 /* Bundle+VPN.swift in Sources */, 4B4BEC452A11B5EE001D9AC5 /* UserText+NetworkProtectionExtensions.swift in Sources */, 4B4BEC422A11B5C7001D9AC5 /* NetworkProtectionOptionKeyExtension.swift in Sources */, + 4B1EFF1D2BD71FCA007CC84F /* UserDefaultsWrapper.swift in Sources */, B602E8222A1E2603006D261F /* Bundle+NetworkProtectionExtensions.swift in Sources */, + 4B1EFF222BD7223D007CC84F /* NetworkProtectionPixelEvent.swift in Sources */, B602E81A2A1E2570006D261F /* URL+NetworkProtection.swift in Sources */, + 4B1EFF1F2BD72170007CC84F /* OptionalExtension.swift in Sources */, EEAD7A7C2A1D3E20002A24E7 /* AppLauncher.swift in Sources */, + 4B1EFF1E2BD72034007CC84F /* BundleExtension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -11420,6 +10665,7 @@ 4B4D609F2A0B2C7300BCD287 /* Logging.swift in Sources */, EE66418C2B9B1981005BCD17 /* NetworkProtectionTokenStore+SubscriptionTokenKeychainStorage.swift in Sources */, 7B7DFB202B7E736B009EA1A3 /* MacPacketTunnelProvider.swift in Sources */, + EEBCA0C62BD7CE2C004DF19C /* VPNFailureRecoveryPixel.swift in Sources */, 4B4D60A12A0B2D6100BCD287 /* NetworkProtectionOptionKeyExtension.swift in Sources */, B602E8182A1E2570006D261F /* URL+NetworkProtection.swift in Sources */, B65DA5F52A77D3FA00CBEE8D /* BundleExtension.swift in Sources */, @@ -11433,771 +10679,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 4B9579452AC7AE700062CA31 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4B9579462AC7AE700062CA31 /* FaviconUserScript.swift in Sources */, - 4B9579472AC7AE700062CA31 /* BWResponse.swift in Sources */, - 4B37EE7A2B4CFF7200A89A61 /* DataBrokerProtectionRemoteMessaging.swift in Sources */, - 1E2AE4C72ACB215900684E0A /* NetworkProtectionRemoteMessaging.swift in Sources */, - 4B9579482AC7AE700062CA31 /* LottieAnimationCache.swift in Sources */, - 4B9579492AC7AE700062CA31 /* WaitlistDialogView.swift in Sources */, - 4B95794A2AC7AE700062CA31 /* TabIndex.swift in Sources */, - 4B95794B2AC7AE700062CA31 /* SavePanelAccessoryView.swift in Sources */, - 4B95794C2AC7AE700062CA31 /* TabLazyLoaderDataSource.swift in Sources */, - 4B95794D2AC7AE700062CA31 /* LoginImport.swift in Sources */, - 4B95794E2AC7AE700062CA31 /* JoinWaitlistView.swift in Sources */, - 4B95794F2AC7AE700062CA31 /* LazyLoadable.swift in Sources */, - 4B9579502AC7AE700062CA31 /* ClickToLoadModel.swift in Sources */, - B6F9BDDE2B45B7EE00677B33 /* WebsiteInfo.swift in Sources */, - 4B9579512AC7AE700062CA31 /* KeyedCodingExtension.swift in Sources */, - 31AA6B992B960BA60025014E /* DataBrokerProtectionLoginItemPixels.swift in Sources */, - 4B9579522AC7AE700062CA31 /* PrivacyDashboardTabExtension.swift in Sources */, - 4B9579542AC7AE700062CA31 /* DownloadListStore.swift in Sources */, - 4B9579552AC7AE700062CA31 /* Logging.swift in Sources */, - 4B9579562AC7AE700062CA31 /* CrashReportPromptPresenter.swift in Sources */, - 1DDC84F92B83558F00670238 /* PreferencesPrivateSearchView.swift in Sources */, - B6B4D1CD2B0C8C9200C26286 /* FirefoxCompatibilityPreferences.swift in Sources */, - 9FA173ED2B7B232200EE4E6E /* AddEditBookmarkDialogView.swift in Sources */, - 4B9579572AC7AE700062CA31 /* BWCredential.swift in Sources */, - 4B9579582AC7AE700062CA31 /* PreferencesRootView.swift in Sources */, - 4B9579592AC7AE700062CA31 /* AppStateChangedPublisher.swift in Sources */, - 4B95795A2AC7AE700062CA31 /* BookmarkTableCellView.swift in Sources */, - 4B95795B2AC7AE700062CA31 /* BookmarkManagementSidebarViewController.swift in Sources */, - 4B95795C2AC7AE700062CA31 /* NSStackViewExtension.swift in Sources */, - 4B95795D2AC7AE700062CA31 /* OptionalExtension.swift in Sources */, - 4B95795E2AC7AE700062CA31 /* PasswordManagementLoginItemView.swift in Sources */, - 4B95795F2AC7AE700062CA31 /* UserText.swift in Sources */, - 9F872D9A2B8DA9F800138637 /* Bookmarks+Tab.swift in Sources */, - 4B9579602AC7AE700062CA31 /* WKWebView+Download.swift in Sources */, - 4B9579612AC7AE700062CA31 /* TabShadowConfig.swift in Sources */, - 4B9579622AC7AE700062CA31 /* URLSessionExtension.swift in Sources */, - C13909FD2B861039001626ED /* AutofillActionPresenter.swift in Sources */, - 4B9579632AC7AE700062CA31 /* WKWebsiteDataStoreExtension.swift in Sources */, - 4B9579642AC7AE700062CA31 /* WindowDraggingView.swift in Sources */, - 4B9579652AC7AE700062CA31 /* SecureVaultSorting.swift in Sources */, - 4B9579662AC7AE700062CA31 /* PreferencesSidebarModel.swift in Sources */, - 4B9579672AC7AE700062CA31 /* DuckPlayerURLExtension.swift in Sources */, - C1E961F22B87AA29001760E1 /* AutofillActionBuilder.swift in Sources */, - 4B41EDB72B169887001EEDF4 /* VPNFeedbackFormView.swift in Sources */, - 4B9579682AC7AE700062CA31 /* BWEncryptionOutput.m in Sources */, - 4B9579692AC7AE700062CA31 /* PermissionState.swift in Sources */, - 4B95796A2AC7AE700062CA31 /* FeedbackPresenter.swift in Sources */, - 4B95796B2AC7AE700062CA31 /* NavigationProtectionTabExtension.swift in Sources */, - 4B95796C2AC7AE700062CA31 /* BurnerMode.swift in Sources */, - 4B95796D2AC7AE700062CA31 /* UserAgent.swift in Sources */, - 4B95796E2AC7AE700062CA31 /* LegacyBookmarkStore.swift in Sources */, - 4B95796F2AC7AE700062CA31 /* NSAlert+DataImport.swift in Sources */, - 4B9579702AC7AE700062CA31 /* MainWindow.swift in Sources */, - 9F872DA52B90920F00138637 /* BookmarkFolderInfo.swift in Sources */, - 9FEE986B2B85B869002E44E8 /* BookmarksDialogViewModel.swift in Sources */, - 4B9579712AC7AE700062CA31 /* CrashReportPromptViewController.swift in Sources */, - 4B9579722AC7AE700062CA31 /* BookmarksCleanupErrorHandling.swift in Sources */, - 4B9579732AC7AE700062CA31 /* ContextMenuManager.swift in Sources */, - 4B9579742AC7AE700062CA31 /* GradientView.swift in Sources */, - 4B9579752AC7AE700062CA31 /* PreferencesSidebar.swift in Sources */, - 1D9A4E5C2B43213B00F449E2 /* TabSnapshotExtension.swift in Sources */, - 4B9579762AC7AE700062CA31 /* HoveredLinkTabExtension.swift in Sources */, - 4B9579772AC7AE700062CA31 /* NSPointExtension.swift in Sources */, - 4B9579782AC7AE700062CA31 /* WindowsManager.swift in Sources */, - 4B9579792AC7AE700062CA31 /* BWRequest.swift in Sources */, - 4B95797A2AC7AE700062CA31 /* WKWebViewConfigurationExtensions.swift in Sources */, - 4B95797B2AC7AE700062CA31 /* HomePageDefaultBrowserModel.swift in Sources */, - 9F514F932B7D88AD001832A9 /* AddEditBookmarkFolderDialogView.swift in Sources */, - 4B95797C2AC7AE700062CA31 /* CrashReporter.swift in Sources */, - 4B95797D2AC7AE700062CA31 /* AddressBarTextSelectionNavigation.swift in Sources */, - 1D01A3DA2B88DF8B00FE8150 /* PreferencesSyncView.swift in Sources */, - 4B37EE7D2B4CFF8300A89A61 /* SurveyURLBuilder.swift in Sources */, - 4B95797E2AC7AE700062CA31 /* BadgeNotificationAnimationModel.swift in Sources */, - 4B95797F2AC7AE700062CA31 /* HyperLink.swift in Sources */, - 4B9579802AC7AE700062CA31 /* SyncDataProviders.swift in Sources */, - 4B9579812AC7AE700062CA31 /* PasteboardWriting.swift in Sources */, - 4B9579822AC7AE700062CA31 /* BookmarkOutlineCellView.swift in Sources */, - 4B9579832AC7AE700062CA31 /* UnprotectedDomains.xcdatamodeld in Sources */, - 4B9579842AC7AE700062CA31 /* TabInstrumentation.swift in Sources */, - 4B9579872AC7AE700062CA31 /* ConfigurationManager.swift in Sources */, - 4B9579882AC7AE700062CA31 /* YoutubePlayerUserScript.swift in Sources */, - 4B9579892AC7AE700062CA31 /* PixelParameters.swift in Sources */, - 4B95798B2AC7AE700062CA31 /* FaviconImageCache.swift in Sources */, - 4B95798C2AC7AE700062CA31 /* TabBarViewController.swift in Sources */, - 4B95798D2AC7AE700062CA31 /* BookmarkOutlineViewDataSource.swift in Sources */, - 4B95798E2AC7AE700062CA31 /* DataImportStatusProviding.swift in Sources */, - 3158B14C2B0BF74500AF130C /* DataBrokerProtectionDebugMenu.swift in Sources */, - 4B95798F2AC7AE700062CA31 /* PasswordManagementBitwardenItemView.swift in Sources */, - 4B9579912AC7AE700062CA31 /* NSNotificationName+PasswordManager.swift in Sources */, - 4B9579922AC7AE700062CA31 /* RulesCompilationMonitor.swift in Sources */, - 4B9579932AC7AE700062CA31 /* FBProtectionTabExtension.swift in Sources */, - 4B41EDB82B169889001EEDF4 /* VPNFeedbackFormViewModel.swift in Sources */, - 4B9579942AC7AE700062CA31 /* CrashReportReader.swift in Sources */, - 4B9579952AC7AE700062CA31 /* DataTaskProviding.swift in Sources */, - 4B9579962AC7AE700062CA31 /* FeatureFlag.swift in Sources */, - B6B4D1C82B0B3B5400C26286 /* DataImportReportModel.swift in Sources */, - 4B9579972AC7AE700062CA31 /* FeedbackViewController.swift in Sources */, - B6104E9D2BA9C174008636B2 /* DownloadResumeData.swift in Sources */, - 4B9579982AC7AE700062CA31 /* FaviconSelector.swift in Sources */, - 4B95799A2AC7AE700062CA31 /* PrintingUserScript.swift in Sources */, - 4B95799B2AC7AE700062CA31 /* ConnectBitwardenViewController.swift in Sources */, - 4B95799C2AC7AE700062CA31 /* BWManager.swift in Sources */, - B6BCC5262AFCDABB002C5499 /* DataImportSourceViewModel.swift in Sources */, - 4B95799D2AC7AE700062CA31 /* AppTrackerDataSetProvider.swift in Sources */, - D64A5FFB2AEA5C2B00B6D6E7 /* HomeButtonMenuFactory.swift in Sources */, - 4B95799E2AC7AE700062CA31 /* EncryptionKeyGeneration.swift in Sources */, - 4B95799F2AC7AE700062CA31 /* TabLazyLoader.swift in Sources */, - B690152F2ACBF4DA00AD0BAB /* MenuPreview.swift in Sources */, - 1D01A3D22B88CEC600FE8150 /* PreferencesAccessibilityView.swift in Sources */, - 4B9579A02AC7AE700062CA31 /* InvitedToWaitlistView.swift in Sources */, - 4B9579A22AC7AE700062CA31 /* SaveCredentialsViewController.swift in Sources */, - 4B9579A32AC7AE700062CA31 /* PopUpButton.swift in Sources */, - 4B9579A42AC7AE700062CA31 /* NetworkProtectionInviteDialog.swift in Sources */, - 4B9579A52AC7AE700062CA31 /* SuggestionViewController.swift in Sources */, - 4B9579A82AC7AE700062CA31 /* BWKeyStorage.swift in Sources */, - 4B9579A92AC7AE700062CA31 /* VisitViewModel.swift in Sources */, - 4B9579AA2AC7AE700062CA31 /* AddressBarTextEditor.swift in Sources */, - 3158B15B2B0BF76700AF130C /* DataBrokerProtectionFeatureDisabler.swift in Sources */, - 1D26EBAE2B74BECB0002A93F /* NSImageSendable.swift in Sources */, - 4B9579AB2AC7AE700062CA31 /* Atb.swift in Sources */, - 4B9579AC2AC7AE700062CA31 /* BrowserTabView.swift in Sources */, - 4B9579AD2AC7AE700062CA31 /* DownloadsViewController.swift in Sources */, - 4B9579AE2AC7AE700062CA31 /* DataExtension.swift in Sources */, - 4B9579AF2AC7AE700062CA31 /* ConfigurationStore.swift in Sources */, - 4B9579B02AC7AE700062CA31 /* Feedback.swift in Sources */, - 4B9579B22AC7AE700062CA31 /* FirefoxFaviconsReader.swift in Sources */, - 4B9579B32AC7AE700062CA31 /* CopyHandler.swift in Sources */, - 4B9579B42AC7AE700062CA31 /* ContentBlockingRulesUpdateObserver.swift in Sources */, - 4B9579B52AC7AE700062CA31 /* FirefoxLoginReader.swift in Sources */, - 4B9579B62AC7AE700062CA31 /* AtbParser.swift in Sources */, - 4B9579B72AC7AE700062CA31 /* PreferencesDuckPlayerView.swift in Sources */, - 4B41EDB62B169883001EEDF4 /* VPNFeedbackFormViewController.swift in Sources */, - 4B9579B92AC7AE700062CA31 /* BookmarkSidebarTreeController.swift in Sources */, - 4B9579BA2AC7AE700062CA31 /* HomePageFavoritesModel.swift in Sources */, - 4B9579BB2AC7AE700062CA31 /* SequenceExtensions.swift in Sources */, - 4B9579BC2AC7AE700062CA31 /* WKBackForwardListExtension.swift in Sources */, - 5614B3A32BBD639D009B5031 /* ZoomPopover.swift in Sources */, - 4B9579BD2AC7AE700062CA31 /* ChromiumDataImporter.swift in Sources */, - 4B9579BE2AC7AE700062CA31 /* BackForwardListItemViewModel.swift in Sources */, - 4B9579BF2AC7AE700062CA31 /* BWNotRespondingAlert.swift in Sources */, - 1DDC85052B83903E00670238 /* PreferencesWebTrackingProtectionView.swift in Sources */, - 4B9579C02AC7AE700062CA31 /* DebugUserScript.swift in Sources */, - 1DC669722B6CF0D700AA0645 /* TabSnapshotStore.swift in Sources */, - 4B9579C12AC7AE700062CA31 /* RecentlyClosedTab.swift in Sources */, - 4B9579C22AC7AE700062CA31 /* PDFSearchTextMenuItemHandler.swift in Sources */, - 4B9579C42AC7AE700062CA31 /* HistoryMenu.swift in Sources */, - 4B9579C52AC7AE700062CA31 /* ContentScopeFeatureFlagging.swift in Sources */, - 4B9579C62AC7AE700062CA31 /* OnboardingButtonStyles.swift in Sources */, - 4B9579C72AC7AE700062CA31 /* SaveIdentityPopover.swift in Sources */, - 4B9579C82AC7AE700062CA31 /* AuthenticationAlert.swift in Sources */, - 4B9579C92AC7AE700062CA31 /* SetExtension.swift in Sources */, - 4B9579CA2AC7AE700062CA31 /* YoutubePlayerNavigationHandler.swift in Sources */, - 4B9579CB2AC7AE700062CA31 /* PreferencesAboutView.swift in Sources */, - 4B9579CC2AC7AE700062CA31 /* ContentBlocking.swift in Sources */, - 4B37EE792B4CFF6F00A89A61 /* DataBrokerProtectionRemoteMessage.swift in Sources */, - 4B9579CD2AC7AE700062CA31 /* LocalAuthenticationService.swift in Sources */, - 4B9579CE2AC7AE700062CA31 /* CredentialsCleanupErrorHandling.swift in Sources */, - 4B9579CF2AC7AE700062CA31 /* SafariBookmarksReader.swift in Sources */, - 4B9579D02AC7AE700062CA31 /* HTTPCookie.swift in Sources */, - 1DDD3EC62B84F96B004CBF2B /* CookiePopupProtectionPreferences.swift in Sources */, - 4B9579D12AC7AE700062CA31 /* SafariVersionReader.swift in Sources */, - 4B9579D22AC7AE700062CA31 /* LoginFaviconView.swift in Sources */, - 4B9579D32AC7AE700062CA31 /* FireproofDomainsViewController.swift in Sources */, - 1ED910D72B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift in Sources */, - 4B9579D42AC7AE700062CA31 /* URLEventHandler.swift in Sources */, - 3158B15E2B0BF76F00AF130C /* DataBrokerProtectionAppEvents.swift in Sources */, - 4B9579D52AC7AE700062CA31 /* SupportedOsChecker.swift in Sources */, - 4B9579D62AC7AE700062CA31 /* WKWebViewExtension.swift in Sources */, - 4B9579D72AC7AE700062CA31 /* CleanThisHistoryMenuItem.swift in Sources */, - 4B9579D92AC7AE700062CA31 /* DownloadListItem.swift in Sources */, - 4B9579DA2AC7AE700062CA31 /* WaitlistRequest.swift in Sources */, - 4B9579DB2AC7AE700062CA31 /* DownloadsPopover.swift in Sources */, - 37A6A8F92AFCCA59008580A3 /* FaviconsFetcherOnboardingViewController.swift in Sources */, - 4B9579DC2AC7AE700062CA31 /* BookmarksBarMenuFactory.swift in Sources */, - 4B9579DD2AC7AE700062CA31 /* SpacerNode.swift in Sources */, - B62B483C2ADE46FC000DECE5 /* Application.swift in Sources */, - 4B9579DF2AC7AE700062CA31 /* SyncManagementDialogViewController.swift in Sources */, - 4B05265F2B1AEFDB0054955A /* VPNMetadataCollector.swift in Sources */, - 4B9579E02AC7AE700062CA31 /* BookmarkExtension.swift in Sources */, - 4B9579E12AC7AE700062CA31 /* PasswordManagementCreditCardModel.swift in Sources */, - B677FC522B06376B0099EB04 /* ReportFeedbackView.swift in Sources */, - 1D220BFE2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift in Sources */, - 4B9579E22AC7AE700062CA31 /* NSEventExtension.swift in Sources */, - 1D26EBB22B74DB600002A93F /* TabSnapshotCleanupService.swift in Sources */, - 4B9579E32AC7AE700062CA31 /* Onboarding.swift in Sources */, - 4B9579E42AC7AE700062CA31 /* PopUpWindow.swift in Sources */, - 4B9579E52AC7AE700062CA31 /* Favicons.xcdatamodeld in Sources */, - 4B9579E62AC7AE700062CA31 /* Publisher.asVoid.swift in Sources */, - 9FEE986F2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift in Sources */, - 4B9579E72AC7AE700062CA31 /* Waitlist.swift in Sources */, - 3158B1582B0BF76000AF130C /* DataBrokerProtectionFeatureVisibility.swift in Sources */, - 4B9579E82AC7AE700062CA31 /* NavigationButtonMenuDelegate.swift in Sources */, - 4B9579E92AC7AE700062CA31 /* CrashReport.swift in Sources */, - 4B9579EA2AC7AE700062CA31 /* NSPopoverExtension.swift in Sources */, - 4B9579EB2AC7AE700062CA31 /* NSPathControlView.swift in Sources */, - 4B9579EC2AC7AE700062CA31 /* HTTPSUpgradeTabExtension.swift in Sources */, - 4B9579ED2AC7AE700062CA31 /* AppIconChanger.swift in Sources */, - 4B9579EE2AC7AE700062CA31 /* AppMain.swift in Sources */, - 4B9579EF2AC7AE700062CA31 /* ProductWaitlistRequest.swift in Sources */, - 7BEC20442B0F505F00243D3E /* AddBookmarkPopoverView.swift in Sources */, - 4B9579F02AC7AE700062CA31 /* Bookmark.xcdatamodeld in Sources */, - 4B9579F12AC7AE700062CA31 /* DefaultBrowserPromptView.swift in Sources */, - 4B9579F22AC7AE700062CA31 /* WaitlistActivationDateStore.swift in Sources */, - 4B9579F42AC7AE700062CA31 /* FaviconManager.swift in Sources */, - 4B9579F52AC7AE700062CA31 /* PFMoveApplication.m in Sources */, - B68D21D22ACBCA01002DA3C2 /* ContentBlockerRulesManagerMock.swift in Sources */, - 4B9579F62AC7AE700062CA31 /* ChromiumFaviconsReader.swift in Sources */, - 4B9579F72AC7AE700062CA31 /* SuggestionTableRowView.swift in Sources */, - EEC4A6732B2C90AB00F7C0AA /* VPNLocationPreferenceItem.swift in Sources */, - 4B9579F82AC7AE700062CA31 /* DownloadsPreferences.swift in Sources */, - 4B9579F92AC7AE700062CA31 /* PasswordManagementItemList.swift in Sources */, - 4B9579FA2AC7AE700062CA31 /* Bookmark.swift in Sources */, - 4B9579FB2AC7AE700062CA31 /* ConnectBitwardenViewModel.swift in Sources */, - 4B9579FC2AC7AE700062CA31 /* NSNotificationName+DataImport.swift in Sources */, - 4B9579FD2AC7AE700062CA31 /* StoredPermission.swift in Sources */, - B6CC266A2BAD959500F53F8D /* DownloadProgress.swift in Sources */, - 4B9579FE2AC7AE700062CA31 /* FirePopoverCollectionViewHeader.swift in Sources */, - 4B9579FF2AC7AE700062CA31 /* FireViewController.swift in Sources */, - 4B957A002AC7AE700062CA31 /* OutlineSeparatorViewCell.swift in Sources */, - 4B957A012AC7AE700062CA31 /* SafariDataImporter.swift in Sources */, - 4B957A022AC7AE700062CA31 /* WaitlistViewModel.swift in Sources */, - 4B957A032AC7AE700062CA31 /* LocalBookmarkStore.swift in Sources */, - 4B957A042AC7AE700062CA31 /* BWEncryption.m in Sources */, - 4B957A052AC7AE700062CA31 /* StatisticsLoader.swift in Sources */, - 4B957A072AC7AE700062CA31 /* DataClearingPreferences.swift in Sources */, - 4B957A082AC7AE700062CA31 /* LocalUnprotectedDomains.swift in Sources */, - 4B957A092AC7AE700062CA31 /* InternalUserDeciderStore.swift in Sources */, - 4B957A0A2AC7AE700062CA31 /* NewWindowPolicy.swift in Sources */, - 4B957A0B2AC7AE700062CA31 /* NavigationBarBadgeAnimator.swift in Sources */, - 4B957A0C2AC7AE700062CA31 /* NSTextViewExtension.swift in Sources */, - 4B957A0D2AC7AE700062CA31 /* FutureExtension.swift in Sources */, - 4B957A0E2AC7AE700062CA31 /* UserDialogRequest.swift in Sources */, - 4B957A0F2AC7AE700062CA31 /* DownloadsCellView.swift in Sources */, - 4B957A112AC7AE700062CA31 /* PublishedAfter.swift in Sources */, - 1DDC85012B835BC000670238 /* SearchPreferences.swift in Sources */, - B6B5F58C2B03673B008DB58A /* BrowserImportMoreInfoView.swift in Sources */, - 4B957A122AC7AE700062CA31 /* FirefoxBerkeleyDatabaseReader.swift in Sources */, - 4B957A132AC7AE700062CA31 /* WebViewSnapshotView.swift in Sources */, - 4B957A142AC7AE700062CA31 /* DeviceAuthenticationService.swift in Sources */, - 4B957A152AC7AE700062CA31 /* AppConfigurationURLProvider.swift in Sources */, - 4B957A162AC7AE700062CA31 /* SyncSettingsAdapter.swift in Sources */, - 4B957A172AC7AE700062CA31 /* AutofillPreferences.swift in Sources */, - B6DE57F92B05EA9000CD54B9 /* SheetHostingWindow.swift in Sources */, - 4B957A192AC7AE700062CA31 /* PasswordManagerCoordinator.swift in Sources */, - 4B957A1A2AC7AE700062CA31 /* PasswordManagementIdentityModel.swift in Sources */, - 4B957A1B2AC7AE700062CA31 /* UserDefaultsWrapper.swift in Sources */, - B65C7DFD2B886CF0001E2D5C /* WKPDFHUDViewWrapper.swift in Sources */, - 4B957A1C2AC7AE700062CA31 /* PasswordManagementPopover.swift in Sources */, - 4B957A1D2AC7AE700062CA31 /* BWCommunicator.swift in Sources */, - 4B957A1E2AC7AE700062CA31 /* HomePageRecentlyVisitedModel.swift in Sources */, - 4B957A1F2AC7AE700062CA31 /* NavigationBarPopovers.swift in Sources */, - 4B957A202AC7AE700062CA31 /* CancellableExtension.swift in Sources */, - 4B957A212AC7AE700062CA31 /* PinnedTabsHostingView.swift in Sources */, - 4B957A222AC7AE700062CA31 /* FirefoxBookmarksReader.swift in Sources */, - 9F982F0F2B8224BF00231028 /* AddEditBookmarkFolderDialogViewModel.swift in Sources */, - 4B0526622B1D55320054955A /* VPNFeedbackSender.swift in Sources */, - 4B957A232AC7AE700062CA31 /* DeviceIdleStateDetector.swift in Sources */, - 85D0327D2B8E3D090041D1FB /* HistoryCoordinatorExtension.swift in Sources */, - 4B957A242AC7AE700062CA31 /* FlatButton.swift in Sources */, - 4B957A252AC7AE700062CA31 /* PinnedTabView.swift in Sources */, - 4B957A262AC7AE700062CA31 /* DataEncryption.swift in Sources */, - 4B957A272AC7AE700062CA31 /* PrivacyDashboardPopover.swift in Sources */, - 4B957A282AC7AE700062CA31 /* TestsClosureNavigationResponder.swift in Sources */, - 4B957A292AC7AE700062CA31 /* RootView.swift in Sources */, - 4B37EE7C2B4CFF8000A89A61 /* HomePageRemoteMessagingRequest.swift in Sources */, - 4B957A2A2AC7AE700062CA31 /* AddressBarTextField.swift in Sources */, - 4B957A2B2AC7AE700062CA31 /* FocusRingView.swift in Sources */, - 4B957A2C2AC7AE700062CA31 /* BookmarksBarViewModel.swift in Sources */, - 4B957A2D2AC7AE700062CA31 /* NSPopUpButtonView.swift in Sources */, - 4B957A2E2AC7AE700062CA31 /* BlockMenuItem.swift in Sources */, - 4B957A2F2AC7AE700062CA31 /* ContextualMenu.swift in Sources */, - 4B957A302AC7AE700062CA31 /* NavigationBarViewController.swift in Sources */, - 4B957A312AC7AE700062CA31 /* MainViewController.swift in Sources */, - 4B957A322AC7AE700062CA31 /* DuckPlayer.swift in Sources */, - F1D43AF02B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */, - 4B957A332AC7AE700062CA31 /* Favicon.swift in Sources */, - 1E2AE4CA2ACB21A000684E0A /* NetworkProtectionRemoteMessage.swift in Sources */, - 4B957A342AC7AE700062CA31 /* SuggestionContainerViewModel.swift in Sources */, - 9F56CFAF2B84326C00BB7F11 /* AddEditBookmarkDialogViewModel.swift in Sources */, - 4B957A352AC7AE700062CA31 /* FirePopoverWrapperViewController.swift in Sources */, - 4B957A362AC7AE700062CA31 /* NSPasteboardItemExtension.swift in Sources */, - 4B957A372AC7AE700062CA31 /* AutofillPreferencesModel.swift in Sources */, - 4B957A382AC7AE700062CA31 /* NetworkProtectionDebugUtilities.swift in Sources */, - 4B957A392AC7AE700062CA31 /* NSException+Catch.swift in Sources */, - 4B957A3A2AC7AE700062CA31 /* PasswordManagementNoteModel.swift in Sources */, - 4B957A3B2AC7AE700062CA31 /* CookieNotificationAnimationModel.swift in Sources */, - 4B957A3C2AC7AE700062CA31 /* JoinedWaitlistView.swift in Sources */, - 4B957A3D2AC7AE700062CA31 /* SharingMenu.swift in Sources */, - 4B957A3E2AC7AE700062CA31 /* EnableWaitlistFeatureView.swift in Sources */, - 4B957A3F2AC7AE700062CA31 /* GrammarFeaturesManager.swift in Sources */, - 4B957A402AC7AE700062CA31 /* WaitlistModalViewController.swift in Sources */, - B60293E82BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */, - B6BCC53E2AFD15DF002C5499 /* DataImportProfilePicker.swift in Sources */, - 4B957A412AC7AE700062CA31 /* WKMenuItemIdentifier.swift in Sources */, - 4B957A422AC7AE700062CA31 /* SafariFaviconsReader.swift in Sources */, - 4B957A432AC7AE700062CA31 /* NSScreenExtension.swift in Sources */, - 4B957A442AC7AE700062CA31 /* NSBezierPathExtension.swift in Sources */, - 4B957A452AC7AE700062CA31 /* Bundle+VPN.swift in Sources */, - B68D21CA2ACBC971002DA3C2 /* MockPrivacyConfiguration.swift in Sources */, - 4B957A462AC7AE700062CA31 /* WebsiteDataStore.swift in Sources */, - 4B957A472AC7AE700062CA31 /* NetworkProtectionFeatureVisibility.swift in Sources */, - 3778183D2AD6F86D00533759 /* FavoritesDisplayModeSyncHandler.swift in Sources */, - 4B957A482AC7AE700062CA31 /* PermissionContextMenu.swift in Sources */, - 4B957A492AC7AE700062CA31 /* ContextMenuUserScript.swift in Sources */, - 4B957A4A2AC7AE700062CA31 /* NSSavePanelExtension.swift in Sources */, - 4B957A4B2AC7AE700062CA31 /* AppPrivacyConfigurationDataProvider.swift in Sources */, - 4B957A4C2AC7AE700062CA31 /* LinkButton.swift in Sources */, - 4B957A4D2AC7AE700062CA31 /* TemporaryFileHandler.swift in Sources */, - 4B957A4E2AC7AE700062CA31 /* URL+NetworkProtection.swift in Sources */, - 4B957A4F2AC7AE700062CA31 /* PrivacyFeatures.swift in Sources */, - 4B957A512AC7AE700062CA31 /* ViewExtension.swift in Sources */, - 4B957A522AC7AE700062CA31 /* AVCaptureDevice+SwizzledAuthState.swift in Sources */, - 4B957A532AC7AE700062CA31 /* SubscriptionPagesUserScript.swift in Sources */, - 4B957A542AC7AE700062CA31 /* VisitMenuItem.swift in Sources */, - 4B957A552AC7AE700062CA31 /* EncryptionKeyStore.swift in Sources */, - 4B957A562AC7AE700062CA31 /* TabExtensionsBuilder.swift in Sources */, - 9F56CFB32B843F6C00BB7F11 /* BookmarksDialogViewFactory.swift in Sources */, - 1E2AE4C82ACB216B00684E0A /* HoverTrackingArea.swift in Sources */, - 4B957A582AC7AE700062CA31 /* PasswordManagementIdentityItemView.swift in Sources */, - 4B957A592AC7AE700062CA31 /* ProgressExtension.swift in Sources */, - 4B44FEF52B1FEF5A000619D8 /* FocusableTextEditor.swift in Sources */, - 4B957A5A2AC7AE700062CA31 /* CSVParser.swift in Sources */, - 4B957A5B2AC7AE700062CA31 /* PixelDataModel.xcdatamodeld in Sources */, - 4B957A5C2AC7AE700062CA31 /* PrivacyDashboardWebView.swift in Sources */, - B6656E5B2B2ADB1C008798A1 /* RequestFilePermissionView.swift in Sources */, - 4B957A5D2AC7AE700062CA31 /* AppearancePreferences.swift in Sources */, - 4B957A5E2AC7AE700062CA31 /* DownloadListCoordinator.swift in Sources */, - 4B957A5F2AC7AE700062CA31 /* AdClickAttributionTabExtension.swift in Sources */, - 7B3618C52ADE77D3000D6154 /* NetworkProtectionNavBarPopoverManager.swift in Sources */, - 4B957A602AC7AE700062CA31 /* NSNotificationName+Debug.swift in Sources */, - 4B957A612AC7AE700062CA31 /* NavigationBarBadgeAnimationView.swift in Sources */, - 4B957A622AC7AE700062CA31 /* AddressBarButton.swift in Sources */, - 4B957A642AC7AE700062CA31 /* FaviconStore.swift in Sources */, - 4B957A652AC7AE700062CA31 /* WaitlistTermsAndConditionsView.swift in Sources */, - B62B48592ADE730D000DECE5 /* FileImportView.swift in Sources */, - 4B957A662AC7AE700062CA31 /* SuggestionListCharacteristics.swift in Sources */, - 4B957A672AC7AE700062CA31 /* TimeIntervalExtension.swift in Sources */, - 4B957A682AC7AE700062CA31 /* NetworkProtectionFeatureDisabler.swift in Sources */, - 7BBA7CEA2BAB03C1007579A3 /* DefaultSubscriptionFeatureAvailability+DefaultInitializer.swift in Sources */, - 4B957A692AC7AE700062CA31 /* BookmarkListViewController.swift in Sources */, - 4B957A6A2AC7AE700062CA31 /* SecureVaultLoginImporter.swift in Sources */, - 4B957A6B2AC7AE700062CA31 /* WKProcessPoolExtension.swift in Sources */, - 4B957A6D2AC7AE700062CA31 /* LoginItemsManager.swift in Sources */, - 4B957A6E2AC7AE700062CA31 /* PixelExperiment.swift in Sources */, - 4B957A6F2AC7AE700062CA31 /* DuckPlayerTabExtension.swift in Sources */, - 4B957A702AC7AE700062CA31 /* RecentlyClosedCoordinator.swift in Sources */, - 4B957A712AC7AE700062CA31 /* URLRequestExtension.swift in Sources */, - B6080BC82B21E78100B418EF /* DataImportErrorView.swift in Sources */, - 4B957A722AC7AE700062CA31 /* FaviconHostReference.swift in Sources */, - 4B957A732AC7AE700062CA31 /* DownloadsTabExtension.swift in Sources */, - 1D220BFA2B86192200F8BBC6 /* PreferencesEmailProtectionView.swift in Sources */, - 4B957A752AC7AE700062CA31 /* ASN1Parser.swift in Sources */, - 4B957A762AC7AE700062CA31 /* FileDownloadManager.swift in Sources */, - 4B957A772AC7AE700062CA31 /* BookmarkImport.swift in Sources */, - 4BF0E5172AD25A2600FFEC9E /* DuckDuckGoUserAgent.swift in Sources */, - 4B957A782AC7AE700062CA31 /* KeySetDictionary.swift in Sources */, - B68D21CB2ACBC9A3002DA3C2 /* ContentBlockingMock.swift in Sources */, - 4B957A792AC7AE700062CA31 /* HistoryTabExtension.swift in Sources */, - 4B957A7A2AC7AE700062CA31 /* FireCoordinator.swift in Sources */, - 4B957A7B2AC7AE700062CA31 /* GeolocationProvider.swift in Sources */, - 4B957A7C2AC7AE700062CA31 /* NSAlert+ActiveDownloadsTermination.swift in Sources */, - B62B48412ADE48DE000DECE5 /* ArrayBuilder.swift in Sources */, - 4B957A7D2AC7AE700062CA31 /* IndexPathExtension.swift in Sources */, - 4B957A7E2AC7AE700062CA31 /* PasswordManagementNoteItemView.swift in Sources */, - B6B4D1D22B0E0DD000C26286 /* DataImportNoDataView.swift in Sources */, - 4B957A7F2AC7AE700062CA31 /* NSApplicationExtension.swift in Sources */, - 4B957A802AC7AE700062CA31 /* NSWindowExtension.swift in Sources */, - 4B957A812AC7AE700062CA31 /* KeychainType+ClientDefault.swift in Sources */, - C13909F12B85FD4E001626ED /* AutofillActionExecutor.swift in Sources */, - 4B41EDA52B1543B9001EEDF4 /* VPNPreferencesModel.swift in Sources */, - 4B957A822AC7AE700062CA31 /* SyncDebugMenu.swift in Sources */, - 4B957A832AC7AE700062CA31 /* AddBookmarkPopover.swift in Sources */, - 4B957A852AC7AE700062CA31 /* QRSharingService.swift in Sources */, - 4B957A862AC7AE700062CA31 /* ProcessExtension.swift in Sources */, - B68412162B694BA10092F66A /* NSObject+performSelector.m in Sources */, - 4B957A872AC7AE700062CA31 /* PermissionAuthorizationQuery.swift in Sources */, - 4B957A882AC7AE700062CA31 /* BadgeAnimationView.swift in Sources */, - 4B957A892AC7AE700062CA31 /* BrowserTabSelectionDelegate.swift in Sources */, - 4B957A8A2AC7AE700062CA31 /* ContinueSetUpView.swift in Sources */, - B69A14F42B4D6FE800B9417D /* AddBookmarkFolderPopoverViewModel.swift in Sources */, - 4B957A8B2AC7AE700062CA31 /* PasswordManagementListSection.swift in Sources */, - 4B957A8C2AC7AE700062CA31 /* FaviconReferenceCache.swift in Sources */, - 4B957A8D2AC7AE700062CA31 /* BookmarkTreeController.swift in Sources */, - EEC4A6602B277F0D00F7C0AA /* VPNLocationViewModel.swift in Sources */, - 4B957A8E2AC7AE700062CA31 /* FirefoxEncryptionKeyReader.swift in Sources */, - 4B957A8F2AC7AE700062CA31 /* EventMapping+NetworkProtectionError.swift in Sources */, - 4B957A902AC7AE700062CA31 /* BookmarkManagementSplitViewController.swift in Sources */, - 4B957A912AC7AE700062CA31 /* CookieManagedNotificationContainerView.swift in Sources */, - 4B957A922AC7AE700062CA31 /* FileManagerExtension.swift in Sources */, - 1DDD3EBE2B84DCB9004CBF2B /* WebTrackingProtectionPreferences.swift in Sources */, - 4B957A932AC7AE700062CA31 /* PermissionModel.swift in Sources */, - 4B957A942AC7AE700062CA31 /* PasteboardFolder.swift in Sources */, - 4B957A952AC7AE700062CA31 /* CookieManagedNotificationView.swift in Sources */, - 4B957A962AC7AE700062CA31 /* PermissionType.swift in Sources */, - 4B957A982AC7AE700062CA31 /* RecentlyClosedWindow.swift in Sources */, - 4B957A992AC7AE700062CA31 /* ActionSpeech.swift in Sources */, - 4B957A9B2AC7AE700062CA31 /* ModalSheetCancellable.swift in Sources */, - 4B957A9C2AC7AE700062CA31 /* FireproofDomainsStore.swift in Sources */, - 4B957A9D2AC7AE700062CA31 /* NetworkProtectionSimulateFailureMenu.swift in Sources */, - 4B957A9E2AC7AE700062CA31 /* PrivacyDashboardPermissionHandler.swift in Sources */, - 4B957A9F2AC7AE700062CA31 /* TabCollectionViewModel.swift in Sources */, - 4B520F652BA5573A006405C7 /* WaitlistThankYouView.swift in Sources */, - 4B957AA02AC7AE700062CA31 /* BookmarkManager.swift in Sources */, - 4B957AA12AC7AE700062CA31 /* AboutModel.swift in Sources */, - 4B957AA22AC7AE700062CA31 /* PasswordManagementCreditCardItemView.swift in Sources */, - 3158B1552B0BF75900AF130C /* LoginItem+DataBrokerProtection.swift in Sources */, - 4B957AA32AC7AE700062CA31 /* NSTextFieldExtension.swift in Sources */, - 4B957AA42AC7AE700062CA31 /* BWManagement.swift in Sources */, - 4B957AA52AC7AE700062CA31 /* FireproofDomainsContainer.swift in Sources */, - 4B957AA62AC7AE700062CA31 /* ExternalAppSchemeHandler.swift in Sources */, - 4B957AA72AC7AE700062CA31 /* GeolocationService.swift in Sources */, - 4B957AA82AC7AE700062CA31 /* FireproofingURLExtensions.swift in Sources */, - 4B957AA92AC7AE700062CA31 /* ContentOverlayPopover.swift in Sources */, - 4B957AAA2AC7AE700062CA31 /* TabShadowView.swift in Sources */, - 4B957AAB2AC7AE700062CA31 /* BWMessageIdGenerator.swift in Sources */, - B65E5DB12B74E6AA00480415 /* TrackerNetwork.swift in Sources */, - B6E6B9E52BA1F5F1008AA7E1 /* FilePresenter.swift in Sources */, - 31F2D2022AF026D800BF0144 /* WaitlistTermsAndConditionsActionHandler.swift in Sources */, - 4B957AAC2AC7AE700062CA31 /* EncryptedValueTransformer.swift in Sources */, - 4B957AAD2AC7AE700062CA31 /* Tab+Dialogs.swift in Sources */, - 4B957AAE2AC7AE700062CA31 /* PasteboardBookmark.swift in Sources */, - 4B957AAF2AC7AE700062CA31 /* PinnedTabsManager.swift in Sources */, - 1D01A3D62B88CF7700FE8150 /* AccessibilityPreferences.swift in Sources */, - 4B957AB02AC7AE700062CA31 /* HoverUserScript.swift in Sources */, - 4B957AB12AC7AE700062CA31 /* MainMenuActions.swift in Sources */, - 4B957AB22AC7AE700062CA31 /* WKWebView+SessionState.swift in Sources */, - B6F9BDE62B45CD1900677B33 /* ModalView.swift in Sources */, - 4B957AB32AC7AE700062CA31 /* NetworkProtectionControllerErrorStore.swift in Sources */, - 4B957AB42AC7AE700062CA31 /* DataImport.swift in Sources */, - 4B957AB52AC7AE700062CA31 /* NetworkProtectionDebugMenu.swift in Sources */, - 4B957AB62AC7AE700062CA31 /* FireproofDomains.xcdatamodeld in Sources */, - 3158B14F2B0BF74F00AF130C /* DataBrokerProtectionManager.swift in Sources */, - 4B957AB82AC7AE700062CA31 /* HomePageView.swift in Sources */, - 9FEE98672B846870002E44E8 /* AddEditBookmarkView.swift in Sources */, - 4B957AB92AC7AE700062CA31 /* SerpHeadersNavigationResponder.swift in Sources */, - 4B957ABA2AC7AE700062CA31 /* HomePageContinueSetUpModel.swift in Sources */, - 4B957ABB2AC7AE700062CA31 /* WebKitDownloadTask.swift in Sources */, - 4B957ABC2AC7AE700062CA31 /* ChromiumLoginReader.swift in Sources */, - B6BCC5522AFE4F7D002C5499 /* DataImportTypePicker.swift in Sources */, - 4B957ABD2AC7AE700062CA31 /* NSAlert+PasswordManager.swift in Sources */, - 4B957ABE2AC7AE700062CA31 /* UserContentUpdating.swift in Sources */, - 4B957ABF2AC7AE700062CA31 /* ChromiumPreferences.swift in Sources */, - 4B957AC02AC7AE700062CA31 /* FirePopoverViewController.swift in Sources */, - 4B957AC12AC7AE700062CA31 /* SavePaymentMethodPopover.swift in Sources */, - 4B957AC22AC7AE700062CA31 /* FindInPageViewController.swift in Sources */, - 4B957AC32AC7AE700062CA31 /* Cryptography.swift in Sources */, - 4B957AC42AC7AE700062CA31 /* BWVault.swift in Sources */, - 4B957AC52AC7AE700062CA31 /* NSViewExtension.swift in Sources */, - BBDFDC5C2B2B8D7000F62D90 /* DataBrokerProtectionExternalWaitlistPixels.swift in Sources */, - 9FA173E52B7A12B600EE4E6E /* BookmarkDialogFolderManagementView.swift in Sources */, - 4B957AC72AC7AE700062CA31 /* DownloadListViewModel.swift in Sources */, - 4B957AC82AC7AE700062CA31 /* BookmarkManagementDetailViewController.swift in Sources */, - 4B957AC92AC7AE700062CA31 /* CSVImporter.swift in Sources */, - 4B957ACA2AC7AE700062CA31 /* StartupPreferences.swift in Sources */, - 4B957ACB2AC7AE700062CA31 /* UserDefaults+NetworkProtectionWaitlist.swift in Sources */, - 4B957ACC2AC7AE700062CA31 /* MainMenu.swift in Sources */, - 4B957ACE2AC7AE700062CA31 /* BrowserTabViewController.swift in Sources */, - 4B957ACF2AC7AE700062CA31 /* CallToAction.swift in Sources */, - 4B957AD02AC7AE700062CA31 /* MouseOverView.swift in Sources */, - 4B957AD12AC7AE700062CA31 /* EncryptedHistoryStore.swift in Sources */, - 4B957AD22AC7AE700062CA31 /* FirePopoverCollectionViewItem.swift in Sources */, - 4B957AD32AC7AE700062CA31 /* ArrayExtension.swift in Sources */, - 4B957AD42AC7AE700062CA31 /* NetworkProtectionInviteCodeViewModel.swift in Sources */, - 4B957AD52AC7AE700062CA31 /* CrashReportSender.swift in Sources */, - B6BCC5212AFCD9ED002C5499 /* DataImportSourcePicker.swift in Sources */, - 4B957AD62AC7AE700062CA31 /* BookmarkHTMLImporter.swift in Sources */, - 4B957AD72AC7AE700062CA31 /* CustomRoundedCornersShape.swift in Sources */, - 4B957AD82AC7AE700062CA31 /* LocaleExtension.swift in Sources */, - 4B957AD92AC7AE700062CA31 /* SavePaymentMethodViewController.swift in Sources */, - 9FA173E92B7B122E00EE4E6E /* BookmarkDialogStackedContentView.swift in Sources */, - 4B957ADA2AC7AE700062CA31 /* BWStatus.swift in Sources */, - 4B957ADB2AC7AE700062CA31 /* WebKitVersionProvider.swift in Sources */, - B6BCC54D2AFDF24B002C5499 /* TaskWithProgress.swift in Sources */, - 4B957ADC2AC7AE700062CA31 /* NSCoderExtensions.swift in Sources */, - 4B957ADD2AC7AE700062CA31 /* RunningApplicationCheck.swift in Sources */, - 4B957ADE2AC7AE700062CA31 /* StatePersistenceService.swift in Sources */, - 4B957ADF2AC7AE700062CA31 /* WindowManager+StateRestoration.swift in Sources */, - 4B957AE02AC7AE700062CA31 /* TabCollection+NSSecureCoding.swift in Sources */, - 4B957AE12AC7AE700062CA31 /* Instruments.swift in Sources */, - 4B957AE22AC7AE700062CA31 /* ContentBlockerRulesLists.swift in Sources */, - 4B957AE32AC7AE700062CA31 /* NSViewControllerExtension.swift in Sources */, - 4B957AE42AC7AE700062CA31 /* NSAppearanceExtension.swift in Sources */, - 4B957AE52AC7AE700062CA31 /* EmailManagerExtension.swift in Sources */, - 4B957AE62AC7AE700062CA31 /* PermissionManager.swift in Sources */, - 4B957AE72AC7AE700062CA31 /* DefaultBrowserPreferences.swift in Sources */, - 4B957AE82AC7AE700062CA31 /* Permissions.xcdatamodeld in Sources */, - 4B957AE92AC7AE700062CA31 /* JSAlertController.swift in Sources */, - 4B957AEA2AC7AE700062CA31 /* NotificationService.swift in Sources */, - 4B41EDA92B1543C9001EEDF4 /* PreferencesVPNView.swift in Sources */, - 4B957AEB2AC7AE700062CA31 /* SyncPreferences.swift in Sources */, - 4B957AEC2AC7AE700062CA31 /* FaviconNullStore.swift in Sources */, - 4B957AED2AC7AE700062CA31 /* PaddedImageButton.swift in Sources */, - 4B957AEE2AC7AE700062CA31 /* EncryptionKeyStoring.swift in Sources */, - 4B957AEF2AC7AE700062CA31 /* String+Punycode.swift in Sources */, - 4B957AF02AC7AE700062CA31 /* NSException+Catch.m in Sources */, - 4B957AF12AC7AE700062CA31 /* AppStateRestorationManager.swift in Sources */, - 4B957AF22AC7AE700062CA31 /* DailyPixel.swift in Sources */, - 9FDA6C232B79A59D00E099A9 /* BookmarkFavoriteView.swift in Sources */, - 4B957AF32AC7AE700062CA31 /* NavigationHotkeyHandler.swift in Sources */, - B6CC266E2BAD9CD800F53F8D /* FileProgressPresenter.swift in Sources */, - 4B957AF42AC7AE700062CA31 /* ClickToLoadUserScript.swift in Sources */, - 4B957AF52AC7AE700062CA31 /* WindowControllersManager.swift in Sources */, - 4B957AF62AC7AE700062CA31 /* FireAnimationView.swift in Sources */, - 4B957AF72AC7AE700062CA31 /* FaviconUrlReference.swift in Sources */, - 4B957AF92AC7AE700062CA31 /* PasswordManagementItemListModel.swift in Sources */, - 4B957AFA2AC7AE700062CA31 /* SuggestionTableCellView.swift in Sources */, - 4B957AFB2AC7AE700062CA31 /* FireViewModel.swift in Sources */, - 4B957AFC2AC7AE700062CA31 /* SyncCredentialsAdapter.swift in Sources */, - 4B957AFD2AC7AE700062CA31 /* WKUserContentControllerExtension.swift in Sources */, - 4B957AFE2AC7AE700062CA31 /* EditableTextView.swift in Sources */, - 4B957AFF2AC7AE700062CA31 /* TabCollection.swift in Sources */, - 4B957B002AC7AE700062CA31 /* MainView.swift in Sources */, - 4B957B012AC7AE700062CA31 /* Tab+Navigation.swift in Sources */, - 4B957B022AC7AE700062CA31 /* EmailUrlExtensions.swift in Sources */, - 4B957B032AC7AE700062CA31 /* PasswordManagementItemModel.swift in Sources */, - 4B957B042AC7AE700062CA31 /* UpdateController.swift in Sources */, - 4B957B052AC7AE700062CA31 /* FindInPageModel.swift in Sources */, - 4B957B062AC7AE700062CA31 /* PseudoFolder.swift in Sources */, - 4B2F565D2B38F93E001214C0 /* NetworkProtectionSubscriptionEventHandler.swift in Sources */, - 4B957B082AC7AE700062CA31 /* PixelDataStore.swift in Sources */, - 4B957B092AC7AE700062CA31 /* WaitlistStorage.swift in Sources */, - 4B957B0A2AC7AE700062CA31 /* Pixel.swift in Sources */, - 4B957B0B2AC7AE700062CA31 /* PixelEvent.swift in Sources */, - 4B957B0C2AC7AE700062CA31 /* TabBarFooter.swift in Sources */, - C168B9AE2B31DC7F001AFAD9 /* AutofillNeverPromptWebsitesManager.swift in Sources */, - 4B957B0D2AC7AE700062CA31 /* JSAlertViewModel.swift in Sources */, - 4B957B0E2AC7AE700062CA31 /* BookmarksBarCollectionViewItem.swift in Sources */, - B69A14FC2B4D705D00B9417D /* BookmarkFolderPicker.swift in Sources */, - 4B957B0F2AC7AE700062CA31 /* FileDownloadError.swift in Sources */, - 4B957B102AC7AE700062CA31 /* MoreOrLessView.swift in Sources */, - 4B957B122AC7AE700062CA31 /* History.xcdatamodeld in Sources */, - 4B957B132AC7AE700062CA31 /* PermissionStore.swift in Sources */, - EEC4A6612B277F1100F7C0AA /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */, - 4B957B142AC7AE700062CA31 /* PrivacyIconViewModel.swift in Sources */, - 4B957B152AC7AE700062CA31 /* ChromiumBookmarksReader.swift in Sources */, - B66CA4212AD910B300447CF0 /* DataImportView.swift in Sources */, - 4B957B162AC7AE700062CA31 /* Downloads.xcdatamodeld in Sources */, - 4B957B172AC7AE700062CA31 /* TabPreviewViewController.swift in Sources */, - 4B957B182AC7AE700062CA31 /* PreferencesDataClearingView.swift in Sources */, - 4B957B182AC7AE700062CA31 /* PreferencesDataClearingView.swift in Sources */, - 4B957B192AC7AE700062CA31 /* NSPasteboardExtension.swift in Sources */, - 4B957B1A2AC7AE700062CA31 /* OnboardingViewModel.swift in Sources */, - F1B33DF42BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */, - 4B957B1B2AC7AE700062CA31 /* ScriptSourceProviding.swift in Sources */, - 4B957B1C2AC7AE700062CA31 /* CoreDataBookmarkImporter.swift in Sources */, - 4B957B1D2AC7AE700062CA31 /* SuggestionViewModel.swift in Sources */, - 4B957B1E2AC7AE700062CA31 /* BookmarkManagedObject.swift in Sources */, - 4B957B1F2AC7AE700062CA31 /* CSVLoginExporter.swift in Sources */, - 4B957B202AC7AE700062CA31 /* NSAttributedStringExtension.swift in Sources */, - 4B957B212AC7AE700062CA31 /* AnimationView.swift in Sources */, - 4B957B222AC7AE700062CA31 /* NSRectExtension.swift in Sources */, - 4B957B232AC7AE700062CA31 /* WaitlistRootView.swift in Sources */, - 4B957B242AC7AE700062CA31 /* YoutubeOverlayUserScript.swift in Sources */, - 4B957B252AC7AE700062CA31 /* DictionaryExtension.swift in Sources */, - 4B957B262AC7AE700062CA31 /* Publishers.NestedObjectChanges.swift in Sources */, - 4B957B272AC7AE700062CA31 /* MenuItemSelectors.swift in Sources */, - 4B957B282AC7AE700062CA31 /* FaviconView.swift in Sources */, - 4B957B292AC7AE700062CA31 /* OnboardingFlow.swift in Sources */, - 4B957B2A2AC7AE700062CA31 /* PasswordManagementLoginModel.swift in Sources */, - 4B957B2B2AC7AE700062CA31 /* TabViewModel.swift in Sources */, - 4B957B2C2AC7AE700062CA31 /* TabDragAndDropManager.swift in Sources */, - B677FC572B064A9C0099EB04 /* DataImportViewModel.swift in Sources */, - 4B957B2D2AC7AE700062CA31 /* NSNotificationName+Favicons.swift in Sources */, - 4B957B2E2AC7AE700062CA31 /* PinningManager.swift in Sources */, - 4B957B2F2AC7AE700062CA31 /* SyncMetadataDatabase.swift in Sources */, - 4B957B302AC7AE700062CA31 /* TabCollectionViewModel+NSSecureCoding.swift in Sources */, - 4B957B312AC7AE700062CA31 /* StringExtension.swift in Sources */, - 4B957B322AC7AE700062CA31 /* EmailManagerRequestDelegate.swift in Sources */, - 4B957B332AC7AE700062CA31 /* ApplicationVersionReader.swift in Sources */, - 4B957B342AC7AE700062CA31 /* BookmarksBarViewController.swift in Sources */, - 4B957B352AC7AE700062CA31 /* PreferencesAutofillView.swift in Sources */, - 4B957B362AC7AE700062CA31 /* BurnerHomePageView.swift in Sources */, - 4B957B372AC7AE700062CA31 /* UserText+PasswordManager.swift in Sources */, - 4B957B382AC7AE700062CA31 /* LoadingProgressView.swift in Sources */, - 7BEC20472B0F505F00243D3E /* AddBookmarkFolderPopoverView.swift in Sources */, - 4B957B392AC7AE700062CA31 /* StatisticsStore.swift in Sources */, - EEC4A66B2B2C87D300F7C0AA /* VPNLocationView.swift in Sources */, - 4B957B3A2AC7AE700062CA31 /* BWInstallationService.swift in Sources */, - 4B957B3B2AC7AE700062CA31 /* BookmarksBarPromptPopover.swift in Sources */, - 4B957B3C2AC7AE700062CA31 /* NetworkProtectionInvitePresenter.swift in Sources */, - 4B957B3D2AC7AE700062CA31 /* ColorView.swift in Sources */, - 4B957B3E2AC7AE700062CA31 /* RecentlyClosedCacheItem.swift in Sources */, - 4B957B3F2AC7AE700062CA31 /* PopupBlockedPopover.swift in Sources */, - 4B957B402AC7AE700062CA31 /* SaveCredentialsPopover.swift in Sources */, - 4B957B412AC7AE700062CA31 /* LegacyBookmarksStoreMigration.swift in Sources */, - 4B957B422AC7AE700062CA31 /* QuartzIdleStateProvider.swift in Sources */, - 4B957B432AC7AE700062CA31 /* DuckPlayerPreferences.swift in Sources */, - 4B957B442AC7AE700062CA31 /* DownloadViewModel.swift in Sources */, - 4B957B452AC7AE700062CA31 /* BookmarkHTMLReader.swift in Sources */, - 4B957B462AC7AE700062CA31 /* Tab+NSSecureCoding.swift in Sources */, - 4B957B472AC7AE700062CA31 /* NSNotificationName+EmailManager.swift in Sources */, - B6619EFE2B111CCC00CD9186 /* InstructionsFormatParser.swift in Sources */, - 1DDD3EC22B84F5D5004CBF2B /* PreferencesCookiePopupProtectionView.swift in Sources */, - 4B957B482AC7AE700062CA31 /* MouseOverButton.swift in Sources */, - 4B957B492AC7AE700062CA31 /* FireInfoViewController.swift in Sources */, - 4B957B4A2AC7AE700062CA31 /* LoginItem+NetworkProtection.swift in Sources */, - B6C8CAAA2AD010DD0060E1CD /* YandexDataImporter.swift in Sources */, - 4B957B4B2AC7AE700062CA31 /* PermissionButton.swift in Sources */, - 4B957B4C2AC7AE700062CA31 /* MoreOptionsMenu.swift in Sources */, - 4B957B4D2AC7AE700062CA31 /* PermissionAuthorizationViewController.swift in Sources */, - EE6666712B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */, - 4B957B4E2AC7AE700062CA31 /* BookmarkNode.swift in Sources */, - 4B957B4F2AC7AE700062CA31 /* LongPressButton.swift in Sources */, - 4B957B502AC7AE700062CA31 /* CoreDataStore.swift in Sources */, - 4B957B512AC7AE700062CA31 /* BundleExtension.swift in Sources */, - 4B957B522AC7AE700062CA31 /* NSOpenPanelExtensions.swift in Sources */, - EEC4A66F2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift in Sources */, - 4B957B532AC7AE700062CA31 /* FirePopover.swift in Sources */, - 4B957B552AC7AE700062CA31 /* NetworkProtectionOnboardingMenu.swift in Sources */, - 4B957B562AC7AE700062CA31 /* VariantManager.swift in Sources */, - 4B957B572AC7AE700062CA31 /* ApplicationDockMenu.swift in Sources */, - 4B957B582AC7AE700062CA31 /* SaveIdentityViewController.swift in Sources */, - 4B957B592AC7AE700062CA31 /* AppLauncher.swift in Sources */, - 4B957B5A2AC7AE700062CA31 /* FileStore.swift in Sources */, - 1DB67F2F2B6FEFDB003DF243 /* ViewSnapshotRenderer.swift in Sources */, - 4B957B5B2AC7AE700062CA31 /* PixelArguments.swift in Sources */, - 4B957B5C2AC7AE700062CA31 /* PinnedTabsViewModel.swift in Sources */, - 4B957B5D2AC7AE700062CA31 /* BookmarkList.swift in Sources */, - 4B957B5E2AC7AE700062CA31 /* NEOnDemandRuleExtension.swift in Sources */, - 1DB67F2B2B6FEB19003DF243 /* WebViewSnapshotRenderer.swift in Sources */, - 4B957B5F2AC7AE700062CA31 /* BookmarkTableRowView.swift in Sources */, - 4B957B602AC7AE700062CA31 /* FavoritesView.swift in Sources */, - 3158B1522B0BF75400AF130C /* DataBrokerProtectionLoginItemScheduler.swift in Sources */, - 4B957B612AC7AE700062CA31 /* HomePage.swift in Sources */, - 4B957B622AC7AE700062CA31 /* RoundedSelectionRowView.swift in Sources */, - B6A22B652B1E29D000ECD2BA /* DataImportSummaryViewModel.swift in Sources */, - 9FA173E12B7A0EFE00EE4E6E /* BookmarkDialogButtonsView.swift in Sources */, - 4B957B632AC7AE700062CA31 /* LocalStatisticsStore.swift in Sources */, - 4B957B642AC7AE700062CA31 /* BackForwardListItem.swift in Sources */, - 4B957B672AC7AE700062CA31 /* AtbAndVariantCleanup.swift in Sources */, - 4B957B692AC7AE700062CA31 /* FeedbackWindow.swift in Sources */, - 4B957B6A2AC7AE700062CA31 /* WorkspaceProtocol.swift in Sources */, - 4B957B6B2AC7AE700062CA31 /* RecentlyVisitedView.swift in Sources */, - 4B957B6C2AC7AE700062CA31 /* MouseOverAnimationButton.swift in Sources */, - 4B957B6D2AC7AE700062CA31 /* TabBarScrollView.swift in Sources */, - B6B5F5822B024105008DB58A /* DataImportSummaryView.swift in Sources */, - B684121E2B6A1D880092F66A /* ErrorPageHTMLTemplate.swift in Sources */, - 4B957B6E2AC7AE700062CA31 /* BookmarkListTreeControllerDataSource.swift in Sources */, - 4B957B6F2AC7AE700062CA31 /* AddressBarViewController.swift in Sources */, - 4B957B702AC7AE700062CA31 /* Permissions.swift in Sources */, - 4B957B712AC7AE700062CA31 /* TabPreviewWindowController.swift in Sources */, - 4B957B722AC7AE700062CA31 /* NSSizeExtension.swift in Sources */, - 4B957B732AC7AE700062CA31 /* Fire.swift in Sources */, - 1DDC84FD2B8356CE00670238 /* PreferencesDefaultBrowserView.swift in Sources */, - 4B957B742AC7AE700062CA31 /* SyncBookmarksAdapter.swift in Sources */, - B6ABC5982B4861D4008343B9 /* FocusableTextField.swift in Sources */, - 4B957B752AC7AE700062CA31 /* RandomAccessCollectionExtension.swift in Sources */, - 4B957B762AC7AE700062CA31 /* NSOutlineViewExtensions.swift in Sources */, - 4B957B772AC7AE700062CA31 /* AppDelegate.swift in Sources */, - 4B957B782AC7AE700062CA31 /* ContentOverlayViewController.swift in Sources */, - 4B957B792AC7AE700062CA31 /* ContentBlockingTabExtension.swift in Sources */, - 4B957B7A2AC7AE700062CA31 /* OnboardingViewController.swift in Sources */, - B68412292B6A68C90092F66A /* WKBackForwardListItemExtension.swift in Sources */, - 4B957B7B2AC7AE700062CA31 /* DeviceAuthenticator.swift in Sources */, - 4B957B7C2AC7AE700062CA31 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift in Sources */, - 4B957B7D2AC7AE700062CA31 /* TabBarCollectionView.swift in Sources */, - C1DAF3B72B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */, - 4B957B7E2AC7AE700062CA31 /* NetworkProtection+ConvenienceInitializers.swift in Sources */, - 7BA7CC502AD11F6F0042E5CE /* NetworkProtectionIPCTunnelController.swift in Sources */, - 4B957B7F2AC7AE700062CA31 /* NavigationActionExtension.swift in Sources */, - F1B33DF82BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */, - 4B957B802AC7AE700062CA31 /* NSAlertExtension.swift in Sources */, - 4B957B812AC7AE700062CA31 /* ThirdPartyBrowser.swift in Sources */, - 4B957B822AC7AE700062CA31 /* SearchNonexistentDomainNavigationResponder.swift in Sources */, - 4B6B64862BA930420009FF9F /* WaitlistThankYouPromptPresenter.swift in Sources */, - B6B71C5A2B23379600487131 /* NSLayoutConstraintExtension.swift in Sources */, - B65211272B29A43000B30633 /* BookmarkStoreMock.swift in Sources */, - 4B957B832AC7AE700062CA31 /* CircularProgressView.swift in Sources */, - 4B957B842AC7AE700062CA31 /* SuggestionContainer.swift in Sources */, - 4B957B852AC7AE700062CA31 /* FindInPageTabExtension.swift in Sources */, - 4B957B862AC7AE700062CA31 /* HomePageViewController.swift in Sources */, - 4B957B882AC7AE700062CA31 /* OperatingSystemVersionExtension.swift in Sources */, - 4B957B892AC7AE700062CA31 /* ToggleableScrollView.swift in Sources */, - 4B957B8A2AC7AE700062CA31 /* TabCleanupPreparer.swift in Sources */, - 4B37EE7B2B4CFF7C00A89A61 /* HomePageRemoteMessagingStorage.swift in Sources */, - 4B957B8B2AC7AE700062CA31 /* NetworkProtectionOptionKeyExtension.swift in Sources */, - 372A0FEE2B2379310033BF7F /* SyncMetricsEventsHandler.swift in Sources */, - 316850702AF3AD1D009A2828 /* WaitlistViewControllerPresenter.swift in Sources */, - 1E2AE4CB2ACB21C800684E0A /* HardwareModel.swift in Sources */, - 4B957B8C2AC7AE700062CA31 /* UserScripts.swift in Sources */, - 4B957B8D2AC7AE700062CA31 /* NSWorkspaceExtension.swift in Sources */, - 4B957B8E2AC7AE700062CA31 /* AutofillTabExtension.swift in Sources */, - 4B957B8F2AC7AE700062CA31 /* Assertions.swift in Sources */, - 4B0EF7282B5780AB009D6481 /* AppVersionExtension.swift in Sources */, - 4B957B902AC7AE700062CA31 /* BookmarkViewModel.swift in Sources */, - 4B957B912AC7AE700062CA31 /* DaxSpeech.swift in Sources */, - BB5789732B2CC0300009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift in Sources */, - 4B957B922AC7AE700062CA31 /* DuckURLSchemeHandler.swift in Sources */, - 4B957B932AC7AE700062CA31 /* FirePopoverViewModel.swift in Sources */, - 4B957B942AC7AE700062CA31 /* BWCommand.swift in Sources */, - 4B957B952AC7AE700062CA31 /* NSColorExtension.swift in Sources */, - 4B957B972AC7AE700062CA31 /* AddressBarButtonsViewController.swift in Sources */, - 4B957B982AC7AE700062CA31 /* BWError.swift in Sources */, - 4B957B9A2AC7AE700062CA31 /* PixelDataRecord.swift in Sources */, - 4B957B9B2AC7AE700062CA31 /* PageObserverUserScript.swift in Sources */, - 4B957B9C2AC7AE700062CA31 /* SecureVaultErrorReporter.swift in Sources */, - 4B68DDFF2ACBA14100FB0973 /* FileLineError.swift in Sources */, - 4B957B9D2AC7AE700062CA31 /* NSImageExtensions.swift in Sources */, - 4B957B9E2AC7AE700062CA31 /* WaitlistKeychainStorage.swift in Sources */, - B69A14F82B4D701F00B9417D /* AddBookmarkPopoverViewModel.swift in Sources */, - 4B957B9F2AC7AE700062CA31 /* PasswordManagementViewController.swift in Sources */, - 4B957BA02AC7AE700062CA31 /* ImportedBookmarks.swift in Sources */, - 4B957BA12AC7AE700062CA31 /* UserDefaults+NetworkProtectionShared.swift in Sources */, - 4B957BA22AC7AE700062CA31 /* NavigationActionPolicyExtension.swift in Sources */, - 4B957BA32AC7AE700062CA31 /* CIImageExtension.swift in Sources */, - 9F56CFAB2B82DC4300BB7F11 /* AddEditBookmarkFolderView.swift in Sources */, - 9FA173DC2B79BD8A00EE4E6E /* BookmarkDialogContainerView.swift in Sources */, - 4B957BA42AC7AE700062CA31 /* NSMenuExtension.swift in Sources */, - 4B957BA52AC7AE700062CA31 /* MainWindowController.swift in Sources */, - 4B957BA62AC7AE700062CA31 /* Tab.swift in Sources */, - 4B957BA72AC7AE700062CA31 /* ConnectBitwardenView.swift in Sources */, - 4B957BA82AC7AE700062CA31 /* DispatchQueueExtensions.swift in Sources */, - 4B957BA92AC7AE700062CA31 /* BookmarksBarAppearance.swift in Sources */, - 31C9ADE82AF0564500CEF57D /* WaitlistFeatureSetupHandler.swift in Sources */, - 3158B1472B0BF72E00AF130C /* DBPHomeViewController.swift in Sources */, - 4B957BAA2AC7AE700062CA31 /* PermissionAuthorizationPopover.swift in Sources */, - 4B957BAB2AC7AE700062CA31 /* PopoverMessageViewController.swift in Sources */, - 4B957BAC2AC7AE700062CA31 /* WebView.swift in Sources */, - 4B957BAD2AC7AE700062CA31 /* ShadowView.swift in Sources */, - 4B957BAE2AC7AE700062CA31 /* FeedbackSender.swift in Sources */, - 4B957BAF2AC7AE700062CA31 /* TabExtensions.swift in Sources */, - 4B957BB02AC7AE700062CA31 /* TabBarViewItem.swift in Sources */, - 4B957BB12AC7AE700062CA31 /* NSWindow+Toast.swift in Sources */, - 4B0526652B1D55D80054955A /* VPNFeedbackCategory.swift in Sources */, - 4B957BB22AC7AE700062CA31 /* AutoconsentUserScript.swift in Sources */, - 4B957BB32AC7AE700062CA31 /* BookmarksExporter.swift in Sources */, - 4B957BB42AC7AE700062CA31 /* NetworkProtectionAppEvents.swift in Sources */, - 4B957BB52AC7AE700062CA31 /* FirefoxDataImporter.swift in Sources */, - 4B957BB62AC7AE700062CA31 /* PreferencesGeneralView.swift in Sources */, - 4B957BB72AC7AE700062CA31 /* PinnedTabsView.swift in Sources */, - 4B957BB92AC7AE700062CA31 /* SyncErrorHandler.swift in Sources */, - 4BF0E50A2AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, - 4B957BBA2AC7AE700062CA31 /* URLExtension.swift in Sources */, - 4B957BBB2AC7AE700062CA31 /* Tab+UIDelegate.swift in Sources */, - 4B957BBD2AC7AE700062CA31 /* NSStoryboardExtension.swift in Sources */, - 4B957BBE2AC7AE700062CA31 /* PreferencesViewController.swift in Sources */, - 4B957BBF2AC7AE700062CA31 /* FireproofDomains.swift in Sources */, - 4B957BC02AC7AE700062CA31 /* Database.swift in Sources */, - 4B957BC12AC7AE700062CA31 /* HorizontallyCenteredLayout.swift in Sources */, - 4B957BC22AC7AE700062CA31 /* BookmarksOutlineView.swift in Sources */, - 4B957BC32AC7AE700062CA31 /* CountryList.swift in Sources */, - 4B957BC42AC7AE700062CA31 /* PreferencesSection.swift in Sources */, - 4B957BC52AC7AE700062CA31 /* NetworkProtectionNavBarButtonModel.swift in Sources */, - 4B957BC62AC7AE700062CA31 /* AutoconsentManagement.swift in Sources */, - 4B957BC72AC7AE700062CA31 /* UserText+NetworkProtection.swift in Sources */, - 4B957BC82AC7AE700062CA31 /* WebViewContainerView.swift in Sources */, - 4B957BC92AC7AE700062CA31 /* BookmarkStore.swift in Sources */, - 4B957BCA2AC7AE700062CA31 /* PrivacyDashboardViewController.swift in Sources */, - 37A6A8F42AFCC988008580A3 /* FaviconsFetcherOnboarding.swift in Sources */, - 4B957BCB2AC7AE700062CA31 /* PreferencesAppearanceView.swift in Sources */, - 4B957BCC2AC7AE700062CA31 /* NSMenuItemExtension.swift in Sources */, - 4B957BCD2AC7AE700062CA31 /* ContiguousBytesExtension.swift in Sources */, - 7B7FCD112BA33B2700C04FBE /* UserDefaults+vpnLegacyUser.swift in Sources */, - 4B957BCE2AC7AE700062CA31 /* AdjacentItemEnumerator.swift in Sources */, - 4B957BCF2AC7AE700062CA31 /* BookmarkDatabase.swift in Sources */, - 4B957BD02AC7AE700062CA31 /* ChromiumKeychainPrompt.swift in Sources */, - 4B957BD12AC7AE700062CA31 /* WKProcessPool+GeolocationProvider.swift in Sources */, - 4B957BD22AC7AE700062CA31 /* RecentlyClosedMenu.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 565E46D92B2725DC0013AC2A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -12211,11 +10692,16 @@ buildActionMask = 2147483647; files = ( EEBCE6842BA4643200B9DF00 /* NSSizeExtension.swift in Sources */, + EE7F74912BB5D76600CD9456 /* BookmarksBarTests.swift in Sources */, EE02D41C2BB460A600DBE6B3 /* BrowsingHistoryTests.swift in Sources */, EE02D41A2BB4609900DBE6B3 /* UITests.swift in Sources */, EE0429E02BA31D2F009EB20F /* FindInPageTests.swift in Sources */, EE02D4212BB460FE00DBE6B3 /* StringExtension.swift in Sources */, + EE9D81C32BC57A3700338BE3 /* StateRestorationTests.swift in Sources */, + EEC7BE2E2BC6C09500F86835 /* AddressBarKeyboardShortcutsTests.swift in Sources */, + EE54F7B32BBFEA49006218DB /* BookmarksAndFavoritesTests.swift in Sources */, EE02D4222BB4611A00DBE6B3 /* TestsURLExtension.swift in Sources */, + EE42CBCC2BC8004700AD411C /* PermissionsTests.swift in Sources */, 7B4CE8E726F02135009134B1 /* TabBarTests.swift in Sources */, EEBCE6832BA463DD00B9DF00 /* NSImageExtensions.swift in Sources */, EEBCE6822BA444FA00B9DF00 /* XCUIElementExtension.swift in Sources */, @@ -12228,7 +10714,6 @@ buildActionMask = 2147483647; files = ( 7B97CD5C2B7E0BBB004FEF43 /* UserDefaultsWrapper.swift in Sources */, - 7B97CD602B7E0C2E004FEF43 /* Logging.swift in Sources */, 7B97CD5E2B7E0BEA004FEF43 /* OptionalExtension.swift in Sources */, 7B97CD5F2B7E0BF7004FEF43 /* NSApplicationExtension.swift in Sources */, 7BDA36F52B7E055800AD5388 /* MacTransparentProxyProvider.swift in Sources */, @@ -12240,6 +10725,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 31A83FB72BE28D8A00F74E67 /* UserText+DBP.swift in Sources */, 9D9AE92C2AAB84FF0026E7DC /* DBPMocks.swift in Sources */, 7B0099792B65013800FE7C31 /* BrowserWindowManager.swift in Sources */, 9D9AE9292AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */, @@ -12253,6 +10739,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 31A83FB82BE28D8A00F74E67 /* UserText+DBP.swift in Sources */, 7B1459542B7D437200047F2C /* BrowserWindowManager.swift in Sources */, 9D9AE92D2AAB84FF0026E7DC /* DBPMocks.swift in Sources */, 9D9AE92A2AAA43EB0026E7DC /* DataBrokerProtectionBackgroundManager.swift in Sources */, @@ -12283,11 +10770,14 @@ 0230C0A3272080090018F728 /* KeyedCodingExtension.swift in Sources */, 31AA6B972B960B870025014E /* DataBrokerProtectionLoginItemPixels.swift in Sources */, B6BF5D852946FFDA006742B1 /* PrivacyDashboardTabExtension.swift in Sources */, + B6E3E55B2BC0041900A41922 /* DownloadListStoreMock.swift in Sources */, + 9FA5A0A52BC8F34900153786 /* UserDefaultsBookmarkFoldersStore.swift in Sources */, B6C0B23026E61D630031CB7F /* DownloadListStore.swift in Sources */, 85799C1825DEBB3F0007EC87 /* Logging.swift in Sources */, AAC30A2E268F1EE300D2D9CD /* CrashReportPromptPresenter.swift in Sources */, 1D2DC00629016798008083A1 /* BWCredential.swift in Sources */, EEA3EEB12B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */, + 316913232BD2B6250051B46D /* DataBrokerProtectionPixelsHandler.swift in Sources */, 37AFCE8727DA334800471A10 /* PreferencesRootView.swift in Sources */, B684590825C9027900DC17B6 /* AppStateChangedPublisher.swift in Sources */, 4B92928F26670D1700AD2C21 /* BookmarkTableCellView.swift in Sources */, @@ -12334,6 +10824,7 @@ 85AC7ADD27BEB6EE00FFB69B /* HomePageDefaultBrowserModel.swift in Sources */, 1D01A3D82B88DF8B00FE8150 /* PreferencesSyncView.swift in Sources */, B6619EFB2B111CC500CD9186 /* InstructionsFormatParser.swift in Sources */, + 9FBD84522BB3AACB00220859 /* AttributionOriginFileProvider.swift in Sources */, 1DC669702B6CF0D700AA0645 /* TabSnapshotStore.swift in Sources */, AAC30A26268DFEE200D2D9CD /* CrashReporter.swift in Sources */, B60D64492AAF1B7C00B26F50 /* AddressBarTextSelectionNavigation.swift in Sources */, @@ -12345,12 +10836,12 @@ 1D26EBAC2B74BECB0002A93F /* NSImageSendable.swift in Sources */, B6B4D1C52B0B3B5400C26286 /* DataImportReportModel.swift in Sources */, 4B92928D26670D1700AD2C21 /* BookmarkOutlineCellView.swift in Sources */, + F18826802BBEB58100D9AC4F /* PrivacyProPixel.swift in Sources */, B604085C274B8FBA00680351 /* UnprotectedDomains.xcdatamodeld in Sources */, 4BB88B5025B7BA2B006F6B06 /* TabInstrumentation.swift in Sources */, 85D33F1225C82EB3002B91A6 /* ConfigurationManager.swift in Sources */, 31F28C4F28C8EEC500119F70 /* YoutubePlayerUserScript.swift in Sources */, 4B41EDAE2B168AFF001EEDF4 /* VPNFeedbackFormViewController.swift in Sources */, - B6A9E48426146AAB0067D1B9 /* PixelParameters.swift in Sources */, AA5FA697275F90C400DCE9C9 /* FaviconImageCache.swift in Sources */, 1430DFF524D0580F00B8978C /* TabBarViewController.swift in Sources */, B62B483E2ADE48DE000DECE5 /* ArrayBuilder.swift in Sources */, @@ -12367,8 +10858,10 @@ AA3D531727A1EEED00074EC1 /* FeedbackViewController.swift in Sources */, AAEF6BC8276A081C0024DCF4 /* FaviconSelector.swift in Sources */, 4B2E7D6326FF9D6500D2DB17 /* PrintingUserScript.swift in Sources */, + B6E3E5542BBFCEE300A41922 /* NoDownloadsCellView.swift in Sources */, 4BBDEE9428FC14760092FAA6 /* ConnectBitwardenViewController.swift in Sources */, 1DDF076428F815AD00EDFBE3 /* BWManager.swift in Sources */, + 560C3FFF2BCD5A1E00F589CE /* PermanentSurveyManager.swift in Sources */, 9833912F27AAA3CE00DAF119 /* AppTrackerDataSetProvider.swift in Sources */, B65211252B29A42C00B30633 /* BookmarkStoreMock.swift in Sources */, 4BA1A6B3258B080A00F6F690 /* EncryptionKeyGeneration.swift in Sources */, @@ -12376,7 +10869,6 @@ 4B9DB03B2A983B24000927DB /* InvitedToWaitlistView.swift in Sources */, 8589063C267BCDC000D23B0D /* SaveCredentialsViewController.swift in Sources */, 4BBE0AA727B9B027003B37A8 /* PopUpButton.swift in Sources */, - 4B4D60CF2A0C849600BCD287 /* NetworkProtectionInviteDialog.swift in Sources */, AABEE6A524AA0A7F0043105B /* SuggestionViewController.swift in Sources */, 1D6216B229069BBF00386B2C /* BWKeyStorage.swift in Sources */, AA7E919F287872EA00AB6B62 /* VisitViewModel.swift in Sources */, @@ -12393,6 +10885,8 @@ 858A798326A8B75F00A75A42 /* CopyHandler.swift in Sources */, 1E7E2E9029029A2A00C01B54 /* ContentBlockingRulesUpdateObserver.swift in Sources */, 4B8AC93926B48A5100879451 /* FirefoxLoginReader.swift in Sources */, + F18826902BC0105800D9AC4F /* PixelDataRecord.swift in Sources */, + F18826912BC0105800D9AC4F /* PixelDataStore.swift in Sources */, B69B503E2726A12500758A2B /* AtbParser.swift in Sources */, 37F19A6528E1B3FB00740DC6 /* PreferencesDuckPlayerView.swift in Sources */, 4B92929E26670D2A00AD2C21 /* BookmarkSidebarTreeController.swift in Sources */, @@ -12421,11 +10915,13 @@ 4B379C2227BDBA29008A968E /* LocalAuthenticationService.swift in Sources */, 37CEFCA92A6737A2001EF741 /* CredentialsCleanupErrorHandling.swift in Sources */, 4BB99D0326FE191E001E4761 /* SafariBookmarksReader.swift in Sources */, + 316913292BD2C7570051B46D /* DataBrokerProtectionErrorViewController.swift in Sources */, 1DA6D0FD2A1FF9A100540406 /* HTTPCookie.swift in Sources */, AACF6FD626BC366D00CF09F9 /* SafariVersionReader.swift in Sources */, 4BE65485271FCD7B008D1D63 /* LoginFaviconView.swift in Sources */, 4B0511CA262CAA5A00F6079C /* FireproofDomainsViewController.swift in Sources */, AA4D700725545EF800C3411E /* URLEventHandler.swift in Sources */, + 56BA1E8A2BB1CB5B001CF69F /* CertificateTrustEvaluator.swift in Sources */, 1D8057C82A83CAEE00F4FED6 /* SupportedOsChecker.swift in Sources */, AA92127725ADA07900600CD4 /* WKWebViewExtension.swift in Sources */, AAAB9114288EB1D600A057A9 /* CleanThisHistoryMenuItem.swift in Sources */, @@ -12495,6 +10991,7 @@ 37054FCE2876472D00033B6F /* WebViewSnapshotView.swift in Sources */, 4BBC16A027C4859400E00A38 /* DeviceAuthenticationService.swift in Sources */, CB24F70C29A3D9CB006DCC58 /* AppConfigurationURLProvider.swift in Sources */, + 1DEF3BAD2BD145A9004A2FBA /* AutoClearHandler.swift in Sources */, 37CBCA9A2A8966E60050218F /* SyncSettingsAdapter.swift in Sources */, EEC4A66D2B2C894F00F7C0AA /* VPNLocationPreferenceItemModel.swift in Sources */, 3776582F27F82E62009A6B35 /* AutofillPreferences.swift in Sources */, @@ -12541,7 +11038,6 @@ 3184AC6F288F2A1100C35E4B /* CookieNotificationAnimationModel.swift in Sources */, 4B9DB0382A983B24000927DB /* JoinedWaitlistView.swift in Sources */, B63ED0E526BB8FB900A9DAD1 /* SharingMenu.swift in Sources */, - 4B9DB0322A983B24000927DB /* EnableWaitlistFeatureView.swift in Sources */, AA4FF40C2624751A004E2377 /* GrammarFeaturesManager.swift in Sources */, 4B9DB0442A983B24000927DB /* WaitlistModalViewController.swift in Sources */, B6DA06E8291401D700225DE2 /* WKMenuItemIdentifier.swift in Sources */, @@ -12572,7 +11068,6 @@ B68412142B694BA10092F66A /* NSObject+performSelector.m in Sources */, B6F41031264D2B23003DA42C /* ProgressExtension.swift in Sources */, 4B723E0F26B0006500E14D75 /* CSVParser.swift in Sources */, - B6DA44082616B30600DD1EC2 /* PixelDataModel.xcdatamodeld in Sources */, B63BDF7E27FDAA640072D75B /* PrivacyDashboardWebView.swift in Sources */, 37CD54CF27F2FDD100F1F7B9 /* AppearancePreferences.swift in Sources */, B6B1E87B26D381710062C350 /* DownloadListCoordinator.swift in Sources */, @@ -12652,6 +11147,7 @@ 85707F2A276A35FE00DC0649 /* ActionSpeech.swift in Sources */, B6BE9FAA293F7955006363C6 /* ModalSheetCancellable.swift in Sources */, B6830963274CDEC7004B46BB /* FireproofDomainsStore.swift in Sources */, + F188268D2BBF01C300D9AC4F /* PixelDataModel.xcdatamodeld in Sources */, 7B430EA12A71411A00BAC4A1 /* NetworkProtectionSimulateFailureMenu.swift in Sources */, 1E7E2E942902AC0E00C01B54 /* PrivacyDashboardPermissionHandler.swift in Sources */, AA9FF95F24A1FB690039E328 /* TabCollectionViewModel.swift in Sources */, @@ -12659,6 +11155,7 @@ 4BF0E5052AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, AAC5E4D125D6A709007F5990 /* BookmarkManager.swift in Sources */, 37CD54CD27F2FDD100F1F7B9 /* AboutModel.swift in Sources */, + B6F1B0262BCE5A50005E863C /* TabContent.swift in Sources */, 4BE65476271FCD41008D1D63 /* PasswordManagementCreditCardItemView.swift in Sources */, AA5C8F59258FE21F00748EB7 /* NSTextFieldExtension.swift in Sources */, 3706FEC8293F6F7500E42796 /* BWManagement.swift in Sources */, @@ -12681,10 +11178,12 @@ B6DE57F62B05EA9000CD54B9 /* SheetHostingWindow.swift in Sources */, AA6EF9B525081B4C004754E6 /* MainMenuActions.swift in Sources */, B63D466925BEB6C200874977 /* WKWebView+SessionState.swift in Sources */, + B6F1B0222BCE5658005E863C /* BrokenSiteInfoTabExtension.swift in Sources */, 4B4D60C02A0C848D00BCD287 /* NetworkProtectionControllerErrorStore.swift in Sources */, 4B723E1226B0006E00E14D75 /* DataImport.swift in Sources */, 7BE146072A6A83C700C313B8 /* NetworkProtectionDebugMenu.swift in Sources */, B6085D092743AAB600A9C456 /* FireproofDomains.xcdatamodeld in Sources */, + 56BA1E752BAAF70F001CF69F /* SSLErrorPageTabExtension.swift in Sources */, 85589E8227BBB8630038AD11 /* HomePageView.swift in Sources */, B6BF5D932947199A006742B1 /* SerpHeadersNavigationResponder.swift in Sources */, 569277C129DDCBB500B633EF /* HomePageContinueSetUpModel.swift in Sources */, @@ -12697,6 +11196,7 @@ 85D885B326A5A9DE0077C374 /* NSAlert+PasswordManager.swift in Sources */, 983DFB2528B67036006B7E34 /* UserContentUpdating.swift in Sources */, 1D9A4E5A2B43213B00F449E2 /* TabSnapshotExtension.swift in Sources */, + 316913262BD2B76F0051B46D /* DataBrokerPrerequisitesStatusVerifier.swift in Sources */, 4B7A57CF279A4EF300B1C70E /* ChromiumPreferences.swift in Sources */, AA6AD95B2704B6DB00159F8A /* FirePopoverViewController.swift in Sources */, 4BE4005327CF3DC3007D3161 /* SavePaymentMethodPopover.swift in Sources */, @@ -12706,6 +11206,7 @@ AA6FFB4424DC33320028F4D0 /* NSViewExtension.swift in Sources */, B6C0B23E26E8BF1F0031CB7F /* DownloadListViewModel.swift in Sources */, 4B9292D52667123700AD2C21 /* BookmarkManagementDetailViewController.swift in Sources */, + F188267C2BBEB3AA00D9AC4F /* GeneralPixel.swift in Sources */, 4B723E1026B0006700E14D75 /* CSVImporter.swift in Sources */, 37A4CEBA282E992F00D75B89 /* StartupPreferences.swift in Sources */, 4B41EDB12B168B1E001EEDF4 /* VPNFeedbackFormView.swift in Sources */, @@ -12718,8 +11219,6 @@ AAE246F32709EF3B00BEEAEE /* FirePopoverCollectionViewItem.swift in Sources */, 4B41EDA32B1543B9001EEDF4 /* VPNPreferencesModel.swift in Sources */, AA61C0D22727F59B00E6B681 /* ArrayExtension.swift in Sources */, - 4B4D60CC2A0C849600BCD287 /* NetworkProtectionInviteCodeViewModel.swift in Sources */, - AAC30A2C268F1ECD00D2D9CD /* CrashReportSender.swift in Sources */, 373A1AB02842C4EA00586521 /* BookmarkHTMLImporter.swift in Sources */, B6B5F57F2B024105008DB58A /* DataImportSummaryView.swift in Sources */, 31C3CE0228EDC1E70002C24A /* CustomRoundedCornersShape.swift in Sources */, @@ -12755,10 +11254,10 @@ B65783E725F8AAFB00D8DB33 /* String+Punycode.swift in Sources */, B657841A25FA484B00D8DB33 /* NSException+Catch.m in Sources */, B684592F25C93FBF00DC17B6 /* AppStateRestorationManager.swift in Sources */, - 4B67853F2AA7C726008A5004 /* DailyPixel.swift in Sources */, B66260E629ACAE4B00E9E3EE /* NavigationHotkeyHandler.swift in Sources */, EA0BA3A9272217E6002A0B6C /* ClickToLoadUserScript.swift in Sources */, AAA892EA250A4CEF005B37B2 /* WindowControllersManager.swift in Sources */, + 56BA1E822BAC506F001CF69F /* SSLErrorPageUserScript.swift in Sources */, 85C5991B27D10CF000E605B2 /* FireAnimationView.swift in Sources */, B6B4D1CA2B0C8C9200C26286 /* FirefoxCompatibilityPreferences.swift in Sources */, AA6197C4276B314D008396F0 /* FaviconUrlReference.swift in Sources */, @@ -12778,14 +11277,12 @@ AAD86E52267A0DFF005C11BE /* UpdateController.swift in Sources */, 85A0118225AF60E700FA6A0C /* FindInPageModel.swift in Sources */, 7BA7CC4E2AD11F6F0042E5CE /* NetworkProtectionIPCTunnelController.swift in Sources */, + 9F9C49FD2BC7E9830099738D /* BookmarkAllTabsDialogViewModel.swift in Sources */, 4B9292A226670D2A00AD2C21 /* PseudoFolder.swift in Sources */, 1DDD3EC42B84F96B004CBF2B /* CookiePopupProtectionPreferences.swift in Sources */, 4BCF15D92ABB8A7F0083F6DF /* NetworkProtectionRemoteMessage.swift in Sources */, 4B05265E2B1AE5C70054955A /* VPNMetadataCollector.swift in Sources */, - B6DA44022616B28300DD1EC2 /* PixelDataStore.swift in Sources */, 4B9DB0292A983B24000927DB /* WaitlistStorage.swift in Sources */, - B6A9E45326142B070067D1B9 /* Pixel.swift in Sources */, - B6A9E47726146A570067D1B9 /* PixelEvent.swift in Sources */, AA2CB1352587C29500AA6FBE /* TabBarFooter.swift in Sources */, EEC111E6294D06290086524F /* JSAlertViewModel.swift in Sources */, 4BE5336C286912D40019DBFD /* BookmarksBarCollectionViewItem.swift in Sources */, @@ -12797,7 +11294,9 @@ AA75A0AE26F3500C0086B667 /* PrivacyIconViewModel.swift in Sources */, 4BB99D0126FE191E001E4761 /* ChromiumBookmarksReader.swift in Sources */, B6C0B23426E71BCD0031CB7F /* Downloads.xcdatamodeld in Sources */, + 9FBD84732BB3E15D00220859 /* InstallationAttributionPixelHandler.swift in Sources */, AAE8B110258A456C00E81239 /* TabPreviewViewController.swift in Sources */, + B6F1B02A2BCE675C005E863C /* NetworkProtectionControllerTabExtension.swift in Sources */, B6C8CAA72AD010DD0060E1CD /* YandexDataImporter.swift in Sources */, EE66666F2B56EDE4001D898D /* VPNLocationsHostingViewController.swift in Sources */, 37CC53EC27E8A4D10028713D /* PreferencesDataClearingView.swift in Sources */, @@ -12821,10 +11320,12 @@ 4B37EE5F2B4CFC3C00A89A61 /* HomePageRemoteMessagingStorage.swift in Sources */, 4B9DB0472A983B24000927DB /* WaitlistRootView.swift in Sources */, 31F28C5128C8EEC500119F70 /* YoutubeOverlayUserScript.swift in Sources */, + B6ABD0CA2BC03F610000EB69 /* SecurityScopedFileURLController.swift in Sources */, B6040856274B830F00680351 /* DictionaryExtension.swift in Sources */, B684592725C93C0500DC17B6 /* Publishers.NestedObjectChanges.swift in Sources */, B6DA06E62913F39400225DE2 /* MenuItemSelectors.swift in Sources */, 85589E9A27BFE3C30038AD11 /* FaviconView.swift in Sources */, + 021EA0802BD2A9D500772C9A /* TabsPreferences.swift in Sources */, 85707F2C276A364E00DC0649 /* OnboardingFlow.swift in Sources */, 4BE65480271FCD4D008D1D63 /* PasswordManagementLoginModel.swift in Sources */, AA9FF95B24A1EFC20039E328 /* TabViewModel.swift in Sources */, @@ -12845,13 +11346,14 @@ B69B503C2726A12500758A2B /* StatisticsStore.swift in Sources */, 3158B14A2B0BF74300AF130C /* DataBrokerProtectionDebugMenu.swift in Sources */, 4BBDEE9128FC14760092FAA6 /* BWInstallationService.swift in Sources */, + 7B4D8A212BDA857300852966 /* VPNOperationErrorRecorder.swift in Sources */, 859F30642A72A7BB00C20372 /* BookmarksBarPromptPopover.swift in Sources */, - 4B4D60CA2A0C849600BCD287 /* NetworkProtectionInvitePresenter.swift in Sources */, B693955426F04BEC0015B914 /* ColorView.swift in Sources */, AA5C1DD3285A217F0089850C /* RecentlyClosedCacheItem.swift in Sources */, B6BBF17427475B15004F850E /* PopupBlockedPopover.swift in Sources */, 8589063A267BCD8E00D23B0D /* SaveCredentialsPopover.swift in Sources */, 987799F32999993C005D8EB6 /* LegacyBookmarksStoreMigration.swift in Sources */, + B6E3E5582BBFD51400A41922 /* PreviewViewController.swift in Sources */, 4B379C1527BD91E3008A968E /* QuartzIdleStateProvider.swift in Sources */, 37F19A6728E1B43200740DC6 /* DuckPlayerPreferences.swift in Sources */, 1D01A3D42B88CF7700FE8150 /* AccessibilityPreferences.swift in Sources */, @@ -12866,6 +11368,7 @@ B693955726F04BEC0015B914 /* MouseOverButton.swift in Sources */, AA61C0D02722159B00E6B681 /* FireInfoViewController.swift in Sources */, 9D9AE8692AA76CDC0026E7DC /* LoginItem+NetworkProtection.swift in Sources */, + 9F9C49F92BC7BC970099738D /* BookmarkAllTabsDialogView.swift in Sources */, B64C85422694590B0048FEBE /* PermissionButton.swift in Sources */, AAA0CC472533833C0079BC96 /* MoreOptionsMenu.swift in Sources */, B64C84E32692DC9F0048FEBE /* PermissionAuthorizationViewController.swift in Sources */, @@ -12883,12 +11386,12 @@ F1B33DF62BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */, EEC589D92A4F1CE300BCD60C /* AppLauncher.swift in Sources */, 4BA1A69B258B076900F6F690 /* FileStore.swift in Sources */, - B6A9E47F26146A800067D1B9 /* PixelArguments.swift in Sources */, 1D01A3D02B88CEC600FE8150 /* PreferencesAccessibilityView.swift in Sources */, 37BF3F21286F0A7A00BD9014 /* PinnedTabsViewModel.swift in Sources */, EEC4A6692B2C87D300F7C0AA /* VPNLocationView.swift in Sources */, AAC5E4D225D6A709007F5990 /* BookmarkList.swift in Sources */, B602E81D2A1E25B1006D261F /* NEOnDemandRuleExtension.swift in Sources */, + C1372EF42BBC5BAD003F8793 /* SecureTextField.swift in Sources */, 4B9292D12667123700AD2C21 /* BookmarkTableRowView.swift in Sources */, 85589E9427BFE1E70038AD11 /* FavoritesView.swift in Sources */, 85AC7ADB27BD628400FFB69B /* HomePage.swift in Sources */, @@ -12902,6 +11405,8 @@ 85F0FF1327CFAB04001C7C6E /* RecentlyVisitedView.swift in Sources */, AA7EB6DF27E7C57D00036718 /* MouseOverAnimationButton.swift in Sources */, AA7412B724D1687000D22FE0 /* TabBarScrollView.swift in Sources */, + 1E559BB12BBCA9F1002B4AF6 /* RedirectNavigationResponder.swift in Sources */, + 9F33445E2BBFA77F0040CBEB /* BookmarksBarVisibilityManager.swift in Sources */, 4B9292D92667124B00AD2C21 /* BookmarkListTreeControllerDataSource.swift in Sources */, 14D9B8FB24F7E089000D4D13 /* AddressBarViewController.swift in Sources */, B65536A62685B82B00085A79 /* Permissions.swift in Sources */, @@ -12921,10 +11426,10 @@ B687B7CA2947A029001DEA6F /* ContentBlockingTabExtension.swift in Sources */, 85B7184C27677C6500B4277F /* OnboardingViewController.swift in Sources */, 4B379C1E27BDB7FF008A968E /* DeviceAuthenticator.swift in Sources */, - 7BFE95522A9DF1CE0081ABE9 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift in Sources */, 1456D6E124EFCBC300775049 /* TabBarCollectionView.swift in Sources */, 4B4D60BF2A0C848A00BCD287 /* NetworkProtection+ConvenienceInitializers.swift in Sources */, 4B6B64842BA930420009FF9F /* WaitlistThankYouPromptPresenter.swift in Sources */, + BDA7647C2BC497BE00D0400C /* DefaultVPNLocationFormatter.swift in Sources */, 3158B1592B0BF76400AF130C /* DataBrokerProtectionFeatureDisabler.swift in Sources */, B655124829A79465009BFE1C /* NavigationActionExtension.swift in Sources */, 9FA173EB2B7B232200EE4E6E /* AddEditBookmarkDialogView.swift in Sources */, @@ -12940,6 +11445,7 @@ B6A9E46B2614618A0067D1B9 /* OperatingSystemVersionExtension.swift in Sources */, 4BDFA4AE27BF19E500648192 /* ToggleableScrollView.swift in Sources */, 1D36F4242A3B85C50052B527 /* TabCleanupPreparer.swift in Sources */, + B6ABD0CE2BC042CE0000EB69 /* NSURL+sandboxExtensionRetainCount.m in Sources */, 4B4D60DF2A0C875F00BCD287 /* NetworkProtectionOptionKeyExtension.swift in Sources */, 85AC3AEF25D5CE9800C7D2AA /* UserScripts.swift in Sources */, B643BF1427ABF772000BACEC /* NSWorkspaceExtension.swift in Sources */, @@ -12954,11 +11460,12 @@ F41D174125CB131900472416 /* NSColorExtension.swift in Sources */, AAC5E4F625D6BF2C007F5990 /* AddressBarButtonsViewController.swift in Sources */, B6F9BDE42B45CD1900677B33 /* ModalView.swift in Sources */, + F18826842BBEE31700D9AC4F /* PixelKit+Assertion.swift in Sources */, 1D2DC0072901679C008083A1 /* BWError.swift in Sources */, - B68C92C42750EF76002AC6B0 /* PixelDataRecord.swift in Sources */, 853014D625E671A000FB8205 /* PageObserverUserScript.swift in Sources */, B677FC4F2B06376B0099EB04 /* ReportFeedbackView.swift in Sources */, - B642738227B65BAC0005DFD1 /* SecureVaultErrorReporter.swift in Sources */, + B642738227B65BAC0005DFD1 /* SecureVaultReporter.swift in Sources */, + 9F9C4A012BC7F36D0099738D /* BookmarkAllTabsDialogCoordinatorViewModel.swift in Sources */, 4B139AFD26B60BD800894F82 /* NSImageExtensions.swift in Sources */, B62B48392ADE46FC000DECE5 /* Application.swift in Sources */, 4B9DB02C2A983B24000927DB /* WaitlistKeychainStorage.swift in Sources */, @@ -12980,6 +11487,7 @@ 1DDD3EC02B84F5D5004CBF2B /* PreferencesCookiePopupProtectionView.swift in Sources */, B693955026F04BEB0015B914 /* ShadowView.swift in Sources */, AA3D531D27A2F58F00074EC1 /* FeedbackSender.swift in Sources */, + B6E3E5502BBFCDEE00A41922 /* OpenDownloadsCellView.swift in Sources */, B6BDDA012942389000F68088 /* TabExtensions.swift in Sources */, AA7412B224D0B3AC00D22FE0 /* TabBarViewItem.swift in Sources */, 856C98D52570116900A22F1F /* NSWindow+Toast.swift in Sources */, @@ -12994,8 +11502,9 @@ 37FD78112A29EBD100B36DB1 /* SyncErrorHandler.swift in Sources */, AA8EDF2424923E980071C2E8 /* URLExtension.swift in Sources */, B634DBDF293C8F7F00C3C99E /* Tab+UIDelegate.swift in Sources */, - 4BE0DF06267819A1006337B7 /* NSStoryboardExtension.swift in Sources */, + B6F1B02E2BCE6B47005E863C /* TunnelControllerProvider.swift in Sources */, 37AFCE8127DA2CA600471A10 /* PreferencesViewController.swift in Sources */, + 31A83FB52BE28D7D00F74E67 /* UserText+DBP.swift in Sources */, 4B02198A25E05FAC00ED7DEA /* FireproofDomains.swift in Sources */, 4B677442255DBEEA00025BD8 /* Database.swift in Sources */, 1DDC85032B83903E00670238 /* PreferencesWebTrackingProtectionView.swift in Sources */, @@ -13036,13 +11545,14 @@ B67C6C472654C643006C872E /* FileManagerExtensionTests.swift in Sources */, 4BD57C042AC112DF00B580EE /* NetworkProtectionRemoteMessagingTests.swift in Sources */, B69B50482726C5C200758A2B /* StatisticsLoaderTests.swift in Sources */, + 56BA1E872BAC8239001CF69F /* SSLErrorPageUserScriptTests.swift in Sources */, 142879DA24CE1179005419BB /* SuggestionViewModelTests.swift in Sources */, 4B9292BC2667103100AD2C21 /* BookmarkSidebarTreeControllerTests.swift in Sources */, 4B9DB05A2A983B55000927DB /* MockWaitlistRequest.swift in Sources */, 37D2377C287EBDA300BCE03B /* TabIndexTests.swift in Sources */, 37534CA52811987D002621E7 /* AdjacentItemEnumeratorTests.swift in Sources */, - B6DA44232616CABC00DD1EC2 /* PixelArgumentsTests.swift in Sources */, 56B234BF2A84EFD200F2A1CC /* NavigationBarUrlExtensionsTests.swift in Sources */, + 9FAD623A2BCFDB32007F3A65 /* WebsiteInfoHelpers.swift in Sources */, C13909F42B85FD79001626ED /* AutofillDeleteAllPasswordsExecutorTests.swift in Sources */, 37534C9E28104D9B002621E7 /* TabLazyLoaderTests.swift in Sources */, B6619EF62B10DFF700CD9186 /* InstructionsFormatParserTests.swift in Sources */, @@ -13052,6 +11562,7 @@ 4B9292BD2667103100AD2C21 /* BookmarkOutlineViewDataSourceTests.swift in Sources */, C17CA7B22B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift in Sources */, 4BF6961D28BE911100D402D4 /* RecentlyVisitedSiteModelTests.swift in Sources */, + 9FA5A0A92BC900FC00153786 /* BookmarkAllTabsDialogViewModelTests.swift in Sources */, B6619F062B17138D00CD9186 /* DataImportSourceViewModelTests.swift in Sources */, 4BBF0917282DD6EF00EE1418 /* TemporaryFileHandlerTests.swift in Sources */, B6A5A27925B93FFF00AA7ADA /* StateRestorationManagerTests.swift in Sources */, @@ -13064,7 +11575,6 @@ 1D3B1ABF29369FC8006F4388 /* BWEncryptionTests.swift in Sources */, B6F56567299A414300A04298 /* WKWebViewMockingExtension.swift in Sources */, 1D9FDEC62B9B64DB0040B78C /* PrivacyProtectionStatusTests.swift in Sources */, - B6656E122B29E3BE008798A1 /* DownloadListStoreMock.swift in Sources */, 37D23780287EFEE200BCE03B /* PinnedTabsManagerTests.swift in Sources */, AA0877BA26D5161D00B05660 /* WebKitVersionProviderTests.swift in Sources */, 9FA75A3E2BA00E1400DA5FA6 /* BookmarksBarMenuFactoryTests.swift in Sources */, @@ -13081,6 +11591,7 @@ AAC9C01C24CB594C00AD1325 /* TabViewModelTests.swift in Sources */, 567DA93F29E8045D008AC5EE /* MockEmailStorage.swift in Sources */, 37CD54B727F1B28A00F1F7B9 /* DefaultBrowserPreferencesTests.swift in Sources */, + 9F3344622BBFBDA40040CBEB /* BookmarksBarVisibilityManagerTests.swift in Sources */, 028904202A7B25380028369C /* AppConfigurationURLProviderTests.swift in Sources */, B65349AA265CF45000DCC645 /* DispatchQueueExtensionsTests.swift in Sources */, 858A798A26A9B35E00A75A42 /* PasswordManagementItemModelTests.swift in Sources */, @@ -13100,6 +11611,7 @@ 858A798826A99DBE00A75A42 /* PasswordManagementItemListModelTests.swift in Sources */, 566B196529CDB828007E38F4 /* CapturingOptionsButtonMenuDelegate.swift in Sources */, 4B8AD0B127A86D9200AE44D6 /* WKWebsiteDataStoreExtensionTests.swift in Sources */, + 9FA5A0B02BC9039200153786 /* BookmarkFolderStoreMock.swift in Sources */, B69B50472726C5C200758A2B /* VariantManagerTests.swift in Sources */, 8546DE6225C03056000CA5E1 /* UserAgentTests.swift in Sources */, 9F26060B2B85C20A00819292 /* AddEditBookmarkDialogViewModelTests.swift in Sources */, @@ -13116,16 +11628,18 @@ 85AC3B4925DAC9BD00C7D2AA /* ConfigurationStorageTests.swift in Sources */, 9F180D122B69C665000D695F /* DownloadsTabExtensionMock.swift in Sources */, AA91F83927076F1900771A0D /* PrivacyIconViewModelTests.swift in Sources */, + 9F9C49F62BC786790099738D /* MoreOptionsMenu+BookmarksTests.swift in Sources */, 4B723E0726B0003E00E14D75 /* CSVImporterTests.swift in Sources */, 4BCF15EC2ABB9AF80083F6DF /* NetworkProtectionRemoteMessageTests.swift in Sources */, B62EB47C25BAD3BB005745C6 /* WKWebViewPrivateMethodsAvailabilityTests.swift in Sources */, + 9F0FFFBB2BCCAEC2007C87DD /* AddEditBookmarkFolderDialogViewModelMock.swift in Sources */, 4BBC16A527C488C900E00A38 /* DeviceAuthenticatorTests.swift in Sources */, 4B3F641E27A8D3BD00E0C118 /* BrowserProfileTests.swift in Sources */, B6106BA026A7BE0B0013B453 /* PermissionManagerTests.swift in Sources */, 4B59CC8C290083240058F2F6 /* ConnectBitwardenViewModelTests.swift in Sources */, B68412202B6A30680092F66A /* StringExtensionTests.swift in Sources */, - B662D3D92755D7AD0035D4D6 /* PixelStoreTests.swift in Sources */, B6106BB526A809E60013B453 /* GeolocationProviderTests.swift in Sources */, + BDA764912BC4E57200D0400C /* MockVPNLocationFormatter.swift in Sources */, B6E6BA232BA2EDDE008AA7E1 /* FileReadResult.swift in Sources */, B6A5A2A025B96E8300AA7ADA /* AppStateChangePublisherTests.swift in Sources */, B63ED0E326B3E7FA00A9DAD1 /* CLLocationManagerMock.swift in Sources */, @@ -13138,7 +11652,6 @@ AA0F3DB7261A566C0077F2D9 /* SuggestionLoadingMock.swift in Sources */, B6E6BA162BA2CF5F008AA7E1 /* SandboxTestToolNotifications.swift in Sources */, B60C6F8129B1B4AD007BFAA8 /* TestRunHelper.swift in Sources */, - 4B9DB0582A983B55000927DB /* MockNetworkProtectionCodeRedeemer.swift in Sources */, 9F872DA02B90644800138637 /* ContextualMenuTests.swift in Sources */, 4B9292BE2667103100AD2C21 /* PasteboardFolderTests.swift in Sources */, 4B9292C52667104B00AD2C21 /* CoreDataTestUtilities.swift in Sources */, @@ -13151,6 +11664,7 @@ 142879DC24CE1185005419BB /* SuggestionContainerViewModelTests.swift in Sources */, 566B195D29CDB692007E38F4 /* MoreOptionsMenuTests.swift in Sources */, AA0877B826D5160D00B05660 /* SafariVersionReaderTests.swift in Sources */, + 31DC2F222BD6DE6C001354EF /* DataBrokerPrerequisitesStatusVerifierTests.swift in Sources */, B69B50452726C5C200758A2B /* AtbParserTests.swift in Sources */, 1D8C2FED2B70F5D0005E4BBD /* MockViewSnapshotRenderer.swift in Sources */, B6106BAF26A7C6180013B453 /* PermissionStoreMock.swift in Sources */, @@ -13164,11 +11678,14 @@ AAE39D1B24F44885008EF28B /* TabCollectionViewModelDelegateMock.swift in Sources */, 9F0A2CF82B96A58600C5B8C0 /* BaseBookmarkEntityTests.swift in Sources */, 373A1AAA283ED86C00586521 /* BookmarksHTMLReaderTests.swift in Sources */, + 560C3FFC2BC9911000F589CE /* PermanentSurveyManagerTests.swift in Sources */, 317295D42AF058D3002C3206 /* MockWaitlistFeatureSetupHandler.swift in Sources */, + 9FBD84772BB3E54200220859 /* InstallationAttributionPixelHandlerTests.swift in Sources */, AA9C363025518CA9004B1BA3 /* FireTests.swift in Sources */, B6106BB126A7D8720013B453 /* PermissionStoreTests.swift in Sources */, 4BF4951826C08395000547B8 /* ThirdPartyBrowserTests.swift in Sources */, 4B98D27C28D960DD003C2B6F /* FirefoxFaviconsReaderTests.swift in Sources */, + 9F0FFFBE2BCCAF1F007C87DD /* BookmarkAllTabsDialogViewModelMock.swift in Sources */, B60C6F7E29B1B41D007BFAA8 /* TestRunHelperInitializer.m in Sources */, 37479F152891BC8300302FE2 /* TabCollectionViewModelTests+WithoutPinnedTabsManager.swift in Sources */, AA63745424C9BF9A00AB2AC4 /* SuggestionContainerTests.swift in Sources */, @@ -13181,6 +11698,7 @@ B6AA64732994B43300D99CD6 /* FutureExtensionTests.swift in Sources */, B603975329C1FFAE00902A34 /* ExpectedNavigationExtension.swift in Sources */, EA1E52B52798CF98002EC53C /* ClickToLoadModelTests.swift in Sources */, + 56BA1E802BAB2E43001CF69F /* ErrorPageTabExtensionTest.swift in Sources */, B603975029C1FF5F00902A34 /* TestsURLExtension.swift in Sources */, B6A5A27E25B9403E00AA7ADA /* FileStoreMock.swift in Sources */, 56534DED29DF252C00121467 /* CapturingDefaultBrowserProvider.swift in Sources */, @@ -13197,13 +11715,13 @@ C1E961EB2B879E79001760E1 /* MockAutofillActionPresenter.swift in Sources */, 4BA1A6FE258C5C1300F6F690 /* EncryptedValueTransformerTests.swift in Sources */, 85F69B3C25EDE81F00978E59 /* URLExtensionTests.swift in Sources */, - B6DA44112616C0FC00DD1EC2 /* PixelTests.swift in Sources */, 4B9292BA2667103100AD2C21 /* BookmarkNodePathTests.swift in Sources */, 562532A02BC069180034D316 /* ZoomPopoverViewModelTests.swift in Sources */, 4B9292C02667103100AD2C21 /* BookmarkManagedObjectTests.swift in Sources */, 373A1AB228451ED400586521 /* BookmarksHTMLImporterTests.swift in Sources */, 4B723E0626B0003E00E14D75 /* CSVParserTests.swift in Sources */, B60C6F8429B1BAD3007BFAA8 /* FileManagerTempDirReplacement.swift in Sources */, + BDA7648D2BC4E4EF00D0400C /* DefaultVPNLocationFormatterTests.swift in Sources */, 85F487B5276A8F2E003CE668 /* OnboardingTests.swift in Sources */, B626A7642992506A00053070 /* SerpHeadersNavigationResponderTests.swift in Sources */, AA652CCE25DD9071009059CC /* BookmarkListTests.swift in Sources */, @@ -13220,7 +11738,9 @@ AABAF59C260A7D130085060C /* FaviconManagerMock.swift in Sources */, 1DFAB5222A8983DE00A0F7F6 /* SetExtensionTests.swift in Sources */, 4BF6962028BEEE8B00D402D4 /* LocalPinningManagerTests.swift in Sources */, + 9F0FFFB82BCCAE9C007C87DD /* AddEditBookmarkDialogViewModelMock.swift in Sources */, AAEC74B82642E43800C2EFBC /* HistoryStoreTests.swift in Sources */, + 9FAD623D2BD09DE5007F3A65 /* WebsiteInfoTests.swift in Sources */, 9F180D0F2B69C553000D695F /* Tab+WKUIDelegateTests.swift in Sources */, 4BA1A6E6258C270800F6F690 /* EncryptionKeyGeneratorTests.swift in Sources */, B6106BB326A7F4AA0013B453 /* GeolocationServiceMock.swift in Sources */, @@ -13229,6 +11749,7 @@ 4BBF09232830812900EE1418 /* FileSystemDSL.swift in Sources */, 4B9DB05C2A983B55000927DB /* WaitlistViewModelTests.swift in Sources */, 1D1C36E329FAE8DA001FA40C /* FaviconManagerTests.swift in Sources */, + 9F0FFFB42BCCAE37007C87DD /* BookmarkAllTabsDialogCoordinatorViewModelTests.swift in Sources */, 4B723E0526B0003E00E14D75 /* DataImportMocks.swift in Sources */, 4B70C00227B0793D000386ED /* CrashReportTests.swift in Sources */, B6656E0D2B29C733008798A1 /* FileImportViewLocalizationTests.swift in Sources */, @@ -13241,14 +11762,16 @@ B610F2EB27AA8E4500FCEBE9 /* ContentBlockingUpdatingTests.swift in Sources */, 4BA1A6F6258C4F9600F6F690 /* EncryptionMocks.swift in Sources */, 3767190028E58513003A2A15 /* DuckPlayerURLExtensionTests.swift in Sources */, + 9FBD847A2BB3EC3300220859 /* MockAttributionOriginProvider.swift in Sources */, 4B2975992828285900187C4E /* FirefoxKeyReaderTests.swift in Sources */, B698E5042908011E00A746A8 /* AppKitPrivateMethodsAvailabilityTests.swift in Sources */, 56D145EE29E6DAD900E3488A /* DataImportProviderTests.swift in Sources */, 4BB99D0F26FE1A84001E4761 /* ChromiumBookmarksReaderTests.swift in Sources */, - 4BC2621D293996410087A482 /* PixelEventTests.swift in Sources */, 1D9FDEB72B9B5D150040B78C /* SearchPreferencesTests.swift in Sources */, + 021EA0842BD6E01A00772C9A /* TabsPreferencesTests.swift in Sources */, 1D12F2E2298BC660009A65FD /* InternalUserDeciderStoreMock.swift in Sources */, 4BB99D1026FE1A84001E4761 /* FirefoxBookmarksReaderTests.swift in Sources */, + 9FBD84702BB3DD8400220859 /* MockAttributionsPixelHandler.swift in Sources */, 4B117F7D276C0CB5002F3D8C /* LocalStatisticsStoreTests.swift in Sources */, AAEC74B42642C69300C2EFBC /* HistoryCoordinatorTests.swift in Sources */, 378205F62837CBA800D1D4AA /* SavedStateMock.swift in Sources */, @@ -13259,8 +11782,10 @@ AA9C362825518C44004B1BA3 /* WebsiteDataStoreMock.swift in Sources */, 857E44652A9F70F300ED77A7 /* CampaignVariantTests.swift in Sources */, 3776582D27F71652009A6B35 /* WebsiteBreakageReportTests.swift in Sources */, + 9FBD84562BB3ACFD00220859 /* AttributionOriginFileProviderTests.swift in Sources */, 31E163BA293A56F400963C10 /* BrokenSiteReportingReferenceTests.swift in Sources */, 1D9FDEC32B9B63C90040B78C /* DataClearingPreferencesTests.swift in Sources */, + 9F8D57322BCCCB9A00AEA660 /* UserDefaultsBookmarkFoldersStoreTests.swift in Sources */, 4B723E0826B0003E00E14D75 /* MockSecureVault.swift in Sources */, 37CD54B527F1AC1300F1F7B9 /* PreferencesSidebarModelTests.swift in Sources */, B6CA4824298CDC2E0067ECCE /* AdClickAttributionTabExtensionTests.swift in Sources */, @@ -13298,7 +11823,10 @@ B6E6BA062BA1FE10008AA7E1 /* NSApplicationExtension.swift in Sources */, B6E6B9F62BA1FD90008AA7E1 /* SandboxTestTool.swift in Sources */, B6E6BA252BA2EDDE008AA7E1 /* FileReadResult.swift in Sources */, + B6EECB322BC40A1400B3CB77 /* FileManagerExtension.swift in Sources */, + B6EECB302BC3FA5A00B3CB77 /* SecurityScopedFileURLController.swift in Sources */, B6E6BA052BA1FE09008AA7E1 /* URLExtension.swift in Sources */, + B6EECB312BC3FAB100B3CB77 /* NSURL+sandboxExtensionRetainCount.m in Sources */, B6E6BA202BA2E462008AA7E1 /* CollectionExtension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -13314,11 +11842,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 31C6E9AB2B0C07A30086DC30 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9D9AE8B22AAA39A70026E7DC /* DuckDuckGoDBPBackgroundAgent */; - targetProxy = 31C6E9AA2B0C07A30086DC30 /* PBXContainerItemProxy */; - }; 31C6E9AD2B0C07BA0086DC30 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 9D9AE8B22AAA39A70026E7DC /* DuckDuckGoDBPBackgroundAgent */; @@ -13355,10 +11878,6 @@ isa = PBXTargetDependency; productRef = 4B5F14FD2A1529230060320F /* InputFilesChecker */; }; - 4B9579262AC7AE700062CA31 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = 4B5F14FB2A15291D0060320F /* InputFilesChecker */; - }; 4BA7C4DF2B3F6F4900AFE511 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4B4D603C2A0B290200BCD287 /* NetworkProtectionAppExtension */; @@ -13389,50 +11908,6 @@ target = 4B2537592A11BE7300610219 /* NetworkProtectionSystemExtension */; targetProxy = 7BEC18302AD5DA3300D30536 /* PBXContainerItemProxy */; }; - B6080B9D2B20AF7700B418EF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B6080B9F2B20AF7B00B418EF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B6080BA12B20AF7F00B418EF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B6080BA32B20AF8300B418EF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B6080BA52B20AF8800B418EF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B6080BA92B20AF8F00B418EF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B6080BAB2B20AF9200B418EF /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B69D06142A4C0AC50032D14D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B69D06162A4C0ACD0032D14D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B69D061A2A4C0AD80032D14D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B69D061C2A4C0BC10032D14D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; B6AEB5552BA3042300781A09 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = B6E6B9F22BA1FD90008AA7E1 /* sandbox-test-tool */; @@ -13463,22 +11938,6 @@ target = B6EC37E729B5DA2A001ACE79 /* tests-server */; targetProxy = B6EC37F329B5DA94001ACE79 /* PBXContainerItemProxy */; }; - B6F997BB2B8F353F00476735 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BA2B8F353F00476735 /* SwiftLintPlugin */; - }; - B6F997BD2B8F35EF00476735 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BC2B8F35EF00476735 /* SwiftLintPlugin */; - }; - B6F997BF2B8F35F400476735 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997BE2B8F35F400476735 /* SwiftLintPlugin */; - }; - B6F997C12B8F35F800476735 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = B6F997C02B8F35F800476735 /* SwiftLintPlugin */; - }; EE02D41E2BB460B500DBE6B3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = B6EC37E729B5DA2A001ACE79 /* tests-server */; @@ -13792,34 +12251,6 @@ }; name = Review; }; - 4B957C3D2AC7AE700062CA31 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 4B957C432AC7AF190062CA31 /* DuckDuckGoPrivacyPro.xcconfig */; - buildSettings = { - }; - name = Debug; - }; - 4B957C3E2AC7AE700062CA31 /* CI */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 4B957C432AC7AF190062CA31 /* DuckDuckGoPrivacyPro.xcconfig */; - buildSettings = { - }; - name = CI; - }; - 4B957C3F2AC7AE700062CA31 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 4B957C432AC7AF190062CA31 /* DuckDuckGoPrivacyPro.xcconfig */; - buildSettings = { - }; - name = Release; - }; - 4B957C402AC7AE700062CA31 /* Review */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 4B957C432AC7AF190062CA31 /* DuckDuckGoPrivacyPro.xcconfig */; - buildSettings = { - }; - name = Review; - }; 565E46E62B2725DD0013AC2A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 376113C52B29BCD600E794BB /* SyncE2EUITests.xcconfig */; @@ -14199,17 +12630,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 4B957C3C2AC7AE700062CA31 /* Build configuration list for PBXNativeTarget "DuckDuckGo Privacy Pro" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 4B957C3D2AC7AE700062CA31 /* Debug */, - 4B957C3E2AC7AE700062CA31 /* CI */, - 4B957C3F2AC7AE700062CA31 /* Release */, - 4B957C402AC7AE700062CA31 /* Review */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 565E46E52B2725DD0013AC2A /* Build configuration list for PBXNativeTarget "SyncE2EUITests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -14347,28 +12767,20 @@ version = 3.1.4000; }; }; - 4B95792A2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "Sparkle" */ = { + 3FFD51CF7C19ACBDB9687474 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/sparkle-project/Sparkle.git"; + repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 2.4.2; + version = 140.0.3; }; }; - 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { + 4311906792B7676CE9535D76 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = revision; - revision = ffdf1872798f23de073586d4b609b349093a0755; - }; - }; - 4B9579392AC7AE700062CA31 /* XCRemoteSwiftPackageReference "OpenSSL-XCFramework" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/duckduckgo/OpenSSL-XCFramework"; - requirement = { - kind = exactVersion; - version = 3.1.2000; + revision = c06709ba8a586f6a40190bacaaaaa96b2d55e540; }; }; 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { @@ -14376,7 +12788,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 132.0.1; + version = 144.0.0; }; }; 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = { @@ -14392,7 +12804,7 @@ repositoryURL = "https://github.com/sparkle-project/Sparkle.git"; requirement = { kind = exactVersion; - version = 2.5.2; + version = 2.6.0; }; }; B65CD8C92B316DF100A595BB /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = { @@ -14424,7 +12836,7 @@ repositoryURL = "https://github.com/duckduckgo/apple-toolbox.git"; requirement = { kind = exactVersion; - version = 2.0.0; + version = 3.1.1; }; }; F1D43AF12B98E47800BAB743 /* XCRemoteSwiftPackageReference "BareBonesBrowser" */ = { @@ -14435,17 +12847,21 @@ version = 0.1.0; }; }; + FAE06B199CA1F209B55B34E9 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; + requirement = { + kind = exactVersion; + version = 137.0.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 1E0068AC2B1673BB00BBF43B /* SubscriptionUI */ = { - isa = XCSwiftPackageProductDependency; - productName = SubscriptionUI; - }; - 1E21F8E22B73E48600FB272E /* Subscription */ = { + 08D4923DC968236E22E373E2 /* Crashes */ = { isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Subscription; + package = FAE06B199CA1F209B55B34E9 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Crashes; }; 1E950E3E2912A10D0051A99B /* ContentBlocking */ = { isa = XCSwiftPackageProductDependency; @@ -14475,10 +12891,6 @@ isa = XCSwiftPackageProductDependency; productName = DataBrokerProtection; }; - 3143C8782B0D1F3D00382627 /* DataBrokerProtection */ = { - isa = XCSwiftPackageProductDependency; - productName = DataBrokerProtection; - }; 315A023E2B6421AE00BFA577 /* Networking */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14490,7 +12902,6 @@ }; 3706FA6B293F65D500E42796 /* TrackerRadarKit */ = { isa = XCSwiftPackageProductDependency; - package = 3706FA6C293F65D500E42796 /* XCRemoteSwiftPackageReference "TrackerRadarKit" */; productName = TrackerRadarKit; }; 3706FA71293F65D500E42796 /* BrowserServicesKit */ = { @@ -14538,11 +12949,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = TestUtils; }; - 372217832B33380E00B8E9C2 /* TestUtils */ = { - isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = TestUtils; - }; 37269EFA2B332F9E005E8E46 /* Common */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14563,11 +12969,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Common; }; - 37269F022B332FD8005E8E46 /* Common */ = { - isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Common; - }; 37269F042B3332C2005E8E46 /* Common */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14583,18 +12984,10 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = DDGSync; }; - 373FB4B02B4D6C42004C88D6 /* PreferencesViews */ = { - isa = XCSwiftPackageProductDependency; - productName = PreferencesViews; - }; 373FB4B22B4D6C4B004C88D6 /* PreferencesViews */ = { isa = XCSwiftPackageProductDependency; productName = PreferencesViews; }; - 373FB4B42B4D6C57004C88D6 /* PreferencesViews */ = { - isa = XCSwiftPackageProductDependency; - productName = PreferencesViews; - }; 378F44E329B4BDE900899924 /* SwiftUIExtensions */ = { isa = XCSwiftPackageProductDependency; productName = SwiftUIExtensions; @@ -14631,10 +13024,16 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Navigation; }; - 4B2537762A11BFE100610219 /* PixelKit */ = { + 4B1EFF1B2BD71EEF007CC84F /* PixelKit */ = { isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = PixelKit; }; + 4B1EFF202BD72189007CC84F /* Networking */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Networking; + }; 4B2D062B2A11C0E100DE1F49 /* Networking */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14656,10 +13055,6 @@ isa = XCSwiftPackageProductDependency; productName = NetworkProtection; }; - 4B4D60972A0B2A5C00BCD287 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 4B4D60AE2A0C837F00BCD287 /* Networking */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14677,95 +13072,6 @@ isa = XCSwiftPackageProductDependency; productName = "plugin:InputFilesChecker"; }; - 4B81AD342B29512B00706C96 /* PixelKitTestingUtilities */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKitTestingUtilities; - }; - 4B81AD362B29513100706C96 /* PixelKitTestingUtilities */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKitTestingUtilities; - }; - 4B9579292AC7AE700062CA31 /* Sparkle */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792A2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "Sparkle" */; - productName = Sparkle; - }; - 4B95792B2AC7AE700062CA31 /* BrowserServicesKit */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = BrowserServicesKit; - }; - 4B95792E2AC7AE700062CA31 /* ContentBlocking */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = ContentBlocking; - }; - 4B95792F2AC7AE700062CA31 /* PrivacyDashboard */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = PrivacyDashboard; - }; - 4B9579302AC7AE700062CA31 /* UserScript */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = UserScript; - }; - 4B9579312AC7AE700062CA31 /* Persistence */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Persistence; - }; - 4B9579322AC7AE700062CA31 /* Configuration */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Configuration; - }; - 4B9579332AC7AE700062CA31 /* Navigation */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Navigation; - }; - 4B9579342AC7AE700062CA31 /* Bookmarks */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Bookmarks; - }; - 4B9579352AC7AE700062CA31 /* DDGSync */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = DDGSync; - }; - 4B9579362AC7AE700062CA31 /* SyncUI */ = { - isa = XCSwiftPackageProductDependency; - productName = SyncUI; - }; - 4B9579372AC7AE700062CA31 /* SwiftUIExtensions */ = { - isa = XCSwiftPackageProductDependency; - productName = SwiftUIExtensions; - }; - 4B9579382AC7AE700062CA31 /* OpenSSL */ = { - isa = XCSwiftPackageProductDependency; - package = 4B9579392AC7AE700062CA31 /* XCRemoteSwiftPackageReference "OpenSSL-XCFramework" */; - productName = OpenSSL; - }; - 4B95793C2AC7AE700062CA31 /* SyncDataProviders */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = SyncDataProviders; - }; - 4B95793D2AC7AE700062CA31 /* NetworkProtectionUI */ = { - isa = XCSwiftPackageProductDependency; - productName = NetworkProtectionUI; - }; - 4B95793E2AC7AE700062CA31 /* NetworkProtection */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = NetworkProtection; - }; - 4B95793F2AC7AE700062CA31 /* LoginItems */ = { - isa = XCSwiftPackageProductDependency; - productName = LoginItems; - }; 4BA7C4DC2B3F64E500AFE511 /* LoginItems */ = { isa = XCSwiftPackageProductDependency; productName = LoginItems; @@ -14797,6 +13103,11 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = NetworkProtection; }; + 537FC71EA5115A983FAF3170 /* Crashes */ = { + isa = XCSwiftPackageProductDependency; + package = 4311906792B7676CE9535D76 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Crashes; + }; 7B00997C2B6508B700FE7C31 /* NetworkProtectionProxy */ = { isa = XCSwiftPackageProductDependency; productName = NetworkProtectionProxy; @@ -14817,23 +13128,11 @@ isa = XCSwiftPackageProductDependency; productName = NetworkProtectionIPC; }; - 7B31FD8F2AD1257B0086AA24 /* NetworkProtectionIPC */ = { - isa = XCSwiftPackageProductDependency; - productName = NetworkProtectionIPC; - }; 7B37C7A42BAA32A50062546A /* Subscription */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Subscription; }; - 7B5DD6992AE51FFA001DE99C /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; - 7B5F9A742AE2BE4E002AEBC0 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 7B624F162BA25C1F00A6C544 /* NetworkProtectionUI */ = { isa = XCSwiftPackageProductDependency; productName = NetworkProtectionUI; @@ -14843,14 +13142,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Networking; }; - 7B8C083B2AE1268E00F4C67F /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; - 7B94E1642B7ED95100E32B96 /* NetworkProtectionProxy */ = { - isa = XCSwiftPackageProductDependency; - productName = NetworkProtectionProxy; - }; 7B97CD582B7E0B57004FEF43 /* NetworkProtectionProxy */ = { isa = XCSwiftPackageProductDependency; productName = NetworkProtectionProxy; @@ -14860,10 +13151,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Common; }; - 7B97CD612B7E0C4B004FEF43 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 7BA076BA2B65D61400D7FB72 /* NetworkProtectionProxy */ = { isa = XCSwiftPackageProductDependency; productName = NetworkProtectionProxy; @@ -14882,10 +13169,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Networking; }; - 7BBD44272AD730A400D0A064 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 7BBE2B7A2B61663C00697445 /* NetworkProtectionProxy */ = { isa = XCSwiftPackageProductDependency; productName = NetworkProtectionProxy; @@ -14906,14 +13189,6 @@ isa = XCSwiftPackageProductDependency; productName = NetworkProtectionUI; }; - 7BFCB74D2ADE7E1A00DA3EA7 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; - 7BFCB74F2ADE7E2300DA3EA7 /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 85D44B852BA08D29001B4AB5 /* Suggestions */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14924,11 +13199,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Suggestions; }; - 85D44B892BA08D3B001B4AB5 /* Suggestions */ = { - isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = Suggestions; - }; 85E2BBCD2B8F534000DBEC7A /* History */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14939,11 +13209,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = History; }; - 85E2BBD12B8F536F00DBEC7A /* History */ = { - isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = History; - }; 9807F644278CA16F00E1547B /* BrowserServicesKit */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14964,14 +13229,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Persistence; }; - 9D6983F82AC773C3002C02FC /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; - 9D6983FA2AC773C8002C02FC /* PixelKit */ = { - isa = XCSwiftPackageProductDependency; - productName = PixelKit; - }; 9D9AE8F82AAA3AD00026E7DC /* DataBrokerProtection */ = { isa = XCSwiftPackageProductDependency; productName = DataBrokerProtection; @@ -14980,10 +13237,6 @@ isa = XCSwiftPackageProductDependency; productName = DataBrokerProtection; }; - 9DB6E7232AA0DC5800A17F3C /* LoginItems */ = { - isa = XCSwiftPackageProductDependency; - productName = LoginItems; - }; 9DC70B192AA1FA5B005A844B /* LoginItems */ = { isa = XCSwiftPackageProductDependency; productName = LoginItems; @@ -15003,11 +13256,6 @@ package = 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */; productName = Lottie; }; - 9FF521492BAA90C400B9819B /* Lottie */ = { - isa = XCSwiftPackageProductDependency; - package = 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */; - productName = Lottie; - }; AA06B6B62672AF8100F541C5 /* Sparkle */ = { isa = XCSwiftPackageProductDependency; package = AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */; @@ -15083,31 +13331,26 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Configuration; }; - B6F997BA2B8F353F00476735 /* SwiftLintPlugin */ = { - isa = XCSwiftPackageProductDependency; - package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; - productName = "plugin:SwiftLintPlugin"; - }; - B6F997BC2B8F35EF00476735 /* SwiftLintPlugin */ = { - isa = XCSwiftPackageProductDependency; - package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; - productName = "plugin:SwiftLintPlugin"; - }; - B6F997BE2B8F35F400476735 /* SwiftLintPlugin */ = { + BDADBDC82BD2BC2200421B9B /* Lottie */ = { isa = XCSwiftPackageProductDependency; - package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; - productName = "plugin:SwiftLintPlugin"; + package = 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */; + productName = Lottie; }; - B6F997C02B8F35F800476735 /* SwiftLintPlugin */ = { + BDADBDCA2BD2BC2800421B9B /* Lottie */ = { isa = XCSwiftPackageProductDependency; - package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; - productName = "plugin:SwiftLintPlugin"; + package = 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */; + productName = Lottie; }; CBC83E3529B63D380008E19C /* Configuration */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Configuration; }; + DC3F73D49B2D44464AFEFCD8 /* Subscription */ = { + isa = XCSwiftPackageProductDependency; + package = 3FFD51CF7C19ACBDB9687474 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Subscription; + }; EE02D41F2BB460C000DBE6B3 /* BrowserServicesKit */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -15143,6 +13386,61 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = NetworkProtection; }; + F116A7C22BD1924B00F3FCF7 /* PixelKitTestingUtilities */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKitTestingUtilities; + }; + F116A7C62BD1925500F3FCF7 /* PixelKitTestingUtilities */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKitTestingUtilities; + }; + F116A7C82BD1929000F3FCF7 /* PixelKitTestingUtilities */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKitTestingUtilities; + }; + F198C7112BD18A28000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C7132BD18A30000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C7152BD18A44000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C7172BD18A4C000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C7192BD18A5B000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C71B2BD18A61000BF24D /* PixelKit */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = PixelKit; + }; + F198C71D2BD18D88000BF24D /* SwiftLintTool */ = { + isa = XCSwiftPackageProductDependency; + package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; + productName = SwiftLintTool; + }; + F198C71F2BD18D92000BF24D /* SwiftLintTool */ = { + isa = XCSwiftPackageProductDependency; + package = B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */; + productName = SwiftLintTool; + }; F1D43AF22B98E47800BAB743 /* BareBonesBrowserKit */ = { isa = XCSwiftPackageProductDependency; package = F1D43AF12B98E47800BAB743 /* XCRemoteSwiftPackageReference "BareBonesBrowser" */; @@ -15153,10 +13451,9 @@ package = F1D43AF12B98E47800BAB743 /* XCRemoteSwiftPackageReference "BareBonesBrowser" */; productName = BareBonesBrowserKit; }; - F1D43AF62B98E48F00BAB743 /* BareBonesBrowserKit */ = { + F1DF95E62BD188B60045E591 /* LoginItems */ = { isa = XCSwiftPackageProductDependency; - package = F1D43AF12B98E47800BAB743 /* XCRemoteSwiftPackageReference "BareBonesBrowser" */; - productName = BareBonesBrowserKit; + productName = LoginItems; }; /* End XCSwiftPackageProductDependency section */ diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index cb0773b436..41fa2b0e67 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/apple-toolbox.git", "state" : { - "revision" : "d51beaf1736013b530576ace13a16d6d1a63742c", - "version" : "2.0.0" + "revision" : "ab53ca41e9044a20eab7e53249526fadcf9acc9f", + "version" : "3.1.1" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "73f68ee1c0dda3cd4a0b0cc3cc38a6cc7e605829", - "version" : "132.0.1" + "revision" : "9906b9464f6f12e94f3cc62456b5b5a9c1a43db8", + "version" : "144.0.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "62d5dc3d02f6a8347dc5f0b52162a0107d38b74c", - "version" : "5.8.0" + "revision" : "1bb3bc5eb565735051f342a87b5405d4374876c7", + "version" : "5.12.0" } }, { @@ -50,8 +50,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/duckduckgo-autofill.git", "state" : { - "revision" : "6493e296934bf09277c03df45f11f4619711cb24", - "version" : "10.2.0" + "revision" : "6053999d6af384a716ab0ce7205dbab5d70ed1b3", + "version" : "11.0.1" } }, { @@ -95,8 +95,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/privacy-dashboard", "state" : { - "revision" : "620921fea14569eb00745cb5a44890d5890d99ec", - "version" : "3.4.0" + "revision" : "14b13d0c3db38f471ce4ba1ecb502ee1986c84d7", + "version" : "3.5.0" } }, { @@ -113,14 +113,14 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/sparkle-project/Sparkle.git", "state" : { - "revision" : "47d3d90aee3c52b6f61d04ceae426e607df62347", - "version" : "2.5.2" + "revision" : "0a4caaf7a81eea2cece651ef4b17331fa0634dff", + "version" : "2.6.0" } }, { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-argument-parser", + "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { "revision" : "46989693916f56d1186bd59ac15124caef896560", "version" : "1.3.1" @@ -138,7 +138,7 @@ { "identity" : "swift-syntax", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax.git", + "location" : "https://github.com/apple/swift-syntax", "state" : { "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", "version" : "509.1.1" @@ -167,8 +167,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/TrackerRadarKit", "state" : { - "revision" : "a6b7ba151d9dc6684484f3785293875ec01cc1ff", - "version" : "1.2.2" + "revision" : "6c84fd19139414fc0edbf9673ade06e532a564f0", + "version" : "2.0.0" } }, { diff --git a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme index 14f7550826..e343e06df9 100644 --- a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme +++ b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser App Store.xcscheme @@ -157,16 +157,6 @@ ReferencedContainer = "container:LocalPackages/SyncUI"> - - - - + + @@ -126,6 +130,9 @@ + + @@ -181,16 +188,6 @@ ReferencedContainer = "container:LocalPackages/NetworkProtectionMac"> - - - - + buildConfiguration = "Review" + selectedDebuggerIdentifier = "" + selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn" + shouldUseLaunchSchemeArgsEnv = "YES"> + scriptText = ""${PROJECT_DIR}/clean-app.sh" review defaults write com.duckduckgo.macos.browser.review moveToApplicationsFolderAlertSuppress 1 killall tests-server # integration tests resources dir pushd "${METAL_LIBRARY_OUTPUT_DIR}" "${BUILT_PRODUCTS_DIR}/tests-server" & popd "> + + + + @@ -65,6 +70,11 @@ BlueprintName = "UI Tests" ReferencedContainer = "container:DuckDuckGo.xcodeproj"> + + + + diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index 1ee442cfe3..2f93c17ac4 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -23,8 +23,10 @@ import Combine import Common import Configuration import CoreData +import Crashes import DDGSync import History +import MetricKit import Networking import Persistence import PixelKit @@ -33,13 +35,8 @@ import SyncDataProviders import UserNotifications import Lottie -#if NETWORK_PROTECTION import NetworkProtection -#endif - -#if SUBSCRIPTION import Subscription -#endif @MainActor final class AppDelegate: NSObject, NSApplicationDelegate { @@ -66,12 +63,18 @@ final class AppDelegate: NSObject, NSApplicationDelegate { let fileStore: FileStore +#if APPSTORE + private let crashCollection = CrashCollection(platform: .macOSAppStore, log: .default) +#else + private let crashReporter = CrashReporter() +#endif + private(set) var stateRestorationManager: AppStateRestorationManager! private var grammarFeaturesManager = GrammarFeaturesManager() - private let crashReporter = CrashReporter() let internalUserDecider: InternalUserDecider let featureFlagger: FeatureFlagger private var appIconChanger: AppIconChanger! + private var autoClearHandler: AutoClearHandler! private(set) var syncDataProviders: SyncDataProviders! private(set) var syncService: DDGSyncing? @@ -82,12 +85,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate { let bookmarksManager = LocalBookmarkManager.shared var privacyDashboardWindow: NSWindow? -#if NETWORK_PROTECTION && SUBSCRIPTION // Needs to be lazy as indirectly depends on AppDelegate private lazy var networkProtectionSubscriptionEventHandler = NetworkProtectionSubscriptionEventHandler() -#endif -#if DBP && SUBSCRIPTION +#if DBP private let dataBrokerProtectionSubscriptionEventHandler = DataBrokerProtectionSubscriptionEventHandler() #endif @@ -97,6 +98,13 @@ final class AppDelegate: NSObject, NSApplicationDelegate { var updateController: UpdateController! #endif + @UserDefaultsWrapper(key: .firstLaunchDate, defaultValue: Date.monthAgo) + static var firstLaunchDate: Date + + static var isNewUser: Bool { + return firstLaunchDate >= Date.weekAgo + } + // swiftlint:disable:next function_body_length override init() { do { @@ -111,22 +119,16 @@ final class AppDelegate: NSObject, NSApplicationDelegate { internalUserDecider = DefaultInternalUserDecider(store: internalUserDeciderStore) if NSApplication.runType.requiresEnvironment { -#if DEBUG - Pixel.setUp(dryRun: true) - Self.setUpPixelKit(dryRun: true) -#else - Pixel.setUp() - Self.setUpPixelKit(dryRun: false) -#endif + Self.configurePixelKit() Database.shared.loadStore { _, error in guard let error = error else { return } switch error { case CoreDataDatabase.Error.containerLocationCouldNotBePrepared(let underlyingError): - Pixel.fire(.debug(event: .dbContainerInitializationError, error: underlyingError)) + PixelKit.fire(DebugEvent(GeneralPixel.dbContainerInitializationError(error: underlyingError))) default: - Pixel.fire(.debug(event: .dbInitializationError, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.dbInitializationError(error: error))) } // Give Pixel a chance to be sent, but not too long @@ -135,12 +137,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } let preMigrationErrorHandling = EventMapping { _, error, _, _ in - if let error = error { - Pixel.fire(.debug(event: .bookmarksCouldNotLoadDatabase, error: error)) - } else { - Pixel.fire(.debug(event: .bookmarksCouldNotLoadDatabase)) - } - + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksCouldNotLoadDatabase(error: error))) Thread.sleep(forTimeInterval: 1) fatalError("Could not create Bookmarks database stack: \(error?.localizedDescription ?? "err")") } @@ -154,12 +151,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { BookmarkDatabase.shared.db.loadStore { context, error in guard let context = context else { - if let error = error { - Pixel.fire(.debug(event: .bookmarksCouldNotLoadDatabase, error: error)) - } else { - Pixel.fire(.debug(event: .bookmarksCouldNotLoadDatabase)) - } - + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksCouldNotLoadDatabase(error: error))) Thread.sleep(forTimeInterval: 1) fatalError("Could not create Bookmarks database stack: \(error?.localizedDescription ?? "err")") } @@ -181,15 +173,23 @@ final class AppDelegate: NSObject, NSApplicationDelegate { AppPrivacyFeatures.shared = AppPrivacyFeatures(contentBlocking: AppContentBlocking(internalUserDecider: internalUserDecider), database: Database.shared) #endif - featureFlagger = DefaultFeatureFlagger(internalUserDecider: internalUserDecider, - privacyConfig: AppPrivacyFeatures.shared.contentBlocking.privacyConfigurationManager.privacyConfig) + featureFlagger = DefaultFeatureFlagger( + internalUserDecider: internalUserDecider, + privacyConfigManager: AppPrivacyFeatures.shared.contentBlocking.privacyConfigurationManager + ) -#if SUBSCRIPTION #if APPSTORE || !STRIPE SubscriptionPurchaseEnvironment.current = .appStore #else SubscriptionPurchaseEnvironment.current = .stripe #endif + } + + static func configurePixelKit() { +#if DEBUG + Self.setUpPixelKit(dryRun: true) +#else + Self.setUpPixelKit(dryRun: false) #endif } @@ -222,6 +222,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate { PrivacyFeatures.httpsUpgrade.loadDataAsync() bookmarksManager.loadBookmarks() + + // Force use of .mainThread to prevent high WindowServer Usage + // Pending Fix with newer Lottie versions + // https://app.asana.com/0/1177771139624306/1207024603216659/f + LottieConfiguration.shared.renderingEngine = .mainThread + if case .normal = NSApp.runType { FaviconManager.shared.loadFavicons() } @@ -230,11 +236,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate { _ = RecentlyClosedCoordinator.shared // Clean up previous experiment - if PixelExperiment.allocatedCohortDoesNotMatchCurrentCohorts { - PixelExperiment.cleanup() - } +// if PixelExperiment.allocatedCohortDoesNotMatchCurrentCohorts { // Re-implement https://app.asana.com/0/0/1207002879349166/f +// PixelExperiment.cleanup() +// } + if LocalStatisticsStore().atb == nil { - Pixel.firstLaunchDate = Date() + AppDelegate.firstLaunchDate = Date() // MARK: Enable pixel experiments here } AtbAndVariantCleanup.cleanup() @@ -247,7 +254,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate { startupSync() -#if SUBSCRIPTION let defaultEnvironment = SubscriptionPurchaseEnvironment.ServiceEnvironment.default let currentEnvironment = UserDefaultsWrapper(key: .subscriptionEnvironment, @@ -261,7 +267,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate { _ = await accountManager.fetchEntitlements(cachePolicy: .reloadIgnoringLocalCacheData) } } -#endif if [.normal, .uiTests].contains(NSApp.runType) { stateRestorationManager.applicationDidFinishLaunching() @@ -278,7 +283,19 @@ final class AppDelegate: NSObject, NSApplicationDelegate { applyPreferredTheme() +#if APPSTORE + crashCollection.start { pixelParameters, payloads, completion in + pixelParameters.forEach { _ in PixelKit.fire(GeneralPixel.crash) } + guard let lastPayload = payloads.last else { + return + } + DispatchQueue.main.async { + CrashReportPromptPresenter().showPrompt(for: lastPayload, userDidAllowToReport: completion) + } + } +#else crashReporter.checkForNewReports() +#endif urlEventHandler.applicationDidFinishLaunching() @@ -287,16 +304,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate { UserDefaultsWrapper.clearRemovedKeys() -#if NETWORK_PROTECTION && SUBSCRIPTION networkProtectionSubscriptionEventHandler.registerForSubscriptionAccountManagerEvents() -#endif -#if NETWORK_PROTECTION NetworkProtectionAppEvents().applicationDidFinishLaunching() UNUserNotificationCenter.current().delegate = self -#endif -#if DBP && SUBSCRIPTION +#if DBP dataBrokerProtectionSubscriptionEventHandler.registerForSubscriptionAccountManagerEvents() #endif @@ -304,9 +317,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { DataBrokerProtectionAppEvents().applicationDidFinishLaunching() #endif -#if SUBSCRIPTION - -#endif + setUpAutoClearHandler() } func applicationDidBecomeActive(_ notification: Notification) { @@ -315,13 +326,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { syncService?.initializeIfNeeded() syncService?.scheduler.notifyAppLifecycleEvent() -#if NETWORK_PROTECTION - NetworkProtectionWaitlist().fetchNetworkProtectionInviteCodeIfAvailable { _ in - // Do nothing when code fetching fails, as the app will try again later - } - NetworkProtectionAppEvents().applicationDidBecomeActive() -#endif #if DBP DataBrokerProtectionAppEvents().applicationDidBecomeActive() @@ -346,6 +351,11 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } stateRestorationManager?.applicationWillTerminate() + // Handling of "Burn on quit" + if let terminationReply = autoClearHandler.handleAppTermination() { + return terminationReply + } + return .terminateNow } @@ -372,7 +382,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } private static func setUpPixelKit(dryRun: Bool) { -#if NETWORK_PROTECTION #if APPSTORE let source = "browser-appstore" #else @@ -383,7 +392,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate { appVersion: AppVersion.shared.versionNumber, source: source, defaultHeaders: [:], - log: .networkProtectionPixel, defaults: .netP) { (pixelName: String, headers: [String: String], parameters: [String: String], _, _, onComplete: @escaping PixelKit.CompletionBlock) in let url = URL.pixelUrl(forPixelNamed: pixelName) @@ -395,7 +403,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate { onComplete(error == nil, error) } } -#endif } // MARK: - Sync @@ -442,9 +449,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate { .filter { $0 } .asVoid() .sink { [weak syncService] in - Pixel.fire(.syncDaily, limitTo: .dailyFirst) + PixelKit.fire(GeneralPixel.syncDaily, frequency: .daily) syncService?.syncDailyStats.sendStatsIfNeeded(handler: { params in - Pixel.fire(.syncSuccessRateDaily, withAdditionalParameters: params) + PixelKit.fire(GeneralPixel.syncSuccessRateDaily, withAdditionalParameters: params) }) } @@ -525,9 +532,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } private func emailDidSignInNotification(_ notification: Notification) { - Pixel.fire(.emailEnabled) - if Pixel.isNewUser { - Pixel.fire(.emailEnabledInitial, limitTo: .initial) + PixelKit.fire(GeneralPixel.emailEnabled) + if AppDelegate.isNewUser { + PixelKit.fire(GeneralPixel.emailEnabledInitial, frequency: .legacyInitial) } if let object = notification.object as? EmailManager, let emailManager = syncDataProviders.settingsAdapter.emailManager, object !== emailManager { @@ -536,22 +543,31 @@ final class AppDelegate: NSObject, NSApplicationDelegate { } private func emailDidSignOutNotification(_ notification: Notification) { - Pixel.fire(.emailDisabled) + PixelKit.fire(GeneralPixel.emailDisabled) if let object = notification.object as? EmailManager, let emailManager = syncDataProviders.settingsAdapter.emailManager, object !== emailManager { syncService?.scheduler.notifyDataChanged() } } @objc private func dataImportCompleteNotification(_ notification: Notification) { - if Pixel.isNewUser { - Pixel.fire(.importDataInitial, limitTo: .initial) + if AppDelegate.isNewUser { + PixelKit.fire(GeneralPixel.importDataInitial, frequency: .legacyInitial) + } + } + + private func setUpAutoClearHandler() { + autoClearHandler = AutoClearHandler(preferences: .shared, + fireViewModel: FireCoordinator.fireViewModel, + stateRestorationManager: stateRestorationManager) + autoClearHandler.handleAppLaunch() + autoClearHandler.onAutoClearCompleted = { + NSApplication.shared.reply(toApplicationShouldTerminate: true) } } } func updateSubscriptionStatus() { -#if SUBSCRIPTION Task { let accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) @@ -559,17 +575,14 @@ func updateSubscriptionStatus() { if case .success(let subscription) = await SubscriptionService.getSubscription(accessToken: token, cachePolicy: .reloadIgnoringLocalCacheData) { if subscription.isActive { - DailyPixel.fire(pixel: .privacyProSubscriptionActive, frequency: .dailyOnly) + PixelKit.fire(PrivacyProPixel.privacyProSubscriptionActive, frequency: .daily) } } _ = await accountManager.fetchEntitlements(cachePolicy: .reloadIgnoringLocalCacheData) } -#endif } -#if NETWORK_PROTECTION || DBP - extension AppDelegate: UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, @@ -583,15 +596,6 @@ extension AppDelegate: UNUserNotificationCenterDelegate { withCompletionHandler completionHandler: @escaping () -> Void) { if response.actionIdentifier == UNNotificationDefaultActionIdentifier { -#if NETWORK_PROTECTION - if response.notification.request.identifier == NetworkProtectionWaitlist.notificationIdentifier { - if NetworkProtectionWaitlist().readyToAcceptTermsAndConditions { - DailyPixel.fire(pixel: .networkProtectionWaitlistNotificationTapped, frequency: .dailyAndCount) - NetworkProtectionWaitlistViewControllerPresenter.show() - } - } -#endif - #if DBP if response.notification.request.identifier == DataBrokerProtectionWaitlist.notificationIdentifier { DataBrokerProtectionAppEvents().handleWaitlistInvitedNotification(source: .localPush) @@ -603,5 +607,3 @@ extension AppDelegate: UNUserNotificationCenterDelegate { } } - -#endif diff --git a/DuckDuckGo/Application/AutoClearHandler.swift b/DuckDuckGo/Application/AutoClearHandler.swift new file mode 100644 index 0000000000..f1044dae5f --- /dev/null +++ b/DuckDuckGo/Application/AutoClearHandler.swift @@ -0,0 +1,125 @@ +// +// AutoClearHandler.swift +// +// 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 Combine + +final class AutoClearHandler { + + private let preferences: DataClearingPreferences + private let fireViewModel: FireViewModel + private let stateRestorationManager: AppStateRestorationManager + + init(preferences: DataClearingPreferences, + fireViewModel: FireViewModel, + stateRestorationManager: AppStateRestorationManager) { + self.preferences = preferences + self.fireViewModel = fireViewModel + self.stateRestorationManager = stateRestorationManager + } + + @MainActor + func handleAppLaunch() { + burnOnStartIfNeeded() + restoreTabsIfNeeded() + resetTheCorrectTerminationFlag() + } + + var onAutoClearCompleted: (() -> Void)? + + @MainActor + func handleAppTermination() -> NSApplication.TerminateReply? { + guard preferences.isAutoClearEnabled else { return nil } + + if preferences.isWarnBeforeClearingEnabled { + switch confirmAutoClear() { + case .alertFirstButtonReturn: + // Clear and Quit + performAutoClear() + return .terminateLater + case .alertSecondButtonReturn: + // Quit without Clearing Data + appTerminationHandledCorrectly = true + restoreTabsOnStartup = true + return .terminateNow + default: + // Cancel + return .terminateCancel + } + } + + performAutoClear() + return .terminateLater + } + + func resetTheCorrectTerminationFlag() { + appTerminationHandledCorrectly = false + } + + // MARK: - Private + + private func confirmAutoClear() -> NSApplication.ModalResponse { + let alert = NSAlert.autoClearAlert() + let response = alert.runModal() + return response + } + + @MainActor + private func performAutoClear() { + fireViewModel.fire.burnAll { [weak self] in + self?.appTerminationHandledCorrectly = true + self?.onAutoClearCompleted?() + } + } + + // MARK: - Burn On Start + // Burning on quit wasn't successful + + @UserDefaultsWrapper(key: .appTerminationHandledCorrectly, defaultValue: false) + private var appTerminationHandledCorrectly: Bool + + @MainActor + @discardableResult + func burnOnStartIfNeeded() -> Bool { + let shouldBurnOnStart = preferences.isAutoClearEnabled && !appTerminationHandledCorrectly + guard shouldBurnOnStart else { return false } + + fireViewModel.fire.burnAll() + return true + } + + // MARK: - Burn without Clearing Data + + @UserDefaultsWrapper(key: .restoreTabsOnStartup, defaultValue: false) + private var restoreTabsOnStartup: Bool + + @MainActor + @discardableResult + func restoreTabsIfNeeded() -> Bool { + let isAutoClearEnabled = preferences.isAutoClearEnabled + let restoreTabsOnStartup = restoreTabsOnStartup + self.restoreTabsOnStartup = false + if isAutoClearEnabled && restoreTabsOnStartup { + stateRestorationManager.restoreLastSessionState(interactive: false) + return true + } + + return false + } + +} diff --git a/DuckDuckGo/Application/URLEventHandler.swift b/DuckDuckGo/Application/URLEventHandler.swift index 7ae97a807f..003cf5500b 100644 --- a/DuckDuckGo/Application/URLEventHandler.swift +++ b/DuckDuckGo/Application/URLEventHandler.swift @@ -19,10 +19,9 @@ import Common import Foundation import AppKit +import PixelKit -#if NETWORK_PROTECTION import NetworkProtectionUI -#endif #if DBP import DataBrokerProtection @@ -63,15 +62,15 @@ final class URLEventHandler { @objc func handleUrlEvent(event: NSAppleEventDescriptor, reply: NSAppleEventDescriptor) { guard let stringValue = event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue else { os_log("UrlEventListener: unable to determine path", type: .error) - Pixel.fire(.debug(event: .appOpenURLFailed, - error: NSError(domain: "CouldNotGetPath", code: -1, userInfo: nil))) + let error = NSError(domain: "CouldNotGetPath", code: -1, userInfo: nil) + PixelKit.fire(DebugEvent(GeneralPixel.appOpenURLFailed, error: error)) return } guard let url = URL.makeURL(from: stringValue) else { os_log("UrlEventListener: failed to construct URL from path %s", type: .error, stringValue) - Pixel.fire(.debug(event: .appOpenURLFailed, - error: NSError(domain: "CouldNotConstructURL", code: -1, userInfo: nil))) + let error = NSError(domain: "CouldNotConstructURL", code: -1, userInfo: nil) + PixelKit.fire(DebugEvent(GeneralPixel.appOpenURLFailed, error: error)) return } @@ -104,11 +103,9 @@ final class URLEventHandler { } private static func openURL(_ url: URL) { -#if NETWORK_PROTECTION if url.scheme?.isNetworkProtectionScheme == true { handleNetworkProtectionURL(url) } -#endif #if DBP if url.scheme?.isDataBrokerProtectionScheme == true { @@ -131,18 +128,12 @@ final class URLEventHandler { return } -#if NETWORK_PROTECTION || DBP if url.scheme?.isNetworkProtectionScheme == false && url.scheme?.isDataBrokerProtectionScheme == false { WaitlistModalDismisser.dismissWaitlistModalViewControllerIfNecessary(url) WindowControllersManager.shared.show(url: url, source: .appOpenUrl, newTab: true) } -#else - WindowControllersManager.shared.show(url: url, source: .appOpenUrl, newTab: true) -#endif } -#if NETWORK_PROTECTION - /// Handles NetP URLs /// private static func handleNetworkProtectionURL(_ url: URL) { @@ -155,14 +146,14 @@ final class URLEventHandler { WindowControllersManager.shared.showPreferencesTab(withSelectedPane: .vpn) case AppLaunchCommand.shareFeedback.launchURL: WindowControllersManager.shared.showShareFeedbackModal() + case AppLaunchCommand.justOpen.launchURL: + WindowControllersManager.shared.showMainWindow() case AppLaunchCommand.showVPNLocations.launchURL: WindowControllersManager.shared.showPreferencesTab(withSelectedPane: .vpn) WindowControllersManager.shared.showLocationPickerSheet() -#if SUBSCRIPTION case AppLaunchCommand.showPrivacyPro.launchURL: WindowControllersManager.shared.showTab(with: .subscription(.subscriptionPurchase)) - Pixel.fire(.privacyProOfferScreenImpression) -#endif + PixelKit.fire(PrivacyProPixel.privacyProOfferScreenImpression) #if !APPSTORE && !DEBUG case AppLaunchCommand.moveAppToApplications.launchURL: // this should be run after NSApplication.shared is set @@ -173,8 +164,6 @@ final class URLEventHandler { } } -#endif - #if DBP /// Handles DBP URLs /// diff --git a/DuckDuckGo/Application/UpdateController.swift b/DuckDuckGo/Application/UpdateController.swift index 13fcacd30d..56f8d5c0fb 100644 --- a/DuckDuckGo/Application/UpdateController.swift +++ b/DuckDuckGo/Application/UpdateController.swift @@ -21,6 +21,7 @@ import Combine import Sparkle import BrowserServicesKit import SwiftUIExtensions +import PixelKit #if SPARKLE @@ -107,7 +108,7 @@ extension UpdateController: SPUUpdaterDelegate { return } - Pixel.fire(.debug(event: .updaterAborted, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.updaterAborted, error: error)) } func updater(_ updater: SPUUpdater, @@ -116,11 +117,11 @@ extension UpdateController: SPUUpdaterDelegate { state: SPUUserUpdateState) { switch choice { case .skip: - Pixel.fire(.debug(event: .userSelectedToSkipUpdate)) + PixelKit.fire(DebugEvent(GeneralPixel.userSelectedToSkipUpdate)) case .install: - Pixel.fire(.debug(event: .userSelectedToInstallUpdate)) + PixelKit.fire(DebugEvent(GeneralPixel.userSelectedToInstallUpdate)) case .dismiss: - Pixel.fire(.debug(event: .userSelectedToDismissUpdate)) + PixelKit.fire(DebugEvent(GeneralPixel.userSelectedToDismissUpdate)) @unknown default: break } diff --git a/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Burn-Original-large.pdf b/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Burn-Original-large.pdf deleted file mode 100644 index 2208d56068..0000000000 Binary files a/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Burn-Original-large.pdf and /dev/null differ diff --git a/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Contents.json index 48111f0d3f..3f5be128a3 100644 --- a/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Contents.json +++ b/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Burn-Original-large.pdf", + "filename" : "Fire-96x96.pdf", "idiom" : "universal" } ], diff --git a/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Fire-96x96.pdf b/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Fire-96x96.pdf new file mode 100644 index 0000000000..297359ff71 Binary files /dev/null and b/DuckDuckGo/Assets.xcassets/Images/BurnAlert.imageset/Fire-96x96.pdf differ diff --git a/DuckDuckGo/Assets.xcassets/Images/Chevron-Right-12.imageset/Chevron-Right-12-light.svg b/DuckDuckGo/Assets.xcassets/Images/Chevron-Right-12.imageset/Chevron-Right-12-light.svg new file mode 100644 index 0000000000..2b4a602355 --- /dev/null +++ b/DuckDuckGo/Assets.xcassets/Images/Chevron-Right-12.imageset/Chevron-Right-12-light.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/DuckDuckGo/Assets.xcassets/Images/Chevron-Right-12.imageset/Chevron-Right-12.svg b/DuckDuckGo/Assets.xcassets/Images/Chevron-Right-12.imageset/Chevron-Right-12.svg new file mode 100644 index 0000000000..4faab69801 --- /dev/null +++ b/DuckDuckGo/Assets.xcassets/Images/Chevron-Right-12.imageset/Chevron-Right-12.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/NetworkProtectionAvailableButton.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/Chevron-Right-12.imageset/Contents.json similarity index 75% rename from DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/NetworkProtectionAvailableButton.imageset/Contents.json rename to DuckDuckGo/Assets.xcassets/Images/Chevron-Right-12.imageset/Contents.json index 89e4996541..7fea6d5282 100644 --- a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/NetworkProtectionAvailableButton.imageset/Contents.json +++ b/DuckDuckGo/Assets.xcassets/Images/Chevron-Right-12.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Toolbar Button.pdf", + "filename" : "Chevron-Right-12.svg", "idiom" : "universal" }, { @@ -11,7 +11,7 @@ "value" : "dark" } ], - "filename" : "Toolbar Button 1.pdf", + "filename" : "Chevron-Right-12-light.svg", "idiom" : "universal" } ], diff --git a/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/Contents.json b/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/Contents.json similarity index 100% rename from DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/Contents.json rename to DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/Contents.json diff --git a/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/DBP-Icon.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/DBP-Icon.imageset/Contents.json similarity index 100% rename from DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/DBP-Icon.imageset/Contents.json rename to DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/DBP-Icon.imageset/Contents.json diff --git a/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/DBP-Icon.imageset/DBP-Icon.pdf b/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/DBP-Icon.imageset/DBP-Icon.pdf similarity index 100% rename from DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/DBP-Icon.imageset/DBP-Icon.pdf rename to DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/DBP-Icon.imageset/DBP-Icon.pdf diff --git a/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/DBP-Information-Remover.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/DBP-Information-Remover.imageset/Contents.json similarity index 100% rename from DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/DBP-Information-Remover.imageset/Contents.json rename to DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/DBP-Information-Remover.imageset/Contents.json diff --git a/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/DBP-Information-Remover.imageset/DBP-Information-Remover.svg b/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/DBP-Information-Remover.imageset/DBP-Information-Remover.svg similarity index 100% rename from DuckDuckGo/Assets.xcassets/Images/DataBrokerProtectionWaitlist/DBP-Information-Remover.imageset/DBP-Information-Remover.svg rename to DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/DBP-Information-Remover.imageset/DBP-Information-Remover.svg diff --git a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Rocket-16.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/dbp-error-info.imageset/Contents.json similarity index 63% rename from DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Rocket-16.imageset/Contents.json rename to DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/dbp-error-info.imageset/Contents.json index b23b52c784..9869fe984d 100644 --- a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Rocket-16.imageset/Contents.json +++ b/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/dbp-error-info.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Rocket-16.pdf", + "filename" : "dbp-error-info.pdf", "idiom" : "universal" } ], @@ -10,6 +10,6 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "template" + "template-rendering-intent" : "original" } } diff --git a/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/dbp-error-info.imageset/dbp-error-info.pdf b/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/dbp-error-info.imageset/dbp-error-info.pdf new file mode 100644 index 0000000000..c9486753e5 Binary files /dev/null and b/DuckDuckGo/Assets.xcassets/Images/DataBrokerProtection/dbp-error-info.imageset/dbp-error-info.pdf differ diff --git a/DuckDuckGo/Assets.xcassets/Images/Error.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/Error.imageset/Contents.json index c8ff07440c..98276ca193 100644 --- a/DuckDuckGo/Assets.xcassets/Images/Error.imageset/Contents.json +++ b/DuckDuckGo/Assets.xcassets/Images/Error.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Error.pdf", + "filename" : "Exclamation-Recolorable-16.pdf", "idiom" : "universal" } ], diff --git a/DuckDuckGo/Assets.xcassets/Images/Error.imageset/Error.pdf b/DuckDuckGo/Assets.xcassets/Images/Error.imageset/Exclamation-Recolorable-16.pdf similarity index 50% rename from DuckDuckGo/Assets.xcassets/Images/Error.imageset/Error.pdf rename to DuckDuckGo/Assets.xcassets/Images/Error.imageset/Exclamation-Recolorable-16.pdf index f8efeca609..4f4f2518c4 100644 Binary files a/DuckDuckGo/Assets.xcassets/Images/Error.imageset/Error.pdf and b/DuckDuckGo/Assets.xcassets/Images/Error.imageset/Exclamation-Recolorable-16.pdf differ diff --git a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Shield-16.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/Identity-Theft-Restoration-Multicolor-16.imageset/Contents.json similarity index 56% rename from DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Shield-16.imageset/Contents.json rename to DuckDuckGo/Assets.xcassets/Images/Identity-Theft-Restoration-Multicolor-16.imageset/Contents.json index 510acba745..c878d4b14f 100644 --- a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Shield-16.imageset/Contents.json +++ b/DuckDuckGo/Assets.xcassets/Images/Identity-Theft-Restoration-Multicolor-16.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Shield-16.pdf", + "filename" : "Identity-Theft-Restoration-Multicolor-16.pdf", "idiom" : "universal" } ], @@ -10,6 +10,6 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "template" + "preserves-vector-representation" : true } } diff --git a/DuckDuckGo/Assets.xcassets/Images/Identity-Theft-Restoration-Multicolor-16.imageset/Identity-Theft-Restoration-Multicolor-16.pdf b/DuckDuckGo/Assets.xcassets/Images/Identity-Theft-Restoration-Multicolor-16.imageset/Identity-Theft-Restoration-Multicolor-16.pdf new file mode 100644 index 0000000000..30563fa583 Binary files /dev/null and b/DuckDuckGo/Assets.xcassets/Images/Identity-Theft-Restoration-Multicolor-16.imageset/Identity-Theft-Restoration-Multicolor-16.pdf differ diff --git a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Card-16.imageset/Card-16.pdf b/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Card-16.imageset/Card-16.pdf deleted file mode 100644 index ead0016185..0000000000 Binary files a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Card-16.imageset/Card-16.pdf and /dev/null differ diff --git a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/NetworkProtectionAvailableButton.imageset/Toolbar Button 1.pdf b/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/NetworkProtectionAvailableButton.imageset/Toolbar Button 1.pdf deleted file mode 100644 index 6fca4a04e3..0000000000 Binary files a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/NetworkProtectionAvailableButton.imageset/Toolbar Button 1.pdf and /dev/null differ diff --git a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/NetworkProtectionAvailableButton.imageset/Toolbar Button.pdf b/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/NetworkProtectionAvailableButton.imageset/Toolbar Button.pdf deleted file mode 100644 index 04826a0a10..0000000000 Binary files a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/NetworkProtectionAvailableButton.imageset/Toolbar Button.pdf and /dev/null differ diff --git a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Rocket-16.imageset/Rocket-16.pdf b/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Rocket-16.imageset/Rocket-16.pdf deleted file mode 100644 index c7dd245c4f..0000000000 Binary files a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Rocket-16.imageset/Rocket-16.pdf and /dev/null differ diff --git a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Shield-16.imageset/Shield-16.pdf b/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Shield-16.imageset/Shield-16.pdf deleted file mode 100644 index 677edb434b..0000000000 Binary files a/DuckDuckGo/Assets.xcassets/Images/NetworkProtectionWaitlist/Shield-16.imageset/Shield-16.pdf and /dev/null differ diff --git a/DuckDuckGo/Assets.xcassets/Images/PersonalInformationRemoval-Multicolor-16.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/PersonalInformationRemoval-Multicolor-16.imageset/Contents.json new file mode 100644 index 0000000000..a30ef3d53e --- /dev/null +++ b/DuckDuckGo/Assets.xcassets/Images/PersonalInformationRemoval-Multicolor-16.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "PersonalInformationRemoval-Multicolor-16.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DuckDuckGo/Assets.xcassets/Images/PersonalInformationRemoval-Multicolor-16.imageset/PersonalInformationRemoval-Multicolor-16.pdf b/DuckDuckGo/Assets.xcassets/Images/PersonalInformationRemoval-Multicolor-16.imageset/PersonalInformationRemoval-Multicolor-16.pdf new file mode 100644 index 0000000000..fbabea4523 Binary files /dev/null and b/DuckDuckGo/Assets.xcassets/Images/PersonalInformationRemoval-Multicolor-16.imageset/PersonalInformationRemoval-Multicolor-16.pdf differ diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Resources/Assets.xcassets/Icons/VPN-128.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/Red-Alert-Circle-16.imageset/Contents.json similarity index 70% rename from LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Resources/Assets.xcassets/Icons/VPN-128.imageset/Contents.json rename to DuckDuckGo/Assets.xcassets/Images/Red-Alert-Circle-16.imageset/Contents.json index 86f2574f00..ca57c1c377 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Resources/Assets.xcassets/Icons/VPN-128.imageset/Contents.json +++ b/DuckDuckGo/Assets.xcassets/Images/Red-Alert-Circle-16.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Network-Protetion-VPN-128.pdf", + "filename" : "Red-Alert-Circle-16.svg", "idiom" : "universal" } ], diff --git a/DuckDuckGo/Assets.xcassets/Images/Red-Alert-Circle-16.imageset/Red-Alert-Circle-16.svg b/DuckDuckGo/Assets.xcassets/Images/Red-Alert-Circle-16.imageset/Red-Alert-Circle-16.svg new file mode 100644 index 0000000000..5de49b6b87 --- /dev/null +++ b/DuckDuckGo/Assets.xcassets/Images/Red-Alert-Circle-16.imageset/Red-Alert-Circle-16.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Resources/Assets.xcassets/Icons/VPN-Disabled-128.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/Settings-Multicolor-16.imageset/Contents.json similarity index 66% rename from LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Resources/Assets.xcassets/Icons/VPN-Disabled-128.imageset/Contents.json rename to DuckDuckGo/Assets.xcassets/Images/Settings-Multicolor-16.imageset/Contents.json index 20e5eff4ab..d4b2052646 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Resources/Assets.xcassets/Icons/VPN-Disabled-128.imageset/Contents.json +++ b/DuckDuckGo/Assets.xcassets/Images/Settings-Multicolor-16.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Network-Protetion-VPN-Disabled-128.pdf", + "filename" : "Settings-Multicolor-16.pdf", "idiom" : "universal" } ], diff --git a/DuckDuckGo/Assets.xcassets/Images/Settings-Multicolor-16.imageset/Settings-Multicolor-16.pdf b/DuckDuckGo/Assets.xcassets/Images/Settings-Multicolor-16.imageset/Settings-Multicolor-16.pdf new file mode 100644 index 0000000000..b3b41002c2 Binary files /dev/null and b/DuckDuckGo/Assets.xcassets/Images/Settings-Multicolor-16.imageset/Settings-Multicolor-16.pdf differ diff --git a/DuckDuckGo/Assets.xcassets/Images/Skipped.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/Skipped.imageset/Contents.json new file mode 100644 index 0000000000..89a905405a --- /dev/null +++ b/DuckDuckGo/Assets.xcassets/Images/Skipped.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Jump-Recolorable-16.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DuckDuckGo/Assets.xcassets/Images/Skipped.imageset/Jump-Recolorable-16.pdf b/DuckDuckGo/Assets.xcassets/Images/Skipped.imageset/Jump-Recolorable-16.pdf new file mode 100644 index 0000000000..f0c7598cc8 Binary files /dev/null and b/DuckDuckGo/Assets.xcassets/Images/Skipped.imageset/Jump-Recolorable-16.pdf differ diff --git a/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/Check-Recolorable-16.pdf b/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/Check-Recolorable-16.pdf new file mode 100644 index 0000000000..719cb643de Binary files /dev/null and b/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/Check-Recolorable-16.pdf differ diff --git a/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/Contents.json index 09a818b90b..07d8227e97 100644 --- a/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/Contents.json +++ b/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "SuccessCheckmark.pdf", + "filename" : "Check-Recolorable-16.pdf", "idiom" : "universal" } ], diff --git a/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/SuccessCheckmark.pdf b/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/SuccessCheckmark.pdf deleted file mode 100644 index bb50d381fa..0000000000 Binary files a/DuckDuckGo/Assets.xcassets/Images/SuccessCheckmark.imageset/SuccessCheckmark.pdf and /dev/null differ diff --git a/DuckDuckGo/Autoconsent/AutoconsentUserScript.swift b/DuckDuckGo/Autoconsent/AutoconsentUserScript.swift index c43f7dc27c..2000073692 100644 --- a/DuckDuckGo/Autoconsent/AutoconsentUserScript.swift +++ b/DuckDuckGo/Autoconsent/AutoconsentUserScript.swift @@ -202,7 +202,7 @@ extension AutoconsentUserScript { return } - guard [.http, .https].contains(url.navigationalScheme) else { + guard url.navigationalScheme?.isHypertextScheme == true else { // ignore special schemes os_log("Ignoring special URL scheme: %s", log: .autoconsent, type: .debug, messageData.url) replyHandler([ "type": "ok" ], nil) // this is just to prevent a Promise rejection diff --git a/DuckDuckGo/Autoconsent/autoconsent-bundle.js b/DuckDuckGo/Autoconsent/autoconsent-bundle.js index db02dcc60b..85e242339a 100644 --- a/DuckDuckGo/Autoconsent/autoconsent-bundle.js +++ b/DuckDuckGo/Autoconsent/autoconsent-bundle.js @@ -1 +1 @@ -!function(){"use strict";var e=class e{static setBase(t){e.base=t}static findElement(t,o=null,c=!1){let i=null;return i=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&&(i=i.filter((e=>{const o=e.textContent.toLowerCase();if(Array.isArray(t.textFilter)){let e=!1;for(const c of t.textFilter)if(-1!==o.indexOf(c.toLowerCase())){e=!0;break}return e}if(null!=t.textFilter)return-1!==o.indexOf(t.textFilter.toLowerCase())}))),null!=t.styleFilters&&(i=i.filter((e=>{const o=window.getComputedStyle(e);let c=!0;for(const e of t.styleFilters){const t=o[e.option];c=e.negated?c&&t!==e.value:c&&t===e.value}return c}))),null!=t.displayFilter&&(i=i.filter((e=>t.displayFilter?0!==e.offsetHeight:0===e.offsetHeight))),null!=t.iframeFilter&&(i=i.filter((()=>t.iframeFilter?window.location!==window.parent.location:window.location===window.parent.location))),null!=t.childFilter&&(i=i.filter((o=>{const c=e.base;e.setBase(o);const i=e.find(t.childFilter);return e.setBase(c),null!=i.target}))),c?i:(i.length>1&&console.warn("Multiple possible targets: ",i,t,o),i[0])}static find(t,o=!1){const c=[];if(null!=t.parent){const i=e.findElement(t.parent,null,o);if(null!=i){if(i instanceof Array)return i.forEach((i=>{const n=e.findElement(t.target,i,o);n instanceof Array?n.forEach((e=>{c.push({parent:i,target:e})})):c.push({parent:i,target:n})})),c;{const n=e.findElement(t.target,i,o);n instanceof Array?n.forEach((e=>{c.push({parent:i,target:e})})):c.push({parent:i,target:n})}}}else{const i=e.findElement(t.target,null,o);i instanceof Array?i.forEach((e=>{c.push({parent:null,target:e})})):c.push({parent:null,target:i})}return 0===c.length&&c.push({parent:null,target:null}),o?c:(1!==c.length&&console.warn("Multiple results found, even though multiple false",c),c[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 c(e,n){switch(e.type){case"click":return async function(e){const o=t.find(e);null!=o.target&&o.target.click();return i(0)}(e);case"list":return async function(e,t){for(const o of e.actions)await c(o,t)}(e,n);case"consent":return async function(e,t){for(const i of e.consents){const e=-1!==t.indexOf(i.type);if(i.matcher&&i.toggleAction){o(i.matcher)!==e&&await c(i.toggleAction)}else e?await c(i.trueAction):await c(i.falseAction)}}(e,n);case"ifcss":return async function(e,o){const i=t.find(e);i.target?e.falseAction&&await c(e.falseAction,o):e.trueAction&&await c(e.trueAction,o)}(e,n);case"waitcss":return async function(e){await new Promise((o=>{let c=e.retries||10;const i=e.waitTime||250,n=()=>{const a=t.find(e);(e.negated&&a.target||!e.negated&&!a.target)&&c>0?(c-=1,setTimeout(n,i)):o()};n()}))}(e);case"foreach":return async function(e,o){const i=t.find(e,!0),n=t.base;for(const n of i)n.target&&(t.setBase(n.target),await c(e.action,o));t.setBase(n)}(e,n);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),c=t.find(e.dragTarget);if(o.target){const e=o.target.getBoundingClientRect(),t=c.target.getBoundingClientRect();let i=t.top-e.top,n=t.left-e.left;"y"===this.config.axis.toLowerCase()&&(n=0),"x"===this.config.axis.toLowerCase()&&(i=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+i,r+n,l+i,!1,!1,!1,!1,0,o.target);const u=document.createEvent("MouseEvents");u.initMouseEvent("mouseup",!0,!0,window,0,a+n,s+i,r+n,l+i,!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 i(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}}function i(e){return new Promise((t=>{setTimeout((()=>{t()}),e)}))}function n(){return crypto&&void 0!==crypto.randomUUID?crypto.randomUUID():Math.random().toString()}var a={pending:new Map,sendContentMessage:null};function s(e,t){const o=n();a.sendContentMessage({type:"eval",id:o,code:e,snippetId:t});const c=new 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)}}(o);return a.pending.set(c.id,c),c.promise}var r={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_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_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_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_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||"moove_gdpr_strict_cookies"===e.name||(e.checked=!1)}))||!0,EVAL_ONENINETWO_0:()=>document.cookie.includes("CC_ADVERTISING=NO")&&document.cookie.includes("CC_ANALYTICS=NO"),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_SIBBO_0:()=>!!window.localStorage.getItem("euconsent-v2"),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_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_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 l={main:!0,frame:!1,urlPattern:""},p=class{constructor(e){this.runContext=l,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=r[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 c=!1;try{c=!!t.call(globalThis)}catch(t){o.evals&&console.error("error evaluating rule",e,t)}return Promise.resolve(c)}const c=`(${t.toString()})()`;return o.evals&&console.log("async eval:",e,c),s(c,e).catch((t=>(o.evals&&console.error("error evaluating rule",e,t),!1)))}checkRunContext(){const e={...l,...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)}},d=class extends p{constructor(e,t){super(t),this.rule=e,this.name=e.name,this.runContext=e.runContext||l}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 c=await this.evaluateRuleStep(e.if);o.rulesteps&&console.log("Condition is",c),c?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}};function u(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 m(e,t,o="display"){const c=`${t} { ${"opacity"===o?"opacity: 0":"display: none"} !important; z-index: -1 !important; pointer-events: none !important; } `;return e instanceof HTMLStyleElement&&(e.innerText+=c,t.length>0)}async function h(e,t,o){const c=await e();return!c&&t>0?new Promise((c=>{setTimeout((async()=>{c(h(e,t-1,o))}),o)})):Promise.resolve(c)}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,logs:{lifecycle:!1,rulesteps:!1,evals:!1,errors:!0,messages:!1}},o=(c=t,globalThis.structuredClone?structuredClone(c):JSON.parse(JSON.stringify(c)));var c;for(const c of Object.keys(t))void 0!==e[c]&&(o[c]=e[c]);return o}var _="#truste-show-consent",g="#truste-consent-track",y=[class extends p{constructor(e){super(e),this.name="TrustArc-top",this.prehideSelectors=[".trustarc-banner-container",`.truste_popframe,.truste_overlay,.truste_box_overlay,${g}`],this.runContext={main:!0,frame:!1},this._shortcutButton=null,this._optInDone=!1}get hasSelfTest(){return!1}get isIntermediate(){return!this._optInDone&&!this._shortcutButton}get isCosmetic(){return!1}async detectCmp(){const e=this.elementExists(`${_},${g}`);return e&&(this._shortcutButton=document.querySelector("#truste-consent-required")),e}async detectPopup(){return this.elementVisible(`#truste-consent-content,#trustarc-banner-overlay,${g}`,"all")}openFrame(){this.click(_)}async optOut(){return this._shortcutButton?(this._shortcutButton.click(),!0):(m(u(),`.truste_popframe, .truste_overlay, .truste_box_overlay, ${g}`),this.click(_),setTimeout((()=>{u().remove()}),1e4),!0)}async optIn(){return this._optInDone=!0,this.click("#truste-consent-button")}async openCmp(){return!0}async test(){return await this.mainWorldEval("EVAL_TRUSTARC_TOP")}},class extends p{constructor(){super(...arguments),this.name="TrustArc-frame",this.runContext={main:!1,frame:!0,urlPattern:"^https://consent-pref\\.trustarc\\.com/\\?"}}get hasSelfTest(){return!1}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 h((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 h((()=>this.elementVisible(".switch span:first-child","any")),5,1e3)}async optOut(){return await h((()=>"complete"===document.readyState),20,100),await this.waitForElement(".mainContent[aria-hidden=false]",5e3),!!this.click(".rejectAll")||(this.elementExists(".prefPanel")&&await this.waitForElement('.prefPanel[style="visibility: visible;"]',3e3),this.click("#catDetails0")?(this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",5e3),!0):this.click(".required")?(this.waitForThenClick("#gwt-debug-close_id",5e3),!0):(await this.navigateToSettings(),this.click(".switch span:nth-child(1):not(.active)",!0),this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",3e5),!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}},class extends p{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 p{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:!1,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 h((()=>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.wait(1500),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 p{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 p{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")||(m(u(),"#evidon-prefdiag-overlay,#evidon-prefdiag-background"),this.click("#_evidon-option-button"),await this.waitForElement("#evidon-prefdiag-overlay",5e3),this.click("#evidon-prefdiag-decline")),!0}async optIn(){return this.click("#_evidon-accept-button")}},class extends p{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 h((()=>this.mainWorldEval("EVAL_ONETRUST_1")),10,500)}},class extends p{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!!this.click(".klaro .cn-decline")||(this.settingsOpen||(this.click(".klaro .cn-learn-more,.klaro .cm-button-manage"),await this.waitForElement(".klaro > .cookie-modal",2e3),this.settingsOpen=!0),!!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 p{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 p{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 h((()=>!!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 p{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 p{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 h((()=>!!document.cookie.match("OptanonAlertBoxClosed")),20,200)}}];var w=[{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:"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:"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"}],detectPopup:[{visible:"#gdpr-new-container"}],optIn:[{waitForThenClick:"#gdpr-new-container .btn-accept"}],optOut:[{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:"aquasana.com",cosmetic:!0,prehideSelectors:["#consent-tracking"],detectCmp:[{exists:"#consent-tracking"}],detectPopup:[{exists:"#consent-tracking"}],optIn:[{click:"#accept_consent"}],optOut:[{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="privacy-policy"]'},{click:'div[role="dialog"] button:nth-child(2)'},{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:"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 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:[{click:"#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:"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:"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"]'}],detectPopup:[{visible:'[data-project="mol-fe-cmp"]'}],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"] button[class*=white]'}]},{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:"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:"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:"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"}],optIn:[{waitForThenClick:'#fides-banner [data-testid="Accept all-btn"]'}],optOut:[{waitForThenClick:'#fides-banner [data-testid="Reject all-btn"]'}]},{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:"generic-cosmetic",cosmetic:!0,prehideSelectors:["#js-cookie-banner,.js-cookie-banner,.cookie-banner,#cookie-banner"],detectCmp:[{exists:"#js-cookie-banner,.js-cookie-banner,.cookie-banner,#cookie-banner"}],detectPopup:[{visible:"#js-cookie-banner,.js-cookie-banner,.cookie-banner,#cookie-banner"}],optIn:[],optOut:[{hide:"#js-cookie-banner,.js-cookie-banner,.cookie-banner,#cookie-banner"}]},{name:"google-consent-standalone",prehideSelectors:[],detectCmp:[{exists:'a[href^="https://policies.google.com/technologies/cookies"'},{exists:'form[action^="https://consent.google."][action$=".com/save"]'}],detectPopup:[{visible:'a[href^="https://policies.google.com/technologies/cookies"'}],optIn:[{waitForThenClick:'form[action^="https://consent.google."][action$=".com/save"]:has(input[name=set_eom][value=false]) button'}],optOut:[{waitForThenClick:'form[action^="https://consent.google."][action$=".com/save"]:has(input[name=set_eom][value=true]) button'}]},{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:"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:[".x78zum5.xdt5ytf.xg6iff7.x1n2onr6"],detectCmp:[{exists:".x1qjc9v5.x9f619.x78zum5.xdt5ytf.x1iyjqo2.xl56j7k"}],detectPopup:[{visible:".x1qjc9v5.x9f619.x78zum5.xdt5ytf.x1iyjqo2.xl56j7k"}],optIn:[{waitForThenClick:"._a9--._a9_0"}],optOut:[{waitForThenClick:"._a9--._a9_1"},{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:[{click:".iubenda-cs-accept-btn"}],optOut:[{click:".iubenda-cs-customize-btn"},{eval:"EVAL_IUBENDA_0"},{click:"#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]",comment:"can be either settings or reject button"}]},{waitFor:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description]",timeout:1e3,optional:!0},{if:{exists:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description]"},then:[{waitForThenClick:"#lanyard_root button[class*=rejectButton]"},{click:"#lanyard_root button[class*=confirmButton],#lanyard_root div[class*=actions_] > button:nth-child(1)"}]}]},{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:"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"}],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:"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:"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",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)"},{click:'div.b-cookies-informer__switchers > div:nth-child(2) > div[at-attr="checkbox"] > span.b-input-radio__container > input[type="checkbox"]'},{click:"div.b-cookies-informer__nav > button"}]},{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:[{exists:"#ccpaCookieBanner, .privacy-sheet-content"}],optIn:[{click:"#acceptAllButton"}],optOut:[{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:".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:"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:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]'},{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:"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:"sibbo-cmp-layout"}],optIn:[{click:"sibbo-cmp-layout [data-accept-all]"}],optOut:[{click:'.sibbo-panel__aside__buttons a[data-nav="purposes"]'},{click:'.sibbo-panel__main__header__actions a[data-focusable="reject-all"]'},{if:{exists:"[data-view=purposes] .sibbo-panel__main__footer__actions [data-save-and-exit]"},then:[],else:[{waitFor:'.sibbo-panel__main__footer__actions a[data-focusable="next"]:not(.sibbo-cmp-button--disabled)'},{click:'.sibbo-panel__main__footer__actions a[data-focusable="next"]'},{click:'.sibbo-panel__main div[data-view="purposesLegInt"] a[data-focusable="reject-all"]'}]},{waitFor:".sibbo-panel__main__footer__actions [data-save-and-exit]:not(.sibbo-cmp-button--disabled)"},{click:".sibbo-panel__main__footer__actions [data-save-and-exit]:not(.sibbo-cmp-button--disabled)"}],test:[{eval:"EVAL_SIBBO_0"}]},{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:["#cookie_initial_modal",".modal-backdrop"],runContext:{urlPattern:"^https://www\\.strato\\.de/"},detectCmp:[{exists:"#cookie_initial_modal"}],detectPopup:[{visible:"#cookie_initial_modal"}],optIn:[{click:"button#jss_consent_all_initial_modal"}],optOut:[{click:"button#jss_open_settings_modal"},{click:"button#jss_consent_checked"}]},{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 #tarteaucitronAlertSmall,#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://[^/]*temu\\.com/"},prehideSelectors:["._2d-8vq-W,._1UdBUwni"],detectCmp:[{exists:"._3YCsmIaS"}],detectPopup:[{visible:"._3YCsmIaS"}],optIn:[{waitForThenClick:"._3fKiu5wx._3zN5SumS._3tAK973O.IYOfhWEs.VGNGF1pA"}],optOut:[{waitForThenClick:"._3fKiu5wx._1_XToJBF._3tAK973O.IYOfhWEs.VGNGF1pA"}]},{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",cosmetic:!0,prehideSelectors:[".cc_dialog.cc_css_reboot"],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:[{hide:".cc_dialog.cc_css_reboot"}]},{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:"tumblr-com",cosmetic:!0,prehideSelectors:["#cmp-app-container"],detectCmp:[{exists:"#cmp-app-container"}],detectPopup:[{visible:"#cmp-app-container"}],optIn:[{click:"#tumblr #cmp-app-container div.components-modal__frame > iframe > html body > div > div > div.cmp__dialog-footer > div > button.components-button.white-space-normal.is-primary"}],optOut:[{hide:"#cmp-app-container"}]},{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\\.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>span[role=button]) > div:last-child > div[role=button]:first-child'}],optOut:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>span[role=button]) > div:last-child > div[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"}],detectPopup:[{eval:"EVAL_USERCENTRICS_API_0"},{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",prehideSelectors:["#cookie-banner-wrapper"],detectCmp:[{exists:"#cookie-banner-wrapper"}],detectPopup:[{visible:"#cookie-banner-wrapper"}],optIn:[{click:"#cookie_banner_accept_mobile"}],optOut:[{click:"#cookie_banner_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:[]}],C={"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"}]}},v={autoconsent:w,consentomatic:C},f=Object.freeze({__proto__:null,autoconsent:w,consentomatic:C,default:v});const A=new class{constructor(e,t=null,o=null){if(this.id=n(),this.rules=[],this.foundCmp=null,this.state={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 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),c=new Array(o.length);return o.forEach(((e,t)=>{c[t]=k(e)})),"none"===t?c.every((e=>!e)):0!==c.length&&("any"===t?c.some((e=>e)):c.every((e=>e)))}waitForElement(e,t=1e4){const o=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForElement]",e),h((()=>this.elementSelector(e).length>0),o,200)}waitForVisible(e,t=1e4,o="any"){return h((()=>this.elementVisible(e,o)),Math.ceil(t/200),200)}async waitForThenClick(e,t=1e4,o=!1){return await this.waitForElement(e,t),this.click(e,o)}wait(e){return new Promise((t=>{setTimeout((()=>{t(!0)}),e)}))}hide(e,t){return m(u(),e,t)}prehide(e){const t=u("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[prehide]",t,location.href),m(t,e,"opacity")}undoPrehide(){const e=u("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),c=document.evaluate(o,t,null,XPathResult.ANY_TYPE,null);let i=null;const n=[];for(;i=c.iterateNext();)n.push(i);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 c of e){if(t=this.querySingleReplySelector(c,o),0===t.length)return[];o=t[0]}return t}elementSelector(e){return"string"==typeof e?this.querySingleReplySelector(e):this.querySelectorChain(e)}}(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),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(){y.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 d(e,this))}addConsentomaticCMP(e,t){this.rules.push(new class{constructor(e,t){this.name=e,this.config=t,this.methods=new Map,this.runContext=l,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)||c(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}}(`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=[],c=[];for(const e of t)e.isCosmetic?c.push(e):o.push(e);let i=!1,n=await this.detectPopups(o,(async e=>{i=await this.handlePopup(e)}));if(0===n.length&&(n=await this.detectPopups(c,(async e=>{i=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 i}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 c=await Promise.allSettled(o),i=[];for(const e of c)"fulfilled"===e.status&&i.push(e.value);return i}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 c=this.config.logs;c.lifecycle&&console.log("checking if popup is open...",e.name);const i=await e.detectPopup().catch((t=>(c.errors&&console.warn(`error detecting popup for ${e.name}`,t),!1)));return!i&&t>0?(await this.domActions.wait(o),this.waitForPopup(e,t-1,o)):(c.lifecycle&&console.log(e.name,"popup is "+(i?"open":"not open")),i)}prehideElements(){const e=this.config.logs,t=this.rules.reduce(((e,t)=>t.prehideSelectors?[...e,...t.prehideSelectors]:e),["#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=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=>{A.receiveMessageCallback(e)}))}),null,f);window.autoconsentMessageCallback=e=>{A.receiveMessageCallback(e)}}(); +!function(){"use strict";var e=class e{static setBase(t){e.base=t}static findElement(t,o=null,c=!1){let i=null;return i=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&&(i=i.filter((e=>{const o=e.textContent.toLowerCase();if(Array.isArray(t.textFilter)){let e=!1;for(const c of t.textFilter)if(-1!==o.indexOf(c.toLowerCase())){e=!0;break}return e}if(null!=t.textFilter)return-1!==o.indexOf(t.textFilter.toLowerCase())}))),null!=t.styleFilters&&(i=i.filter((e=>{const o=window.getComputedStyle(e);let c=!0;for(const e of t.styleFilters){const t=o[e.option];c=e.negated?c&&t!==e.value:c&&t===e.value}return c}))),null!=t.displayFilter&&(i=i.filter((e=>t.displayFilter?0!==e.offsetHeight:0===e.offsetHeight))),null!=t.iframeFilter&&(i=i.filter((()=>t.iframeFilter?window.location!==window.parent.location:window.location===window.parent.location))),null!=t.childFilter&&(i=i.filter((o=>{const c=e.base;e.setBase(o);const i=e.find(t.childFilter);return e.setBase(c),null!=i.target}))),c?i:(i.length>1&&console.warn("Multiple possible targets: ",i,t,o),i[0])}static find(t,o=!1){const c=[];if(null!=t.parent){const i=e.findElement(t.parent,null,o);if(null!=i){if(i instanceof Array)return i.forEach((i=>{const n=e.findElement(t.target,i,o);n instanceof Array?n.forEach((e=>{c.push({parent:i,target:e})})):c.push({parent:i,target:n})})),c;{const n=e.findElement(t.target,i,o);n instanceof Array?n.forEach((e=>{c.push({parent:i,target:e})})):c.push({parent:i,target:n})}}}else{const i=e.findElement(t.target,null,o);i instanceof Array?i.forEach((e=>{c.push({parent:null,target:e})})):c.push({parent:null,target:i})}return 0===c.length&&c.push({parent:null,target:null}),o?c:(1!==c.length&&console.warn("Multiple results found, even though multiple false",c),c[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 c(e,n){switch(e.type){case"click":return async function(e){const o=t.find(e);null!=o.target&&o.target.click();return i(0)}(e);case"list":return async function(e,t){for(const o of e.actions)await c(o,t)}(e,n);case"consent":return async function(e,t){for(const i of e.consents){const e=-1!==t.indexOf(i.type);if(i.matcher&&i.toggleAction){o(i.matcher)!==e&&await c(i.toggleAction)}else e?await c(i.trueAction):await c(i.falseAction)}}(e,n);case"ifcss":return async function(e,o){const i=t.find(e);i.target?e.falseAction&&await c(e.falseAction,o):e.trueAction&&await c(e.trueAction,o)}(e,n);case"waitcss":return async function(e){await new Promise((o=>{let c=e.retries||10;const i=e.waitTime||250,n=()=>{const a=t.find(e);(e.negated&&a.target||!e.negated&&!a.target)&&c>0?(c-=1,setTimeout(n,i)):o()};n()}))}(e);case"foreach":return async function(e,o){const i=t.find(e,!0),n=t.base;for(const n of i)n.target&&(t.setBase(n.target),await c(e.action,o));t.setBase(n)}(e,n);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),c=t.find(e.dragTarget);if(o.target){const e=o.target.getBoundingClientRect(),t=c.target.getBoundingClientRect();let i=t.top-e.top,n=t.left-e.left;"y"===this.config.axis.toLowerCase()&&(n=0),"x"===this.config.axis.toLowerCase()&&(i=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+i,r+n,l+i,!1,!1,!1,!1,0,o.target);const u=document.createEvent("MouseEvents");u.initMouseEvent("mouseup",!0,!0,window,0,a+n,s+i,r+n,l+i,!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 i(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}}function i(e){return new Promise((t=>{setTimeout((()=>{t()}),e)}))}function n(){return crypto&&void 0!==crypto.randomUUID?crypto.randomUUID():Math.random().toString()}var a={pending:new Map,sendContentMessage:null};function s(e,t){const o=n();a.sendContentMessage({type:"eval",id:o,code:e,snippetId:t});const c=new 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)}}(o);return a.pending.set(c.id,c),c.promise}var r={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_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_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_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_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_SIBBO_0:()=>!!window.localStorage.getItem("euconsent-v2"),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_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_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 l={main:!0,frame:!1,urlPattern:""},p=class{constructor(e){this.runContext=l,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=r[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 c=!1;try{c=!!t.call(globalThis)}catch(t){o.evals&&console.error("error evaluating rule",e,t)}return Promise.resolve(c)}const c=`(${t.toString()})()`;return o.evals&&console.log("async eval:",e,c),s(c,e).catch((t=>(o.evals&&console.error("error evaluating rule",e,t),!1)))}checkRunContext(){const e={...l,...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)}},d=class extends p{constructor(e,t){super(t),this.rule=e,this.name=e.name,this.runContext=e.runContext||l}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 c=await this.evaluateRuleStep(e.if);o.rulesteps&&console.log("Condition is",c),c?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}};function u(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 m(e,t,o="display"){const c=`${t} { ${"opacity"===o?"opacity: 0":"display: none"} !important; z-index: -1 !important; pointer-events: none !important; } `;return e instanceof HTMLStyleElement&&(e.innerText+=c,t.length>0)}async function h(e,t,o){const c=await e();return!c&&t>0?new Promise((c=>{setTimeout((async()=>{c(h(e,t-1,o))}),o)})):Promise.resolve(c)}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,logs:{lifecycle:!1,rulesteps:!1,evals:!1,errors:!0,messages:!1}},o=(c=t,globalThis.structuredClone?structuredClone(c):JSON.parse(JSON.stringify(c)));var c;for(const c of Object.keys(t))void 0!==e[c]&&(o[c]=e[c]);return o}var _="#truste-show-consent",g="#truste-consent-track",y=[class extends p{constructor(e){super(e),this.name="TrustArc-top",this.prehideSelectors=[".trustarc-banner-container",`.truste_popframe,.truste_overlay,.truste_box_overlay,${g}`],this.runContext={main:!0,frame:!1},this._shortcutButton=null,this._optInDone=!1}get hasSelfTest(){return!1}get isIntermediate(){return!this._optInDone&&!this._shortcutButton}get isCosmetic(){return!1}async detectCmp(){const e=this.elementExists(`${_},${g}`);return e&&(this._shortcutButton=document.querySelector("#truste-consent-required")),e}async detectPopup(){return this.elementVisible(`#truste-consent-content,#trustarc-banner-overlay,${g}`,"all")}openFrame(){this.click(_)}async optOut(){return this._shortcutButton?(this._shortcutButton.click(),!0):(m(u(),`.truste_popframe, .truste_overlay, .truste_box_overlay, ${g}`),this.click(_),setTimeout((()=>{u().remove()}),1e4),!0)}async optIn(){return this._optInDone=!0,this.click("#truste-consent-button")}async openCmp(){return!0}async test(){return await this.mainWorldEval("EVAL_TRUSTARC_TOP")}},class extends p{constructor(){super(...arguments),this.name="TrustArc-frame",this.runContext={main:!1,frame:!0,urlPattern:"^https://consent-pref\\.trustarc\\.com/\\?"}}get hasSelfTest(){return!1}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 h((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 h((()=>this.elementVisible(".switch span:first-child","any")),5,1e3)}async optOut(){return await h((()=>"complete"===document.readyState),20,100),await this.waitForElement(".mainContent[aria-hidden=false]",5e3),!!this.click(".rejectAll")||(this.elementExists(".prefPanel")&&await this.waitForElement('.prefPanel[style="visibility: visible;"]',3e3),this.click("#catDetails0")?(this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",5e3),!0):this.click(".required")?(this.waitForThenClick("#gwt-debug-close_id",5e3),!0):(await this.navigateToSettings(),this.click(".switch span:nth-child(1):not(.active)",!0),this.click(".submit"),this.waitForThenClick("#gwt-debug-close_id",3e5),!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}},class extends p{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 p{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 h((()=>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.wait(1500),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 p{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 p{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")||(m(u(),"#evidon-prefdiag-overlay,#evidon-prefdiag-background"),this.click("#_evidon-option-button"),await this.waitForElement("#evidon-prefdiag-overlay",5e3),this.click("#evidon-prefdiag-decline")),!0}async optIn(){return this.click("#_evidon-accept-button")}},class extends p{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 h((()=>this.mainWorldEval("EVAL_ONETRUST_1")),10,500)}},class extends p{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 p{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 p{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 h((()=>!!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 p{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 p{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 h((()=>!!document.cookie.match("OptanonAlertBoxClosed")),20,200)}},class extends p{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 h((()=>!!document.querySelector("#cmp-app-container iframe").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)}}];var w=[{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:"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:"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"}],detectPopup:[{visible:"#gdpr-new-container"}],optIn:[{waitForThenClick:"#gdpr-new-container .btn-accept"}],optOut:[{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:"aquasana.com",cosmetic:!0,prehideSelectors:["#consent-tracking"],detectCmp:[{exists:"#consent-tracking"}],detectPopup:[{exists:"#consent-tracking"}],optIn:[{click:"#accept_consent"}],optOut:[{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:"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:[{hide:'[aria-describedby="cookieconsent:desc"]'}]}]},{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:"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:"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"]'}],detectPopup:[{visible:'[data-project="mol-fe-cmp"]'}],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"] button[class*=white]'}]},{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:"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:"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:".ensModal"}],optIn:[{waitForThenClick:"#modalAcceptButton"}],optOut:[{waitForThenClick:".ensCheckbox:checked",all:!0},{waitForThenClick:"#ensSave"}]},{name:"Ensighten ensNotifyBanner",prehideSelectors:["#ensNotifyBanner"],detectCmp:[{exists:"#ensNotifyBanner"}],detectPopup:[{visible:"#ensNotifyBanner"}],optIn:[{waitForThenClick:"#ensCloseBanner"}],optOut:[{waitForThenClick:"#ensRejectAll,#rejectAll,#ensRejectBanner"}]},{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"}],optIn:[{waitForThenClick:'#fides-banner [data-testid="Accept all-btn"]'}],optOut:[{waitForThenClick:'#fides-banner [data-testid="Reject all-btn"]'}]},{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:"generic-cosmetic",cosmetic:!0,prehideSelectors:["#js-cookie-banner,.js-cookie-banner,.cookie-banner,#cookie-banner"],detectCmp:[{exists:"#js-cookie-banner,.js-cookie-banner,.cookie-banner,#cookie-banner"}],detectPopup:[{visible:"#js-cookie-banner,.js-cookie-banner,.cookie-banner,#cookie-banner"}],optIn:[],optOut:[{hide:"#js-cookie-banner,.js-cookie-banner,.cookie-banner,#cookie-banner"}]},{name:"google-consent-standalone",prehideSelectors:[],detectCmp:[{exists:'a[href^="https://policies.google.com/technologies/cookies"'},{exists:'form[action^="https://consent.google."][action$=".com/save"]'}],detectPopup:[{visible:'a[href^="https://policies.google.com/technologies/cookies"'}],optIn:[{waitForThenClick:'form[action^="https://consent.google."][action$=".com/save"]:has(input[name=set_eom][value=false]) button'}],optOut:[{waitForThenClick:'form[action^="https://consent.google."][action$=".com/save"]:has(input[name=set_eom][value=true]) button'}]},{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:"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:[".x78zum5.xdt5ytf.xg6iff7.x1n2onr6"],detectCmp:[{exists:".x1qjc9v5.x9f619.x78zum5.xdt5ytf.x1iyjqo2.xl56j7k"}],detectPopup:[{visible:".x1qjc9v5.x9f619.x78zum5.xdt5ytf.x1iyjqo2.xl56j7k"}],optIn:[{waitForThenClick:"._a9--._a9_0"}],optOut:[{waitForThenClick:"._a9--._a9_1"},{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:[{click:".iubenda-cs-accept-btn"}],optOut:[{click:".iubenda-cs-customize-btn"},{eval:"EVAL_IUBENDA_0"},{click:"#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]",comment:"can be either settings or reject button"}]},{waitFor:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description]",timeout:1e3,optional:!0},{if:{exists:"#lanyard_root [aria-describedby=preference-description],#lanyard_root [aria-describedby=modal-description]"},then:[{waitForThenClick:"#lanyard_root button[class*=rejectButton]"},{click:"#lanyard_root button[class*=confirmButton],#lanyard_root div[class*=actions_] > button:nth-child(1)"}]}]},{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:"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:"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:"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:"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:[{exists:"#ccpaCookieBanner, .privacy-sheet-content"}],optIn:[{click:"#acceptAllButton"}],optOut:[{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:".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:"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:[{click:'.qc-cmp2-summary-buttons > button[mode="secondary"]'},{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:"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:"sibbo-cmp-layout"}],optIn:[{click:"sibbo-cmp-layout [data-accept-all]"}],optOut:[{click:'.sibbo-panel__aside__buttons a[data-nav="purposes"]'},{click:'.sibbo-panel__main__header__actions a[data-focusable="reject-all"]'},{if:{exists:"[data-view=purposes] .sibbo-panel__main__footer__actions [data-save-and-exit]"},then:[],else:[{waitFor:'.sibbo-panel__main__footer__actions a[data-focusable="next"]:not(.sibbo-cmp-button--disabled)'},{click:'.sibbo-panel__main__footer__actions a[data-focusable="next"]'},{click:'.sibbo-panel__main div[data-view="purposesLegInt"] a[data-focusable="reject-all"]'}]},{waitFor:".sibbo-panel__main__footer__actions [data-save-and-exit]:not(.sibbo-cmp-button--disabled)"},{click:".sibbo-panel__main__footer__actions [data-save-and-exit]:not(.sibbo-cmp-button--disabled)"}],test:[{eval:"EVAL_SIBBO_0"}]},{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://[^/]*temu\\.com/"},prehideSelectors:["._2d-8vq-W,._1UdBUwni"],detectCmp:[{exists:"._3YCsmIaS"}],detectPopup:[{visible:"._3YCsmIaS"}],optIn:[{waitForThenClick:"._3fKiu5wx._3zN5SumS._3tAK973O.IYOfhWEs.VGNGF1pA"}],optOut:[{waitForThenClick:"._3fKiu5wx._1_XToJBF._3tAK973O.IYOfhWEs.VGNGF1pA"}]},{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",cosmetic:!0,prehideSelectors:[".cc_dialog.cc_css_reboot"],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:[{hide:".cc_dialog.cc_css_reboot"}]},{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:"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\\.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>span[role=button]) > div:last-child > div[role=button]:first-child'}],optOut:[{waitForThenClick:'[data-testid="BottomBar"] > div:has(>div:first-child>div:last-child>span[role=button]) > div:last-child > div[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"}],detectPopup:[{eval:"EVAL_USERCENTRICS_API_0"},{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",prehideSelectors:["#cookie-banner-wrapper"],detectCmp:[{exists:"#cookie-banner-wrapper"}],detectPopup:[{visible:"#cookie-banner-wrapper"}],optIn:[{click:"#cookie_banner_accept_mobile"}],optOut:[{click:"#cookie_banner_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:[]}],C={"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"}]}},v={autoconsent:w,consentomatic:C},f=Object.freeze({__proto__:null,autoconsent:w,consentomatic:C,default:v});const A=new class{constructor(e,t=null,o=null){if(this.id=n(),this.rules=[],this.foundCmp=null,this.state={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 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),c=new Array(o.length);return o.forEach(((e,t)=>{c[t]=k(e)})),"none"===t?c.every((e=>!e)):0!==c.length&&("any"===t?c.some((e=>e)):c.every((e=>e)))}waitForElement(e,t=1e4){const o=Math.ceil(t/200);return this.autoconsentInstance.config.logs.rulesteps&&console.log("[waitForElement]",e),h((()=>this.elementSelector(e).length>0),o,200)}waitForVisible(e,t=1e4,o="any"){return h((()=>this.elementVisible(e,o)),Math.ceil(t/200),200)}async waitForThenClick(e,t=1e4,o=!1){return await this.waitForElement(e,t),this.click(e,o)}wait(e){return new Promise((t=>{setTimeout((()=>{t(!0)}),e)}))}hide(e,t){return m(u(),e,t)}prehide(e){const t=u("autoconsent-prehide");return this.autoconsentInstance.config.logs.lifecycle&&console.log("[prehide]",t,location.href),m(t,e,"opacity")}undoPrehide(){const e=u("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),c=document.evaluate(o,t,null,XPathResult.ANY_TYPE,null);let i=null;const n=[];for(;i=c.iterateNext();)n.push(i);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 c of e){if(t=this.querySingleReplySelector(c,o),0===t.length)return[];o=t[0]}return t}elementSelector(e){return"string"==typeof e?this.querySingleReplySelector(e):this.querySelectorChain(e)}}(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),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(){y.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 d(e,this))}addConsentomaticCMP(e,t){this.rules.push(new class{constructor(e,t){this.name=e,this.config=t,this.methods=new Map,this.runContext=l,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)||c(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}}(`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=[],c=[];for(const e of t)e.isCosmetic?c.push(e):o.push(e);let i=!1,n=await this.detectPopups(o,(async e=>{i=await this.handlePopup(e)}));if(0===n.length&&(n=await this.detectPopups(c,(async e=>{i=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 i}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 c=await Promise.allSettled(o),i=[];for(const e of c)"fulfilled"===e.status&&i.push(e.value);return i}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 c=this.config.logs;c.lifecycle&&console.log("checking if popup is open...",e.name);const i=await e.detectPopup().catch((t=>(c.errors&&console.warn(`error detecting popup for ${e.name}`,t),!1)));return!i&&t>0?(await this.domActions.wait(o),this.waitForPopup(e,t-1,o)):(c.lifecycle&&console.log(e.name,"popup is "+(i?"open":"not open")),i)}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=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=>{A.receiveMessageCallback(e)}))}),null,f);window.autoconsentMessageCallback=e=>{A.receiveMessageCallback(e)}}(); diff --git a/DuckDuckGo/Autofill/AutofillActionBuilder.swift b/DuckDuckGo/Autofill/AutofillActionBuilder.swift index de48f8d6b3..cbf46a19e2 100644 --- a/DuckDuckGo/Autofill/AutofillActionBuilder.swift +++ b/DuckDuckGo/Autofill/AutofillActionBuilder.swift @@ -35,7 +35,7 @@ extension AutofillActionBuilder { struct AutofillDeleteAllPasswordsBuilder: AutofillActionBuilder { @MainActor func buildExecutor() -> AutofillActionExecutor? { - guard let secureVault = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared), + guard let secureVault = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared), let syncService = NSApp.delegateTyped.syncService else { return nil } return AutofillDeleteAllPasswordsExecutor(userAuthenticator: DeviceAuthenticator.shared, diff --git a/DuckDuckGo/Autofill/AutofillActionExecutor.swift b/DuckDuckGo/Autofill/AutofillActionExecutor.swift index f574c7e974..cbdc445d1f 100644 --- a/DuckDuckGo/Autofill/AutofillActionExecutor.swift +++ b/DuckDuckGo/Autofill/AutofillActionExecutor.swift @@ -20,6 +20,7 @@ import Foundation import BrowserServicesKit import DDGSync import AppKit +import PixelKit /// Conforming types provide an `execute` method which performs some action on autofill types (e.g delete all passwords) protocol AutofillActionExecutor { @@ -68,7 +69,7 @@ struct AutofillDeleteAllPasswordsExecutor: AutofillActionExecutor { syncService.scheduler.notifyDataChanged() onSuccess?() } catch { - Pixel.fire(.debug(event: .secureVaultError, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.secureVaultError(error: error))) } return diff --git a/DuckDuckGo/Autofill/ContentOverlayViewController.swift b/DuckDuckGo/Autofill/ContentOverlayViewController.swift index d90b35f71d..63a6a88368 100644 --- a/DuckDuckGo/Autofill/ContentOverlayViewController.swift +++ b/DuckDuckGo/Autofill/ContentOverlayViewController.swift @@ -22,6 +22,7 @@ import Combine import BrowserServicesKit import SecureStorage import Autofill +import PixelKit @MainActor public final class ContentOverlayViewController: NSViewController, EmailManagerRequestDelegate { @@ -191,7 +192,7 @@ public final class ContentOverlayViewController: NSViewController, EmailManagerR parameters["keychain_operation"] = "save" } - Pixel.fire(.debug(event: .emailAutofillKeychainError, error: error), withAdditionalParameters: parameters) + PixelKit.fire(DebugEvent(GeneralPixel.emailAutofillKeychainError), withAdditionalParameters: parameters) } private enum Constants { @@ -294,7 +295,7 @@ extension ContentOverlayViewController: SecureVaultManagerDelegate { } public func secureVaultManager(_: SecureVaultManager, didAutofill type: AutofillType, withObjectId objectId: String) { - Pixel.fire(.formAutofilled(kind: type.formAutofillKind)) + PixelKit.fire(GeneralPixel.formAutofilled(kind: type.formAutofillKind)) if type.formAutofillKind == .password && passwordManagerCoordinator.isEnabled { @@ -308,8 +309,12 @@ extension ContentOverlayViewController: SecureVaultManagerDelegate { } } - public func secureVaultInitFailed(_ error: SecureStorageError) { - SecureVaultErrorReporter.shared.secureVaultInitFailed(error) + public func secureVaultError(_ error: SecureStorageError) { + SecureVaultReporter.shared.secureVaultError(error) + } + + public func secureVaultKeyStoreEvent(_ event: SecureStorageKeyStoreEvent) { + SecureVaultReporter.shared.secureVaultKeyStoreEvent(event) } public func secureVaultManager(_: BrowserServicesKit.SecureVaultManager, didReceivePixel pixel: AutofillUserScript.JSPixel) { @@ -320,9 +325,9 @@ extension ContentOverlayViewController: SecureVaultManagerDelegate { self.emailManager.updateLastUseDate() - Pixel.fire(.jsPixel(pixel), withAdditionalParameters: pixelParameters) + PixelKit.fire(GeneralPixel.jsPixel(pixel), withAdditionalParameters: pixelParameters) } else { - Pixel.fire(.jsPixel(pixel), withAdditionalParameters: pixel.pixelParameters) + PixelKit.fire(GeneralPixel.jsPixel(pixel), withAdditionalParameters: pixel.pixelParameters) } } diff --git a/DuckDuckGo/Bookmarks/Extensions/Bookmarks+Tab.swift b/DuckDuckGo/Bookmarks/Extensions/Bookmarks+Tab.swift index 82e5748c72..78c60f30ea 100644 --- a/DuckDuckGo/Bookmarks/Extensions/Bookmarks+Tab.swift +++ b/DuckDuckGo/Bookmarks/Extensions/Bookmarks+Tab.swift @@ -22,7 +22,7 @@ extension Tab { @MainActor static func withContentOfBookmark(folder: BookmarkFolder, burnerMode: BurnerMode) -> [Tab] { - folder.children.compactMap { entity in + folder.children.compactMap { entity -> Tab? in guard let url = (entity as? Bookmark)?.urlObject else { return nil } return Tab(content: .url(url, source: .bookmark), shouldLoadInBackground: true, burnerMode: burnerMode) } diff --git a/DuckDuckGo/Bookmarks/Legacy/LegacyBookmarkStore.swift b/DuckDuckGo/Bookmarks/Legacy/LegacyBookmarkStore.swift index 9634ca221f..ebfc15be43 100644 --- a/DuckDuckGo/Bookmarks/Legacy/LegacyBookmarkStore.swift +++ b/DuckDuckGo/Bookmarks/Legacy/LegacyBookmarkStore.swift @@ -19,6 +19,7 @@ import Foundation import CoreData import Cocoa +import PixelKit fileprivate extension UUID { @@ -171,7 +172,7 @@ extension LegacyBookmarkStore { try context.save() } catch { - Pixel.fire(.debug(event: .bookmarksStoreRootFolderMigrationFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksStoreRootFolderMigrationFailed, error: error)) } } @@ -211,7 +212,7 @@ extension LegacyBookmarkStore { // 4. Save the migration: try context.save() } catch { - Pixel.fire(.debug(event: .bookmarksStoreRootFolderMigrationFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksStoreRootFolderMigrationFailed, error: error)) } } } diff --git a/DuckDuckGo/Bookmarks/Legacy/LegacyBookmarksStoreMigration.swift b/DuckDuckGo/Bookmarks/Legacy/LegacyBookmarksStoreMigration.swift index c5ecef1b7c..734275e1c5 100644 --- a/DuckDuckGo/Bookmarks/Legacy/LegacyBookmarksStoreMigration.swift +++ b/DuckDuckGo/Bookmarks/Legacy/LegacyBookmarksStoreMigration.swift @@ -20,6 +20,7 @@ import Foundation import CoreData import Bookmarks import Persistence +import PixelKit public class LegacyBookmarksStoreMigration { @@ -55,7 +56,7 @@ public class LegacyBookmarksStoreMigration { guard BookmarkUtils.fetchRootFolder(destination) == nil else { // There should be no data left as migration has been done already if !bookmarkRoots.isEmpty { - Pixel.fire(.debug(event: .bookmarksMigrationAlreadyPerformed)) + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksMigrationAlreadyPerformed)) cleanupOldData(in: source) } @@ -72,9 +73,9 @@ public class LegacyBookmarksStoreMigration { let newFavoritesRoot = BookmarkUtils.fetchLegacyFavoritesFolder(destination) else { if bookmarkRoots.isEmpty { - Pixel.fire(.debug(event: .bookmarksCouldNotPrepareDatabase)) + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksCouldNotPrepareDatabase)) } else { - Pixel.fire(.debug(event: .bookmarksMigrationCouldNotPrepareDatabase)) + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksMigrationCouldNotPrepareDatabase)) } Thread.sleep(forTimeInterval: 2) @@ -157,7 +158,7 @@ public class LegacyBookmarksStoreMigration { } do { - try destination.save(onErrorFire: .bookmarksMigrationFailed) + try destination.save(onErrorFire: GeneralPixel.bookmarksMigrationFailed) cleanupOldData(in: source) } catch { @@ -165,7 +166,7 @@ public class LegacyBookmarksStoreMigration { BookmarkUtils.prepareLegacyFoldersStructure(in: destination) do { - try destination.save(onErrorFire: .bookmarksMigrationCouldNotPrepareDatabaseOnFailedMigration) + try destination.save(onErrorFire: GeneralPixel.bookmarksMigrationCouldNotPrepareDatabaseOnFailedMigration) } catch { Thread.sleep(forTimeInterval: 2) fatalError("Could not write to Bookmarks DB") @@ -181,7 +182,7 @@ public class LegacyBookmarksStoreMigration { allObjects.forEach { context.delete($0) } if context.hasChanges { - try? context.save(onErrorFire: .bookmarksMigrationCouldNotRemoveOldStore) + try? context.save(onErrorFire: GeneralPixel.bookmarksMigrationCouldNotRemoveOldStore) } } diff --git a/DuckDuckGo/Bookmarks/Model/BookmarkManager.swift b/DuckDuckGo/Bookmarks/Model/BookmarkManager.swift index b3172da78e..1220f5eabb 100644 --- a/DuckDuckGo/Bookmarks/Model/BookmarkManager.swift +++ b/DuckDuckGo/Bookmarks/Model/BookmarkManager.swift @@ -28,8 +28,10 @@ protocol BookmarkManager: AnyObject { func allHosts() -> Set func getBookmark(for url: URL) -> Bookmark? func getBookmark(forUrl url: String) -> Bookmark? + func getBookmarkFolder(withId id: String) -> BookmarkFolder? @discardableResult func makeBookmark(for url: URL, title: String, isFavorite: Bool) -> Bookmark? @discardableResult func makeBookmark(for url: URL, title: String, isFavorite: Bool, index: Int?, parent: BookmarkFolder?) -> Bookmark? + func makeBookmarks(for websitesInfo: [WebsiteInfo], inNewFolderNamed folderName: String, withinParentFolder parent: ParentFolderType) func makeFolder(for title: String, parent: BookmarkFolder?, completion: @escaping (BookmarkFolder) -> Void) func remove(bookmark: Bookmark) func remove(folder: BookmarkFolder) @@ -46,7 +48,6 @@ protocol BookmarkManager: AnyObject { func move(objectUUIDs: [String], toIndex: Int?, withinParentFolder: ParentFolderType, completion: @escaping (Error?) -> Void) func moveFavorites(with objectUUIDs: [String], toIndex: Int?, completion: @escaping (Error?) -> Void) func importBookmarks(_ bookmarks: ImportedBookmarks, source: BookmarkImportSource) -> BookmarksImportSummary - func handleFavoritesAfterDisablingSync() // Wrapper definition in a protocol is not supported yet @@ -138,6 +139,10 @@ final class LocalBookmarkManager: BookmarkManager { return list?[url] } + func getBookmarkFolder(withId id: String) -> BookmarkFolder? { + bookmarkStore.bookmarkFolder(withId: id) + } + @discardableResult func makeBookmark(for url: URL, title: String, isFavorite: Bool) -> Bookmark? { makeBookmark(for: url, title: title, isFavorite: isFavorite, index: nil, parent: nil) } @@ -167,6 +172,12 @@ final class LocalBookmarkManager: BookmarkManager { return bookmark } + func makeBookmarks(for websitesInfo: [WebsiteInfo], inNewFolderNamed folderName: String, withinParentFolder parent: ParentFolderType) { + bookmarkStore.saveBookmarks(for: websitesInfo, inNewFolderNamed: folderName, withinParentFolder: parent) + loadBookmarks() + requestSync() + } + func remove(bookmark: Bookmark) { guard list != nil else { return } guard let latestBookmark = getBookmark(forUrl: bookmark.url) else { diff --git a/DuckDuckGo/Bookmarks/Model/BookmarksCleanupErrorHandling.swift b/DuckDuckGo/Bookmarks/Model/BookmarksCleanupErrorHandling.swift index 815dc8ecf9..467af32bbd 100644 --- a/DuckDuckGo/Bookmarks/Model/BookmarksCleanupErrorHandling.swift +++ b/DuckDuckGo/Bookmarks/Model/BookmarksCleanupErrorHandling.swift @@ -20,18 +20,19 @@ import Foundation import Bookmarks import Common import Persistence +import PixelKit public class BookmarksCleanupErrorHandling: EventMapping { public init() { super.init { event, _, _, _ in if event.cleanupError is BookmarksCleanupCancelledError { - Pixel.fire(.debug(event: .bookmarksCleanupAttemptedWhileSyncWasEnabled)) + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksCleanupAttemptedWhileSyncWasEnabled)) } else { let processedErrors = CoreDataErrorsParser.parse(error: event.cleanupError as NSError) let params = processedErrors.errorPixelParameters - Pixel.fire(.debug(event: .bookmarksCleanupFailed, error: event.cleanupError), withAdditionalParameters: params) + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksCleanupFailed, error: event.cleanupError), withAdditionalParameters: params) } } } diff --git a/DuckDuckGo/Bookmarks/Model/WebsiteInfo.swift b/DuckDuckGo/Bookmarks/Model/WebsiteInfo.swift index fc393b256d..a4d146abd7 100644 --- a/DuckDuckGo/Bookmarks/Model/WebsiteInfo.swift +++ b/DuckDuckGo/Bookmarks/Model/WebsiteInfo.swift @@ -18,15 +18,17 @@ import Foundation -struct WebsiteInfo { +struct WebsiteInfo: Equatable { let url: URL - let title: String? + /// Returns the title of the website if available, otherwise returns the domain of the URL. + /// If both title and and domain are nil, it returns the absolute string representation of the URL. + let title: String init?(_ tab: Tab) { guard case let .url(url, _, _) = tab.content else { return nil } self.url = url - self.title = tab.title + self.title = tab.title ?? url.host ?? url.absoluteString } } diff --git a/DuckDuckGo/Bookmarks/Services/BookmarkStore.swift b/DuckDuckGo/Bookmarks/Services/BookmarkStore.swift index 3466d1a7fa..8c8f4a6d06 100644 --- a/DuckDuckGo/Bookmarks/Services/BookmarkStore.swift +++ b/DuckDuckGo/Bookmarks/Services/BookmarkStore.swift @@ -48,9 +48,11 @@ protocol BookmarkStore { func loadAll(type: BookmarkStoreFetchPredicateType, completion: @escaping ([BaseBookmarkEntity]?, Error?) -> Void) func save(bookmark: Bookmark, parent: BookmarkFolder?, index: Int?, completion: @escaping (Bool, Error?) -> Void) + func saveBookmarks(for websitesInfo: [WebsiteInfo], inNewFolderNamed folderName: String, withinParentFolder parent: ParentFolderType) func save(folder: BookmarkFolder, parent: BookmarkFolder?, completion: @escaping (Bool, Error?) -> Void) func remove(objectsWithUUIDs: [String], completion: @escaping (Bool, Error?) -> Void) func update(bookmark: Bookmark) + func bookmarkFolder(withId id: String) -> BookmarkFolder? func update(folder: BookmarkFolder) func update(folder: BookmarkFolder, andMoveToParent parent: ParentFolderType) func add(objectsWithUUIDs: [String], to parent: BookmarkFolder?, completion: @escaping (Error?) -> Void) @@ -59,6 +61,5 @@ protocol BookmarkStore { func move(objectUUIDs: [String], toIndex: Int?, withinParentFolder: ParentFolderType, completion: @escaping (Error?) -> Void) func moveFavorites(with objectUUIDs: [String], toIndex: Int?, completion: @escaping (Error?) -> Void) func importBookmarks(_ bookmarks: ImportedBookmarks, source: BookmarkImportSource) -> BookmarksImportSummary - func handleFavoritesAfterDisablingSync() } diff --git a/DuckDuckGo/Bookmarks/Services/BookmarkStoreMock.swift b/DuckDuckGo/Bookmarks/Services/BookmarkStoreMock.swift index 2ab57158a9..003ba7bb59 100644 --- a/DuckDuckGo/Bookmarks/Services/BookmarkStoreMock.swift +++ b/DuckDuckGo/Bookmarks/Services/BookmarkStoreMock.swift @@ -104,6 +104,15 @@ public final class BookmarkStoreMock: BookmarkStore { capturedBookmark = bookmark } + var bookmarkFolderWithIdCalled = false + var capturedFolderId: String? + var bookmarkFolder: BookmarkFolder? + func bookmarkFolder(withId id: String) -> BookmarkFolder? { + bookmarkFolderWithIdCalled = true + capturedFolderId = id + return bookmarkFolder + } + var updateFolderCalled = false func update(folder: BookmarkFolder) { updateFolderCalled = true @@ -133,6 +142,16 @@ public final class BookmarkStoreMock: BookmarkStore { return BookmarksImportSummary(successful: 0, duplicates: 0, failed: 0) } + var saveBookmarksInNewFolderNamedCalled = false + var capturedWebsitesInfo: [WebsiteInfo]? + var capturedNewFolderName: String? + func saveBookmarks(for websitesInfo: [WebsiteInfo], inNewFolderNamed folderName: String, withinParentFolder parent: ParentFolderType) { + saveBookmarksInNewFolderNamedCalled = true + capturedWebsitesInfo = websitesInfo + capturedNewFolderName = folderName + capturedParentFolderType = parent + } + var canMoveObjectWithUUIDCalled = false func canMoveObjectWithUUID(objectUUID uuid: String, to parent: BookmarkFolder) -> Bool { canMoveObjectWithUUIDCalled = true diff --git a/DuckDuckGo/Bookmarks/Services/ContextualMenu.swift b/DuckDuckGo/Bookmarks/Services/ContextualMenu.swift index f79e265d96..eb77fd956f 100644 --- a/DuckDuckGo/Bookmarks/Services/ContextualMenu.swift +++ b/DuckDuckGo/Bookmarks/Services/ContextualMenu.swift @@ -163,11 +163,15 @@ private extension ContextualMenu { static func addBookmarkToFavoritesMenuItem(isFavorite: Bool, bookmark: Bookmark?) -> NSMenuItem { let title = isFavorite ? UserText.removeFromFavorites : UserText.addToFavorites return menuItem(title, #selector(BookmarkMenuItemSelectors.toggleBookmarkAsFavorite(_:)), bookmark) + .withAccessibilityIdentifier(isFavorite == false ? "ContextualMenu.addBookmarkToFavoritesMenuItem" : + "ContextualMenu.removeBookmarkFromFavoritesMenuItem") } static func addBookmarksToFavoritesMenuItem(bookmarks: [Bookmark], allFavorites: Bool) -> NSMenuItem { let title = allFavorites ? UserText.removeFromFavorites : UserText.addToFavorites + let accessibilityValue = allFavorites ? "Favorited" : "Unfavorited" return menuItem(title, #selector(BookmarkMenuItemSelectors.toggleBookmarkAsFavorite(_:)), bookmarks) + .withAccessibilityIdentifier("ContextualMenu.addBookmarksToFavoritesMenuItem").withAccessibilityValue(accessibilityValue) } static func editBookmarkMenuItem(bookmark: Bookmark?) -> NSMenuItem { @@ -180,6 +184,7 @@ private extension ContextualMenu { static func deleteBookmarkMenuItem(bookmark: Bookmark?) -> NSMenuItem { menuItem(UserText.bookmarksBarContextMenuDelete, #selector(BookmarkMenuItemSelectors.deleteBookmark(_:)), bookmark) + .withAccessibilityIdentifier("ContextualMenu.deleteBookmark") } static func moveToEndMenuItem(entity: BaseBookmarkEntity?, parent: BookmarkFolder?) -> NSMenuItem { diff --git a/DuckDuckGo/Bookmarks/Services/LocalBookmarkStore.swift b/DuckDuckGo/Bookmarks/Services/LocalBookmarkStore.swift index e2be507a44..d8cdf7773f 100644 --- a/DuckDuckGo/Bookmarks/Services/LocalBookmarkStore.swift +++ b/DuckDuckGo/Bookmarks/Services/LocalBookmarkStore.swift @@ -65,6 +65,7 @@ final class LocalBookmarkStore: BookmarkStore { case missingRoot case missingFavoritesRoot case saveLoopError(Error?) + case badModelMapping } private(set) var favoritesDisplayMode: FavoritesDisplayMode @@ -199,10 +200,10 @@ final class LocalBookmarkStore: BookmarkStore { var params = processedErrors.errorPixelParameters params[PixelKit.Parameters.errorSource] = source - Pixel.fire(.debug(event: .bookmarksSaveFailed, error: error), + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksSaveFailed, error: error), withAdditionalParameters: params) } else { - Pixel.fire(.debug(event: .bookmarksSaveFailed, error: localError), + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksSaveFailed, error: localError), withAdditionalParameters: [PixelKit.Parameters.errorSource: source]) } } else { @@ -211,7 +212,7 @@ final class LocalBookmarkStore: BookmarkStore { var params = processedErrors.errorPixelParameters params[PixelKit.Parameters.errorSource] = source - Pixel.fire(.debug(event: .bookmarksSaveFailed, error: error), + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksSaveFailed, error: error), withAdditionalParameters: params) } } @@ -228,7 +229,7 @@ final class LocalBookmarkStore: BookmarkStore { ) if context.hasChanges { - try context.save(onErrorFire: .bookmarksMigrationCouldNotPrepareMultipleFavoriteFolders) + try context.save(onErrorFire: GeneralPixel.bookmarksMigrationCouldNotPrepareMultipleFavoriteFolders) } } catch { Thread.sleep(forTimeInterval: 1) @@ -310,7 +311,7 @@ final class LocalBookmarkStore: BookmarkStore { } else if let root = bookmarksRoot(in: context) { parentEntity = root } else { - Pixel.fire(.debug(event: .missingParent)) + PixelKit.fire(DebugEvent(GeneralPixel.missingParent)) throw BookmarkStoreError.missingParent } @@ -339,6 +340,23 @@ final class LocalBookmarkStore: BookmarkStore { }) } + func saveBookmarks(for websitesInfo: [WebsiteInfo], inNewFolderNamed folderName: String, withinParentFolder parent: ParentFolderType) { + do { + try applyChangesAndSave { context in + // Fetch Parent folder + let parentFolder = try bookmarkEntity(for: parent, in: context) + // Create new Folder for all bookmarks + let newFolderMO = BookmarkEntity.makeFolder(title: folderName, parent: parentFolder, context: context) + // Save the bookmarks + websitesInfo.forEach { info in + _ = BookmarkEntity.makeBookmark(title: info.title, url: info.url.absoluteString, parent: newFolderMO, context: context) + } + } + } catch { + commonOnSaveErrorHandler(error) + } + } + func remove(objectsWithUUIDs identifiers: [String], completion: @escaping (Bool, Error?) -> Void) { applyChangesAndSave(changes: { [weak self] context in @@ -390,6 +408,38 @@ final class LocalBookmarkStore: BookmarkStore { } } + func bookmarkFolder(withId id: String) -> BookmarkFolder? { + let context = makeContext() + + var bookmarkFolderToReturn: BookmarkFolder? + let favoritesDisplayMode = self.favoritesDisplayMode + + context.performAndWait { + let folderFetchRequest = BaseBookmarkEntity.singleEntity(with: id) + do { + let folderFetchRequestResult = try context.fetch(folderFetchRequest) + guard let bookmarkFolderManagedObject = folderFetchRequestResult.first else { return } + + guard let bookmarkFolder = BaseBookmarkEntity.from( + managedObject: bookmarkFolderManagedObject, + parentFolderUUID: bookmarkFolderManagedObject.parent?.uuid, + favoritesDisplayMode: favoritesDisplayMode + ) as? BookmarkFolder + else { + throw BookmarkStoreError.badModelMapping + } + bookmarkFolderToReturn = bookmarkFolder + + } catch BookmarkStoreError.badModelMapping { + os_log("Failed to map BookmarkEntity to BookmarkFolder, with error: %s", log: .bookmarks, type: .error) + } catch { + os_log("Failed to fetch last saved folder for bookmarks all tabs, with error: %s", log: .bookmarks, type: .error, error.localizedDescription) + } + } + + return bookmarkFolderToReturn + } + func update(folder: BookmarkFolder) { do { _ = try applyChangesAndSave(changes: { [weak self] context in @@ -506,7 +556,7 @@ final class LocalBookmarkStore: BookmarkStore { } else if let root = self.bookmarksRoot(in: context) { parentEntity = root } else { - Pixel.fire(.debug(event: .missingParent)) + PixelKit.fire(DebugEvent(GeneralPixel.missingParent)) throw BookmarkStoreError.missingParent } @@ -605,21 +655,37 @@ final class LocalBookmarkStore: BookmarkStore { currentInsertionIndex > objectIndex { adjustedInsertionIndex -= 1 } + let nextInsertionIndex = adjustedInsertionIndex + 1 bookmarkManagedObject.parent = nil // Removing the bookmark from its current parent may have removed it from the collection it is about to be added to, so re-check // the bounds before adding it back. if adjustedInsertionIndex < newParentFolder.childrenArray.count { - newParentFolder.insertIntoChildren(bookmarkManagedObject, at: adjustedInsertionIndex) + // Handle stubs + let allChildren = (newParentFolder.children?.array as? [BookmarkEntity]) ?? [] + if newParentFolder.childrenArray.count != allChildren.count { + var correctedIndex = 0 + + while adjustedInsertionIndex > 0 && correctedIndex < allChildren.count { + if allChildren[correctedIndex].isStub == false { + adjustedInsertionIndex -= 1 + } + correctedIndex += 1 + } + newParentFolder.insertIntoChildren(bookmarkManagedObject, at: correctedIndex) + } else { + newParentFolder.insertIntoChildren(bookmarkManagedObject, at: adjustedInsertionIndex) + } } else { newParentFolder.addToChildren(bookmarkManagedObject) } - currentInsertionIndex = adjustedInsertionIndex + 1 + currentInsertionIndex = nextInsertionIndex } } + // swiftlint:disable:next function_body_length func moveFavorites(with objectUUIDs: [String], toIndex index: Int?, completion: @escaping (Error?) -> Void) { applyChangesAndSave(changes: { [weak self] context in @@ -642,27 +708,45 @@ final class LocalBookmarkStore: BookmarkStore { return (try? context.fetch(entityFetchRequest))?.first } - if let index = index, index < (displayedFavoritesFolder.favorites?.count ?? 0) { + if let index = index, index < displayedFavoritesFolder.favoritesArray.count { var currentInsertionIndex = max(index, 0) for bookmarkManagedObject in bookmarkManagedObjects { var adjustedInsertionIndex = currentInsertionIndex - if let currentIndex = displayedFavoritesFolder.favorites?.index(of: bookmarkManagedObject), + if let currentIndex = displayedFavoritesFolder.favoritesArray.firstIndex(of: bookmarkManagedObject), currentInsertionIndex > currentIndex { adjustedInsertionIndex -= 1 } + let nextInsertionIndex = adjustedInsertionIndex + 1 bookmarkManagedObject.removeFromFavorites(with: favoritesDisplayMode) - if adjustedInsertionIndex < (displayedFavoritesFolder.favorites?.count ?? 0) { - bookmarkManagedObject.addToFavorites(insertAt: adjustedInsertionIndex, - favoritesRoot: displayedFavoritesFolder) - bookmarkManagedObject.addToFavorites(folders: favoritesFoldersWithoutDisplayed) + + if adjustedInsertionIndex < displayedFavoritesFolder.favoritesArray.count { + // Handle stubs + let allChildren = (displayedFavoritesFolder.favorites?.array as? [BookmarkEntity]) ?? [] + if displayedFavoritesFolder.favoritesArray.count != allChildren.count { + var correctedIndex = 0 + + while adjustedInsertionIndex > 0 && correctedIndex < allChildren.count { + if allChildren[correctedIndex].isStub == false { + adjustedInsertionIndex -= 1 + } + correctedIndex += 1 + } + bookmarkManagedObject.addToFavorites(insertAt: correctedIndex, + favoritesRoot: displayedFavoritesFolder) + bookmarkManagedObject.addToFavorites(folders: favoritesFoldersWithoutDisplayed) + } else { + bookmarkManagedObject.addToFavorites(insertAt: adjustedInsertionIndex, + favoritesRoot: displayedFavoritesFolder) + bookmarkManagedObject.addToFavorites(folders: favoritesFoldersWithoutDisplayed) + } } else { bookmarkManagedObject.addToFavorites(folders: favoritesFolders) } - currentInsertionIndex = adjustedInsertionIndex + 1 + currentInsertionIndex = nextInsertionIndex } } else { for bookmarkManagedObject in bookmarkManagedObjects { @@ -720,7 +804,7 @@ final class LocalBookmarkStore: BookmarkStore { let processedErrors = CoreDataErrorsParser.parse(error: error) if NSApp.runType.requiresEnvironment { - Pixel.fire(.debug(event: .bookmarksSaveFailedOnImport, error: error), + PixelKit.fire(DebugEvent(GeneralPixel.bookmarksSaveFailedOnImport, error: error), withAdditionalParameters: processedErrors.errorPixelParameters) assertionFailure("LocalBookmarkStore: Saving of context failed, error: \(error.localizedDescription)") } @@ -856,7 +940,7 @@ final class LocalBookmarkStore: BookmarkStore { } if deletedEntityCount > 0 { - Pixel.fire(.debug(event: .removedInvalidBookmarkManagedObjects)) + PixelKit.fire(DebugEvent(GeneralPixel.removedInvalidBookmarkManagedObjects)) } } onError: { [weak self] error in self?.commonOnSaveErrorHandler(error) @@ -904,7 +988,7 @@ final class LocalBookmarkStore: BookmarkStore { let nsError = error as NSError let processedErrors = CoreDataErrorsParser.parse(error: nsError) let params = processedErrors.errorPixelParameters - Pixel.fire(.debug(event: .favoritesCleanupFailed, error: error), withAdditionalParameters: params) + PixelKit.fire(DebugEvent(GeneralPixel.favoritesCleanupFailed, error: error), withAdditionalParameters: params) } onDidSave: {} } @@ -998,32 +1082,38 @@ private extension LocalBookmarkStore { } func move(entities: [BookmarkEntity], toIndex index: Int?, withinParentFolderType type: ParentFolderType, in context: NSManagedObjectContext) throws { + let newParentFolder = try bookmarkEntity(for: type, in: context) + + if let index = index, index < newParentFolder.childrenArray.count { + self.move(entities: entities, to: index, within: newParentFolder) + } else { + for bookmarkManagedObject in entities { + bookmarkManagedObject.parent = nil + newParentFolder.addToChildren(bookmarkManagedObject) + } + } + } + + func bookmarkEntity(for parentFolderType: ParentFolderType, in context: NSManagedObjectContext) throws -> BookmarkEntity { guard let rootFolder = bookmarksRoot(in: context) else { throw BookmarkStoreError.missingRoot } - let newParentFolder: BookmarkEntity + let parentFolder: BookmarkEntity - switch type { - case .root: newParentFolder = rootFolder - case .parent(let newParentUUID): - let bookmarksFetchRequest = BaseBookmarkEntity.singleEntity(with: newParentUUID) + switch parentFolderType { + case .root: + parentFolder = rootFolder + case let .parent(parentUUID): + let bookmarksFetchRequest = BaseBookmarkEntity.singleEntity(with: parentUUID) if let fetchedParent = try context.fetch(bookmarksFetchRequest).first, fetchedParent.isFolder { - newParentFolder = fetchedParent + parentFolder = fetchedParent } else { throw BookmarkStoreError.missingEntity } } - - if let index = index, index < newParentFolder.childrenArray.count { - self.move(entities: entities, to: index, within: newParentFolder) - } else { - for bookmarkManagedObject in entities { - bookmarkManagedObject.parent = nil - newParentFolder.addToChildren(bookmarkManagedObject) - } - } + return parentFolder } } @@ -1041,6 +1131,7 @@ extension LocalBookmarkStore.BookmarkStoreError: CustomNSError { case .missingRoot: return 7 case .missingFavoritesRoot: return 8 case .saveLoopError: return 9 + case .badModelMapping: return 10 } } diff --git a/DuckDuckGo/Bookmarks/Services/UserDefaultsBookmarkFoldersStore.swift b/DuckDuckGo/Bookmarks/Services/UserDefaultsBookmarkFoldersStore.swift new file mode 100644 index 0000000000..7fb3187329 --- /dev/null +++ b/DuckDuckGo/Bookmarks/Services/UserDefaultsBookmarkFoldersStore.swift @@ -0,0 +1,48 @@ +// +// UserDefaultsBookmarkFoldersStore.swift +// +// 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 + +/// A type used to provide the ID of the folder where all tabs were last saved. +protocol BookmarkFoldersStore: AnyObject { + /// The ID of the folder where all bookmarks from the last session were saved. + var lastBookmarkAllTabsFolderIdUsed: String? { get set } +} + +final class UserDefaultsBookmarkFoldersStore: BookmarkFoldersStore { + + enum Keys { + static let bookmarkAllTabsFolderUsedKey = "bookmarks.all-tabs.last-used-folder" + } + + private let userDefaults: UserDefaults + + init(userDefaults: UserDefaults = .standard) { + self.userDefaults = userDefaults + } + + var lastBookmarkAllTabsFolderIdUsed: String? { + get { + userDefaults.string(forKey: Keys.bookmarkAllTabsFolderUsedKey) + } + set { + userDefaults.set(newValue, forKey: Keys.bookmarkAllTabsFolderUsedKey) + } + } + +} diff --git a/DuckDuckGo/Bookmarks/View/AddBookmarkFolderPopoverView.swift b/DuckDuckGo/Bookmarks/View/AddBookmarkFolderPopoverView.swift index f15465df36..8ce41c17f2 100644 --- a/DuckDuckGo/Bookmarks/View/AddBookmarkFolderPopoverView.swift +++ b/DuckDuckGo/Bookmarks/View/AddBookmarkFolderPopoverView.swift @@ -36,7 +36,6 @@ struct AddBookmarkFolderPopoverView: ModalView { isDefaultActionDisabled: model.isDefaultActionButtonDisabled, defaultAction: { _ in model.addFolder() } ) - .padding(.vertical, 16.0) .font(.system(size: 13)) .frame(width: 320) } diff --git a/DuckDuckGo/Bookmarks/View/AddBookmarkPopoverView.swift b/DuckDuckGo/Bookmarks/View/AddBookmarkPopoverView.swift index fba84b44bc..1faa240398 100644 --- a/DuckDuckGo/Bookmarks/View/AddBookmarkPopoverView.swift +++ b/DuckDuckGo/Bookmarks/View/AddBookmarkPopoverView.swift @@ -55,7 +55,6 @@ struct AddBookmarkPopoverView: View { isDefaultActionDisabled: model.isDefaultActionButtonDisabled, defaultAction: model.doneButtonAction ) - .padding(.vertical, 16.0) .font(.system(size: 13)) .frame(width: 320) } diff --git a/DuckDuckGo/Bookmarks/View/BookmarkManagementDetailViewController.swift b/DuckDuckGo/Bookmarks/View/BookmarkManagementDetailViewController.swift index ecc643b33d..837af92acd 100644 --- a/DuckDuckGo/Bookmarks/View/BookmarkManagementDetailViewController.swift +++ b/DuckDuckGo/Bookmarks/View/BookmarkManagementDetailViewController.swift @@ -603,7 +603,7 @@ extension BookmarkManagementDetailViewController: NSMenuDelegate { } // If only one item is selected try to get the item and its parent folder otherwise show the menu for multiple items. - if tableView.selectedRowIndexes.contains(row), tableView.selectedRowIndexes.count > 1 { + if tableView.selectedRowIndexes.contains(row), tableView.selectedRowIndexes.count > 1 { return ContextualMenu.menu(for: self.selectedItems()) } diff --git a/DuckDuckGo/Bookmarks/View/BookmarkManagementSidebarViewController.swift b/DuckDuckGo/Bookmarks/View/BookmarkManagementSidebarViewController.swift index 53e502383b..f567a9f124 100644 --- a/DuckDuckGo/Bookmarks/View/BookmarkManagementSidebarViewController.swift +++ b/DuckDuckGo/Bookmarks/View/BookmarkManagementSidebarViewController.swift @@ -89,6 +89,7 @@ final class BookmarkManagementSidebarViewController: NSViewController { tabSwitcherButton.menu = NSMenu { for content in Tab.TabContent.displayableTabTypes { NSMenuItem(title: content.title!, representedObject: content) + .withAccessibilityIdentifier("BookmarkManagementSidebarViewController.\(content.title!)") } } diff --git a/DuckDuckGo/Bookmarks/View/BookmarkOutlineCellView.swift b/DuckDuckGo/Bookmarks/View/BookmarkOutlineCellView.swift index 603849bbbf..813e1ff8ec 100644 --- a/DuckDuckGo/Bookmarks/View/BookmarkOutlineCellView.swift +++ b/DuckDuckGo/Bookmarks/View/BookmarkOutlineCellView.swift @@ -40,6 +40,8 @@ final class BookmarkOutlineCellView: NSTableCellView { init(identifier: NSUserInterfaceItemIdentifier) { super.init(frame: .zero) + self.identifier = identifier + setupUI() } @@ -82,6 +84,7 @@ final class BookmarkOutlineCellView: NSTableCellView { faviconImageView.imageScaling = .scaleProportionallyDown faviconImageView.wantsLayer = true faviconImageView.layer?.cornerRadius = 2.0 + faviconImageView.setAccessibilityIdentifier("BookmarkOutlineCellView.favIconImageView") titleLabel.translatesAutoresizingMaskIntoConstraints = false titleLabel.isEditable = false diff --git a/DuckDuckGo/Bookmarks/View/BookmarkTableCellView.swift b/DuckDuckGo/Bookmarks/View/BookmarkTableCellView.swift index 8bfdc3c4fb..3a3d3ea0d9 100644 --- a/DuckDuckGo/Bookmarks/View/BookmarkTableCellView.swift +++ b/DuckDuckGo/Bookmarks/View/BookmarkTableCellView.swift @@ -129,6 +129,7 @@ final class BookmarkTableCellView: NSTableCellView { menuButton.translatesAutoresizingMaskIntoConstraints = false menuButton.isBordered = false menuButton.isHidden = true + menuButton.setAccessibilityIdentifier("BookmarkTableCellView.menuButton") } private func setupLayout() { @@ -209,11 +210,14 @@ final class BookmarkTableCellView: NSTableCellView { faviconImageView.image = bookmark.favicon(.small) ?? .bookmarkDefaultFavicon + faviconImageView.setAccessibilityIdentifier("BookmarkTableCellView.favIconImageView") if bookmark.isFavorite { accessoryImageView.isHidden = false } accessoryImageView.image = bookmark.isFavorite ? .favoriteFilledBorder : nil + accessoryImageView.setAccessibilityIdentifier("BookmarkTableCellView.accessoryImageView") + accessoryImageView.setAccessibilityValue(bookmark.isFavorite ? "Favorited" : "Unfavorited") titleLabel.stringValue = bookmark.title primaryTitleLabelValue = bookmark.title tertiaryTitleLabelValue = bookmark.url diff --git a/DuckDuckGo/Bookmarks/View/Dialog/AddEditBookmarkDialogView.swift b/DuckDuckGo/Bookmarks/View/Dialog/AddEditBookmarkDialogView.swift index 2c0256bba4..78cdc6efcd 100644 --- a/DuckDuckGo/Bookmarks/View/Dialog/AddEditBookmarkDialogView.swift +++ b/DuckDuckGo/Bookmarks/View/Dialog/AddEditBookmarkDialogView.swift @@ -55,7 +55,7 @@ struct AddEditBookmarkDialogView: ModalView { isDefaultActionDisabled: viewModel.bookmarkModel.isDefaultActionDisabled, defaultAction: viewModel.bookmarkModel.addOrSave ) - .frame(width: 448, height: 288) + .frame(width: 448) } private var addFolderView: some View { diff --git a/DuckDuckGo/Bookmarks/View/Dialog/BookmarkAllTabsDialogView.swift b/DuckDuckGo/Bookmarks/View/Dialog/BookmarkAllTabsDialogView.swift new file mode 100644 index 0000000000..ad920b10c6 --- /dev/null +++ b/DuckDuckGo/Bookmarks/View/Dialog/BookmarkAllTabsDialogView.swift @@ -0,0 +1,141 @@ +// +// BookmarkAllTabsDialogView.swift +// +// 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 SwiftUIExtensions + +struct BookmarkAllTabsDialogView: ModalView { + @ObservedObject private var viewModel: BookmarkAllTabsDialogCoordinatorViewModel + + init(viewModel: BookmarkAllTabsDialogCoordinatorViewModel) { + self.viewModel = viewModel + } + + var body: some View { + Group { + switch viewModel.viewState { + case .bookmarkAllTabs: + bookmarkAllTabsView + case .addFolder: + addFolderView + } + } + .font(.system(size: 13)) + } + + private var bookmarkAllTabsView: some View { + BookmarkDialogContainerView( + title: viewModel.bookmarkModel.title, + middleSection: { + Text(viewModel.bookmarkModel.educationalMessage) + .multilineText() + .multilineTextAlignment(.leading) + .foregroundColor(.secondary) + .font(.system(size: 11)) + BookmarkDialogStackedContentView( + .init( + title: UserText.Bookmarks.Dialog.Field.folderName, + content: TextField("", text: $viewModel.bookmarkModel.folderName) + .focusedOnAppear() + .textFieldStyle(RoundedBorderTextFieldStyle()) + .font(.system(size: 14)) + ), + .init( + title: UserText.Bookmarks.Dialog.Field.location, + content: BookmarkDialogFolderManagementView( + folders: viewModel.bookmarkModel.folders, + selectedFolder: $viewModel.bookmarkModel.selectedFolder, + onActionButton: viewModel.addFolderAction + ) + ) + ) + }, + bottomSection: { + BookmarkDialogButtonsView( + viewState: .init(.compressed), + otherButtonAction: .init( + title: viewModel.bookmarkModel.cancelActionTitle, + isDisabled: viewModel.bookmarkModel.isOtherActionDisabled, + action: viewModel.bookmarkModel.cancel + ), + defaultButtonAction: .init( + title: viewModel.bookmarkModel.defaultActionTitle, + keyboardShortCut: .defaultAction, + isDisabled: viewModel.bookmarkModel.isDefaultActionDisabled, + action: viewModel.bookmarkModel.addOrSave + ) + ) + } + + ) + .frame(width: 448) + } + + private var addFolderView: some View { + AddEditBookmarkFolderView( + title: viewModel.folderModel.title, + buttonsState: .compressed, + folders: viewModel.folderModel.folders, + folderName: $viewModel.folderModel.folderName, + selectedFolder: $viewModel.folderModel.selectedFolder, + cancelActionTitle: viewModel.folderModel.cancelActionTitle, + isCancelActionDisabled: viewModel.folderModel.isOtherActionDisabled, + cancelAction: { _ in + viewModel.dismissAction() + }, + defaultActionTitle: viewModel.folderModel.defaultActionTitle, + isDefaultActionDisabled: viewModel.folderModel.isDefaultActionDisabled, + defaultAction: { _ in + viewModel.folderModel.addOrSave { + viewModel.dismissAction() + } + } + ) + .frame(width: 448, height: 210) + } +} + +#if DEBUG +#Preview("Bookmark All Tabs - Light") { + let parentFolder = BookmarkFolder(id: "7", title: "DuckDuckGo") + let bookmark = Bookmark(id: "1", url: "www.duckduckgo.com", title: "DuckDuckGo", isFavorite: true, parentFolderUUID: "7") + let bookmarkManager = LocalBookmarkManager(bookmarkStore: BookmarkStoreMock(bookmarks: [bookmark, parentFolder])) + bookmarkManager.loadBookmarks() + let websitesInfo: [WebsiteInfo] = [ + .init(.init(content: .url(URL.duckDuckGo, credential: nil, source: .ui)))!, + .init(.init(content: .url(URL.duckDuckGoEmail, credential: nil, source: .ui)))!, + ] + + return BookmarksDialogViewFactory.makeBookmarkAllOpenTabsView(websitesInfo: websitesInfo, bookmarkManager: bookmarkManager) + .preferredColorScheme(.light) +} + +#Preview("Bookmark All Tabs - Dark") { + let parentFolder = BookmarkFolder(id: "7", title: "DuckDuckGo") + let bookmark = Bookmark(id: "1", url: "www.duckduckgo.com", title: "DuckDuckGo", isFavorite: true, parentFolderUUID: "7") + let bookmarkManager = LocalBookmarkManager(bookmarkStore: BookmarkStoreMock(bookmarks: [bookmark, parentFolder])) + bookmarkManager.loadBookmarks() + let websitesInfo: [WebsiteInfo] = [ + .init(.init(content: .url(URL.duckDuckGo, credential: nil, source: .ui)))!, + .init(.init(content: .url(URL.duckDuckGoEmail, credential: nil, source: .ui)))!, + ] + + return BookmarksDialogViewFactory.makeBookmarkAllOpenTabsView(websitesInfo: websitesInfo, bookmarkManager: bookmarkManager) + .preferredColorScheme(.dark) +} +#endif diff --git a/DuckDuckGo/Bookmarks/View/Dialog/BookmarkDialogButtonsView.swift b/DuckDuckGo/Bookmarks/View/Dialog/BookmarkDialogButtonsView.swift index d55f6dd34f..80e9320dc2 100644 --- a/DuckDuckGo/Bookmarks/View/Dialog/BookmarkDialogButtonsView.swift +++ b/DuckDuckGo/Bookmarks/View/Dialog/BookmarkDialogButtonsView.swift @@ -40,7 +40,7 @@ struct BookmarkDialogButtonsView: View { Spacer() } - actionButton(action: otherButtonAction, viewState: viewState) + actionButton(action: otherButtonAction, viewState: viewState).accessibilityIdentifier("BookmarkDialogButtonsView.otherButton") actionButton(action: defaultButtonAction, viewState: viewState).accessibilityIdentifier("BookmarkDialogButtonsView.defaultButton") } diff --git a/DuckDuckGo/Bookmarks/View/Dialog/BookmarkDialogContainerView.swift b/DuckDuckGo/Bookmarks/View/Dialog/BookmarkDialogContainerView.swift index ea49712abb..120869ea4f 100644 --- a/DuckDuckGo/Bookmarks/View/Dialog/BookmarkDialogContainerView.swift +++ b/DuckDuckGo/Bookmarks/View/Dialog/BookmarkDialogContainerView.swift @@ -42,9 +42,13 @@ struct BookmarkDialogContainerView: View { Text(title) .foregroundColor(.primary) .fontWeight(.semibold) + .padding(.top, 20) }, center: middleSection, - bottom: bottomSection + bottom: { + bottomSection() + .padding(.bottom, 16.0) + } ) } } diff --git a/DuckDuckGo/Bookmarks/View/Dialog/BookmarksDialogViewFactory.swift b/DuckDuckGo/Bookmarks/View/Dialog/BookmarksDialogViewFactory.swift index b29b50bbbb..3bff7ff4af 100644 --- a/DuckDuckGo/Bookmarks/View/Dialog/BookmarksDialogViewFactory.swift +++ b/DuckDuckGo/Bookmarks/View/Dialog/BookmarksDialogViewFactory.swift @@ -80,6 +80,18 @@ enum BookmarksDialogViewFactory { return makeAddEditBookmarkDialogView(viewModel: viewModel, bookmarkManager: bookmarkManager) } + /// Creates an instance of AddEditBookmarkDialogView for adding Bookmarks for all the open Tabs. + /// - Parameters: + /// - websitesInfo: A list of websites to add as bookmarks. + /// - bookmarkManager: An instance of `BookmarkManager`. This should be used for `#previews` only. + /// - Returns: An instance of BookmarkAllTabsDialogView + static func makeBookmarkAllOpenTabsView(websitesInfo: [WebsiteInfo], bookmarkManager: LocalBookmarkManager = .shared) -> BookmarkAllTabsDialogView { + let addFolderViewModel = AddEditBookmarkFolderDialogViewModel(mode: .add(parentFolder: nil), bookmarkManager: bookmarkManager) + let bookmarkAllTabsViewModel = BookmarkAllTabsDialogViewModel(websites: websitesInfo, foldersStore: UserDefaultsBookmarkFoldersStore(), bookmarkManager: bookmarkManager) + let viewModel = BookmarkAllTabsDialogCoordinatorViewModel(bookmarkModel: bookmarkAllTabsViewModel, folderModel: addFolderViewModel) + return BookmarkAllTabsDialogView(viewModel: viewModel) + } + } private extension BookmarksDialogViewFactory { diff --git a/DuckDuckGo/Bookmarks/ViewModel/AddEditBookmarkFolderDialogViewModel.swift b/DuckDuckGo/Bookmarks/ViewModel/AddEditBookmarkFolderDialogViewModel.swift index 62c1e0356c..48815ebc8d 100644 --- a/DuckDuckGo/Bookmarks/ViewModel/AddEditBookmarkFolderDialogViewModel.swift +++ b/DuckDuckGo/Bookmarks/ViewModel/AddEditBookmarkFolderDialogViewModel.swift @@ -42,8 +42,9 @@ final class AddEditBookmarkFolderDialogViewModel: BookmarkFolderDialogEditing { @Published var folderName: String @Published var selectedFolder: BookmarkFolder? + @Published private(set) var folders: [FolderViewModel] - let folders: [FolderViewModel] + private var folderCancellable: AnyCancellable? var title: String { mode.title @@ -77,14 +78,20 @@ final class AddEditBookmarkFolderDialogViewModel: BookmarkFolderDialogEditing { folderName = mode.folderName folders = .init(bookmarkManager.list) selectedFolder = mode.parentFolder + + bind() } func cancel(dismiss: () -> Void) { + reset() dismiss() } func addOrSave(dismiss: () -> Void) { - defer { dismiss() } + defer { + reset() + dismiss() + } guard !folderName.isEmpty else { assertionFailure("folderName is empty, button should be disabled") @@ -110,6 +117,14 @@ final class AddEditBookmarkFolderDialogViewModel: BookmarkFolderDialogEditing { private extension AddEditBookmarkFolderDialogViewModel { + func bind() { + folderCancellable = bookmarkManager.listPublisher + .receive(on: DispatchQueue.main) + .sink(receiveValue: { [weak self] bookmarkList in + self?.folders = .init(bookmarkList) + }) + } + func update(folder: BookmarkFolder, originalParent: BookmarkFolder?, newParent: BookmarkFolder?) { // If the original location of the folder changed move it to the new folder. if selectedFolder?.id != originalParent?.id { @@ -129,6 +144,10 @@ private extension AddEditBookmarkFolderDialogViewModel { } } + func reset() { + self.folderName = "" + } + } // MARK: - AddEditBookmarkFolderDialogViewModel.Mode diff --git a/DuckDuckGo/Bookmarks/ViewModel/BookmarkAllTabsDialogCoordinatorViewModel.swift b/DuckDuckGo/Bookmarks/ViewModel/BookmarkAllTabsDialogCoordinatorViewModel.swift new file mode 100644 index 0000000000..975c8811b6 --- /dev/null +++ b/DuckDuckGo/Bookmarks/ViewModel/BookmarkAllTabsDialogCoordinatorViewModel.swift @@ -0,0 +1,74 @@ +// +// BookmarkAllTabsDialogCoordinatorViewModel.swift +// +// 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 Combine + +final class BookmarkAllTabsDialogCoordinatorViewModel: ObservableObject { + @ObservedObject var bookmarkModel: BookmarkViewModel + @ObservedObject var folderModel: AddFolderViewModel + @Published var viewState: ViewState + + private var cancellables: Set = [] + + init(bookmarkModel: BookmarkViewModel, folderModel: AddFolderViewModel) { + self.bookmarkModel = bookmarkModel + self.folderModel = folderModel + viewState = .bookmarkAllTabs + bind() + } + + func dismissAction() { + viewState = .bookmarkAllTabs + } + + func addFolderAction() { + folderModel.selectedFolder = bookmarkModel.selectedFolder + viewState = .addFolder + } + + private func bind() { + bookmarkModel.objectWillChange + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + self?.objectWillChange.send() + } + .store(in: &cancellables) + + folderModel.objectWillChange + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + self?.objectWillChange.send() + } + .store(in: &cancellables) + + folderModel.addFolderPublisher + .receive(on: DispatchQueue.main) + .sink { [weak self] bookmarkFolder in + self?.bookmarkModel.selectedFolder = bookmarkFolder + } + .store(in: &cancellables) + } +} + +extension BookmarkAllTabsDialogCoordinatorViewModel { + enum ViewState { + case bookmarkAllTabs + case addFolder + } +} diff --git a/DuckDuckGo/Bookmarks/ViewModel/BookmarkAllTabsDialogViewModel.swift b/DuckDuckGo/Bookmarks/ViewModel/BookmarkAllTabsDialogViewModel.swift new file mode 100644 index 0000000000..daf6018403 --- /dev/null +++ b/DuckDuckGo/Bookmarks/ViewModel/BookmarkAllTabsDialogViewModel.swift @@ -0,0 +1,127 @@ +// +// BookmarkAllTabsDialogViewModel.swift +// +// 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 Combine + +@MainActor +protocol BookmarkAllTabsDialogEditing: BookmarksDialogViewModel { + var folderName: String { get set } + var educationalMessage: String { get } + var folderNameFieldTitle: String { get } + var locationFieldTitle: String { get } +} + +final class BookmarkAllTabsDialogViewModel: BookmarkAllTabsDialogEditing { + private static let dateFormatter: ISO8601DateFormatter = { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withFullDate, .withDashSeparatorInDate] + return formatter + }() + + private let websites: [WebsiteInfo] + private let foldersStore: BookmarkFoldersStore + private let bookmarkManager: BookmarkManager + + private var folderCancellable: AnyCancellable? + + @Published private(set) var folders: [FolderViewModel] + @Published var selectedFolder: BookmarkFolder? + @Published var folderName: String + + var title: String { + String(format: UserText.Bookmarks.Dialog.Title.bookmarkOpenTabs, websites.count) + } + let cancelActionTitle = UserText.cancel + let defaultActionTitle = UserText.Bookmarks.Dialog.Action.addAllBookmarks + let educationalMessage = UserText.Bookmarks.Dialog.Message.bookmarkOpenTabsEducational + let folderNameFieldTitle = UserText.Bookmarks.Dialog.Field.folderName + let locationFieldTitle = UserText.Bookmarks.Dialog.Field.location + let isOtherActionDisabled = false + + var isDefaultActionDisabled: Bool { + folderName.trimmingWhitespace().isEmpty + } + + init( + websites: [WebsiteInfo], + foldersStore: BookmarkFoldersStore, + bookmarkManager: BookmarkManager = LocalBookmarkManager.shared, + dateFormatterConfigurationProvider: () -> DateFormatterConfiguration = DateFormatterConfiguration.defaultConfiguration + ) { + self.websites = websites + self.foldersStore = foldersStore + self.bookmarkManager = bookmarkManager + + folders = .init(bookmarkManager.list) + selectedFolder = foldersStore.lastBookmarkAllTabsFolderIdUsed.flatMap(bookmarkManager.getBookmarkFolder(withId:)) + folderName = Self.folderName(configuration: dateFormatterConfigurationProvider(), websitesNumber: websites.count) + bind() + } + + func cancel(dismiss: () -> Void) { + dismiss() + } + + func addOrSave(dismiss: () -> Void) { + // Save last used folder + foldersStore.lastBookmarkAllTabsFolderIdUsed = selectedFolder?.id + + // Save all bookmarks + let parentFolder: ParentFolderType = selectedFolder.flatMap { .parent(uuid: $0.id) } ?? .root + bookmarkManager.makeBookmarks(for: websites, inNewFolderNamed: folderName, withinParentFolder: parentFolder) + + // Dismiss the view + dismiss() + } +} + +// MARK: - Private + +private extension BookmarkAllTabsDialogViewModel { + + static func folderName(configuration: DateFormatterConfiguration, websitesNumber: Int) -> String { + Self.dateFormatter.timeZone = configuration.timeZone + let dateString = Self.dateFormatter.string(from: configuration.date) + return String(format: UserText.Bookmarks.Dialog.Value.folderName, dateString, websitesNumber) + } + + func bind() { + folderCancellable = bookmarkManager.listPublisher + .receive(on: DispatchQueue.main) + .sink(receiveValue: { [weak self] bookmarkList in + self?.folders = .init(bookmarkList) + }) + } + +} + +// MARK: - DateConfiguration + +extension BookmarkAllTabsDialogViewModel { + + struct DateFormatterConfiguration { + let date: Date + let timeZone: TimeZone + + static func defaultConfiguration() -> DateFormatterConfiguration { + .init(date: Date(), timeZone: .current) + } + } + +} diff --git a/DuckDuckGo/BookmarksBar/BookmarksBarVisibilityManager.swift b/DuckDuckGo/BookmarksBar/BookmarksBarVisibilityManager.swift new file mode 100644 index 0000000000..9e837b1a47 --- /dev/null +++ b/DuckDuckGo/BookmarksBar/BookmarksBarVisibilityManager.swift @@ -0,0 +1,96 @@ +// +// BookmarksBarVisibilityManager.swift +// +// 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 Combine + +/// Decides if the BookmarksBar should be visible based on the Tab.Content and Appearance preferences. +final class BookmarksBarVisibilityManager { + private var bookmarkBarVisibilityCancellable: AnyCancellable? + private var bookmarkContentCancellable: AnyCancellable? + + /// A published value indicating the visibility of the bookmarks bar. + /// Returns`true` if the bookmarks bar is visible; otherwise, `false`. + @Published var isBookmarksBarVisible: Bool = false + + private let selectedTabPublisher: AnyPublisher + private let preferences: AppearancePreferences + + /// Create an instance given the specified `TabViewModel` publisher and `AppearancePreferences`. + /// - Parameters: + /// - selectedTabPublisher: A publisher that returns the selected Tab view model. + /// - preferences: The `AppearancePreferences` to read the bookmarks appearance preferences from. + init(selectedTabPublisher: AnyPublisher, preferences: AppearancePreferences = .shared) { + self.selectedTabPublisher = selectedTabPublisher + self.preferences = preferences + bind() + } + +} + +// MARK: - Private + +private extension BookmarksBarVisibilityManager { + + func bind() { + let bookmarksBarVisibilityPublisher = NotificationCenter.default + .publisher(for: AppearancePreferences.Notifications.showBookmarksBarSettingChanged) + + let bookmarksBarAppearancePublisher = NotificationCenter.default + .publisher(for: AppearancePreferences.Notifications.bookmarksBarSettingAppearanceChanged) + + let bookmarksBarNotificationsPublisher = Publishers.Merge(bookmarksBarVisibilityPublisher, bookmarksBarAppearancePublisher) + .map { _ in () } // Map To Void, we're not interested in the notification itself + .prepend(()) // Start with a value so combineLatest can fire + + // Every time the user select a tab or the Appeareance preference changes check if bookmarks bar should be visible or not. + // For the selected Tab we should also check if the Tab content changes as it can switch from empty to url if the user loads a web page. + bookmarkBarVisibilityCancellable = bookmarksBarNotificationsPublisher + .combineLatest(selectedTabPublisher) + .compactMap { _, selectedTab -> TabViewModel? in + guard let selectedTab else { return nil } + return selectedTab + } + .flatMap { tabViewModel in + // Subscribe to the selected tab content. + // When a tab is empty and the bookmarksBar should show only on empty Tabs it should disappear when we load a website. + tabViewModel.tab.$content.eraseToAnyPublisher() + } + .sink(receiveValue: { [weak self] tabContent in + guard let self = self else { return } + self.updateBookmarksBar(content: tabContent, preferences: self.preferences) + }) + } + + func updateBookmarksBar(content: Tab.TabContent, preferences: AppearancePreferences) { + // If visibility should be off, set visibility off and exit + guard preferences.showBookmarksBar else { + isBookmarksBarVisible = false + return + } + + // If visibility is on check Appearance + switch preferences.bookmarksBarAppearance { + case .newTabOnly: + isBookmarksBarVisible = content.isEmpty + case .alwaysOn: + isBookmarksBarVisible = true + } + } + +} diff --git a/DuckDuckGo/BookmarksBar/View/BookmarksBarViewController.swift b/DuckDuckGo/BookmarksBar/View/BookmarksBarViewController.swift index e298a6335e..b927a05751 100644 --- a/DuckDuckGo/BookmarksBar/View/BookmarksBarViewController.swift +++ b/DuckDuckGo/BookmarksBar/View/BookmarksBarViewController.swift @@ -82,6 +82,7 @@ final class BookmarksBarViewController: NSViewController { bookmarksBarCollectionView.collectionViewLayout = createCenteredCollectionViewLayout() view.postsFrameChangedNotifications = true + bookmarksBarCollectionView.setAccessibilityIdentifier("BookmarksBarViewController.bookmarksBarCollectionView") } private func addContextMenu() { diff --git a/DuckDuckGo/Common/Database/Database.swift b/DuckDuckGo/Common/Database/Database.swift index 10e116d3a7..dee8aef2d8 100644 --- a/DuckDuckGo/Common/Database/Database.swift +++ b/DuckDuckGo/Common/Database/Database.swift @@ -21,6 +21,7 @@ import BrowserServicesKit import CoreData import Foundation import Persistence +import PixelKit final class Database { @@ -100,7 +101,7 @@ final class Database { // Fire the pixel once a day at max if lastPixelSentAt < Date.daysAgo(1) { lastDatabaseFactoryFailurePixelDate = Date() - Pixel.fire(.debug(event: .dbMakeDatabaseError, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.dbMakeDatabaseError(error: error))) } } } @@ -185,14 +186,14 @@ extension NSManagedObjectModel { extension NSManagedObjectContext { - func save(onErrorFire event: Pixel.Event.Debug) throws { + func save(onErrorFire event: PixelKitEventV2) throws { do { try save() } catch { let nsError = error as NSError let processedErrors = CoreDataErrorsParser.parse(error: nsError) - Pixel.fire(.debug(event: event, error: error), + PixelKit.fire(DebugEvent(event, error: error), withAdditionalParameters: processedErrors.errorPixelParameters) throw error diff --git a/DuckDuckGo/Common/Extensions/BundleExtension.swift b/DuckDuckGo/Common/Extensions/BundleExtension.swift index b3c7a629f5..28133debd8 100644 --- a/DuckDuckGo/Common/Extensions/BundleExtension.swift +++ b/DuckDuckGo/Common/Extensions/BundleExtension.swift @@ -26,6 +26,8 @@ extension Bundle { static let buildNumber = kCFBundleVersionKey as String static let versionNumber = "CFBundleShortVersionString" static let displayName = "CFBundleDisplayName" + static let documentTypes = "CFBundleDocumentTypes" + static let typeExtensions = "CFBundleTypeExtensions" static let vpnMenuAgentBundleId = "AGENT_BUNDLE_ID" static let vpnMenuAgentProductName = "AGENT_PRODUCT_NAME" @@ -115,6 +117,14 @@ extension Bundle { return path.hasPrefix(applicationsPath) } + var documentTypes: [[String: Any]] { + infoDictionary?[Keys.documentTypes] as? [[String: Any]] ?? [] + } + + var fileTypeExtensions: Set { + documentTypes.reduce(into: []) { $0.formUnion($1[Keys.typeExtensions] as? [String] ?? []) } + } + } enum BundleGroup { diff --git a/DuckDuckGo/Common/Extensions/FileManagerExtension.swift b/DuckDuckGo/Common/Extensions/FileManagerExtension.swift index c524d39c8c..b7e767fece 100644 --- a/DuckDuckGo/Common/Extensions/FileManagerExtension.swift +++ b/DuckDuckGo/Common/Extensions/FileManagerExtension.swift @@ -101,4 +101,16 @@ extension FileManager { return resolvedUrl.path.hasPrefix(trashUrl.path) } + /// Check if location pointed by the URL is writable by writing an empty data to it and removing the file if write succeeds + /// - Throws error if writing to the location fails + func checkWritability(_ url: URL) throws { + if fileExists(atPath: url.path), isWritableFile(atPath: url.path) { + return // we can write + } else { + // either we can‘t write or there‘s no file at the url – try writing throwing access error if no permission + try Data().write(to: url) + try removeItem(at: url) + } + } + } diff --git a/DuckDuckGo/Common/Extensions/NSAlertExtension.swift b/DuckDuckGo/Common/Extensions/NSAlertExtension.swift index 554ce896e5..017389de08 100644 --- a/DuckDuckGo/Common/Extensions/NSAlertExtension.swift +++ b/DuckDuckGo/Common/Extensions/NSAlertExtension.swift @@ -137,15 +137,6 @@ extension NSAlert { return alert } - static func noAccessToSelectedFolder() -> NSAlert { - let alert = NSAlert() - alert.messageText = UserText.noAccessToSelectedFolderHeader - alert.informativeText = UserText.noAccessToSelectedFolder - alert.alertStyle = .warning - alert.addButton(withTitle: UserText.cancel) - return alert - } - static func disableEmailProtection() -> NSAlert { let alert = NSAlert() alert.messageText = UserText.disableEmailProtectionTitle @@ -224,6 +215,37 @@ extension NSAlert { return alert } + static func autoClearAlert() -> NSAlert { + let alert = NSAlert() + alert.messageText = UserText.warnBeforeQuitDialogHeader + alert.alertStyle = .warning + alert.icon = .burnAlert + alert.addButton(withTitle: UserText.clearAndQuit) + alert.addButton(withTitle: UserText.quitWithoutClearing) + alert.addButton(withTitle: UserText.cancel) + + let checkbox = NSButton(checkboxWithTitle: UserText.warnBeforeQuitDialogCheckboxMessage, + target: DataClearingPreferences.shared, + action: #selector(DataClearingPreferences.toggleWarnBeforeClearing)) + checkbox.state = DataClearingPreferences.shared.isWarnBeforeClearingEnabled ? .on : .off + checkbox.lineBreakMode = .byWordWrapping + checkbox.translatesAutoresizingMaskIntoConstraints = false + + // Create a container view for the checkbox with custom padding + let containerView = NSView(frame: NSRect(x: 0, y: 0, width: 240, height: 25)) + containerView.addSubview(checkbox) + + NSLayoutConstraint.activate([ + checkbox.centerXAnchor.constraint(equalTo: containerView.centerXAnchor), + checkbox.centerYAnchor.constraint(equalTo: containerView.centerYAnchor, constant: -10), // Slightly up for better visual alignment + checkbox.widthAnchor.constraint(lessThanOrEqualTo: containerView.widthAnchor) + ]) + + alert.accessoryView = containerView + + return alert + } + @discardableResult func runModal() async -> NSApplication.ModalResponse { await withCheckedContinuation { continuation in diff --git a/DuckDuckGo/Common/Extensions/NSAttributedStringExtension.swift b/DuckDuckGo/Common/Extensions/NSAttributedStringExtension.swift index 01f2d1c255..58a1cd7fb0 100644 --- a/DuckDuckGo/Common/Extensions/NSAttributedStringExtension.swift +++ b/DuckDuckGo/Common/Extensions/NSAttributedStringExtension.swift @@ -18,6 +18,7 @@ import AppKit +typealias NSAttributedStringBuilder = ArrayBuilder extension NSAttributedString { /// These values come from Figma. Click on the text in Figma and choose Code > iOS to see the values. @@ -31,6 +32,31 @@ extension NSAttributedString { ]) } + convenience init(image: NSImage, rect: CGRect) { + let attachment = NSTextAttachment() + attachment.image = image + attachment.bounds = rect + self.init(attachment: attachment) + } + + convenience init(@NSAttributedStringBuilder components: () -> [NSAttributedString]) { + let components = components() + guard !components.isEmpty else { + self.init() + return + } + guard components.count > 1 else { + self.init(attributedString: components[0]) + return + } + let result = NSMutableAttributedString(attributedString: components[0]) + for component in components[1...] { + result.append(component) + } + + self.init(attributedString: result) + } + } extension NSMutableAttributedString { @@ -48,12 +74,3 @@ extension NSMutableAttributedString { } } - -extension NSTextAttachment { - func setImageHeight(height: CGFloat, offset: CGPoint = .zero) { - guard let image = image else { return } - let ratio = image.size.width / image.size.height - - bounds = CGRect(x: bounds.origin.x + offset.x, y: bounds.origin.y + offset.y, width: ratio * height, height: height) - } -} diff --git a/DuckDuckGo/Common/Extensions/NSMenuItemExtension.swift b/DuckDuckGo/Common/Extensions/NSMenuItemExtension.swift index b3f0870252..dfe76b5092 100644 --- a/DuckDuckGo/Common/Extensions/NSMenuItemExtension.swift +++ b/DuckDuckGo/Common/Extensions/NSMenuItemExtension.swift @@ -110,6 +110,11 @@ extension NSMenuItem { return self } + func withAccessibilityValue(_ accessibilityValue: String) -> NSMenuItem { + self.setAccessibilityValue(accessibilityValue) + return self + } + @discardableResult func withImage(_ image: NSImage?) -> NSMenuItem { self.image = image diff --git a/DuckDuckGo/Common/Extensions/NSPointExtension.swift b/DuckDuckGo/Common/Extensions/NSPointExtension.swift index 18bfbf0c2e..594cea0de4 100644 --- a/DuckDuckGo/Common/Extensions/NSPointExtension.swift +++ b/DuckDuckGo/Common/Extensions/NSPointExtension.swift @@ -20,6 +20,12 @@ import Foundation extension NSPoint { + func distance(to point: NSPoint) -> CGFloat { + let deltaX = self.x - point.x + let deltaY = self.y - point.y + return sqrt(deltaX * deltaX + deltaY * deltaY) + } + func isNearRect(_ rect: NSRect, allowedDistance: CGFloat) -> Bool { let expandedRect = rect.insetBy(dx: -allowedDistance, dy: -allowedDistance) return expandedRect.contains(self) diff --git a/DuckDuckGo/Common/Extensions/NSViewExtension.swift b/DuckDuckGo/Common/Extensions/NSViewExtension.swift index b82095c1f0..333dce57cf 100644 --- a/DuckDuckGo/Common/Extensions/NSViewExtension.swift +++ b/DuckDuckGo/Common/Extensions/NSViewExtension.swift @@ -79,6 +79,11 @@ extension NSView { return self } + var isShown: Bool { + get { !isHidden } + set { isHidden = !newValue } + } + func makeMeFirstResponder() { guard let window = window else { os_log("%s: Window not available", type: .error, className) diff --git a/DuckDuckGo/Common/Extensions/StringExtension.swift b/DuckDuckGo/Common/Extensions/StringExtension.swift index eeb8e5bedb..6128d9906a 100644 --- a/DuckDuckGo/Common/Extensions/StringExtension.swift +++ b/DuckDuckGo/Common/Extensions/StringExtension.swift @@ -71,6 +71,10 @@ extension String { return result } + func replacingInvalidFileNameCharacters(with replacement: String = "_") -> String { + replacingOccurrences(of: "[~#@*+%{}<>\\[\\]|\"\\_^\\/:\\\\]", with: replacement, options: .regularExpression) + } + init(_ staticString: StaticString) { self = staticString.withUTF8Buffer { String(decoding: $0, as: UTF8.self) diff --git a/DuckDuckGo/Common/Extensions/URLExtension.swift b/DuckDuckGo/Common/Extensions/URLExtension.swift index 4c68d32b01..07683d29cc 100644 --- a/DuckDuckGo/Common/Extensions/URLExtension.swift +++ b/DuckDuckGo/Common/Extensions/URLExtension.swift @@ -24,11 +24,17 @@ import Foundation extension URL.NavigationalScheme { static let duck = URL.NavigationalScheme(rawValue: "duck") + static let javascript = URL.NavigationalScheme(rawValue: "javascript") static var validSchemes: [URL.NavigationalScheme] { return [.http, .https, .file] } + /// HTTP or HTTPS + var isHypertextScheme: Bool { + Self.hypertextSchemes.contains(self) + } + } extension URL { @@ -136,12 +142,16 @@ extension URL { // base url for Error Page Alternate HTML loaded into Web View static let error = URL(string: "duck://error")! - static let dataBrokerProtection = URL(string: "duck://dbp")! + static let dataBrokerProtection = URL(string: "duck://personal-information-removal")! #if !SANDBOX_TEST_TOOL static func settingsPane(_ pane: PreferencePaneIdentifier) -> URL { return settings.appendingPathComponent(pane.rawValue) } + + var isSettingsURL: Bool { + isChild(of: .settings) && (pathComponents.isEmpty || PreferencePaneIdentifier(url: self) != nil) + } #endif enum Invalid { @@ -278,6 +288,14 @@ extension URL { return string } + func hostAndPort() -> String? { + guard let host else { return nil } + + guard let port = port else { return host } + + return "\(host):\(port)" + } + #if !SANDBOX_TEST_TOOL func toString(forUserInput input: String, decodePunycode: Bool = true) -> String { let hasInputScheme = input.hasOrIsPrefix(of: self.separatedScheme ?? "") @@ -323,7 +341,7 @@ extension URL { } var isExternalSchemeLink: Bool { - return !["https", "http", "about", "file", "blob", "data", "ftp"].contains(scheme) + return ![.https, .http, .about, .file, .blob, .data, .ftp, .javascript].contains(navigationalScheme) } // MARK: - DuckDuckGo @@ -373,6 +391,10 @@ extension URL { return URL(string: "https://duckduckgo.com/privacy")! } + static var privacyPro: URL { + return URL(string: "https://duckduckgo.com/pro")! + } + static var duckDuckGoEmail = URL(string: "https://duckduckgo.com/email-protection")! static var duckDuckGoEmailLogin = URL(string: "https://duckduckgo.com/email")! @@ -391,6 +413,10 @@ extension URL { return false } + var isEmailProtection: Bool { + self.isChild(of: .duckDuckGoEmailLogin) || self == .duckDuckGoEmail + } + enum DuckDuckGoParameters: String { case search = "q" case ia @@ -465,10 +491,63 @@ extension URL { } + var isFileHidden: Bool { + get throws { + try self.resourceValues(forKeys: [.isHiddenKey]).isHidden ?? false + } + } + + var isDirectory: Bool { + var isDirectory: ObjCBool = false + guard isFileURL, + FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) else { return false } + return isDirectory.boolValue + } + + mutating func setFileHidden(_ hidden: Bool) throws { + var resourceValues = URLResourceValues() + resourceValues.isHidden = true + try setResourceValues(resourceValues) + } + + /// Check if location pointed by the URL is writable + /// - Note: if there‘s no file at the URL, it will try to create a file and then remove it + func isWritableLocation() -> Bool { + do { + try FileManager.default.checkWritability(self) + return true + } catch { + return false + } + } + +#if DEBUG && APPSTORE + /// sandbox extension URL access should be stopped after SecurityScopedFileURLController is deallocated - this function validates it and breaks if the file is still writable + func ensureUrlIsNotWritable(or handler: () -> Void) { + let fm = FileManager.default + // is the URL ~/Downloads? + if self.resolvingSymlinksInPath() == fm.urls(for: .downloadsDirectory, in: .userDomainMask).first!.resolvingSymlinksInPath() { + assert(isWritableLocation()) + return + } + // is parent directory writable (e.g. ~/Downloads)? + if fm.isWritableFile(atPath: self.deletingLastPathComponent().path) + // trashed files are still accessible for some reason even after stopping access + || fm.isInTrash(self) + // other file is being saved at the same URL + || NSURL.activeSecurityScopedUrlUsages.contains(where: { $0.url !== self as NSURL && $0.url == self as NSURL }) + || !isWritableLocation() { return } + + handler() + } +#endif + // MARK: - System Settings static var fullDiskAccess = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles")! + static var touchIDAndPassword = URL(string: "x-apple.systempreferences:com.apple.preferences.password")! + // MARK: - Blob URLs var isBlobURL: Bool { @@ -481,7 +560,7 @@ extension URL { return false } - func stripUnsupportedCredentials() -> String { + func strippingUnsupportedCredentials() -> String { if self.absoluteString.firstIndex(of: "@") != nil { let authPattern = "([^:]+):\\/\\/[^\\/]*@" let strippedURL = self.absoluteString.replacingOccurrences(of: authPattern, with: "$1://", options: .regularExpression) @@ -491,10 +570,15 @@ extension URL { return self.absoluteString } - public func isChild(of url: URL) -> Bool { - var components = URLComponents(string: url.absoluteString) - components?.query = nil - - return self.absoluteString.hasPrefix(components?.url?.absoluteString ?? url.absoluteString) + public func isChild(of parentURL: URL) -> Bool { + if scheme == parentURL.scheme, + port == parentURL.port, + let parentURLHost = parentURL.host, + self.isPart(ofDomain: parentURLHost), + pathComponents.starts(with: parentURL.pathComponents) { + return true + } else { + return false + } } } diff --git a/DuckDuckGo/Common/Extensions/WKWebView+Private.h b/DuckDuckGo/Common/Extensions/WKWebView+Private.h index b5e8c44d99..daa465149f 100644 --- a/DuckDuckGo/Common/Extensions/WKWebView+Private.h +++ b/DuckDuckGo/Common/Extensions/WKWebView+Private.h @@ -63,8 +63,6 @@ typedef NS_OPTIONS(NSUInteger, _WKFindOptions) { - (void)_stopMediaCapture API_AVAILABLE(macos(10.15.4), ios(13.4)); - (void)_stopAllMediaPlayback; -- (_WKMediaMutedState)_mediaMutedState API_AVAILABLE(macos(11.0), ios(14.0));; -- (void)_setPageMuted:(_WKMediaMutedState)mutedState API_AVAILABLE(macos(10.13), ios(11.0)); @end diff --git a/DuckDuckGo/Common/Extensions/WKWebViewExtension.swift b/DuckDuckGo/Common/Extensions/WKWebViewExtension.swift index fcd19de900..5f7a7b316c 100644 --- a/DuckDuckGo/Common/Extensions/WKWebViewExtension.swift +++ b/DuckDuckGo/Common/Extensions/WKWebViewExtension.swift @@ -32,7 +32,17 @@ extension WKWebView { enum AudioState { case muted case unmuted - case notSupported + + init(wkMediaMutedState: _WKMediaMutedState) { + self = wkMediaMutedState.contains(.audioMuted) ? .muted : .unmuted + } + + mutating func toggle() { + self = switch self { + case .muted: .unmuted + case .unmuted: .muted + } + } } enum CaptureState { @@ -114,96 +124,84 @@ extension WKWebView { return .active } -#if !APPSTORE - private func setMediaCaptureMuted(_ muted: Bool) { - guard self.responds(to: #selector(WKWebView._setPageMuted(_:))) else { - assertionFailure("WKWebView does not respond to selector _stopMediaCapture") - return + @objc dynamic var mediaMutedState: _WKMediaMutedState { + get { + // swizzle the method to call `_mediaMutedState` without performSelector: usage + guard Self.swizzleMediaMutedStateOnce else { return [] } + return self.mediaMutedState // call the original } - let mutedState: _WKMediaMutedState = { - guard self.responds(to: #selector(WKWebView._mediaMutedState)) else { return [] } - return self._mediaMutedState() - }() - var newState = mutedState - if muted { - newState.insert(.captureDevicesMuted) - } else { - newState.remove(.captureDevicesMuted) + set { + // swizzle the method to call `_setPageMuted:` without performSelector: usage (as there‘s a non-object argument to pass) + guard Self.swizzleSetPageMutedOnce else { return } + self.mediaMutedState = newValue // call the original } - guard newState != mutedState else { return } - self._setPageMuted(newState) } -#endif - func muteOrUnmute() { -#if !APPSTORE - guard self.responds(to: #selector(WKWebView._setPageMuted(_:))) else { - assertionFailure("WKWebView does not respond to selector _stopMediaCapture") - return + static private let swizzleMediaMutedStateOnce: Bool = { + guard let originalMethod = class_getInstanceMethod(WKWebView.self, Selector.mediaMutedState), + let swizzledMethod = class_getInstanceMethod(WKWebView.self, #selector(getter: mediaMutedState)) else { + assertionFailure("WKWebView does not respond to selector _mediaMutedState") + return false } - let mutedState: _WKMediaMutedState = { - guard self.responds(to: #selector(WKWebView._mediaMutedState)) else { return [] } - return self._mediaMutedState() - }() - var newState = mutedState - - if newState == .audioMuted { - newState.remove(.audioMuted) - } else { - newState.insert(.audioMuted) + method_exchangeImplementations(originalMethod, swizzledMethod) + return true + }() + + static private let swizzleSetPageMutedOnce: Bool = { + guard let originalMethod = class_getInstanceMethod(WKWebView.self, Selector.setPageMuted), + let swizzledMethod = class_getInstanceMethod(WKWebView.self, #selector(setter: mediaMutedState)) else { + assertionFailure("WKWebView does not respond to selector _setPageMuted:") + return false } - guard newState != mutedState else { return } - self._setPageMuted(newState) -#endif - } + method_exchangeImplementations(originalMethod, swizzledMethod) + return true + }() /// Returns the audio state of the WKWebView. /// /// - Returns: `muted` if the web view is muted /// `unmuted` if the web view is unmuted - /// `notSupported` if the web view does not support fetching the current audio state - func audioState() -> AudioState { -#if APPSTORE - return .notSupported -#else - guard self.responds(to: #selector(WKWebView._mediaMutedState)) else { - assertionFailure("WKWebView does not respond to selector _mediaMutedState") - return .notSupported + var audioState: AudioState { + get { + AudioState(wkMediaMutedState: mediaMutedState) + } + set { + switch newValue { + case .muted: + self.mediaMutedState.insert(.audioMuted) + case .unmuted: + self.mediaMutedState.remove(.audioMuted) + } } - - let mutedState = self._mediaMutedState() - - return mutedState.contains(.audioMuted) ? .muted : .unmuted -#endif } func stopMediaCapture() { - guard #available(macOS 12.0, *) else { #if !APPSTORE + guard #available(macOS 12.0, *) else { guard self.responds(to: #selector(_stopMediaCapture)) else { assertionFailure("WKWebView does not respond to _stopMediaCapture") return } self._stopMediaCapture() -#endif return } +#endif setCameraCaptureState(.none) setMicrophoneCaptureState(.none) } func stopAllMediaPlayback() { - guard #available(macOS 12.0, *) else { #if !APPSTORE + guard #available(macOS 12.0, *) else { guard self.responds(to: #selector(_stopAllMediaPlayback)) else { assertionFailure("WKWebView does not respond to _stopAllMediaPlayback") return } self._stopAllMediaPlayback() return -#endif } +#endif pauseAllMediaPlayback() } @@ -212,20 +210,26 @@ extension WKWebView { switch permission { case .camera: guard #available(macOS 12.0, *) else { -#if !APPSTORE - self.setMediaCaptureMuted(muted) -#endif + if muted { + self.mediaMutedState.insert(.captureDevicesMuted) + } else { + self.mediaMutedState.remove(.captureDevicesMuted) + } return } + self.setCameraCaptureState(muted ? .muted : .active, completionHandler: {}) case .microphone: guard #available(macOS 12.0, *) else { -#if !APPSTORE - self.setMediaCaptureMuted(muted) -#endif + if muted { + self.mediaMutedState.insert(.captureDevicesMuted) + } else { + self.mediaMutedState.remove(.captureDevicesMuted) + } return } + self.setMicrophoneCaptureState(muted ? .muted : .active, completionHandler: {}) case .geolocation: self.configuration.processPool.geolocationProvider?.isPaused = muted @@ -360,6 +364,8 @@ extension WKWebView { static let fullScreenPlaceholderView = NSSelectorFromString("_fullScreenPlaceholderView") static let printOperationWithPrintInfoForFrame = NSSelectorFromString("_printOperationWithPrintInfo:forFrame:") static let loadAlternateHTMLString = NSSelectorFromString("_loadAlternateHTMLString:baseURL:forUnreachableURL:") + static let mediaMutedState = NSSelectorFromString("_mediaMutedState") + static let setPageMuted = NSSelectorFromString("_setPageMuted:") } } diff --git a/DuckDuckGo/Common/FileSystem/FileStore.swift b/DuckDuckGo/Common/FileSystem/FileStore.swift index 99b03e5a01..22dc52c7d1 100644 --- a/DuckDuckGo/Common/FileSystem/FileStore.swift +++ b/DuckDuckGo/Common/FileSystem/FileStore.swift @@ -18,6 +18,7 @@ import Foundation import CryptoKit +import PixelKit protocol FileStore { func persist(_ data: Data, url: URL) -> Bool @@ -57,7 +58,7 @@ final class EncryptedFileStore: FileStore { return true } catch { - Pixel.fire(.debug(event: .fileStoreWriteFailed, error: error), + PixelKit.fire(DebugEvent(GeneralPixel.fileStoreWriteFailed, error: error), withAdditionalParameters: ["config": url.lastPathComponent]) return false } diff --git a/DuckDuckGo/Common/Localizables/UserText+DBP.swift b/DuckDuckGo/Common/Localizables/UserText+DBP.swift new file mode 100644 index 0000000000..65590075e0 --- /dev/null +++ b/DuckDuckGo/Common/Localizables/UserText+DBP.swift @@ -0,0 +1,86 @@ +// +// UserText+DBP.swift +// +// 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 + +#if DBP +// MARK: - Data Broker Protection Waitlist +extension UserText { + // "data-broker-protection.privacy-policy.title" - Privacy Policy title for Personal Information Removal + static let dataBrokerProtectionPrivacyPolicyTitle = "Privacy Policy" + // "data-broker-protection.waitlist.notification.title" - Title for Personal Information Removal waitlist notification + static let dataBrokerProtectionWaitlistNotificationTitle = "Personal Information Removal beta is ready!" + // "data-broker-protection.waitlist.notification.text" - Title for Personal Information Removal waitlist notification + static let dataBrokerProtectionWaitlistNotificationText = "Open your invite" + // "data-broker-protection.waitlist.join.title" - Title for Personal Information Removal join waitlist screen + static let dataBrokerProtectionWaitlistJoinTitle = "Personal Information Removal Beta" + // "data-broker-protection.waitlist.join.subtitle.1" - First subtitle for Personal Information Removal join waitlist screen + static let dataBrokerProtectionWaitlistJoinSubtitle1 = "Automatically scan and remove your data from 17+ sites that sell personal information with DuckDuckGo’s Personal Information Removal." + // "data-broker-protection.waitlist.joined.title" - Title for Personal Information Removal joined waitlist screen + static let dataBrokerProtectionWaitlistJoinedTitle = "You’re on the list!" + // "data-broker-protection.waitlist.joined.with-notifications.subtitle.1" - Subtitle 1 for Personal Information Removal joined waitlist screen when notifications are enabled + static let dataBrokerProtectionWaitlistJoinedWithNotificationsSubtitle1 = "New invites are sent every few days, on a first come, first served basis." + // "data-broker-protection.waitlist.joined.with-notifications.subtitle.2" - Subtitle 2 for Personal Information Removal joined waitlist screen when notifications are enabled + static let dataBrokerProtectionWaitlistJoinedWithNotificationsSubtitle2 = "We’ll notify you when your invite is ready." + // "data-broker-protection.waitlist.enable-notifications" - Enable notifications prompt for Personal Information Removal joined waitlist screen + static let dataBrokerProtectionWaitlistEnableNotifications = "Want to get a notification when your Personal Information Removal invite is ready?" + // "data-broker-protection.waitlist.invited.title" - Title for Personal Information Removal invited screen + static let dataBrokerProtectionWaitlistInvitedTitle = "You’re invited to try\nPersonal Information Removal beta!" + // "data-broker-protection.waitlist.invited.subtitle" - Subtitle for Personal Information Removal invited screen + static let dataBrokerProtectionWaitlistInvitedSubtitle = "Automatically find and remove your personal information – such as your name and address – from 17+ sites that store and sell it, reducing the risk of identity theft and spam." + // "data-broker-protection.waitlist.enable.title" - Title for Personal Information Removal enable screen + static let dataBrokerProtectionWaitlistEnableTitle = "Let’s get started" + // "data-broker-protection.waitlist.enable.subtitle" - Subtitle for Personal Information Removal enable screen + static let dataBrokerProtectionWaitlistEnableSubtitle = "We’ll need your name, address and the year you were born in order to find your personal information on data broker sites\n\nThis info is stored securely on your device, and is never sent to DuckDuckGo." + // "data-broker-protection.waitlist.availability-disclaimer" - Availability disclaimer for Personal Information Removal join waitlist screen + static let dataBrokerProtectionWaitlistAvailabilityDisclaimer = "Personal Information Removal is free during the beta.\nJoin the waitlist and we'll notify you when ready." + // "data-broker-protection.waitlist.button.close" - Close button for Personal Information Removal join waitlist screen + static let dataBrokerProtectionWaitlistButtonClose = "Close" + // "data-broker-protection.waitlist.button.done" - Close button for Personal Information Removal joined waitlist screen + static let dataBrokerProtectionWaitlistButtonDone = "Done" + // "data-broker-protection.waitlist.button.dismiss" - Dismiss button for Personal Information Removal join waitlist screen + static let dataBrokerProtectionWaitlistButtonDismiss = "Dismiss" + // "data-broker-protection.waitlist.button.cancel" - Cancel button for Personal Information Removal join waitlist screen + static let dataBrokerProtectionWaitlistButtonCancel = "Cancel" + // "data-broker-protection.waitlist.button.no-thanks" - No Thanks button for Personal Information Removal joined waitlist screen + static let dataBrokerProtectionWaitlistButtonNoThanks = "No Thanks" + // "data-broker-protection.waitlist.button.get-started" - Get Started button for Personal Information Removal joined waitlist screen + static let dataBrokerProtectionWaitlistButtonGetStarted = "Get Started" + // "data-broker-protection.waitlist.button.got-it" - Get started button for Personal Information Removal joined waitlist screen + static let dataBrokerProtectionWaitlistButtonGotIt = "Get started" + // "data-broker-protection.waitlist.button.enable-notifications" - Enable Notifications button for Personal Information Removal joined waitlist screen + static let dataBrokerProtectionWaitlistButtonEnableNotifications = "Enable Notifications" + // "data-broker-protection.waitlist.button.join-waitlist" - Join Waitlist button for Personal Information Removal join waitlist screen + static let dataBrokerProtectionWaitlistButtonJoinWaitlist = "Join the Waitlist" + // "data-broker-protection.waitlist.button.agree-and-continue" - Agree and Continue button for Personal Information Removal join waitlist screen + static let dataBrokerProtectionWaitlistButtonAgreeAndContinue = "Agree and Continue" +} + +// MARK: - DBP Error pages +extension UserText { + static let dbpErrorPageBadPathTitle = NotLocalizedString("dbp.errorpage.bad.path.title", value: "Move DuckDuckGo App to Applications", comment: "Title for Personal Information Removal bad path error screen") + static let dbpErrorPageBadPathMessage = NotLocalizedString("dbp.errorpage.bad.path.message", value: "To use Personal Information Removal, the DuckDuckGo app needs to be in the Applications folder on your Mac. You can move the app yourself and restart the browser, or we can do it for you.", comment: "Message for Personal Information Removal bad path error screen") + static let dbpErrorPageBadPathCTA = NotLocalizedString("dbp.errorpage.bad.path.cta", value: "Move App for Me...", comment: "Call to action for moving the app to the Applications folder") + + static let dbpErrorPageNoPermissionTitle = NotLocalizedString("dbp.errorpage.no.permission.title", value: "Change System Setting", comment: "Title for error screen when there is no permission") + static let dbpErrorPageNoPermissionMessage = NotLocalizedString("dbp.errorpage.no.permission.message", value: "Open System Settings and allow DuckDuckGo Personal Information Removal to run in the background.", comment: "Message for error screen when there is no permission") + static let dbpErrorPageNoPermissionCTA = NotLocalizedString("dbp.errorpage.no.permission.cta", value: "Open System Settings...", comment: "Call to action for opening system settings") +} + +#endif diff --git a/DuckDuckGo/Common/Localizables/UserText+NetworkProtection.swift b/DuckDuckGo/Common/Localizables/UserText+NetworkProtection.swift index 69d36bb228..d908735e23 100644 --- a/DuckDuckGo/Common/Localizables/UserText+NetworkProtection.swift +++ b/DuckDuckGo/Common/Localizables/UserText+NetworkProtection.swift @@ -42,8 +42,8 @@ extension UserText { static let networkProtectionInviteSuccessMessage = "DuckDuckGo's VPN secures all of your device's Internet traffic anytime, anywhere." // MARK: - Navigation Bar Status View - // "network.protection.navbar.status.view.share.feedback" - Menu item for 'Send VPN Feedback' in the VPN status view that's shown in the navigation bar - static let networkProtectionNavBarStatusViewShareFeedback = "Send VPN Feedback…" + // "network.protection.navbar.status.view.share.feedback" - Menu item for 'Share VPN Feedback' in the VPN status view that's shown in the navigation bar + static let networkProtectionNavBarStatusViewShareFeedback = "Share VPN Feedback…" // "network.protection.status.menu.vpn.settings" - The status menu 'VPN Settings' menu item static let networkProtectionNavBarStatusMenuVPNSettings = "VPN Settings…" // "network.protection.status.menu.faq" - The status menu 'FAQ' menu item @@ -67,163 +67,11 @@ extension UserText { // "network.protection.system.extension.unknown.activation.error" - Message shown to users when they try to enable NetP and there is an unexpected activation error. static let networkProtectionUnknownActivationError = "There as an unexpected error. Please try again." // "network.protection.system.extension.please.reboot" - Message shown to users when they try to enable NetP and they need to reboot the computer to complete the installation - static let networkProtectionPleaseReboot = "Please reboot to activate the VPN" + static let networkProtectionPleaseReboot = "VPN update available. Restart your Mac to reconnect." } -// MARK: - VPN Waitlist - -extension UserText { - - // "network-protection.waitlist.notification.title" - Title for VPN waitlist notification - static let networkProtectionWaitlistNotificationTitle = "DuckDuckGo VPN beta is ready!" - // "network-protection.waitlist.notification.text" - Title for VPN waitlist notification - static let networkProtectionWaitlistNotificationText = "Open your invite" - - // "network-protection.waitlist.join.title" - Title for VPN join waitlist screen - static let networkProtectionWaitlistJoinTitle = "DuckDuckGo VPN Beta" - // "network-protection.waitlist.join.subtitle.1" - First subtitle for VPN join waitlist screen - static let networkProtectionWaitlistJoinSubtitle1 = "Secure your connection anytime, anywhere with DuckDuckGo VPN." - // "network-protection.waitlist.join.subtitle.2" - Second subtitle for VPN join waitlist screen - static let networkProtectionWaitlistJoinSubtitle2 = "Join the waitlist, and we’ll notify you when it’s your turn." - - // "network-protection.waitlist.joined.title" - Title for VPN joined waitlist screen - static let networkProtectionWaitlistJoinedTitle = "You’re on the list!" - // "network-protection.waitlist.joined.with-notifications.subtitle.1" - Subtitle 1 for VPN joined waitlist screen when notifications are enabled - static let networkProtectionWaitlistJoinedWithNotificationsSubtitle1 = "New invites are sent every few days, on a first come, first served basis." - // "network-protection.waitlist.joined.with-notifications.subtitle.2" - Subtitle 2 for VPN joined waitlist screen when notifications are enabled - static let networkProtectionWaitlistJoinedWithNotificationsSubtitle2 = "We’ll notify you when your invite is ready." - // "network-protection.waitlist.enable-notifications" - Enable notifications prompt for VPN joined waitlist screen - static let networkProtectionWaitlistEnableNotifications = "Want to get a notification when your VPN invite is ready?" - - // "network-protection.waitlist.invited.title" - Title for VPN invited screen - static let networkProtectionWaitlistInvitedTitle = "You’re invited to try\nDuckDuckGo VPN beta!" - // "network-protection.waitlist.invited.subtitle" - Subtitle for VPN invited screen - static let networkProtectionWaitlistInvitedSubtitle = "Get an extra layer of protection online with the VPN built for speed and simplicity. Encrypt your internet connection across your entire device and hide your location and IP address from sites you visit." - - // "network-protection.waitlist.invited.section-1.title" - Title for section 1 of the VPN invited screen - static let networkProtectionWaitlistInvitedSection1Title = "Full-device coverage" - // "network-protection.waitlist.invited.section-1.subtitle" - Subtitle for section 1 of the VPN invited screen - static let networkProtectionWaitlistInvitedSection1Subtitle = "Encrypt online traffic across your browsers and apps." - - // "network-protection.waitlist.invited.section-2.title" - Title for section 2 of the VPN invited screen - static let networkProtectionWaitlistInvitedSection2Title = "Fast, reliable, and easy to use" - // "network-protection.waitlist.invited.section-2.subtitle" - Subtitle for section 2 of the VPN invited screen - static let networkProtectionWaitlistInvitedSection2Subtitle = "No need for a separate app. Connect in one click and see your connection status at a glance." - - // "network-protection.waitlist.invited.section-3.title" - Title for section 3 of the VPN invited screen - static let networkProtectionWaitlistInvitedSection3Title = "Strict no-logging policy" - // "network-protection.waitlist.invited.section-3.subtitle" - Subtitle for section 3 of the VPN invited screen - static let networkProtectionWaitlistInvitedSection3Subtitle = "We do not log or save any data that can connect you to your online activity." - - // "network-protection.waitlist.enable.title" - Title for VPN enable screen - static let networkProtectionWaitlistEnableTitle = "Ready to enable DuckDuckGo VPN?" - // "network-protection.waitlist.enable.subtitle" - Subtitle for VPN enable screen - static let networkProtectionWaitlistEnableSubtitle = "Look for the globe icon in the browser toolbar or in the Mac menu bar.\n\nYou'll be asked to Allow a VPN connection once when setting up DuckDuckGo VPN the first time." - - // "network-protection.waitlist.availability-disclaimer" - Availability disclaimer for VPN join waitlist screen - static let networkProtectionWaitlistAvailabilityDisclaimer = "DuckDuckGo VPN is free to use during the beta." - - // "network-protection.waitlist.button.close" - Close button for VPN join waitlist screen - static let networkProtectionWaitlistButtonClose = "Close" - // "network-protection.waitlist.button.done" - Close button for VPN joined waitlist screen - static let networkProtectionWaitlistButtonDone = "Done" - // "network-protection.waitlist.button.dismiss" - Dismiss button for VPN join waitlist screen - static let networkProtectionWaitlistButtonDismiss = "Dismiss" - // "network-protection.waitlist.button.cancel" - Cancel button for VPN join waitlist screen - static let networkProtectionWaitlistButtonCancel = "Cancel" - // "network-protection.waitlist.button.no-thanks" - No Thanks button for VPN joined waitlist screen - static let networkProtectionWaitlistButtonNoThanks = "No Thanks" - // "network-protection.waitlist.button.get-started" - Get Started button for VPN joined waitlist screen - static let networkProtectionWaitlistButtonGetStarted = "Get Started" - // "network-protection.waitlist.button.got-it" - Got It button for VPN joined waitlist screen - static let networkProtectionWaitlistButtonGotIt = "Got It" - // "network-protection.waitlist.button.enable-notifications" - Enable Notifications button for VPN joined waitlist screen - static let networkProtectionWaitlistButtonEnableNotifications = "Enable Notifications" - // "network-protection.waitlist.button.join-waitlist" - Join Waitlist button for VPN join waitlist screen - static let networkProtectionWaitlistButtonJoinWaitlist = "Join the Waitlist" - // "network-protection.waitlist.button.agree-and-continue" - Agree and Continue button for VPN join waitlist screen - static let networkProtectionWaitlistButtonAgreeAndContinue = "Agree and Continue" -} - -// MARK: - VPN Terms of Service - extension UserText { - // "network-protection.privacy-policy.title" - Privacy Policy title for VPN - static let networkProtectionPrivacyPolicyTitle = "Privacy Policy" - - // "network-protection.privacy-policy.section.1.title" - Privacy Policy title for VPN - static let networkProtectionPrivacyPolicySection1Title = "We don’t ask for any personal information from you in order to use this beta service." - // "network-protection.privacy-policy.section.1.list" - Privacy Policy list for VPN (Markdown version) - static let networkProtectionPrivacyPolicySection1ListMarkdown = "This Privacy Policy is for our limited waitlist beta VPN product.\n\nOur main [Privacy Policy](https://duckduckgo.com/privacy) also applies here." - // "network-protection.privacy-policy.section.1.list" - Privacy Policy list for VPN (Non-Markdown version) - static let networkProtectionPrivacyPolicySection1ListNonMarkdown = "This Privacy Policy is for our limited waitlist beta VPN product.\n\nOur main Privacy Policy also applies here." - - // "network-protection.privacy-policy.section.2.title" - Privacy Policy title for VPN - static let networkProtectionPrivacyPolicySection2Title = "We don’t keep any logs of your online activity." - // "network-protection.privacy-policy.section.2.list" - Privacy Policy list for VPN - static let networkProtectionPrivacyPolicySection2List = "That means we have no way to tie what you do online to you as an individual and we don’t have any record of things like:\n • Website visits\n • DNS requests\n • Connections made\n • IP addresses used\n • Session lengths" - - // "network-protection.privacy-policy.section.3.title" - Privacy Policy title for VPN - static let networkProtectionPrivacyPolicySection3Title = "We only keep anonymous performance metrics that we cannot connect to your online activity." - // "network-protection.privacy-policy.section.3.list" - Privacy Policy list for VPN - static let networkProtectionPrivacyPolicySection3List = "Our servers store generic usage (for example, CPU load) and diagnostic data (for example, errors), but none of that data is connected to any individual’s activity.\n\nWe use this non-identifying information to monitor and ensure the performance and quality of the service, for example to make sure servers aren’t overloaded." - - // "network-protection.privacy-policy.section.4.title" - Privacy Policy title for VPN - static let networkProtectionPrivacyPolicySection4Title = "We use dedicated servers for all VPN traffic." - // "network-protection.privacy-policy.section.4.list" - Privacy Policy list for VPN - static let networkProtectionPrivacyPolicySection4List = "Dedicated servers means they are not shared with anyone else.\n\nWe rent our servers from providers we carefully selected because they meet our privacy requirements.\n\nWe have strict access controls in place so that only limited DuckDuckGo team members have access to our servers." - - // "network-protection.privacy-policy.section.5.title" - Privacy Policy title for VPN - static let networkProtectionPrivacyPolicySection5Title = "We protect and limit use of your data when you communicate directly with DuckDuckGo." - // "network-protection.privacy-policy.section.5.list" - Privacy Policy list for VPN - static let networkProtectionPrivacyPolicySection5List = "If you reach out to us for support by submitting a bug report or through email and agree to be contacted to troubleshoot the issue, we’ll contact you using the information you provide.\n\nIf you participate in a voluntary product survey or questionnaire and agree to provide further feedback, we may contact you using the information you provide.\n\nWe will permanently delete all personal information you provided to us (email, contact information), within 30 days after closing a support case or, in the case of follow up feedback, within 60 days after ending this beta service." - - // "network-protection.terms-of-service.title" - Terms of Service title for VPN - static let networkProtectionTermsOfServiceTitle = "Terms of Service" - - // "network-protection.terms-of-service.section.1.title" - Terms of Service title for VPN - static let networkProtectionTermsOfServiceSection1Title = "The service is for limited and personal use only." - // "network-protection.terms-of-service.section.1.list" - Terms of Service list for VPN - static let networkProtectionTermsOfServiceSection1List = "This service is provided for your personal use only.\n\nYou are responsible for all activity in the service that occurs on or through your device.\n\nThis service may only be used through the DuckDuckGo app on the device on which you are given access. If you delete the DuckDuckGo app, you will lose access to the service.\n\nYou may not use this service through a third-party client." - - // "network-protection.terms-of-service.section.2.title" - Terms of Service title for VPN - static let networkProtectionTermsOfServiceSection2Title = "You agree to comply with all applicable laws, rules, and regulations." - // "network-protection.terms-of-service.section.2.list" - Terms of Service list for VPN (Markdown version) - static let networkProtectionTermsOfServiceSection2ListMarkdown = "You agree that you will not use the service for any unlawful, illicit, criminal, or fraudulent purpose, or in any manner that could give rise to civil or criminal liability under applicable law.\n\nYou agree to comply with our [DuckDuckGo Terms of Service](https://duckduckgo.com/terms), which are incorporated by reference." - // "network-protection.terms-of-service.section.2.list" - Terms of Service list for VPN (Non-Markdown version) - static let networkProtectionTermsOfServiceSection2ListNonMarkdown = "You agree that you will not use the service for any unlawful, illicit, criminal, or fraudulent purpose, or in any manner that could give rise to civil or criminal liability under applicable law.\n\nYou agree to comply with our DuckDuckGo Terms of Service, which are incorporated by reference." - - // "network-protection.terms-of-service.section.3.title" - Terms of Service title for VPN - static let networkProtectionTermsOfServiceSection3Title = "You must be eligible to use this service." - // "network-protection.terms-of-service.section.3.list" - Terms of Service list for VPN - static let networkProtectionTermsOfServiceSection3List = "Access to this beta is randomly awarded. You are responsible for ensuring eligibility.\n\nYou must be at least 18 years old and live in a location where use of a VPN is legal in order to be eligible to use this service." - - // "network-protection.terms-of-service.section.4.title" - Terms of Service title for VPN - static let networkProtectionTermsOfServiceSection4Title = "We provide this beta service as-is and without warranty." - // "network-protection.terms-of-service.section.4.list" - Terms of Service list for VPN - static let networkProtectionTermsOfServiceSection4List = "This service is provided as-is and without warranties or guarantees of any kind.\n\nTo the extent possible under applicable law, DuckDuckGo will not be liable for any damage or loss arising from your use of the service. In any event, the total aggregate liability of DuckDuckGo shall not exceed $25 or the equivalent in your local currency.\n\nWe may in the future transfer responsibility for the service to a subsidiary of DuckDuckGo. If that happens, you agree that references to “DuckDuckGo” will refer to our subsidiary, which will then become responsible for providing the service and for any liabilities relating to it." - - // "network-protection.terms-of-service.section.5.title" - Terms of Service title for VPN - static let networkProtectionTermsOfServiceSection5Title = "We may terminate access at any time." - // "network-protection.terms-of-service.section.5.list" - Terms of Service list for VPN - static let networkProtectionTermsOfServiceSection5List = "We reserve the right to revoke access to the service at any time in our sole discretion.\n\nWe may also terminate access for violation of these terms, including for repeated infringement of the intellectual property rights of others." - - // "network-protection.terms-of-service.section.6.title" - Terms of Service title for VPN - static let networkProtectionTermsOfServiceSection6Title = "The service is free during the beta period." - // "network-protection.terms-of-service.section.6.list" - Terms of Service list for VPN - static let networkProtectionTermsOfServiceSection6List = "Access to this service is currently free of charge, but that is limited to this beta period.\n\nYou understand and agree that this service is provided on a temporary, testing basis only." - - // "network-protection.terms-of-service.section.7.title" - Terms of Service title for VPN - static let networkProtectionTermsOfServiceSection7Title = "We are continually updating the service." - // "network-protection.terms-of-service.section.7.list" - Terms of Service list for VPN - static let networkProtectionTermsOfServiceSection7List = "The service is in beta, and we are regularly changing it.\n\nService coverage, speed, server locations, and quality may vary without warning." - - // "network-protection.terms-of-service.section.8.title" - Terms of Service title for VPN - static let networkProtectionTermsOfServiceSection8Title = "We need your feedback." - // "network-protection.terms-of-service.section.8.list" - Terms of Service list for VPN - static let networkProtectionTermsOfServiceSection8List = "You may be asked during the beta period to provide feedback about your experience. Doing so is optional and your feedback may be used to improve the service.\n\nIf you have enabled notifications for the DuckDuckGo app, we may use notifications to ask about your experience. You can disable notifications if you do not want to receive them." - // MARK: - Feedback Form // "vpn.feedback-form.title" - Title for each screen of the VPN feedback form static let vpnFeedbackFormTitle = "Help Improve the DuckDuckGo VPN" @@ -299,7 +147,7 @@ extension UserText { // "vpn.location.description.nearest" - Nearest city setting description static let vpnLocationNearest = "Nearest" // "vpn.location.description.nearest.available" - Nearest available location setting description - static let vpnLocationNearestAvailable = "Nearest available" + static let vpnLocationNearestAvailable = "Nearest Location" // "vpn.location.nearest.available.title" - Subtitle underneath the nearest available vpn location preference text. static let vpnLocationNearestAvailableSubtitle = "Automatically connect to the nearest server we can find." @@ -330,61 +178,16 @@ extension UserText { static let uninstallVPNAlertTitle = "Are you sure you want to uninstall the VPN?" // "vpn.uninstall.alert.informative.text" - Informative text for the alert that comes up when the user decides to uninstall our VPN static let uninstallVPNInformativeText = "Uninstalling the DuckDuckGo VPN will disconnect the VPN and remove it from your device." -} -#if DBP -// MARK: - Data Broker Protection Waitlist -extension UserText { - // "data-broker-protection.privacy-policy.title" - Privacy Policy title for Personal Information Removal - static let dataBrokerProtectionPrivacyPolicyTitle = "Privacy Policy" - // "data-broker-protection.waitlist.notification.title" - Title for Personal Information Removal waitlist notification - static let dataBrokerProtectionWaitlistNotificationTitle = "Personal Information Removal beta is ready!" - // "data-broker-protection.waitlist.notification.text" - Title for Personal Information Removal waitlist notification - static let dataBrokerProtectionWaitlistNotificationText = "Open your invite" - // "data-broker-protection.waitlist.join.title" - Title for Personal Information Removal join waitlist screen - static let dataBrokerProtectionWaitlistJoinTitle = "Personal Information Removal Beta" - // "data-broker-protection.waitlist.join.subtitle.1" - First subtitle for Personal Information Removal join waitlist screen - static let dataBrokerProtectionWaitlistJoinSubtitle1 = "Automatically scan and remove your data from 17+ sites that sell personal information with DuckDuckGo’s Personal Information Removal." - // "data-broker-protection.waitlist.joined.title" - Title for Personal Information Removal joined waitlist screen - static let dataBrokerProtectionWaitlistJoinedTitle = "You’re on the list!" - // "data-broker-protection.waitlist.joined.with-notifications.subtitle.1" - Subtitle 1 for Personal Information Removal joined waitlist screen when notifications are enabled - static let dataBrokerProtectionWaitlistJoinedWithNotificationsSubtitle1 = "New invites are sent every few days, on a first come, first served basis." - // "data-broker-protection.waitlist.joined.with-notifications.subtitle.2" - Subtitle 2 for Personal Information Removal joined waitlist screen when notifications are enabled - static let dataBrokerProtectionWaitlistJoinedWithNotificationsSubtitle2 = "We’ll notify you when your invite is ready." - // "data-broker-protection.waitlist.enable-notifications" - Enable notifications prompt for Personal Information Removal joined waitlist screen - static let dataBrokerProtectionWaitlistEnableNotifications = "Want to get a notification when your Personal Information Removal invite is ready?" - // "data-broker-protection.waitlist.invited.title" - Title for Personal Information Removal invited screen - static let dataBrokerProtectionWaitlistInvitedTitle = "You’re invited to try\nPersonal Information Removal beta!" - // "data-broker-protection.waitlist.invited.subtitle" - Subtitle for Personal Information Removal invited screen - static let dataBrokerProtectionWaitlistInvitedSubtitle = "Automatically find and remove your personal information – such as your name and address – from 17+ sites that store and sell it, reducing the risk of identity theft and spam." - // "data-broker-protection.waitlist.enable.title" - Title for Personal Information Removal enable screen - static let dataBrokerProtectionWaitlistEnableTitle = "Let’s get started" - // "data-broker-protection.waitlist.enable.subtitle" - Subtitle for Personal Information Removal enable screen - static let dataBrokerProtectionWaitlistEnableSubtitle = "We’ll need your name, address and the year you were born in order to find your personal information on data broker sites\n\nThis info is stored securely on your device, and is never sent to DuckDuckGo." - // "data-broker-protection.waitlist.availability-disclaimer" - Availability disclaimer for Personal Information Removal join waitlist screen - static let dataBrokerProtectionWaitlistAvailabilityDisclaimer = "Personal Information Removal is free during the beta.\nJoin the waitlist and we'll notify you when ready." - // "data-broker-protection.waitlist.button.close" - Close button for Personal Information Removal join waitlist screen - static let dataBrokerProtectionWaitlistButtonClose = "Close" - // "data-broker-protection.waitlist.button.done" - Close button for Personal Information Removal joined waitlist screen - static let dataBrokerProtectionWaitlistButtonDone = "Done" - // "data-broker-protection.waitlist.button.dismiss" - Dismiss button for Personal Information Removal join waitlist screen - static let dataBrokerProtectionWaitlistButtonDismiss = "Dismiss" - // "data-broker-protection.waitlist.button.cancel" - Cancel button for Personal Information Removal join waitlist screen - static let dataBrokerProtectionWaitlistButtonCancel = "Cancel" - // "data-broker-protection.waitlist.button.no-thanks" - No Thanks button for Personal Information Removal joined waitlist screen - static let dataBrokerProtectionWaitlistButtonNoThanks = "No Thanks" - // "data-broker-protection.waitlist.button.get-started" - Get Started button for Personal Information Removal joined waitlist screen - static let dataBrokerProtectionWaitlistButtonGetStarted = "Get Started" - // "data-broker-protection.waitlist.button.got-it" - Get started button for Personal Information Removal joined waitlist screen - static let dataBrokerProtectionWaitlistButtonGotIt = "Get started" - // "data-broker-protection.waitlist.button.enable-notifications" - Enable Notifications button for Personal Information Removal joined waitlist screen - static let dataBrokerProtectionWaitlistButtonEnableNotifications = "Enable Notifications" - // "data-broker-protection.waitlist.button.join-waitlist" - Join Waitlist button for Personal Information Removal join waitlist screen - static let dataBrokerProtectionWaitlistButtonJoinWaitlist = "Join the Waitlist" - // "data-broker-protection.waitlist.button.agree-and-continue" - Agree and Continue button for Personal Information Removal join waitlist screen - static let dataBrokerProtectionWaitlistButtonAgreeAndContinue = "Agree and Continue" + // MARK: - VPN Screen + // "network.protection.vpn.location.nearest" - Description of the location type in the VPN status view + static let netPVPNLocationNearest = "(Nearest)" + + // "network.protection.vpn.location.subtitle.formatted.city.and.country" - Subtitle for the preferred location item that formats a city and country. E.g Chicago, United States + static func netPVPNSettingsLocationSubtitleFormattedCityAndCountry(city: String, country: String) -> String { + return "\(city), \(country)" + } } -#endif // MARK: - Thank You Modals diff --git a/DuckDuckGo/Common/Localizables/UserText.swift b/DuckDuckGo/Common/Localizables/UserText.swift index 5f17e7d9b2..b6c361c836 100644 --- a/DuckDuckGo/Common/Localizables/UserText.swift +++ b/DuckDuckGo/Common/Localizables/UserText.swift @@ -53,6 +53,8 @@ struct UserText { static let pasteAndGo = NSLocalizedString("paste.and.go", value: "Paste & Go", comment: "Paste & Go button") static let pasteAndSearch = NSLocalizedString("paste.and.search", value: "Paste & Search", comment: "Paste & Search button") static let clear = NSLocalizedString("clear", value: "Clear", comment: "Clear button") + static let clearAndQuit = NSLocalizedString("clear.and.quit", value: "Clear and Quit", comment: "Button to clear data and quit the application") + static let quitWithoutClearing = NSLocalizedString("quit.without.clearing", value: "Quit Without Clearing", comment: "Button to quit the application without clearing data") static let `continue` = NSLocalizedString("`continue`", value: "Continue", comment: "Continue button") static let bookmarkDialogAdd = NSLocalizedString("bookmark.dialog.add", value: "Add", comment: "Button to confim a bookmark creation") static let newFolderDialogAdd = NSLocalizedString("folder.dialog.add", value: "Add", comment: "Button to confim a bookmark folder creation") @@ -66,54 +68,54 @@ struct UserText { } // MARK: - Main Menu -> DuckDuckGo - static let mainMenuAppPreferences = NSLocalizedString("main-menu.app.preferences" ,value:"Preferences…", comment: "Main Menu DuckDuckGo item") - static let mainMenuAppServices = NSLocalizedString("main-menu.app.services", value:"Services", comment: "Main Menu DuckDuckGo item") - static let mainMenuAppCheckforUpdates = NSLocalizedString("main-menu.app.check-for-updates", value:"Check for Updates…", comment: "Main Menu DuckDuckGo item") - static let mainMenuAppHideDuckDuckGo = NSLocalizedString("main-menu.app.hide-duck-duck-go", value:"Hide DuckDuckGo", comment: "Main Menu DuckDuckGo item") - static let mainMenuAppHideOthers = NSLocalizedString("main-menu.app.hide-others", value:"Hide Others", comment: "Main Menu DuckDuckGo item") - static let mainMenuAppShowAll = NSLocalizedString("main-menu.app.show-all", value:"Show All", comment: "Main Menu DuckDuckGo item") - static let mainMenuAppQuitDuckDuckGo = NSLocalizedString("main-menu.app.quit-duck-duck-go", value:"Quit DuckDuckGo", comment: "Main Menu DuckDuckGo item") + static let mainMenuAppPreferences = NSLocalizedString("main-menu.app.preferences", value: "Preferences…", comment: "Main Menu DuckDuckGo item") + static let mainMenuAppServices = NSLocalizedString("main-menu.app.services", value: "Services", comment: "Main Menu DuckDuckGo item") + static let mainMenuAppCheckforUpdates = NSLocalizedString("main-menu.app.check-for-updates", value: "Check for Updates…", comment: "Main Menu DuckDuckGo item") + static let mainMenuAppHideDuckDuckGo = NSLocalizedString("main-menu.app.hide-duck-duck-go", value: "Hide DuckDuckGo", comment: "Main Menu DuckDuckGo item") + static let mainMenuAppHideOthers = NSLocalizedString("main-menu.app.hide-others", value: "Hide Others", comment: "Main Menu DuckDuckGo item") + static let mainMenuAppShowAll = NSLocalizedString("main-menu.app.show-all", value: "Show All", comment: "Main Menu DuckDuckGo item") + static let mainMenuAppQuitDuckDuckGo = NSLocalizedString("main-menu.app.quit-duck-duck-go", value: "Quit DuckDuckGo", comment: "Main Menu DuckDuckGo item") // MARK: - Main Menu -> -File - static let mainMenuFile = NSLocalizedString("main-menu.file", value:"File", comment: "Main Menu File") - static let mainMenuFileNewTab = NSLocalizedString("main-menu.file.new-tab", value:"New Tab", comment: "Main Menu File item") - static let mainMenuFileOpenLocation = NSLocalizedString("main-menu.file.open-location", value:"Open Location…", comment: "Main Menu File item- Menu option that allows the user to connect to an address (type an address) on click the address bar of the browser is selected and the user can type.") - static let mainMenuFileCloseWindow = NSLocalizedString("main-menu.file.close-window", value:"Close Window", comment: "Main Menu File item") - static let mainMenuFileCloseAllWindows = NSLocalizedString("main-menu.file.close-all-windows", value:"Close All Windows", comment: "Main Menu File item") - static let mainMenuFileSaveAs = NSLocalizedString("main-menu.file.save-as", value:"Save As…", comment: "Main Menu File item") - static let mainMenuFileImportBookmarksandPasswords = NSLocalizedString("main-menu.file.import-bookmarks-and-passwords", value:"Import Bookmarks and Passwords…", comment: "Main Menu File item") - static let mainMenuFileExport = NSLocalizedString("main-menu.file.export", value:"Export", comment: "Main Menu File item") - static let mainMenuFileExportPasswords = NSLocalizedString("main-menu.file.export-passwords", value:"Passwords…", comment: "Main Menu File-Export item") - static let mainMenuFileExportBookmarks = NSLocalizedString("main-menu.file.export-bookmarks", value:"Bookmarks…", comment: "Main Menu File-Export item") + static let mainMenuFile = NSLocalizedString("main-menu.file", value: "File", comment: "Main Menu File") + static let mainMenuFileNewTab = NSLocalizedString("main-menu.file.new-tab", value: "New Tab", comment: "Main Menu File item") + static let mainMenuFileOpenLocation = NSLocalizedString("main-menu.file.open-location", value: "Open Location…", comment: "Main Menu File item- Menu option that allows the user to connect to an address (type an address) on click the address bar of the browser is selected and the user can type.") + static let mainMenuFileCloseWindow = NSLocalizedString("main-menu.file.close-window", value: "Close Window", comment: "Main Menu File item") + static let mainMenuFileCloseAllWindows = NSLocalizedString("main-menu.file.close-all-windows", value: "Close All Windows", comment: "Main Menu File item") + static let mainMenuFileSaveAs = NSLocalizedString("main-menu.file.save-as", value: "Save As…", comment: "Main Menu File item") + static let mainMenuFileImportBookmarksandPasswords = NSLocalizedString("main-menu.file.import-bookmarks-and-passwords", value: "Import Bookmarks and Passwords…", comment: "Main Menu File item") + static let mainMenuFileExport = NSLocalizedString("main-menu.file.export", value: "Export", comment: "Main Menu File item") + static let mainMenuFileExportPasswords = NSLocalizedString("main-menu.file.export-passwords", value: "Passwords…", comment: "Main Menu File-Export item") + static let mainMenuFileExportBookmarks = NSLocalizedString("main-menu.file.export-bookmarks", value: "Bookmarks…", comment: "Main Menu File-Export item") // MARK: - Main Menu -> Edit - static let mainMenuEdit = NSLocalizedString("main-menu.edit", value:"Edit", comment: "Main Menu Edit") - static let mainMenuEditUndo = NSLocalizedString("main-menu.edit.undo", value:"Undo", comment: "Main Menu Edit item") - static let mainMenuEditRedo = NSLocalizedString("main-menu.edit.redo", value:"Redo", comment: "Main Menu Edit item") - static let mainMenuEditCut = NSLocalizedString("main-menu.edit.cut", value:"Cut", comment: "Main Menu Edit item") - static let mainMenuEditCopy = NSLocalizedString("main-menu.edit.copy", value:"Copy", comment: "Main Menu Edit item") - static let mainMenuEditPaste = NSLocalizedString("main-menu.edit.paste", value:"Paste", comment: "Main Menu Edit item") - static let mainMenuEditPasteAndMatchStyle = NSLocalizedString("main-menu.edit.paste-and-match-style", value:"Paste and Match Style", comment: "Main Menu Edit item - Action that allows the user to paste copy into a target document and the target document's style will be retained (instead of the source style)") - static let mainMenuEditDelete = NSLocalizedString("main-menu.edit.delete", value:"Delete", comment: "Main Menu Edit item") - static let mainMenuEditSelectAll = NSLocalizedString("main-menu.edit.select-all", value:"Select All", comment: "Main Menu Edit item") - - static let mainMenuEditFind = NSLocalizedString("main-menu.edit.find", value:"Find", comment: "Main Menu Edit item") + static let mainMenuEdit = NSLocalizedString("main-menu.edit", value: "Edit", comment: "Main Menu Edit") + static let mainMenuEditUndo = NSLocalizedString("main-menu.edit.undo", value: "Undo", comment: "Main Menu Edit item") + static let mainMenuEditRedo = NSLocalizedString("main-menu.edit.redo", value: "Redo", comment: "Main Menu Edit item") + static let mainMenuEditCut = NSLocalizedString("main-menu.edit.cut", value: "Cut", comment: "Main Menu Edit item") + static let mainMenuEditCopy = NSLocalizedString("main-menu.edit.copy", value: "Copy", comment: "Main Menu Edit item") + static let mainMenuEditPaste = NSLocalizedString("main-menu.edit.paste", value: "Paste", comment: "Main Menu Edit item") + static let mainMenuEditPasteAndMatchStyle = NSLocalizedString("main-menu.edit.paste-and-match-style", value: "Paste and Match Style", comment: "Main Menu Edit item - Action that allows the user to paste copy into a target document and the target document's style will be retained (instead of the source style)") + static let mainMenuEditDelete = NSLocalizedString("main-menu.edit.delete", value: "Delete", comment: "Main Menu Edit item") + static let mainMenuEditSelectAll = NSLocalizedString("main-menu.edit.select-all", value: "Select All", comment: "Main Menu Edit item") + + static let mainMenuEditFind = NSLocalizedString("main-menu.edit.find", value: "Find", comment: "Main Menu Edit item") // MARK: Main Menu -> Edit -> Find - static let mainMenuEditFindFindNext = NSLocalizedString("main-menu.edit.find.find-next", value:"Find Next", comment: "Main Menu Edit-Find item") - static let mainMenuEditFindFindPrevious = NSLocalizedString("main-menu.edit.find.find-previous", value:"Find Previous", comment: "Main Menu Edit-Find item") - static let mainMenuEditFindHideFind = NSLocalizedString("main-menu.edit.find.hide-find", value:"Hide Find", comment: "Main Menu Edit-Find item") + static let mainMenuEditFindFindNext = NSLocalizedString("main-menu.edit.find.find-next", value: "Find Next", comment: "Main Menu Edit-Find item") + static let mainMenuEditFindFindPrevious = NSLocalizedString("main-menu.edit.find.find-previous", value: "Find Previous", comment: "Main Menu Edit-Find item") + static let mainMenuEditFindHideFind = NSLocalizedString("main-menu.edit.find.hide-find", value: "Hide Find", comment: "Main Menu Edit-Find item") static let mainMenuEditSpellingandGrammar = NSLocalizedString("main-menu.edit.edit-spelling-and-grammar", value: "Spelling and Grammar", comment: "Main Menu Edit item") // MARK: Main Menu -> Edit -> Spellingand - static let mainMenuEditSpellingandShowSpellingandGrammar = NSLocalizedString("main-menu.edit.spelling-and.show-spelling-and-grammar", value:"Show Spelling and Grammar", comment: "Main Menu Edit-Spellingand item") - static let mainMenuEditSpellingandCheckDocumentNow = NSLocalizedString("main-menu.edit.spelling-and.check-document-now", value:"Check Document Now", comment: "Main Menu Edit-Spellingand item") - static let mainMenuEditSpellingandCheckSpellingWhileTyping = NSLocalizedString("main-menu.edit.spelling-and.check-spelling-while-typing", value:"Check Spelling While Typing", comment: "Main Menu Edit-Spellingand item") - static let mainMenuEditSpellingandCheckGrammarWithSpelling = NSLocalizedString("main-menu.edit.spelling-and.check-grammar-with-spelling", value:"Check Grammar With Spelling", comment: "Main Menu Edit-Spellingand item") - static let mainMenuEditSpellingandCorrectSpellingAutomatically = NSLocalizedString("main-menu.edit.spelling-and.correct-spelling-automatically", value:"Correct Spelling Automatically", comment: "Main Menu Edit-Spellingand item") + static let mainMenuEditSpellingandShowSpellingandGrammar = NSLocalizedString("main-menu.edit.spelling-and.show-spelling-and-grammar", value: "Show Spelling and Grammar", comment: "Main Menu Edit-Spellingand item") + static let mainMenuEditSpellingandCheckDocumentNow = NSLocalizedString("main-menu.edit.spelling-and.check-document-now", value: "Check Document Now", comment: "Main Menu Edit-Spellingand item") + static let mainMenuEditSpellingandCheckSpellingWhileTyping = NSLocalizedString("main-menu.edit.spelling-and.check-spelling-while-typing", value: "Check Spelling While Typing", comment: "Main Menu Edit-Spellingand item") + static let mainMenuEditSpellingandCheckGrammarWithSpelling = NSLocalizedString("main-menu.edit.spelling-and.check-grammar-with-spelling", value: "Check Grammar With Spelling", comment: "Main Menu Edit-Spellingand item") + static let mainMenuEditSpellingandCorrectSpellingAutomatically = NSLocalizedString("main-menu.edit.spelling-and.correct-spelling-automatically", value: "Correct Spelling Automatically", comment: "Main Menu Edit-Spellingand item") - static let mainMenuEditSubstitutions = NSLocalizedString("main-menu.edit.subsitutions", value:"Substitutions", comment: "Main Menu Edit item") + static let mainMenuEditSubstitutions = NSLocalizedString("main-menu.edit.subsitutions", value: "Substitutions", comment: "Main Menu Edit item") // TODO: Done till here // MARK: Main Menu -> Edit -> Substitutions static let mainMenuEditSubstitutionsShowSubstitutions = NSLocalizedString("Show Substitutions", comment: "Main Menu Edit-Substitutions item") @@ -143,7 +145,7 @@ struct UserText { static let mainMenuViewReloadPage = NSLocalizedString("Reload Page", comment: "Main Menu View item") static let mainMenuViewHome = NSLocalizedString("Home", comment: "Main Menu View item") static let mainMenuHomeButton = NSLocalizedString("Home Button", comment: "Main Menu > View > Home Button item") - + static func mainMenuHomeButtonMode(for position: HomeButtonPosition) -> String { switch position { case .hidden: @@ -154,7 +156,7 @@ struct UserText { return NSLocalizedString("main.menu.home.button.mode.right", value: "Show Right of the Reload Button", comment: "Main Menu > View > Home Button > right position item") } } - + static let mainMenuViewShowAutofillShortcut = NSLocalizedString("Show Autofill Shortcut", comment: "Main Menu View item") static let mainMenuViewShowBookmarksShortcut = NSLocalizedString("Show Bookmarks Shortcut", comment: "Main Menu View item") static let mainMenuViewShowDownloadsShortcut = NSLocalizedString("Show Downloads Shortcut", comment: "Main Menu View item") @@ -202,6 +204,8 @@ struct UserText { static let muteTab = NSLocalizedString("mute.tab", value: "Mute Tab", comment: "Menu item. Mute tab") static let unmuteTab = NSLocalizedString("unmute.tab", value: "Unmute Tab", comment: "Menu item. Unmute tab") static let closeOtherTabs = NSLocalizedString("close.other.tabs", value: "Close Other Tabs", comment: "Menu item") + static let closeAllOtherTabs = NSLocalizedString("close.all.other.tabs", value: "Close All Other Tabs", comment: "Menu item") + static let closeTabsToTheLeft = NSLocalizedString("close.tabs.to.the.left", value: "Close Tabs to the Left", comment: "Menu item") static let closeTabsToTheRight = NSLocalizedString("close.tabs.to.the.right", value: "Close Tabs to the Right", comment: "Menu item") static let openInNewTab = NSLocalizedString("open.in.new.tab", value: "Open in New Tab", comment: "Menu item that opens the link in a new tab") static let openInNewWindow = NSLocalizedString("open.in.new.window", value: "Open in New Window", comment: "Menu item that opens the link in a new window") @@ -212,13 +216,50 @@ struct UserText { static let addFolder = NSLocalizedString("menu.add.folder", value: "Add Folder…", comment: "Menu item to add a folder") static let tabHomeTitle = NSLocalizedString("tab.home.title", value: "New Tab", comment: "Tab home title") + static let tabUntitledTitle = NSLocalizedString("tab.empty.title", value: "Untitled", comment: "Title for an empty tab without a title") static let tabPreferencesTitle = NSLocalizedString("tab.preferences.title", value: "Settings", comment: "Tab preferences title") static let tabBookmarksTitle = NSLocalizedString("tab.bookmarks.title", value: "Bookmarks", comment: "Tab bookmarks title") static let tabOnboardingTitle = NSLocalizedString("tab.onboarding.title", value: "Welcome", comment: "Tab onboarding title") + + // MARK: Error Pages static let tabErrorTitle = NSLocalizedString("tab.error.title", value: "Failed to open page", comment: "Tab error title") static let errorPageHeader = NSLocalizedString("page.error.header", value: "DuckDuckGo can’t load this page.", comment: "Error page heading text") static let webProcessCrashPageHeader = NSLocalizedString("page.crash.header", value: "This webpage has crashed.", comment: "Error page heading text shown when a Web Page process had crashed") static let webProcessCrashPageMessage = NSLocalizedString("page.crash.message", value: "Try reloading the page or come back later.", comment: "Error page message text shown when a Web Page process had crashed") + static let sslErrorPageHeader = NSLocalizedString("ssl.error.page.header", value: "Warning: This site may be insecure", comment: "Title shown in an error page that warn users of security risks on a website due to SSL issues") + static let sslErrorPageTabTitle = NSLocalizedString("ssl.error.page.tab.title", value: "Warning: Site May Be Insecure", comment: "Title shown in an error page tab that warn users of security risks on a website due to SSL issues") + static func sslErrorPageBody(_ domain: String) -> String { + let localized = NSLocalizedString("ssl.error.page.body", + value: "The certificate for this site is invalid. You might be connecting to a server that is pretending to be %1$@ which could put your confidential information at risk.", + comment: "Error description shown in an error page that warns users of security risks on a website due to SSL issues. %1$@ represent the site domain.") + return String(format: localized, domain) + } + static let sslErrorPageAdvancedButton = NSLocalizedString("ssl.error.page.advanced.button", value: "Advanced…", comment: "Button shown in an error page that warns users of security risks on a website due to SSL issues. The buttons allows the user to see advanced options on click.") + static let sslErrorPageLeaveSiteButton = NSLocalizedString("ssl.error.page.leave.site.button", value: "Leave This Site", comment: "Button shown in an error page that warns users of security risks on a website due to SSL issues. The buttons allows the user to leave the website and navigate to previous page.") + static let sslErrorPageVisitSiteButton = NSLocalizedString("ssl.error.page.visit.site.button", value: "Accept Risk and Visit Site", comment: "Button shown in an error page that warns users of security risks on a website due to SSL issues. The buttons allows the user to visit the website anyway despite the risks.") + static let sslErrorAdvancedInfoTitle = NSLocalizedString("ssl.error.page.advanced.info.title", value: "DuckDuckGo warns you when a website has an invalid certificate.", comment: "Title of the Advanced info section shown in an error page that warns users of security risks on a website due to SSL issues.") + static let sslErrorAdvancedInfoBodyWrongHost = NSLocalizedString("ssl.error.page.advanced.info.body.wrong.host", value: "It’s possible that the website is misconfigured or that an attacker has compromised your connection.", comment: "Body of the text of the Advanced info shown in an error page that warns users of security risks on a website due to SSL issues.") + static let sslErrorAdvancedInfoBodyExpired = NSLocalizedString("ssl.error.page.advanced.info.body.expired", value: "It’s possible that the website is misconfigured, that an attacker has compromised your connection, or that your system clock is incorrect.", comment: "Body of the text of the Advanced info shown in an error page that warns users of security risks on a website due to SSL issues.") + static func sslErrorCertificateExpiredMessage(_ domain: String) -> String { + let localized = NSLocalizedString("ssl.error.certificate.expired.message", + value: "The security certificate for %1$@ is expired.", + comment: "Describes an SSL error where a website's security certificate is expired. '%1$@' is a placeholder for the website's domain.") + return String(format: localized, domain) + } + static func sslErrorCertificateWrongHostMessage(_ domain: String, eTldPlus1: String) -> String { + let localized = NSLocalizedString("ssl.error.wrong.host.message", + value: "The security certificate for %1$@ does not match *.%2$@.", + comment: "Explains an SSL error when a site's certificate doesn't match its domain. '%1$@' is the site's domain.") + return String(format: localized, domain, eTldPlus1) + } + static func sslErrorCertificateSelfSignedMessage(_ domain: String) -> String { + let localized = NSLocalizedString("ssl.error.self.signed.message", + value: "The security certificate for %1$@ is not trusted by your device's operating system.", + comment: "Warns the user that the site's security certificate is self-signed and not trusted. '%1$@' is the site's domain.") + return String(format: localized, domain) + } + + static let openSystemPreferences = NSLocalizedString("open.preferences", value: "Open System Preferences", comment: "Open System Preferences (to re-enable permission for the App) (up to and including macOS 12") static let openSystemSettings = NSLocalizedString("open.settings", value: "Open System Settings…", comment: "This string represents a prompt or button label prompting the user to open system settings") @@ -355,7 +396,7 @@ struct UserText { static let restartBitwarden = NSLocalizedString("restart.bitwarden", value: "Restart Bitwarden", comment: "Button to restart Bitwarden application") static let restartBitwardenInfo = NSLocalizedString("restart.bitwarden.info", value: "Bitwarden is not responding. Please restart it to initiate the communication again", comment: "This string represents a message informing the user that Bitwarden is not responding and prompts them to restart the application to initiate communication again.") - static let autofillViewContentButton = NSLocalizedString("autofill.view-autofill-content", value: "View Autofill Content…", comment: "View Autofill Content Button name in the autofill settings") + static let autofillViewContentButton = NSLocalizedString("autofill.view-autofill-content", value: "View Autofill Content…", comment: "View Autofill Content Button name in the autofill settings") static let autofillAskToSave = NSLocalizedString("autofill.ask-to-save", value: "Save and Autofill", comment: "Autofill settings section title") static let autofillAskToSaveExplanation = NSLocalizedString("autofill.ask-to-save.explanation", value: "Receive prompts to save new information and autofill online forms.", comment: "Description of Autofill autosaving feature - used in settings") static let autofillUsernamesAndPasswords = NSLocalizedString("autofill.usernames-and-passwords", value: "Usernames and passwords", comment: "Autofill autosaved data type") @@ -364,14 +405,14 @@ struct UserText { static let autofillExcludedSites = NSLocalizedString("autofill.excluded-sites", value: "Excluded Sites", comment: "Autofill settings section title") static let autofillExcludedSitesExplanation = NSLocalizedString("autofill.excluded-sites.explanation", value: "Websites you selected to never ask to save your password.", comment: "Subtitle providing additional information about the excluded sites section") static let autofillExcludedSitesReset = NSLocalizedString("autofill.excluded-sites.reset", value: "Reset", comment: "Button title allowing users to reset their list of excluded sites") - static let autofillExcludedSitesResetActionTitle = NSLocalizedString("autofill.excluded-sites.reset.action.title", value:"Reset Excluded Sites?", comment: "Alert title") - static let autofillExcludedSitesResetActionMessage = NSLocalizedString("autofill.excluded-sites.reset.action.message", value:"If you reset excluded sites, you will be prompted to save your password next time you sign in to any of these sites.", comment: "Alert title") + static let autofillExcludedSitesResetActionTitle = NSLocalizedString("autofill.excluded-sites.reset.action.title", value: "Reset Excluded Sites?", comment: "Alert title") + static let autofillExcludedSitesResetActionMessage = NSLocalizedString("autofill.excluded-sites.reset.action.message", value: "If you reset excluded sites, you will be prompted to save your password next time you sign in to any of these sites.", comment: "Alert title") static let autofillAutoLock = NSLocalizedString("autofill.auto-lock", value: "Auto-lock", comment: "Autofill settings section title") static let autofillLockWhenIdle = NSLocalizedString("autofill.lock-when-idle", value: "Lock autofill after computer is idle for", comment: "Autofill auto-lock setting") static let autofillNeverLock = NSLocalizedString("autofill.never-lock", value: "Never lock autofill", comment: "Autofill auto-lock setting") static let autofillNeverLockWarning = NSLocalizedString("autofill.never-lock-warning", value: "If not locked, anyone with access to your device will be able to use and modify your autofill data. For security purposes, credit card form fill always requires authentication.", comment: "Autofill disabled auto-lock warning") static let autolockLocksFormFill = NSLocalizedString("autofill.autolock-locks-form-filling", value: "Also lock password form fill", comment: "Lock form filling when auto-lock is active text") - + static let downloadsLocation = NSLocalizedString("downloads.location", value: "Location", comment: "Downloads directory location") static let downloadsAlwaysAsk = NSLocalizedString("downloads.always-ask", value: "Always ask where to save files", comment: "Downloads preferences checkbox") static let downloadsChangeDirectory = NSLocalizedString("downloads.change", value: "Change…", comment: "Change downloads directory button") @@ -428,7 +469,8 @@ struct UserText { static let addFavorite = NSLocalizedString("add.favorite", value: "Add Favorite", comment: "Button for adding a favorite bookmark") static let editFavorite = NSLocalizedString("edit.favorite", value: "Edit Favorite", comment: "Header of the view that edits a favorite bookmark") static let removeFromFavorites = NSLocalizedString("remove.from.favorites", value: "Remove from Favorites", comment: "Button for removing bookmarks from favorites") - static let bookmarkThisPage = NSLocalizedString("bookmark.this.page", value: "Bookmark This Page", comment: "Menu item for bookmarking current page") + static let bookmarkThisPage = NSLocalizedString("bookmark.this.page", value: "Bookmark This Page…", comment: "Menu item for bookmarking current page") + static let bookmarkAllTabs = NSLocalizedString("bookmark.all.tabs", value: "Bookmark All Tabs…", comment: "Menu item for bookmarking all the open tabs") static let bookmarksShowToolbarPanel = NSLocalizedString("bookmarks.show-toolbar-panel", value: "Open Bookmarks Panel", comment: "Menu item for opening the bookmarks panel") static let bookmarksManageBookmarks = NSLocalizedString("bookmarks.manage-bookmarks", value: "Manage Bookmarks", comment: "Menu item for opening the bookmarks management interface") static let bookmarkImportedFromFolder = NSLocalizedString("bookmarks.imported.from.folder", value: "Imported from", comment: "Name of the folder the imported bookmarks are saved into") @@ -519,7 +561,7 @@ struct UserText { static let general = NSLocalizedString("preferences.general", value: "General", comment: "Title of the option to show the General preferences") static let sync = NSLocalizedString("preferences.sync", value: "Sync & Backup", comment: "Title of the option to show the Sync preferences") - static let syncAutoLockPrompt = NSLocalizedString("preferences.sync.auto-lock-prompt", value:"Unlock device to setup Sync & Backup", comment: "Reason for auth when setting up Sync") + static let syncAutoLockPrompt = NSLocalizedString("preferences.sync.auto-lock-prompt", value: "Unlock device to setup Sync & Backup", comment: "Reason for auth when setting up Sync") static let syncBookmarkPausedAlertTitle = NSLocalizedString("alert.sync-bookmarks-paused-title", value: "Bookmarks Sync is Paused", comment: "Title for alert shown when sync bookmarks paused for too many items") static let syncBookmarkPausedAlertDescription = NSLocalizedString("alert.sync-bookmarks-paused-description", value: "You have exceeded the bookmarks sync limit. Try deleting some bookmarks. Until this is resolved your bookmarks will not be backed up.", comment: "Description for alert shown when sync bookmarks paused for too many items") static let syncCredentialsPausedAlertTitle = NSLocalizedString("alert.sync-credentials-paused-title", value: "Passwords Sync is Paused", comment: "Title for alert shown when sync credentials paused for too many items") @@ -556,7 +598,7 @@ struct UserText { static let onStartup = NSLocalizedString("preferences.on-startup", value: "On Startup", comment: "Name of the preferences section related to app startup") static let reopenAllWindowsFromLastSession = NSLocalizedString("preferences.reopen-windows", value: "Reopen all windows from last session", comment: "Option to control session restoration") static let showHomePage = NSLocalizedString("preferences.show-home", value: "Open a new window", comment: "Option to control session startup") - + static let homePage = NSLocalizedString("preferences-homepage.title", value: "Homepage", comment: "Title for Homepage section in settings") static let homePageDescription = NSLocalizedString("preferences-homepage.description", value: "When navigating home or opening new windows.", comment: "Homepage behavior description") static let newTab = NSLocalizedString("preferences-homepage-newTab", value: "New Tab page", comment: "Option to open a new tab") @@ -566,6 +608,20 @@ struct UserText { static let setHomePage = NSLocalizedString("preferences-homepage-set-homePage", value: "Set Homepage", comment: "Set Homepage dialog title") static let addressLabel = NSLocalizedString("preferences-homepage-address", value: "Address:", comment: "Homepage address field label") + static let tabs = NSLocalizedString("preferences-tabs.title", value: "Tabs", comment: "Title for tabs section in settings") + static let preferNewTabsToWindows = NSLocalizedString("preferences-tabs.prefer.new.tabs.to.windows", value: "Open links in new tabs instead of new windows whenever possible", comment: "Option to prefer opening new tabs instead of windows when opening links") + static let switchToNewTabWhenOpened = NSLocalizedString("preferences-tabs.switch.tab.when.opened", value: "When opening links, switch to the new tab or window immediately", comment: "Option to switch to a new tab/window when it is opened") + static let newTabPositionTitle = NSLocalizedString("preferences-tabs.new.tab.position.title", value: "When creating a new tab", comment: "Title for new tab positioning") + + static func newTabPositionMode(for position: NewTabPosition) -> String { + switch position { + case .atEnd: + return NSLocalizedString("context.menu.new.tab.mode.at.end", value: "Add to the right of other tabs", comment: "Preferences > Tabs > At end of list") + case .nextToCurrent: + return NSLocalizedString("context.menu.new.tab.mode.next.to.current", value: "Add to the right of the current tab", comment: "Preferences > Tabs > Next to current tab") + } + } + static func homeButtonMode(for position: HomeButtonPosition) -> String { switch position { case .hidden: @@ -603,7 +659,6 @@ struct UserText { static let aboutUnsupportedDeviceInfo2Part4 = "of DuckDuckGo. You can also keep using your current version of the browser, but it will not receive further updates." static let unsupportedDeviceInfoAlertHeader = NSLocalizedString("unsupported.device.info.alert.header", value: "Your version of macOS is no longer supported.", comment: "his string represents the header for an alert informing the user that their version of macOS is no longer supported") - static func moreAt(url: String) -> String { let localized = NSLocalizedString("preferences.about.more-at", value: "More at %@", comment: "Link to the about page") return String(format: localized, url) @@ -636,6 +691,13 @@ struct UserText { String(format: NSLocalizedString("import.logins.select-csv-file.source", value: "Select %@ CSV File…", comment: "Button text for selecting a CSV file exported from (LastPass or Bitwarden or 1Password - %@)"), source.importSourceName) } + static func importNoDataBookmarksSubtitle(from source: DataImport.Source) -> String { + String(format: NSLocalizedString("import.nodata.bookmarks.subtitle", value: "If you have %@ bookmarks, try importing them manually instead.", comment: "Data import error subtitle: suggestion to import Bookmarks manually by selecting a CSV or HTML file. The placeholder here represents the source browser, e.g Firefox."), source.importSourceName) + } + static func importNoDataPasswordsSubtitle(from source: DataImport.Source) -> String { + String(format: NSLocalizedString("import.nodata.passwords.subtitle", value: "If you have %@ passwords, try importing them manually instead.", comment: "Data import error subtitle: suggestion to import passwords manually by selecting a CSV or HTML file. The placeholder here represents the source browser, e.g Firefox."), source.importSourceName) + } + static let importLoginsPasswords = NSLocalizedString("import.logins.passwords", value: "Passwords", comment: "Title text for the Passwords import option") static let importBookmarksButtonTitle = NSLocalizedString("bookmarks.import.button.title", value: "Import", comment: "Button text to open bookmark import dialog") @@ -825,6 +887,9 @@ struct UserText { static let bitwardenError = NSLocalizedString("bitwarden.error", value: "Unable to find or connect to Bitwarden", comment: "This message appears when the application is unable to find or connect to Bitwarden, indicating a connection issue.") static let bitwardenNotInstalled = NSLocalizedString("bitwarden.not.installed", value: "Bitwarden app is not installed", comment: "") static let bitwardenOldVersion = NSLocalizedString("bitwarden.old.version", value: "Please update Bitwarden to the latest version", comment: "Message that warns user they need to update their password manager Bitwarden app vesion") + static let bitwardenIncompatible = NSLocalizedString("bitwarden.incompatible", value: "The following Bitwarden versions are incompatible with DuckDuckGo: v2024.3.0, v2024.3.2, v2024.4.0, v2024.4.1. Please revert to an older version by following these steps:", comment: "Message that warns user that specific Bitwarden app vesions are not compatible with this app") + static let bitwardenIncompatibleStep1 = NSLocalizedString("bitwarden.incompatible.step.1", value: "Download v2014.2.1", comment: "First step to downgrade Bitwarden") + static let bitwardenIncompatibleStep2 = NSLocalizedString("bitwarden.incompatible.step.2", value: "2. Open the downloaded DMG file and drag the Bitwarden application to\nthe /Applications folder.", comment: "Second step to downgrade Bitwarden") static let bitwardenIntegrationNotApproved = NSLocalizedString("bitwarden.integration.not.approved", value: "Integration with DuckDuckGo is not approved in Bitwarden app", comment: "While the user tries to connect the DuckDuckGo Browser to password manager Bitwarden This message indicates that the integration with DuckDuckGo has not been approved in the Bitwarden app.") static let bitwardenMissingHandshake = NSLocalizedString("bitwarden.missing.handshake", value: "Missing handshake", comment: "While the user tries to connect the DuckDuckGo Browser to password manager Bitwarden This message indicates a missing handshake (a way for two devices or systems to say hello to each other and agree to communicate or exchange information).") static let bitwardenWaitingForHandshake = NSLocalizedString("bitwarden.waiting.for.handshake", value: "Waiting for the handshake approval in Bitwarden app", comment: "While the user tries to connect the DuckDuckGo Browser to password manager Bitwarden This message indicates the system is waiting for the handshake (a way for two devices or systems to say hello to each other and agree to communicate or exchange information).") @@ -873,9 +938,9 @@ struct UserText { // MARK: - Tooltips static let autofillShortcutTooltip = NSLocalizedString("tooltip.autofill.shortcut", value: "Autofill", comment: "Tooltip for the autofill shortcut") - + static let homeButtonTooltip = NSLocalizedString("tooltip.home.button", value: "Home", comment: "Tooltip for the home button") - + static let bookmarksShortcutTooltip = NSLocalizedString("tooltip.bookmarks.shortcut", value: "Bookmarks", comment: "Tooltip for the bookmarks shortcut") static let downloadsShortcutTooltip = NSLocalizedString("tooltip.downloads.shortcut", value: "Downloads", comment: "Tooltip for the downloads shortcut") @@ -915,6 +980,9 @@ struct UserText { static let showPasswordTooltip = NSLocalizedString("autofill.show-password", value: "Show password", comment: "Tooltip for the Autofill panel's Show Password button") static let hidePasswordTooltip = NSLocalizedString("autofill.hide-password", value: "Hide password", comment: "Tooltip for the Autofill panel's Hide Password button") + static let autofillShowCardCvvTooltip = NSLocalizedString("autofill.show-card-cvv", value: "Show CVV", comment: "Tooltip for the Autofill panel's Show CVV button") + static let autofillHideCardCvvTooltip = NSLocalizedString("autofill.hide-card-cvv", value: "Hide CVV", comment: "Tooltip for the Autofill panel's Hide CVV button") + static let databaseFactoryFailedMessage = NSLocalizedString("database.factory.failed.message", value: "There was an error initializing the database", comment: "Alert title when we fail to init database") static let databaseFactoryFailedInformative = NSLocalizedString("database.factory.failed.information", value: "Restart your Mac and try again", comment: "Info to restart macOS after database init failure") @@ -929,17 +997,16 @@ struct UserText { let localized = NSLocalizedString("autofill.popover.password-manager-connected-to-user", value: "Connected to user %@", comment: "Label describing what user is connected to the password manager") return String(format: localized, user) } - + static func passwordManagerAutosavePopoverText(domain: String) -> String { let localized = NSLocalizedString("autofill.popover.autosave.text", value: "Password saved for %@", comment: "Text confirming a password has been saved for the %@ domain") return String(format: localized, domain) } - + static let passwordManagerAutosaveButtonText = NSLocalizedString("autofill.popover.autosave.button.text", value: "View", comment: "Button to view the recently autosaved password") - static func openPasswordManagerButton(managerName: String) -> String { let localized = NSLocalizedString("autofill.popover.open-password-manager", value: "Open %@", comment: "Open password manager button") return String(format: localized, managerName) @@ -947,7 +1014,7 @@ struct UserText { static let passwordManagerLockedStatus = NSLocalizedString("autofill.manager.status.locked", value: "Locked", comment: "Locked status for password manager") static let passwordManagerUnlockedStatus = NSLocalizedString("autofill.manager.status.unlocked", value: "Unlocked", comment: "Unlocked status for password manager") - + static func alertTitle(from domain: String) -> String { let localized = NSLocalizedString("alert.title", value: "A message from %@", comment: "Title formatted with presenting domain") return String(format: localized, domain) @@ -966,8 +1033,6 @@ struct UserText { } } - static let noAccessToSelectedFolderHeader = NSLocalizedString("no.access.to.selected.folder.header", value: "DuckDuckGo needs permission to access selected folder", comment: "Header of the alert dialog informing user about failed download") - static let noAccessToSelectedFolder = NSLocalizedString("no.access.to.selected.folder", value: "Grant access to the location of download.", comment: "Alert presented to user if the app doesn't have rights to access selected folder") static let cannotOpenFileAlertHeader = NSLocalizedString("cannot.open.file.alert.header", value: "Cannot Open File", comment: "Header of the alert dialog informing user it is not possible to open the file") static let cannotOpenFileAlertInformative = NSLocalizedString("cannot.open.file.alert.informative", value: "The App Store version of DuckDuckGo can only access local files if you drag-and-drop them into a browser window.\n\n To navigate local files using the address bar, please download DuckDuckGo directly from https://duckduckgo.com/mac.", comment: "Informative of the alert dialog informing user it is not possible to open the file") @@ -987,23 +1052,17 @@ struct UserText { static let newTabSetUpImportCardTitle = NSLocalizedString("newTab.setup.import.title", value: "Bring Your Stuff", comment: "Title of the Import card of the Set Up section in the home page") static let newTabSetUpDuckPlayerCardTitle = NSLocalizedString("newTab.setup.duck.player.title", value: "Clean Up YouTube", comment: "Title of the Duck Player card of the Set Up section in the home page") static let newTabSetUpEmailProtectionCardTitle = NSLocalizedString("newTab.setup.email.protection.title", value: "Protect Your Inbox", comment: "Title of the Email Protection card of the Set Up section in the home page") - static let newTabSetUpSurveyDay0CardTitle = NSLocalizedString("newTab.setup.survey.day.0.title", value: "Share Your Thoughts With Us", comment: "Title of the Day 0 durvey of the Set Up section in the home page") - static let newTabSetUpSurveyDay14CardTitle = NSLocalizedString("newTab.setup.survey.day.14.title", value: "Share Your Thoughts With Us", comment: "Title of the Day 14 durvey of the Set Up section in the home page") static let newTabSetUpDefaultBrowserAction = NSLocalizedString("newTab.setup.default.browser.action", value: "Make Default Browser", comment: "Action title on the action menu of the Default Browser card") static let newTabSetUpImportAction = NSLocalizedString("newTab.setup.Import.action", value: "Import Now", comment: "Action title on the action menu of the Import card of the Set Up section in the home page") static let newTabSetUpDuckPlayerAction = NSLocalizedString("newTab.setup.duck.player.action", value: "Try Duck Player", comment: "Action title on the action menu of the Duck Player card of the Set Up section in the home page") static let newTabSetUpEmailProtectionAction = NSLocalizedString("newTab.setup.email.protection.action", value: "Get a Duck Address", comment: "Action title on the action menu of the Email Protection card of the Set Up section in the home page") static let newTabSetUpRemoveItemAction = NSLocalizedString("newTab.setup.remove.item", value: "Dismiss", comment: "Action title on the action menu of the set up cards card of the SetUp section in the home page to remove the item") - static let newTabSetUpSurveyDay0Action = NSLocalizedString("newTab.setup.survey.day.0.action", value: "Sign Up To Participate", comment: "Action title of the Day 0 survey of the Set Up section in the home page") - static let newTabSetUpSurveyDay14Action = NSLocalizedString("newTab.setup.survey.day.14.action", value: "Sign Up To Participate", comment: "Action title of the Day 14 survey of the Set Up section in the home page") static let newTabSetUpDefaultBrowserSummary = NSLocalizedString("newTab.setup.default.browser.summary", value: "We automatically block trackers as you browse. It's privacy, simplified.", comment: "Summary of the Default Browser card") static let newTabSetUpImportSummary = NSLocalizedString("newTab.setup.import.summary", value: "Import bookmarks, favorites, and passwords from your old browser.", comment: "Summary of the Import card of the Set Up section in the home page") static let newTabSetUpDuckPlayerSummary = NSLocalizedString("newTab.setup.duck.player.summary", value: "Enjoy a clean viewing experience without personalized ads.", comment: "Summary of the Duck Player card of the Set Up section in the home page") static let newTabSetUpEmailProtectionSummary = NSLocalizedString("newTab.setup.email.protection.summary", value: "Generate custom @duck.com addresses that clean trackers from incoming email.", comment: "Summary of the Email Protection card of the Set Up section in the home page") - static let newTabSetUpSurveyDay0Summary = NSLocalizedString("newTab.setup.survey.day.0.summary", value: "Join an interview with a member of our research team to help us build the best browser.", comment: "Summary of the card on the new tab page that invites users to partecipate to a survey") - static let newTabSetUpSurveyDay14Summary = NSLocalizedString("newTab.setup.survey.day.14.summary", value: "Join an interview with a member of our research team to help us build the best browser.", comment: "Summary of the card on the new tab page that invites users to partecipate to a survey") // Recent Activity static let newTabRecentActivitySectionTitle = NSLocalizedString("newTab.recent.activity.section.title", value: "Recent Activity", comment: "Title of the RecentActivity section in the home page") @@ -1024,7 +1083,6 @@ struct UserText { // "tab.dbp.title" - Tab data broker protection title static let tabDataBrokerProtectionTitle = "Personal Information Removal" - // Bookmarks bar prompt static let bookmarksBarPromptTitle = NSLocalizedString("bookmarks.bar.prompt.title", value: "Show Bookmarks Bar?", comment: "Title for bookmarks bar prompt") static let bookmarksBarPromptMessage = NSLocalizedString("bookmarks.bar.prompt.message", value: "Show the Bookmarks Bar for quick access to your new bookmarks.", comment: "Message show for bookmarks bar prompt") @@ -1037,6 +1095,17 @@ struct UserText { static let fireproofCheckboxTitle = NSLocalizedString("fireproof.checkbox.title", value: "Ask to Fireproof websites when signing in", comment: "Fireproof settings checkbox title") static let fireproofExplanation = NSLocalizedString("fireproof.explanation", value: "When you Fireproof a site, cookies won't be erased and you'll stay signed in, even after using the Fire Button.", comment: "Fireproofing mechanism explanation") static let manageFireproofSites = NSLocalizedString("fireproof.manage-sites", value: "Manage Fireproof Sites…", comment: "Fireproof settings button caption") + static let autoClear = NSLocalizedString("auto.clear", value: "Auto-Clear", comment: "Header of a section in Settings. The setting configures clearing data automatically after quitting the app.") + static let automaticallyClearData = NSLocalizedString("automatically.clear.data", value: "Automatically clear tabs and browsing data when DuckDuckGo quits", comment: "Label after the checkbox in Settings which configures clearing data automatically after quitting the app.") + static let warnBeforeQuit = NSLocalizedString("warn.before.quit", value: "Warn me that tabs and data will be cleared when quitting", comment: "Label after the checkbox in Settings which configures a warning before clearing data on the application termination.") + static let warnBeforeQuitDialogHeader = NSLocalizedString("warn.before.quit.dialog.header", value: "Clear tabs and browsing data and quit DuckDuckGo?", comment: "A header of warning before clearing data on the application termination.") + static let warnBeforeQuitDialogCheckboxMessage = NSLocalizedString("warn.before.quit.dialog.checkbox.message", value: "Warn me every time", comment: "A label after checkbox to configure the warning before clearing data on the application termination.") + static let disableAutoClearToEnableSessionRestore = NSLocalizedString("disable.auto.clear.to.enable.session.restore", + value: "Disable auto-clear on quit to turn on session restore.", + comment: "Information label in Settings. It tells user that to enable session restoration setting they have to disable burn on quit. Auto-Clear should match the string with 'auto.clear' key") + static let showDataClearingSettings = NSLocalizedString("show.data.clearing.settings", + value: "Open Data Clearing Settings", + comment: "Button in Settings. It navigates user to Data Clearing Settings. The Data Clearing string should match the string with the preferences.data-clearing key") // MARK: Crash Report static let crashReportTitle = NSLocalizedString("crash-report.title", value: "DuckDuckGo Privacy Browser quit unexpectedly.", comment: "Title of the dialog where the user can send a crash report") @@ -1053,7 +1122,7 @@ struct UserText { static let downloadsOpenWebsiteItem = NSLocalizedString("downloads.open-website.item", value: "Open Originating Website", comment: "Contextual menu item in downloads manager to open the downloaded file originating website") static let downloadsRemoveFromListItem = NSLocalizedString("downloads.remove-from-list.item", value: "Remove from List", comment: "Contextual menu item in downloads manager to remove the given downloaded from the list of downloaded files") static let downloadsStopItem = NSLocalizedString("downloads.stop.item", value: "Stop", comment: "Contextual menu item in downloads manager to stop the download") - static let downloadsRestartItem = NSLocalizedString("downloads.restart.item", value: "Stop", comment: "Contextual menu item in downloads manager to restart the download") + static let downloadsRestartItem = restartDownloadToolTip static let downloadsClearAllItem = NSLocalizedString("downloads.clear-all.item", value: "Clear All", comment: "Contextual menu item in downloads manager to clear all downloaded items from the list") static let downloadsNoRecentDownload = NSLocalizedString("downloads.no-recent-downloads", value: "No recent downloads", comment: "Label in the downloads manager that shows that there are no recently downloaded items") static let downloadsOpenDownloadsFolder = NSLocalizedString("downloads.open-downloads-folder", value: "Open Downloads Folder", comment: "Button in the downloads manager that allows the user to open the downloads folder") @@ -1066,20 +1135,28 @@ struct UserText { static let editBookmark = NSLocalizedString("bookmarks.dialog.title.edit", value: "Edit Bookmark", comment: "Bookmark edit dialog title") static let addFolder = NSLocalizedString("bookmarks.dialog.folder.title.add", value: "Add Folder", comment: "Bookmark folder creation dialog title") static let editFolder = NSLocalizedString("bookmarks.dialog.folder.title.edit", value: "Edit Folder", comment: "Bookmark folder edit dialog title") + static let bookmarkOpenTabs = NSLocalizedString("bookmarks.dialog.allTabs.title.add", value: "Bookmark Open Tabs (%d)", comment: "Title of dialog to bookmark all open tabs. E.g. 'Bookmark Open Tabs (42)'") + } + enum Message { + static let bookmarkOpenTabsEducational = NSLocalizedString("bookmarks.dialog.allTabs.message.add", value: "These bookmarks will be saved in a new folder:", comment: "Bookmark creation for all open tabs dialog title") } enum Field { static let name = NSLocalizedString("bookmarks.dialog.field.name", value: "Name", comment: "Name field label for Bookmark or Folder") static let url = NSLocalizedString("bookmarks.dialog.field.url", value: "URL", comment: "URL field label for Bookmar") static let location = NSLocalizedString("bookmarks.dialog.field.location", value: "Location", comment: "Location field label for Bookmark folder") + static let folderName = NSLocalizedString("bookmarks.dialog.field.folderName", value: "Folder Name", comment: "Folder name field label for Bookmarks folder") + } + enum Value { + static let folderName = NSLocalizedString("bookmarks.dialog.field.folderName.value", value: "%@ - Tabs (%d)", comment: "The suggested name of the folder that will contain the bookmark tabs. Eg. 2024-02-12 - Tabs (42)") } enum Action { static let addBookmark = NSLocalizedString("bookmarks.dialog.action.addBookmark", value: "Add Bookmark", comment: "CTA title for adding a Bookmark") static let addFolder = NSLocalizedString("bookmarks.dialog.action.addFolder", value: "Add Folder", comment: "CTA title for adding a Folder") + static let addAllBookmarks = NSLocalizedString("bookmarks.dialog.action.addAllBookmarks", value: "Save Bookmarks", comment: "CTA title for saving multiple Bookmarks at once") } } } -#if SUBSCRIPTION // Key: "subscription.menu.item" // Comment: "Title for Subscription item in the options menu" static let subscriptionOptionsMenuItem = "Privacy Pro" @@ -1101,5 +1178,5 @@ struct UserText { // Key: "subscription.progress.view.completing.purchase" // Comment: "Progress view title when completing the purchase" static let completingPurchaseTitle = "Completing purchase..." -#endif + } diff --git a/DuckDuckGo/Common/Logging/Logging.swift b/DuckDuckGo/Common/Logging/Logging.swift index de04f91cb7..3740e0e223 100644 --- a/DuckDuckGo/Common/Logging/Logging.swift +++ b/DuckDuckGo/Common/Logging/Logging.swift @@ -140,3 +140,45 @@ func logOrAssertionFailure(_ message: String) { os_log("%{public}s", type: .error, message) #endif } + +#if DEBUG + +func breakByRaisingSigInt(_ description: String, file: StaticString = #file, line: Int = #line) { + let fileLine = "\(("\(file)" as NSString).lastPathComponent):\(line)" + os_log(""" + + + ------------------------------------------------------------------------------------------------------ + BREAK at %s: + ------------------------------------------------------------------------------------------------------ + + %s + + Hit Continue (^⌘Y) to continue program execution + ------------------------------------------------------------------------------------------------------ + + """, type: .debug, fileLine, description.components(separatedBy: "\n").map { " " + $0.trimmingWhitespace() }.joined(separator: "\n")) + raise(SIGINT) +} + +// get symbol from stack trace for a caller of a calling method +func callingSymbol() -> String { + let stackTrace = Thread.callStackSymbols + // find `callingSymbol` itself or dispatch_once_callout + var callingSymbolIdx = stackTrace.firstIndex(where: { $0.contains("_dispatch_once_callout") }) + ?? stackTrace.firstIndex(where: { $0.contains("callingSymbol") })! + // procedure calling `callingSymbol` + callingSymbolIdx += 1 + + var symbolName: String + repeat { + // caller for the procedure + callingSymbolIdx += 1 + let line = stackTrace[callingSymbolIdx].replacingOccurrences(of: Bundle.main.executableURL!.lastPathComponent, with: "DDG") + symbolName = String(line.split(separator: " ", maxSplits: 3)[3]).components(separatedBy: " + ")[0] + } while stackTrace[callingSymbolIdx - 1].contains(symbolName.dropping(suffix: "To")) // skip objc wrappers + + return symbolName +} + +#endif diff --git a/DuckDuckGo/Common/Utilities/CertificateTrustEvaluator.swift b/DuckDuckGo/Common/Utilities/CertificateTrustEvaluator.swift new file mode 100644 index 0000000000..63ea3638cd --- /dev/null +++ b/DuckDuckGo/Common/Utilities/CertificateTrustEvaluator.swift @@ -0,0 +1,32 @@ +// +// CertificateTrustEvaluator.swift +// +// 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 + +protocol CertificateTrustEvaluating { + func evaluateCertificateTrust(trust: SecTrust?) async -> Bool? +} + +struct CertificateTrustEvaluator: CertificateTrustEvaluating { + func evaluateCertificateTrust(trust: SecTrust?) async -> Bool? { + var error: CFError? + guard let trust = trust else { return nil } + let result = SecTrustEvaluateWithError(trust, &error) + return result + } +} diff --git a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift index 3d01e96108..43e1401a2f 100644 --- a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift +++ b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift @@ -55,6 +55,8 @@ public struct UserDefaultsWrapper { case grammarCheckEnabledOnce = "grammar.check.enabled.once" case loginDetectionEnabled = "fireproofing.login-detection-enabled" + case autoClearEnabled = "preferences.auto-clear-enabled" + case warnBeforeClearingEnabled = "preferences.warn-before-clearing-enabled" case gpcEnabled = "preferences.gpc-enabled" case selectedDownloadLocationKey = "preferences.download-location" case lastUsedCustomDownloadLocation = "preferences.custom-last-used-download-location" @@ -78,6 +80,8 @@ public struct UserDefaultsWrapper { case lastCrashReportCheckDate = "last.crash.report.check.date" case fireInfoPresentedOnce = "fire.info.presented.once" + case appTerminationHandledCorrectly = "app.termination.handled.correctly" + case restoreTabsOnStartup = "restore.tabs.on.startup" case restorePreviousSession = "preferences.startup.restore-previous-session" case launchToCustomHomePage = "preferences.startup.launch-to-custom-home-page" @@ -85,6 +89,9 @@ public struct UserDefaultsWrapper { case currentThemeName = "com.duckduckgo.macos.currentThemeNameKey" case showFullURL = "preferences.appearance.show-full-url" case showAutocompleteSuggestions = "preferences.appearance.show-autocomplete-suggestions" + case preferNewTabsToWindows = "preferences.tabs.prefer-new-tabs-to-windows" + case switchToNewTabWhenOpened = "preferences.tabs.switch-to-new-tab-when-opened" + case newTabPosition = "preferences.tabs.new-tab-position" case defaultPageZoom = "preferences.appearance.default-page-zoom" case websitePageZoom = "preferences.appearance.website-page-zoom" case bookmarksBarAppearance = "preferences.appearance.bookmarks-bar" @@ -112,11 +119,8 @@ public struct UserDefaultsWrapper { case homePageShowImport = "home.page.show.import" case homePageShowDuckPlayer = "home.page.show.duck.player" case homePageShowEmailProtection = "home.page.show.email.protection" - case homePageShowSurveyDay0 = "home.page.show.survey.0" - case homePageShowSurveyDay0in10Percent = "home.page.show.survey.0.in.10.pervent" - case homePageShowSurveyDay14in10Percent = "home.page.show.survey.0.in.14.pervent" - case homePageUserInteractedWithSurveyDay0 = "home.page.user.interacted.with.survey.0" - case homePageShowSurveyDay14 = "home.page.show.survey.14" + case homePageUserInSurveyShare = "home.page.user.in.survey.share" + case homePageShowPermanentSurvey = "home.page.show.import.permanent.survey" case homePageShowPageTitles = "home.page.show.page.titles" case homePageShowRecentlyVisited = "home.page.show.recently.visited" case homePageContinueSetUpImport = "home.page.continue.set.up.import" diff --git a/DuckDuckGo/Common/View/AppKit/CircularProgressView.swift b/DuckDuckGo/Common/View/AppKit/CircularProgressView.swift index 204d950546..3e1190a9e9 100644 --- a/DuckDuckGo/Common/View/AppKit/CircularProgressView.swift +++ b/DuckDuckGo/Common/View/AppKit/CircularProgressView.swift @@ -164,6 +164,14 @@ final class CircularProgressView: NSView { guard !isBackgroundAnimating || !animated else { // will call `updateProgressState` on animation completion completion(false) + // if background animation is in progress but 1.0 was received before + // the `progress = nil` update – complete the progress animation + // before hiding + if progress == nil && oldValue == 1.0, animated, + // shouldn‘t be already animating to 100% + progressLayer.strokeStart != 0.0 { + updateProgress(from: 0, to: 1, animated: animated) { _ in } + } return } @@ -177,7 +185,7 @@ final class CircularProgressView: NSView { completion(true) } case (true, true): - updateProgress(oldValue: oldValue, animated: animated, completion: completion) + updateProgress(from: oldValue, to: progress, animated: animated, completion: completion) case (false, false): backgroundLayer.removeAllAnimations() progressLayer.removeAllAnimations() @@ -216,17 +224,16 @@ final class CircularProgressView: NSView { } } - private func updateProgress(oldValue: Double?, animated: Bool, completion: @escaping (Bool) -> Void) { + private func updateProgress(from oldValue: Double?, to progress: Double?, animated: Bool, completion: @escaping (Bool) -> Void) { guard let progress else { assertionFailure("Unexpected flow") completion(false) return } - let currentStrokeStart = (progressLayer.presentation() ?? progressLayer).strokeStart + let currentStrokeStart = progressLayer.currentStrokeStart let newStrokeStart = 1.0 - (progress >= 0.0 ? CGFloat(progress) : max(Constants.indeterminateProgressValue, min(0.9, 1.0 - currentStrokeStart))) - guard animated else { progressLayer.strokeStart = newStrokeStart @@ -274,7 +281,7 @@ final class CircularProgressView: NSView { guard let progress, progress == value else { return } if let oldValue, oldValue < 0, value != progress, animated { - updateProgress(oldValue: value, animated: animated) { _ in } + updateProgress(from: value, to: progress, animated: animated) { _ in } return } @@ -356,7 +363,7 @@ final class CircularProgressView: NSView { progressLayer.add(progressEndAnimation, forKey: #keyPath(CAShapeLayer.strokeEnd)) let progressAnimation = CABasicAnimation(keyPath: #keyPath(CAShapeLayer.strokeStart)) - let currentStrokeStart = (progressLayer.presentation() ?? progressLayer).strokeStart + let currentStrokeStart = progressLayer.currentStrokeStart progressLayer.removeAnimation(forKey: #keyPath(CAShapeLayer.strokeStart)) progressLayer.strokeStart = 0.0 @@ -375,6 +382,14 @@ final class CircularProgressView: NSView { private extension CAShapeLayer { + var currentStrokeStart: CGFloat { + if animation(forKey: #keyPath(CAShapeLayer.strokeStart)) != nil, + let presentation = self.presentation() { + return presentation.strokeStart + } + return strokeStart + } + func configureCircle(radius: CGFloat, lineWidth: CGFloat) { self.bounds = CGRect(x: 0, y: 0, width: (radius + lineWidth) * 2, height: (radius + lineWidth) * 2) @@ -530,14 +545,97 @@ struct CircularProgress: NSViewRepresentable { perform { progress = 1 } - perform { - progress = nil + Task { + perform { + progress = nil + } } } } label: { Text(verbatim: "0->1->nil").frame(width: 120) } + Button { + Task { + progress = nil + perform { + progress = 1 + } + Task { + perform { + progress = nil + } + } + } + } label: { + Text(verbatim: "nil->1->nil").frame(width: 120) + } + + Button { + Task { + progress = nil + perform { + progress = 1 + } + Task { + perform { + progress = nil + } + Task { + perform { + progress = 1 + } + Task { + perform { + progress = nil + } + } + } + } + } + } label: { + Text(verbatim: "nil->1->nil->1->nil").frame(width: 120) + } + + Button { + Task { + progress = nil + perform { + progress = 1 + } + Task { + perform { + progress = nil + } + Task { + perform { + progress = nil + } + } + } + } + } label: { + Text(verbatim: "nil->1->nil->nil").frame(width: 120) + } + + Button { + Task { + progress = nil + perform { + progress = 0 + } + try await Task.sleep(interval: 0.2) + for p in [0.26, 0.64, 0.95, 1, nil] { + perform { + progress = p + } + try await Task.sleep(interval: 0.001) + } + } + } label: { + Text(verbatim: "nil->0.2…1->nil").frame(width: 120) + } + Button { Task { perform { @@ -581,7 +679,7 @@ struct CircularProgress: NSViewRepresentable { .background(Color.white) Spacer() } - }.frame(width: 600, height: 400) + }.frame(width: 600, height: 500) } } return ProgressPreview() diff --git a/DuckDuckGo/Common/View/AppKit/LoadingProgressView.swift b/DuckDuckGo/Common/View/AppKit/LoadingProgressView.swift index 56f6b2de2b..9c444e511b 100644 --- a/DuckDuckGo/Common/View/AppKit/LoadingProgressView.swift +++ b/DuckDuckGo/Common/View/AppKit/LoadingProgressView.swift @@ -31,7 +31,7 @@ final class LoadingProgressView: NSView, CAAnimationDelegate { private var targetProgress: Double = 0.0 private var targetTime: CFTimeInterval = 0.0 - var isShown: Bool { + var isProgressShown: Bool { progressMask.opacity == 1.0 } diff --git a/DuckDuckGo/Common/View/AppKit/PreviewViewController.swift b/DuckDuckGo/Common/View/AppKit/PreviewViewController.swift new file mode 100644 index 0000000000..d62feef70b --- /dev/null +++ b/DuckDuckGo/Common/View/AppKit/PreviewViewController.swift @@ -0,0 +1,77 @@ +// +// PreviewViewController.swift +// +// 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 AppKit + +@resultBuilder +struct NSViewBuilder { + static func buildBlock(_ component: NSView) -> NSView { + return component + } +} + +#if DEBUG +/// Used to preview an NSView using Xcode #Preview macro +/// Usage: +/// ``` +/// @available(macOS 14.0, *) +/// #Preview { +/// PreviewViewController(showWindowTitle: false /*hide preview window title*/, adjustWindowFrame: true /*set the window size to the view size*/) { +/// MyNSView() +/// } +/// } +/// ``` +@available(macOS 14.0, *) +final class PreviewViewController: NSViewController { + let showWindowTitle: Bool + let adjustWindowFrame: Bool + + init(showWindowTitle: Bool = true, adjustWindowFrame: Bool = false, @NSViewBuilder builder: () -> NSView) { + self.showWindowTitle = showWindowTitle + self.adjustWindowFrame = adjustWindowFrame + super.init(nibName: nil, bundle: nil) + self.view = builder() + } + + required init?(coder: NSCoder) { + fatalError("\(Self.self): Bad initializer") + } + + override func viewDidAppear() { + guard let window = view.window else { return } + if !showWindowTitle { + window.titlebarAppearsTransparent = true + window.titleVisibility = .hidden + window.styleMask = [] + } + if adjustWindowFrame { + window.setFrame(NSRect(origin: .zero, size: view.bounds.size), display: true) + } + } + +} +#else +final class PreviewViewController: NSViewController { + init(showWindowTitle: Bool = true, adjustWindowFrame: Bool = false, @NSViewBuilder builder: () -> NSView) { + fatalError("only for DEBUG") + } + required init?(coder: NSCoder) { + fatalError("only for DEBUG") + } +} +#endif diff --git a/DuckDuckGo/Common/View/SwiftUI/SecureTextField.swift b/DuckDuckGo/Common/View/SwiftUI/SecureTextField.swift new file mode 100644 index 0000000000..c1359c8ce6 --- /dev/null +++ b/DuckDuckGo/Common/View/SwiftUI/SecureTextField.swift @@ -0,0 +1,90 @@ +// +// SecureTextField.swift +// +// 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 + +/// View which uses the provided `isVisible` property to display either a `TextField` or a `SecureField` +struct SecureTextField: View { + + @Binding var textValue: String + let isVisible: Bool + var bottomPadding: CGFloat = 0 + + var body: some View { + if isVisible { + + TextField("", text: $textValue) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .padding(.bottom, bottomPadding) + } else { + + SecureField("", text: $textValue) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .padding(.bottom, bottomPadding) + } + } +} + +/// View which provides a Button styled to show/hide text with an action that toggles the provided `isVisible` property +struct SecureTextFieldButton: View { + + @Binding var isVisible: Bool + let toolTipHideText: String + let toolTipShowText: String + + var body: some View { + Button { + isVisible = !isVisible + } label: { + Image(.secureEyeToggle) + } + .buttonStyle(PlainButtonStyle()) + .tooltip(isVisible ? toolTipHideText : toolTipShowText) + } +} + +/// View which uses the provided `isVisible` property to display either the provided `text` or a string of `•` +struct HiddenText: View { + + let isVisible: Bool + let text: String + let hiddenTextLength: Int + + var body: some View { + if isVisible { + Text(text) + } else { + Text(text.isEmpty ? "" : String(repeating: "•", count: hiddenTextLength)) + } + } +} + +/// View which provides a Button styled to copy text which executes the provided `copyAction` +struct CopyButton: View { + + let copyAction: () -> Void + + var body: some View { + Button { + copyAction() + } label: { + Image(.copy) + } + .buttonStyle(PlainButtonStyle()) + } +} diff --git a/DuckDuckGo/Configuration/ConfigurationManager.swift b/DuckDuckGo/Configuration/ConfigurationManager.swift index a64673dfc0..531fbe4985 100644 --- a/DuckDuckGo/Configuration/ConfigurationManager.swift +++ b/DuckDuckGo/Configuration/ConfigurationManager.swift @@ -22,6 +22,7 @@ import BrowserServicesKit import Configuration import Common import Networking +import PixelKit @MainActor final class ConfigurationManager { @@ -72,13 +73,13 @@ final class ConfigurationManager { eventMapping: Self.configurationDebugEvents) private static let configurationDebugEvents = EventMapping { event, error, _, _ in - let domainEvent: Pixel.Event.Debug + let domainEvent: GeneralPixel switch event { case .invalidPayload(let configuration): domainEvent = .invalidPayload(configuration) } - Pixel.fire(.debug(event: domainEvent, error: error)) + PixelKit.fire(DebugEvent(domainEvent, error: error)) } func start() { @@ -170,7 +171,7 @@ final class ConfigurationManager { } os_log("Failed to complete configuration update %@", log: .config, type: .error, error.localizedDescription) - Pixel.fire(.debug(event: .configurationFetchError, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.configurationFetchError(error: error))) tryAgainSoon() } diff --git a/DuckDuckGo/Configuration/ConfigurationStore.swift b/DuckDuckGo/Configuration/ConfigurationStore.swift index 179e5addd7..fe58ca3df2 100644 --- a/DuckDuckGo/Configuration/ConfigurationStore.swift +++ b/DuckDuckGo/Configuration/ConfigurationStore.swift @@ -19,6 +19,7 @@ import Common import Foundation import Configuration +import PixelKit final class ConfigurationStore: ConfigurationStoring { @@ -99,7 +100,7 @@ final class ConfigurationStore: ConfigurationStoring { let nserror = error as NSError if nserror.domain != NSCocoaErrorDomain || nserror.code != NSFileReadNoSuchFileError { - Pixel.fire(.debug(event: .trackerDataCouldNotBeLoaded, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.trackerDataCouldNotBeLoaded, error: error)) } return nil diff --git a/DuckDuckGo/ContentBlocker/AppPrivacyConfigurationDataProvider.swift b/DuckDuckGo/ContentBlocker/AppPrivacyConfigurationDataProvider.swift index 07639c0bb4..224457323d 100644 --- a/DuckDuckGo/ContentBlocker/AppPrivacyConfigurationDataProvider.swift +++ b/DuckDuckGo/ContentBlocker/AppPrivacyConfigurationDataProvider.swift @@ -22,8 +22,8 @@ import BrowserServicesKit final class AppPrivacyConfigurationDataProvider: EmbeddedDataProvider { public struct Constants { - public static let embeddedDataETag = "\"8838582254dfa215a99ea4d38e04cd20\"" - public static let embeddedDataSHA = "4851da5558dde2ec548d4e6ca4778e2040ad97c7edecf701de0e8ec907cb42bb" + public static let embeddedDataETag = "\"6cbc7738304e5eaef20e98417f412fc9\"" + public static let embeddedDataSHA = "0fda36c6cb3a0f2bcd34562ad9d4bc8fe7dc2d21e029b87e323cb4992bfddb01" } var embeddedDataEtag: String { diff --git a/DuckDuckGo/ContentBlocker/AppTrackerDataSetProvider.swift b/DuckDuckGo/ContentBlocker/AppTrackerDataSetProvider.swift index 12d6d8fbbd..a182f36fd5 100644 --- a/DuckDuckGo/ContentBlocker/AppTrackerDataSetProvider.swift +++ b/DuckDuckGo/ContentBlocker/AppTrackerDataSetProvider.swift @@ -22,8 +22,8 @@ import BrowserServicesKit final class AppTrackerDataSetProvider: EmbeddedDataProvider { public struct Constants { - public static let embeddedDataETag = "\"07bd7f610e3fa234856abcc2b56ab10e\"" - public static let embeddedDataSHA = "1d7ef8f4c5a717a5d82f43383e33290021358d6255db12b6fdd0928e28d123ee" + public static let embeddedDataETag = "\"ef8ebcc98d8abccca793c7e04422b160\"" + public static let embeddedDataSHA = "e2e8e5e191df54227222fbb0545a7eb8634b1156a69182323981bb6aed2c639d" } var embeddedDataEtag: String { diff --git a/DuckDuckGo/ContentBlocker/ContentBlocking.swift b/DuckDuckGo/ContentBlocker/ContentBlocking.swift index 795f5ec581..d935081755 100644 --- a/DuckDuckGo/ContentBlocker/ContentBlocking.swift +++ b/DuckDuckGo/ContentBlocker/ContentBlocking.swift @@ -21,6 +21,7 @@ import WebKit import Combine import BrowserServicesKit import Common +import PixelKit protocol ContentBlockingProtocol { @@ -98,18 +99,18 @@ final class AppContentBlocking { } private let toggleProtectionsEvents = EventMapping { event, _, parameters, _ in - let domainEvent: Pixel.Event + let domainEvent: GeneralPixel switch event { case .toggleProtectionsCounterDaily: domainEvent = .toggleProtectionsDailyCount } - Pixel.fire(domainEvent, withAdditionalParameters: parameters ?? [:]) + PixelKit.fire(domainEvent, withAdditionalParameters: parameters ?? [:]) } private static let debugEvents = EventMapping { event, error, parameters, onComplete in guard NSApp.runType.requiresEnvironment else { return } - let domainEvent: Pixel.Event.Debug + let domainEvent: GeneralPixel switch event { case .trackerDataParseFailed: domainEvent = .trackerDataParseFailed @@ -132,7 +133,7 @@ final class AppContentBlocking { case .contentBlockingCompilationFailed(let listName, let component): let defaultTDSListName = DefaultContentBlockerRulesListsSource.Constants.trackerDataSetRulesListName - let listType: Pixel.Event.CompileRulesListType + let listType: GeneralPixel.CompileRulesListType switch listName { case defaultTDSListName: listType = .tds @@ -154,13 +155,15 @@ final class AppContentBlocking { return } - Pixel.fire(.debug(event: domainEvent, error: error), withAdditionalParameters: parameters, onComplete: onComplete) + PixelKit.fire(DebugEvent(domainEvent, error: error), withAdditionalParameters: parameters) { _, error in + onComplete(error) + } } // MARK: - Ad Click Attribution let attributionEvents: EventMapping? = .init { event, _, parameters, _ in - let domainEvent: Pixel.Event + let domainEvent: GeneralPixel switch event { case .adAttributionDetected: domainEvent = .adClickAttributionDetected @@ -170,11 +173,11 @@ final class AppContentBlocking { domainEvent = .adClickAttributionPageLoads } - Pixel.fire(domainEvent, withAdditionalParameters: parameters ?? [:]) + PixelKit.fire(domainEvent, withAdditionalParameters: parameters ?? [:]) } let attributionDebugEvents: EventMapping? = .init { event, _, _, _ in - let domainEvent: Pixel.Event.Debug + let domainEvent: GeneralPixel switch event { case .adAttributionCompilationFailedForAttributedRulesList: domainEvent = .adAttributionCompilationFailedForAttributedRulesList @@ -198,8 +201,7 @@ final class AppContentBlocking { domainEvent = .adAttributionLogicWrongVendorOnFailedCompilation } - Pixel.fire(.debug(event: domainEvent, error: nil), - includeAppVersionParameter: false) + PixelKit.fire(DebugEvent(domainEvent), includeAppVersionParameter: false) } } diff --git a/DuckDuckGo/ContentBlocker/Mocks/MockPrivacyConfiguration.swift b/DuckDuckGo/ContentBlocker/Mocks/MockPrivacyConfiguration.swift index 60dc35a8e1..d18f6ce82f 100644 --- a/DuckDuckGo/ContentBlocker/Mocks/MockPrivacyConfiguration.swift +++ b/DuckDuckGo/ContentBlocker/Mocks/MockPrivacyConfiguration.swift @@ -61,7 +61,8 @@ final class MockPrivacyConfiguration: PrivacyConfiguration { func isUserUnprotected(domain: String?) -> Bool { false } func isTempUnprotected(domain: String?) -> Bool { false } func isInExceptionList(domain: String?, forFeature featureKey: PrivacyFeature) -> Bool { false } - func settings(for feature: PrivacyFeature) -> PrivacyConfigurationData.PrivacyFeature.FeatureSettings { featureSettings } + func settings(for feature: PrivacyFeature) -> PrivacyConfigurationData.PrivacyFeature.FeatureSettings { + featureSettings } func userEnabledProtection(forDomain: String) {} func userDisabledProtection(forDomain: String) {} } diff --git a/DuckDuckGo/ContentBlocker/macos-config.json b/DuckDuckGo/ContentBlocker/macos-config.json index 4ddf3a01ba..cce44b20c4 100644 --- a/DuckDuckGo/ContentBlocker/macos-config.json +++ b/DuckDuckGo/ContentBlocker/macos-config.json @@ -1,6 +1,6 @@ { "readme": "https://github.com/duckduckgo/privacy-configuration", - "version": 1712071688011, + "version": 1714746648846, "features": { "adClickAttribution": { "readme": "https://help.duckduckgo.com/duckduckgo-help-pages/privacy/web-tracking-protections/#3rd-party-tracker-loading-protection", @@ -74,12 +74,6 @@ { "domain": "thehustle.co" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -111,7 +105,7 @@ ] }, "state": "enabled", - "hash": "51b76aa7b92d78ad52106b04ac809843" + "hash": "16c6e3fb43797e3ca13a9259569a9e4e" }, "androidBrowserConfig": { "exceptions": [], @@ -141,6 +135,9 @@ { "domain": "ksta.de" }, + { + "domain": "larazon.es" + }, { "domain": "motherdenim.com" }, @@ -286,10 +283,19 @@ "domain": "condell-ltd.com" }, { - "domain": "earth.google.com" + "domain": "leefgemeenschapzilt.nl" + }, + { + "domain": "healthline.com" + }, + { + "domain": "sporthoj.com" + }, + { + "domain": "www.michelinman.com" }, { - "domain": "iscorp.com" + "domain": "malmostadsteater.se" }, { "domain": "marvel.com" @@ -302,23 +308,20 @@ "disabledCMPs": [ "generic-cosmetic", "termsfeed3", - "strato.de" + "tarteaucitron.js" ] }, "state": "enabled", - "hash": "98e57a3eb872c9dfb4a019b90dc6c0ec" + "hash": "7096d80d39c6c9a98d98ff6bde5644e0" }, "autofill": { "exceptions": [ { "domain": "roll20.net" - }, - { - "domain": "rumble.com" } ], "state": "enabled", - "hash": "5bb5c0fc0d462da4674e4ca07dbc9363" + "hash": "b1ae580a636957bcbe90d16aa92c40bd" }, "clickToLoad": { "exceptions": [ @@ -922,12 +925,6 @@ { "domain": "pocketbook.digital" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -950,16 +947,10 @@ } }, "state": "disabled", - "hash": "36e8971fa9bb204b78a5929a14a108dd" + "hash": "770f7ae0f752e976764771bccec352b2" }, "clickToPlay": { "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -977,7 +968,7 @@ } }, "state": "enabled", - "hash": "f1b7de266435cd2e414f50deb2c9234a" + "hash": "2cff3d9b2df1ed9375f362848c8ed5f3" }, "clientBrandHint": { "exceptions": [], @@ -1008,12 +999,6 @@ { "domain": "soranews24.com" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -1021,7 +1006,7 @@ "domain": "sundancecatalog.com" } ], - "hash": "e37447d42ee8194f185e35e40f577f41" + "hash": "593797946074a1f304add65e7543b9be" }, "cookie": { "settings": { @@ -1063,12 +1048,6 @@ { "domain": "news.ti.com" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -1077,7 +1056,7 @@ } ], "state": "disabled", - "hash": "37a27966915571085613911b47e6e2eb" + "hash": "7ade754b885238cd191f1a61b4eeb0b6" }, "customUserAgent": { "settings": { @@ -1096,7 +1075,7 @@ "reason": "https://github.com/duckduckgo/privacy-configuration/issues/667" }, { - "domain": "www.canva.com", + "domain": "canva.com", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1818" }, { @@ -1118,6 +1097,10 @@ { "domain": "web.de", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1931" + }, + { + "domain": "id.seb.se", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/2025" } ], "webViewDefault": [ @@ -1136,12 +1119,16 @@ { "domain": "sas.dk", "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1347" + }, + { + "domain": "nationalmssociety.org", + "reason": "https://github.com/duckduckgo/privacy-configuration/issues/1963" } ] }, "exceptions": [], "state": "enabled", - "hash": "7edfa8344fd2577b31426130696d8b23" + "hash": "c52448ca8da413a93de9822cac039920" }, "dbp": { "state": "enabled", @@ -1184,7 +1171,9 @@ "videoElement": "#player video", "videoElementContainer": "#player .html5-video-player", "hoverExcluded": [], - "clickExcluded": [], + "clickExcluded": [ + "ytd-thumbnail-overlay-toggle-button-renderer" + ], "allowedEventTargets": [ ".ytp-inline-preview-scrim", ".ytd-video-preview", @@ -1231,19 +1220,13 @@ ] }, "state": "enabled", - "hash": "ab2c73639ad75b2d6efb18f324230397" + "hash": "b685397a8317384bec3b8d7e8b7571bb" }, "elementHiding": { "exceptions": [ { "domain": "duckduckgo.com" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -1915,6 +1898,14 @@ { "selector": ".proper-dynamic-insertion", "type": "closest-empty" + }, + { + "selector": ".Page-header-leaderboardAd", + "type": "hide-empty" + }, + { + "selector": ".SovrnAd", + "type": "hide-empty" } ] }, @@ -2285,6 +2276,15 @@ } ] }, + { + "domain": "doodle.com", + "rules": [ + { + "selector": "[data-testid*='ads-layout-placement']", + "type": "hide" + } + ] + }, { "domain": "dpreview.com", "rules": [ @@ -2365,6 +2365,23 @@ } ] }, + { + "domain": "eurogamer.net", + "rules": [ + { + "selector": "#sticky_leaderboard", + "type": "hide-empty" + }, + { + "selector": ".primis_wrapper", + "type": "hide" + }, + { + "selector": ".autoad", + "type": "hide-empty" + } + ] + }, { "domain": "examiner.com.au", "rules": [ @@ -2843,6 +2860,27 @@ } ] }, + { + "domain": "independent.co.uk", + "rules": [ + { + "selector": "#partners", + "type": "hide-empty" + }, + { + "selector": "#top-banner-wrapper", + "type": "hide-empty" + }, + { + "selector": "[data-mpu1=true]", + "type": "hide-empty" + }, + { + "selector": "#stickyFooterRoot", + "type": "hide" + } + ] + }, { "domain": "indiatimes.com", "rules": [ @@ -3490,6 +3528,15 @@ } ] }, + { + "domain": "realtor.com", + "rules": [ + { + "selector": ".ads_container", + "type": "hide" + } + ] + }, { "domain": "reddit.com", "rules": [ @@ -4018,6 +4065,15 @@ } ] }, + { + "domain": "woot.com", + "rules": [ + { + "selector": "[data-test-ui*='advertisementLeaderboard']", + "type": "hide-empty" + } + ] + }, { "domain": "wsj.com", "rules": [ @@ -4218,20 +4274,23 @@ "type": "override" } ] + }, + { + "domain": "wideopencountry.com", + "rules": [ + { + "selector": ".entry-ad", + "type": "hide-empty" + } + ] } ] }, "state": "enabled", - "hash": "10545dae34a5b5f2cc26c91976be5809" + "hash": "893bd7422971b3a7b4c6e02cdfc6332d" }, "exceptionHandler": { "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4240,7 +4299,12 @@ } ], "state": "disabled", - "hash": "5e792dd491428702bc0104240fbce0ce" + "hash": "dc1b4fa301193a03ddcd4bdf7ee3e610" + }, + "extendedOnboarding": { + "exceptions": [], + "state": "disabled", + "hash": "728493ef7a1488e4781656d3f9db84aa" }, "fingerprintingAudio": { "state": "disabled", @@ -4248,12 +4312,6 @@ { "domain": "litebluesso.usps.gov" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4261,19 +4319,13 @@ "domain": "sundancecatalog.com" } ], - "hash": "f25a8f2709e865c2bd743828c7ee2f77" + "hash": "2037fcd805ece181cfffc482f262941f" }, "fingerprintingBattery": { "exceptions": [ { "domain": "litebluesso.usps.gov" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4282,7 +4334,7 @@ } ], "state": "disabled", - "hash": "4085f1593faff2feac2093533b819a41" + "hash": "07ee708dc740aab3b1f048d9bb571dac" }, "fingerprintingCanvas": { "settings": { @@ -4373,12 +4425,6 @@ { "domain": "godaddy.com" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4387,7 +4433,7 @@ } ], "state": "disabled", - "hash": "ea4c565bae27996f0d651300d757594c" + "hash": "d48bfb1151476f49970ffd3b1f778bf9" }, "fingerprintingHardware": { "settings": { @@ -4439,12 +4485,6 @@ { "domain": "proton.me" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4486,7 +4526,7 @@ } ], "state": "enabled", - "hash": "37e16df501e3e68416a13f991b4e4147" + "hash": "aefca8e7a9a3d9b65370608dd639cd3f" }, "fingerprintingScreenSize": { "settings": { @@ -4526,12 +4566,6 @@ { "domain": "secureserver.net" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4540,7 +4574,7 @@ } ], "state": "disabled", - "hash": "466b85680f138657de9bfd222c440887" + "hash": "eef4614273c28d50dd298a68ffbac309" }, "fingerprintingTemporaryStorage": { "exceptions": [ @@ -4553,12 +4587,6 @@ { "domain": "tattoogenius.art" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4567,16 +4595,10 @@ } ], "state": "disabled", - "hash": "f858697949c90842c450daee64a1dc30" + "hash": "2746e6cb6c773e80a36fda03618ef930" }, "googleRejected": { "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4585,7 +4607,7 @@ } ], "state": "disabled", - "hash": "5e792dd491428702bc0104240fbce0ce" + "hash": "dc1b4fa301193a03ddcd4bdf7ee3e610" }, "gpc": { "state": "enabled", @@ -4602,6 +4624,9 @@ { "domain": "crunchyroll.com" }, + { + "domain": "espn.com" + }, { "domain": "eventbrite.com" }, @@ -4620,12 +4645,6 @@ { "domain": "tirerack.com" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4642,7 +4661,7 @@ "privacy-test-pages.site" ] }, - "hash": "1a1373bcf16647d63220659fce650a83" + "hash": "05bddff3ae61a9536e38a6ef7d383eb3" }, "harmfulApis": { "settings": { @@ -4744,12 +4763,6 @@ "domains": [] }, "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4758,7 +4771,7 @@ } ], "state": "disabled", - "hash": "44d3e707cba3ee0a3578f52dc2ce2aa4" + "hash": "f29eae11500edcda80aa8b32b12869eb" }, "history": { "state": "disabled", @@ -4777,12 +4790,6 @@ { "domain": "jp.square-enix.com" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4790,7 +4797,7 @@ "domain": "sundancecatalog.com" } ], - "hash": "f772808ed34cc9ea8cbcbb7cdaf74429" + "hash": "ea2c4fc84f27eb3694acd9ccf1023e95" }, "incontextSignup": { "exceptions": [], @@ -4827,12 +4834,6 @@ }, "navigatorInterface": { "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4848,7 +4849,7 @@ ] }, "state": "enabled", - "hash": "698de7b963d7d7942c5c5d1e986bb1b1" + "hash": "bb2ed420e76ecaf31a1f99decd370e55" }, "networkProtection": { "state": "enabled", @@ -4893,23 +4894,25 @@ "exceptions": [], "state": "enabled", "settings": { - "surveyCardDay0": "enabled", + "surveyCardDay0": "disabled", "surveyCardDay7": "disabled", - "surveyCardDay14": "enabled" + "surveyCardDay14": "disabled", + "permanentSurvey": { + "state": "enabled", + "localization": "disabled", + "url": "https://selfserve.decipherinc.com/survey/selfserve/32ab/240404?list=2", + "firstDay": 5, + "lastDay": 8, + "sharePercentage": 60 + } }, - "hash": "eb826d9079211f30d624211f44aed184" + "hash": "8a5c9011216219c6576ec362acb51fd0" }, "nonTracking3pCookies": { "settings": { "excludedCookieDomains": [] }, "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4918,17 +4921,11 @@ } ], "state": "disabled", - "hash": "841fa92b9728c9754f050662678f82c7" + "hash": "522e3e42e2612ac2811342d3f6754c5a" }, "performanceMetrics": { "state": "enabled", "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -4936,7 +4933,7 @@ "domain": "sundancecatalog.com" } ], - "hash": "38558d5e7b231d4b27e7dd76814387a7" + "hash": "936f00970c108fd646f73d00b3f3f5b5" }, "privacyDashboard": { "exceptions": [], @@ -4948,25 +4945,38 @@ } }, "toggleReports": { - "state": "enabled", - "rollout": { - "steps": [ - { - "percent": 5 - } - ] - } + "state": "enabled" } }, "state": "enabled", - "hash": "f7cce63c16c142db4ff5764b542a6c52" + "hash": "66968d9b69520975185476473cc11824" }, "privacyPro": { "state": "enabled", "exceptions": [], "features": { "isLaunched": { - "state": "disabled" + "state": "enabled", + "rollout": { + "steps": [ + { + "percent": 1 + }, + { + "percent": 10 + }, + { + "percent": 30 + }, + { + "percent": 50 + }, + { + "percent": 100 + } + ] + }, + "minSupportedVersion": "1.82.1" }, "isLaunchedOverride": { "state": "disabled" @@ -4975,13 +4985,33 @@ "state": "enabled" }, "isLaunchedStripe": { - "state": "disabled" + "state": "enabled", + "rollout": { + "steps": [ + { + "percent": 1 + }, + { + "percent": 10 + }, + { + "percent": 30 + }, + { + "percent": 50 + }, + { + "percent": 100 + } + ] + }, + "minSupportedVersion": "1.82.1" }, "allowPurchaseStripe": { "state": "enabled" } }, - "hash": "c9153c5cc3b6b7eba024c6c597e15edb" + "hash": "1a10a68ea8885db0d1d9bab371c0f738" }, "privacyProtectionsPopup": { "state": "disabled", @@ -5008,12 +5038,6 @@ { "domain": "xcelenergy.com" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -5022,17 +5046,11 @@ } ], "state": "disabled", - "hash": "0d3df0f7c24ebde89d2dced4e2d34322" + "hash": "1cfe449de8a4fcb542757383d846c031" }, "requestFilterer": { "state": "disabled", "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -5043,17 +5061,11 @@ "settings": { "windowInMs": 0 }, - "hash": "0fff8017d8ea4b5609b8f5c110be1401" + "hash": "3218faa098a2e9da61447fb63e3a5ed9" }, "runtimeChecks": { "state": "disabled", "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -5062,16 +5074,10 @@ } ], "settings": {}, - "hash": "800a19533c728bbec7e31e466f898268" + "hash": "ddb64344aa42e9593964f14b6de3d6df" }, "serviceworkerInitiatedRequests": { "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -5080,7 +5086,17 @@ } ], "state": "disabled", - "hash": "5e792dd491428702bc0104240fbce0ce" + "hash": "dc1b4fa301193a03ddcd4bdf7ee3e610" + }, + "sslCertificates": { + "state": "enabled", + "exceptions": [], + "features": { + "allowBypass": { + "state": "enabled" + } + }, + "hash": "abe9584048f7f8157f71a14e7914cb1c" }, "sync": { "state": "enabled", @@ -5256,7 +5272,8 @@ { "rule": "static.adsafeprotected.com/iasPET.1.js", "domains": [ - "corriere.it" + "corriere.it", + "independent.co.uk" ] }, { @@ -5366,6 +5383,7 @@ "fattoincasadabenedetta.it", "inquirer.com", "thesurfersview.com", + "twitchy.com", "wildrivers.lostcoastoutpost.com" ] }, @@ -5526,6 +5544,12 @@ }, "boldapps.net": { "rules": [ + { + "rule": "mc.boldapps.net/install_assets/bold.multicurrency.js", + "domains": [ + "" + ] + }, { "rule": "option.boldapps.net/js/options.js", "domains": [ @@ -5826,6 +5850,16 @@ } ] }, + "curalate.com": { + "rules": [ + { + "rule": "edge.curalate.com/sites/", + "domains": [ + "" + ] + } + ] + }, "cxense.com": { "rules": [ { @@ -5989,6 +6023,18 @@ "sbs.com.au" ] }, + { + "rule": "https://googleads.g.doubleclick.net/ads/preferences/naioptout", + "domains": [ + "zojirushi.com" + ] + }, + { + "rule": "www3.doubleclick.net", + "domains": [ + "scrolller.com" + ] + }, { "rule": "doubleclick.net", "domains": [ @@ -6012,11 +6058,7 @@ { "rule": "cdn.dynamicyield.com/api/", "domains": [ - "asics.com", - "brooklinen.com", - "carters.com", - "otterbox.com", - "seatosummit.com" + "" ] } ] @@ -6145,6 +6187,24 @@ }, "facebook.com": { "rules": [ + { + "rule": "facebook.com/plugins/customer_chat/", + "domains": [ + "danibowman.com" + ] + }, + { + "rule": "facebook.com/v6.0/plugins/customer_chat/", + "domains": [ + "danibowman.com" + ] + }, + { + "rule": "facebook.com/v6.0/plugins/customerchat.php", + "domains": [ + "danibowman.com" + ] + }, { "rule": "facebook.com", "domains": [ @@ -6170,6 +6230,12 @@ "nordicwellness.se" ] }, + { + "rule": "connect.facebook.net/en_US/sdk/xfbml.customerchat.js", + "domains": [ + "danibowman.com" + ] + }, { "rule": "connect.facebook.net/en_UK/sdk.js", "domains": [ @@ -6421,6 +6487,12 @@ "domains": [ "" ] + }, + { + "rule": "marketingplatform.google.com/about/enterprise", + "domains": [ + "scrolller.com" + ] } ] }, @@ -6429,19 +6501,7 @@ { "rule": "imasdk.googleapis.com/js/sdkloader/ima3.js", "domains": [ - "arkadium.com", - "bloomberg.com", - "cbssports.com", - "crunchyroll.com", - "gamak.tv", - "games.washingtonpost.com", - "metro.co.uk", - "nfl.com", - "pandora.com", - "paper-io.com", - "rawstory.com", - "usatoday.com", - "washingtonpost.com" + "" ] } ] @@ -6466,6 +6526,7 @@ "daotranslate.com", "drakescans.com", "duden.de", + "edealinfo.com", "freetubetv.net", "hscprojects.com", "kits4beats.com", @@ -6694,6 +6755,16 @@ } ] }, + "grow.me": { + "rules": [ + { + "rule": "grow.me/main.js", + "domains": [ + "budgetbytes.com" + ] + } + ] + }, "gstatic.com": { "rules": [ { @@ -6733,6 +6804,12 @@ "domains": [ "" ] + }, + { + "rule": "api.hubspot.com/livechat-public/v1/message/public", + "domains": [ + "" + ] } ] }, @@ -6920,6 +6997,7 @@ { "rule": "a.klaviyo.com/media/js/onsite/onsite.js", "domains": [ + "bonescoffee.com", "tanglefree.com" ] }, @@ -6928,7 +7006,8 @@ "domains": [ "andieswim.com", "footweartruth.com", - "kmail-lists.com" + "kmail-lists.com", + "usafacts.org" ] } ] @@ -6959,6 +7038,16 @@ } ] }, + "litix.io": { + "rules": [ + { + "rule": "src.litix.io/videojs/", + "domains": [ + "" + ] + } + ] + }, "loggly.com": { "rules": [ { @@ -7121,7 +7210,7 @@ { "rule": "connect.nosto.com/script/shopify/nosto.js", "domains": [ - "oneill.com" + "" ] } ] @@ -7131,7 +7220,8 @@ { "rule": "npttech.com/advertising.js", "domains": [ - "blick.ch" + "blick.ch", + "independent.co.uk" ] } ] @@ -7170,6 +7260,12 @@ "cigna.com" ] }, + { + "rule": "altriagroupinc.tt.omtrdc.net/rest/v1/delivery", + "domains": [ + "marlboro.com" + ] + }, { "rule": "omtrdc.net", "domains": [ @@ -7216,6 +7312,7 @@ "abc.net.au", "emol.com", "oufc.co.uk", + "the-afc.com", "theposh.com" ] } @@ -7234,6 +7331,12 @@ "domains": [ "hgtv.com" ] + }, + { + "rule": "https://cdn.optimizely.com/js/271989291.js", + "domains": [ + "my.zipcar.com" + ] } ] }, @@ -7318,10 +7421,23 @@ "primis.tech": { "rules": [ { - "rule": "live.primis.tech/live/liveView.php", + "rule": "video.primis.tech/", + "domains": [ + "wideopencountry.com" + ] + }, + { + "rule": "live.primis.tech/content/omid/static/", + "domains": [ + "wideopencountry.com" + ] + }, + { + "rule": "live.primis.tech/live/", "domains": [ "belfastlive.co.uk", - "cornwalllive.com" + "cornwalllive.com", + "wideopencountry.com" ] } ] @@ -7697,6 +7813,16 @@ } ] }, + "skimresources.com": { + "rules": [ + { + "rule": "go.skimresources.com/", + "domains": [ + "www.lotustalk.com" + ] + } + ] + }, "slickstream.com": { "rules": [ { @@ -7777,6 +7903,16 @@ } ] }, + "sundaysky.com": { + "rules": [ + { + "rule": "sundaysky.com", + "domains": [ + "bankofamerica.com" + ] + } + ] + }, "taboola.com": { "rules": [ { @@ -7930,6 +8066,12 @@ "domains": [ "winnipegfreepress.com" ] + }, + { + "rule": "platform.twitter.com/_next/static", + "domains": [ + "" + ] } ] }, @@ -8196,12 +8338,6 @@ } }, "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -8209,7 +8345,7 @@ "domain": "sundancecatalog.com" } ], - "hash": "adf596be88e8975a3cdcaaef3d24990d" + "hash": "8abdf819c66bc3e2391e900958ed0294" }, "trackingCookies1p": { "settings": { @@ -8219,12 +8355,6 @@ } }, "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -8233,19 +8363,13 @@ } ], "state": "disabled", - "hash": "4dddf681372a2aea9788090b13db6e6f" + "hash": "dab51f5ad2454727f8bc474cdd3da65b" }, "trackingCookies3p": { "settings": { "excludedCookieDomains": [] }, "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -8254,19 +8378,13 @@ } ], "state": "disabled", - "hash": "841fa92b9728c9754f050662678f82c7" + "hash": "522e3e42e2612ac2811342d3f6754c5a" }, "trackingParameters": { "exceptions": [ { "domain": "axs.com" }, - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -8305,19 +8423,13 @@ }, "state": "enabled", "minSupportedVersion": "0.22.3", - "hash": "9a0282376084874f0245c421d6943841" + "hash": "44005192b6dba245e95de042fc224228" }, "userAgentRotation": { "settings": { "agentExcludePatterns": [] }, "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -8326,7 +8438,7 @@ } ], "state": "disabled", - "hash": "f65d10dfdf6739feab99a08d42734747" + "hash": "e30277704ddbf20c14136baab08519c5" }, "voiceSearch": { "exceptions": [], @@ -8335,12 +8447,6 @@ }, "webCompat": { "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -8609,7 +8715,7 @@ } ] }, - "hash": "151d7ee40451c4aac4badfcc829ea0b5" + "hash": "90687b1a5ac7aec8bf26f24a75cd883f" }, "windowsPermissionUsage": { "exceptions": [], @@ -8618,12 +8724,6 @@ }, "windowsStartupBoost": { "exceptions": [ - { - "domain": "earth.google.com" - }, - { - "domain": "iscorp.com" - }, { "domain": "marvel.com" }, @@ -8632,7 +8732,7 @@ } ], "state": "disabled", - "hash": "5e792dd491428702bc0104240fbce0ce" + "hash": "dc1b4fa301193a03ddcd4bdf7ee3e610" }, "windowsWaitlist": { "exceptions": [], diff --git a/DuckDuckGo/ContentBlocker/trackerData.json b/DuckDuckGo/ContentBlocker/trackerData.json index 647e15dbb6..f7618c909f 100644 --- a/DuckDuckGo/ContentBlocker/trackerData.json +++ b/DuckDuckGo/ContentBlocker/trackerData.json @@ -1,7 +1,7 @@ { "_builtWith": { - "tracker-radar": "09133e827d9dcbba9465c87efdf0229ddd910d3e867f8ccd5efc31abd7073963-4013b4e91930c643394cb31c6c745356f133b04f", - "tracker-surrogates": "ba0d8cefe4432723ec75b998241efd2454dff35a" + "tracker-radar": "74dd9601901673a7c0f87e609695b5a0e31b808adabd62e6db6ed7c99bde966d-4013b4e91930c643394cb31c6c745356f133b04f", + "tracker-surrogates": "0528e3226df15b1a3e319ad68ef76612a8f26623" }, "readme": "https://github.com/duckduckgo/tracker-blocklists", "trackers": { @@ -464,7 +464,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -475,7 +475,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -521,7 +521,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -2409,7 +2409,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -2420,7 +2420,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -2464,7 +2464,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -2475,7 +2475,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -2590,7 +2590,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -2724,7 +2724,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -2735,7 +2735,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3054,7 +3054,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3181,7 +3181,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3305,7 +3305,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3689,7 +3689,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3700,7 +3700,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3711,7 +3711,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3722,7 +3722,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3788,7 +3788,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3840,7 +3840,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3851,7 +3851,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -3988,7 +3988,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -4339,7 +4339,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -4374,7 +4374,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -4820,7 +4820,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -4831,7 +4831,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5033,7 +5033,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5075,7 +5075,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5098,7 +5098,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5133,7 +5133,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5162,7 +5162,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5450,7 +5450,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5567,7 +5567,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5578,7 +5578,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5589,7 +5589,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5600,7 +5600,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5637,7 +5637,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -5692,7 +5692,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -6228,7 +6228,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -6382,7 +6382,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -6698,7 +6698,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -6709,7 +6709,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -6829,7 +6829,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7025,7 +7025,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7061,7 +7061,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7072,7 +7072,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7083,7 +7083,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7666,7 +7666,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7677,7 +7677,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7688,7 +7688,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7769,7 +7769,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7892,7 +7892,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7903,7 +7903,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7981,7 +7981,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -7992,7 +7992,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -8107,7 +8107,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -8258,7 +8258,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -8269,7 +8269,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -8760,7 +8760,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -8771,7 +8771,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -8812,7 +8812,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -9228,7 +9228,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -9833,7 +9833,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -9844,7 +9844,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -9855,7 +9855,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -9895,7 +9895,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -9937,7 +9937,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -9991,7 +9991,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10059,7 +10059,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10070,7 +10070,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10118,7 +10118,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10244,7 +10244,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10404,7 +10404,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10415,7 +10415,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10426,7 +10426,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10453,7 +10453,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10503,7 +10503,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -10550,7 +10550,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -11028,7 +11028,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -11068,7 +11068,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -11804,7 +11804,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -11893,7 +11893,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -11904,7 +11904,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -12126,7 +12126,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -12166,7 +12166,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -12177,7 +12177,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -12188,7 +12188,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -12199,7 +12199,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -12525,7 +12525,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -12536,7 +12536,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -12547,7 +12547,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -14455,7 +14455,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -15140,7 +15140,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -15215,7 +15215,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -15266,7 +15266,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -16125,7 +16125,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -16136,7 +16136,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -16165,7 +16165,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -16384,7 +16384,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -16693,7 +16693,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -16704,7 +16704,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -16889,7 +16889,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -16938,7 +16938,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -17212,7 +17212,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -17223,7 +17223,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -17786,7 +17786,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -18134,7 +18134,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -18273,7 +18273,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -18632,7 +18632,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -18843,7 +18843,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -20020,7 +20020,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -20241,7 +20241,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -20252,7 +20252,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -20263,7 +20263,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -20403,7 +20403,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -20890,7 +20890,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -20919,7 +20919,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -20930,7 +20930,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -20941,7 +20941,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21005,7 +21005,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21085,7 +21085,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21133,7 +21133,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21144,7 +21144,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21184,7 +21184,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21195,7 +21195,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21230,7 +21230,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21241,7 +21241,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21374,7 +21374,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21458,7 +21458,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21929,7 +21929,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21940,7 +21940,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -21951,7 +21951,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22021,7 +22021,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22032,7 +22032,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22185,7 +22185,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22196,7 +22196,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22238,7 +22238,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22249,7 +22249,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22260,7 +22260,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22530,7 +22530,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22541,7 +22541,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22602,7 +22602,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22660,7 +22660,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22671,7 +22671,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22771,7 +22771,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22794,7 +22794,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -22805,7 +22805,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23162,7 +23162,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23266,7 +23266,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23402,7 +23402,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23477,7 +23477,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23488,7 +23488,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23532,7 +23532,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23543,7 +23543,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23554,7 +23554,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23565,7 +23565,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23645,7 +23645,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23678,7 +23678,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23729,7 +23729,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23865,7 +23865,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -23994,7 +23994,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24005,7 +24005,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24252,7 +24252,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24263,7 +24263,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24274,7 +24274,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24555,7 +24555,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24590,7 +24590,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24631,7 +24631,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24747,7 +24747,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24758,7 +24758,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24787,7 +24787,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24883,7 +24883,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24940,7 +24940,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -24951,7 +24951,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25072,7 +25072,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25229,7 +25229,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25255,7 +25255,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25266,7 +25266,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25329,7 +25329,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25340,7 +25340,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25351,7 +25351,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25582,7 +25582,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25609,7 +25609,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25620,7 +25620,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25631,7 +25631,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25661,7 +25661,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25672,7 +25672,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25700,7 +25700,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25711,7 +25711,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25784,7 +25784,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25832,7 +25832,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25843,7 +25843,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25854,7 +25854,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25865,7 +25865,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25876,7 +25876,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25887,7 +25887,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25959,7 +25959,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -25970,7 +25970,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -26024,7 +26024,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -26226,7 +26226,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -26534,7 +26534,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -26545,7 +26545,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -26556,7 +26556,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -26807,7 +26807,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -26818,7 +26818,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -27236,7 +27236,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -28093,7 +28093,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -28223,7 +28223,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -28234,7 +28234,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -28367,7 +28367,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -28450,7 +28450,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -28461,7 +28461,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -28822,7 +28822,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -29129,7 +29129,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -29140,7 +29140,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -29266,7 +29266,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -29277,7 +29277,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -31019,7 +31019,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -31324,7 +31324,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32484,7 +32484,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32495,7 +32495,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32506,7 +32506,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32517,7 +32517,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32528,7 +32528,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32539,7 +32539,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32550,7 +32550,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "accurateanimal.com": { + "domain": "accurateanimal.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32561,7 +32572,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32572,7 +32583,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32583,7 +32594,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32594,7 +32605,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32605,7 +32616,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32616,7 +32627,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32627,7 +32638,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32638,7 +32649,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32649,7 +32660,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32660,7 +32671,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32671,7 +32682,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32682,7 +32693,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32693,7 +32704,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32704,7 +32715,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32715,7 +32726,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32726,7 +32737,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32737,7 +32748,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32748,7 +32759,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32759,7 +32770,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32770,7 +32781,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32781,7 +32792,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32792,7 +32803,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32803,7 +32814,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32814,7 +32825,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32825,7 +32836,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32836,7 +32847,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32847,7 +32858,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32858,7 +32869,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32869,7 +32880,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32880,7 +32891,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32891,7 +32902,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32902,7 +32913,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32913,7 +32924,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32924,7 +32935,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32935,7 +32946,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32946,7 +32957,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32957,7 +32968,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32968,7 +32979,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32979,7 +32990,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -32990,7 +33001,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33001,7 +33012,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33012,7 +33023,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33023,7 +33034,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33034,7 +33045,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33045,7 +33056,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33056,7 +33067,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33067,7 +33078,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33078,7 +33089,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33089,7 +33100,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33100,7 +33111,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33111,7 +33122,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33122,7 +33133,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33133,7 +33144,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33144,7 +33155,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33155,7 +33166,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33166,7 +33177,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33177,7 +33188,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33188,7 +33199,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33199,7 +33210,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33210,7 +33221,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33221,7 +33232,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33232,7 +33243,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33243,7 +33254,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33254,7 +33265,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33265,7 +33276,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33276,7 +33287,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33287,7 +33298,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33298,7 +33309,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33309,7 +33320,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33320,7 +33331,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33331,7 +33342,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "calypsocapsule.com": { + "domain": "calypsocapsule.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33342,7 +33364,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33353,7 +33375,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33364,7 +33386,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33375,7 +33397,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33386,7 +33408,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33397,7 +33419,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33408,7 +33430,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33419,7 +33441,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33430,7 +33452,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33441,7 +33463,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33452,7 +33474,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33463,7 +33485,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33474,7 +33496,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33485,7 +33507,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33496,7 +33518,29 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "chaireggnog.com": { + "domain": "chaireggnog.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "chairsdonkey.com": { + "domain": "chairsdonkey.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33507,7 +33551,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33518,7 +33562,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33529,7 +33573,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33540,7 +33584,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33551,7 +33595,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33562,7 +33606,29 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "chipperisle.com": { + "domain": "chipperisle.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "chivalrouscord.com": { + "domain": "chivalrouscord.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33573,7 +33639,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33584,7 +33650,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33595,7 +33661,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33606,7 +33672,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33617,7 +33683,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "cobaltoverture.com": { + "domain": "cobaltoverture.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33628,7 +33705,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33639,7 +33716,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33650,7 +33727,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33661,7 +33738,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33672,7 +33749,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33683,7 +33760,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33694,7 +33771,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33705,7 +33782,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33716,7 +33793,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33727,7 +33804,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33738,7 +33815,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33749,7 +33826,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33760,7 +33837,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33771,7 +33848,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33782,7 +33859,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33793,7 +33870,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33804,7 +33881,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33815,7 +33892,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33826,7 +33903,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33837,7 +33914,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33848,7 +33925,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33859,7 +33936,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33870,7 +33947,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "creatorpassenger.com": { + "domain": "creatorpassenger.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33881,7 +33969,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33892,7 +33980,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33903,7 +33991,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33914,7 +34002,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33925,7 +34013,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33936,7 +34024,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33947,7 +34035,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33958,7 +34046,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33969,7 +34057,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33980,7 +34068,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -33991,7 +34079,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34002,7 +34090,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34013,7 +34101,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34024,7 +34112,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34035,7 +34123,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34046,7 +34134,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34057,7 +34145,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34068,7 +34156,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34079,7 +34167,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34090,7 +34178,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34101,7 +34189,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34112,7 +34200,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34123,7 +34211,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34134,7 +34222,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34145,7 +34233,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34156,7 +34244,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34167,7 +34255,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34178,7 +34266,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34189,7 +34277,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34200,7 +34288,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34211,7 +34299,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34222,7 +34310,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34233,7 +34321,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34244,7 +34332,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34255,7 +34343,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34266,7 +34354,29 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "eagerknight.com": { + "domain": "eagerknight.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "echoinghaven.com": { + "domain": "echoinghaven.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34277,7 +34387,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34288,7 +34398,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "effulgenttempest.com": { + "domain": "effulgenttempest.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34299,7 +34420,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34310,7 +34431,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34321,7 +34442,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34332,7 +34453,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34343,7 +34464,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34354,7 +34475,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34365,7 +34486,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34376,7 +34497,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "engineertrick.com": { + "domain": "engineertrick.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34387,7 +34519,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34398,7 +34530,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34409,7 +34541,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34420,7 +34552,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34431,7 +34563,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34442,7 +34574,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34453,7 +34585,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34464,7 +34596,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34475,7 +34607,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34486,7 +34618,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34497,7 +34629,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34508,7 +34640,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "exquisiteartisanship.com": { + "domain": "exquisiteartisanship.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34519,7 +34662,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34530,7 +34673,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34541,7 +34684,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34552,7 +34695,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34563,7 +34706,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34574,7 +34717,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34585,7 +34728,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34596,7 +34739,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34607,7 +34750,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34618,7 +34761,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34629,7 +34772,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34640,7 +34783,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34651,7 +34794,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34662,7 +34805,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34673,7 +34816,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34684,7 +34827,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34695,7 +34838,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "flameuncle.com": { + "domain": "flameuncle.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34706,7 +34860,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34717,7 +34871,40 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "flourishingcollaboration.com": { + "domain": "flourishingcollaboration.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "flourishinginnovation.com": { + "domain": "flourishinginnovation.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "flourishingpartnership.com": { + "domain": "flourishingpartnership.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34728,7 +34915,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34739,7 +34926,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34750,7 +34937,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34761,7 +34948,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34772,7 +34959,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34783,7 +34970,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34794,7 +34981,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34805,7 +34992,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34816,7 +35003,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34827,7 +35014,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34838,7 +35025,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34849,7 +35036,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34860,7 +35047,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34871,7 +35058,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34882,7 +35069,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34893,7 +35080,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34904,7 +35091,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34915,7 +35102,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "gladysway.com": { + "domain": "gladysway.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34926,7 +35124,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34937,7 +35135,29 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "glitteringbrook.com": { + "domain": "glitteringbrook.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "goldfishgrowth.com": { + "domain": "goldfishgrowth.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34948,7 +35168,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34959,7 +35179,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34970,7 +35190,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34981,7 +35201,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -34992,7 +35212,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35003,7 +35223,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35014,7 +35234,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35025,7 +35245,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35036,7 +35256,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35047,7 +35267,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35058,7 +35278,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35069,7 +35289,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35080,7 +35300,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35091,7 +35311,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35102,7 +35322,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35113,7 +35333,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35124,7 +35344,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35135,7 +35355,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35146,7 +35366,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35157,7 +35377,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35168,7 +35388,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35179,7 +35399,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35190,7 +35410,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35201,7 +35421,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35212,7 +35432,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35223,7 +35443,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35234,7 +35454,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35245,7 +35465,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35256,7 +35476,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35267,7 +35487,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35278,7 +35498,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35289,7 +35509,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35300,7 +35520,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35311,7 +35531,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35322,7 +35542,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35333,7 +35553,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35344,7 +35564,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35355,7 +35575,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35366,7 +35586,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "impulselumber.com": { + "domain": "impulselumber.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35377,7 +35608,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35388,7 +35619,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35399,7 +35630,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35410,7 +35641,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35421,7 +35652,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35432,7 +35663,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35443,7 +35674,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35454,7 +35685,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35465,7 +35696,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35476,7 +35707,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35487,7 +35718,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35498,7 +35729,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35509,7 +35740,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "keenquill.com": { + "domain": "keenquill.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35520,7 +35762,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35531,7 +35773,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35542,7 +35784,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35553,7 +35795,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35564,7 +35806,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35575,7 +35817,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "lighttalon.com": { + "domain": "lighttalon.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35586,7 +35839,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35597,7 +35850,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35608,7 +35861,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35619,7 +35872,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35630,7 +35883,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35641,7 +35894,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35652,7 +35905,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35663,7 +35916,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35674,7 +35927,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35685,7 +35938,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35696,7 +35949,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35707,7 +35960,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35718,7 +35971,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35729,7 +35982,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35740,7 +35993,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "majesticwaterscape.com": { + "domain": "majesticwaterscape.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35751,7 +36015,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35762,7 +36026,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35773,7 +36037,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35784,7 +36048,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35795,7 +36059,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35806,7 +36070,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35817,7 +36081,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "melodiouscomposition.com": { + "domain": "melodiouscomposition.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35828,7 +36103,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35839,7 +36114,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35850,7 +36125,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35861,7 +36136,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35872,7 +36147,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35883,7 +36158,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35894,7 +36169,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35905,7 +36180,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35916,7 +36191,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35927,7 +36202,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35938,7 +36213,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35949,7 +36224,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35960,7 +36235,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35971,7 +36246,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35982,7 +36257,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -35993,7 +36268,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36004,7 +36279,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36015,7 +36290,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36026,7 +36301,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36037,7 +36312,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36048,7 +36323,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36059,7 +36334,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36070,7 +36345,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36081,7 +36356,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36092,7 +36367,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36103,7 +36378,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36114,7 +36389,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36125,7 +36400,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36136,7 +36411,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36147,7 +36422,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36158,7 +36433,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36169,7 +36444,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36180,7 +36455,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36191,7 +36466,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36202,7 +36477,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36213,7 +36488,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36224,7 +36499,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36235,7 +36510,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "opulentsylvan.com": { + "domain": "opulentsylvan.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36246,7 +36532,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36257,7 +36543,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36268,7 +36554,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36279,7 +36565,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36290,7 +36576,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36301,7 +36587,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36312,7 +36598,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36323,7 +36609,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36334,7 +36620,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36345,7 +36631,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36356,7 +36642,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36367,7 +36653,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36378,7 +36664,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36389,7 +36675,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36400,7 +36686,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36411,7 +36697,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36422,7 +36708,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "pluckyzone.com": { + "domain": "pluckyzone.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36433,7 +36730,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36444,7 +36741,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36455,7 +36752,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36466,7 +36763,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "polishedfolly.com": { + "domain": "polishedfolly.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36477,7 +36785,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36488,7 +36796,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "popplantation.com": { + "domain": "popplantation.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36499,7 +36818,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36510,7 +36829,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36521,7 +36840,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36532,7 +36851,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36543,7 +36862,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36554,7 +36873,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "publicsofa.com": { + "domain": "publicsofa.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36565,7 +36895,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "pulsatingmeadow.com": { + "domain": "pulsatingmeadow.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36576,7 +36917,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36587,7 +36928,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36598,7 +36939,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36609,7 +36950,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36620,7 +36961,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36631,7 +36972,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36642,7 +36983,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36653,7 +36994,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36664,7 +37005,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36675,7 +37016,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36686,7 +37027,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36697,7 +37038,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36708,7 +37049,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36719,7 +37060,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36730,7 +37071,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36741,7 +37082,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36752,7 +37093,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36763,7 +37104,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36774,7 +37115,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36785,7 +37126,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36796,7 +37137,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36807,7 +37148,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36818,7 +37159,29 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "relationrest.com": { + "domain": "relationrest.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "rememberdiscussion.com": { + "domain": "rememberdiscussion.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36829,7 +37192,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36840,7 +37203,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36851,7 +37214,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36862,7 +37225,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36873,7 +37236,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36884,7 +37247,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36895,7 +37258,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36906,7 +37269,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36917,7 +37280,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36928,7 +37291,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36939,7 +37302,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36950,7 +37313,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36961,7 +37324,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36972,7 +37335,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36983,7 +37346,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -36994,7 +37357,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37005,7 +37368,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37016,7 +37379,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37027,7 +37390,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37038,7 +37401,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37049,7 +37412,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37060,7 +37423,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37071,7 +37434,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37082,7 +37445,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37093,7 +37456,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37104,7 +37467,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37115,7 +37478,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37126,7 +37489,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37137,7 +37500,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37148,7 +37511,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37159,7 +37522,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37170,7 +37533,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37181,7 +37544,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37192,7 +37555,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37203,7 +37566,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "serenecascade.com": { + "domain": "serenecascade.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37214,7 +37588,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37225,7 +37599,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37236,7 +37610,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37247,7 +37621,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37258,7 +37632,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37269,7 +37643,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37280,7 +37654,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37291,7 +37665,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37302,7 +37676,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37313,7 +37687,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37324,7 +37698,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37335,7 +37709,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37346,7 +37720,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37357,7 +37731,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37368,7 +37742,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37379,7 +37753,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37390,7 +37764,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37401,7 +37775,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37412,7 +37786,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37423,7 +37797,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37434,7 +37808,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37445,7 +37819,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37456,7 +37830,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37467,7 +37841,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37478,7 +37852,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37489,7 +37863,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37500,7 +37874,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37511,7 +37885,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37522,7 +37896,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37533,7 +37907,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37544,7 +37918,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37555,7 +37929,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37566,7 +37940,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37577,7 +37951,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37588,7 +37962,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37599,7 +37973,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37610,7 +37984,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37621,7 +37995,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37632,7 +38006,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37643,7 +38017,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37654,7 +38028,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37665,7 +38039,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37676,7 +38050,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37687,7 +38061,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37698,7 +38072,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37709,7 +38083,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37720,7 +38094,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37731,7 +38105,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37742,7 +38116,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37753,7 +38127,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37764,7 +38138,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37775,7 +38149,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37786,7 +38160,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37797,7 +38171,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37808,7 +38182,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37819,7 +38193,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37830,7 +38204,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37841,7 +38215,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37852,7 +38226,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37863,7 +38237,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37874,7 +38248,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37885,7 +38259,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37896,7 +38270,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37907,7 +38281,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37918,7 +38292,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37929,7 +38303,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37940,7 +38314,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37951,7 +38325,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37962,7 +38336,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37973,7 +38347,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "sublimequartz.com": { + "domain": "sublimequartz.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37984,7 +38369,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -37995,7 +38380,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38006,7 +38391,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38017,7 +38402,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38028,7 +38413,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38039,7 +38424,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38050,7 +38435,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38061,7 +38446,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38072,7 +38457,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38083,7 +38468,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38094,7 +38479,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38105,7 +38490,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38116,7 +38501,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38127,7 +38512,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38138,7 +38523,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38149,7 +38534,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "tearfulglass.com": { + "domain": "tearfulglass.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38160,7 +38556,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38171,7 +38567,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38182,7 +38578,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38193,7 +38589,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38204,7 +38600,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38215,7 +38611,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38226,7 +38622,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38237,7 +38633,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38248,7 +38644,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38259,7 +38655,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "thrivingmarketplace.com": { + "domain": "thrivingmarketplace.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38270,7 +38677,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38281,7 +38688,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38292,7 +38699,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38303,7 +38710,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38314,7 +38721,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38325,7 +38732,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38336,7 +38743,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38347,7 +38754,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38358,7 +38765,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38369,7 +38776,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38380,7 +38787,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38391,7 +38798,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38402,7 +38809,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38413,7 +38820,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38424,7 +38831,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38435,7 +38842,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38446,7 +38853,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38457,7 +38864,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38468,7 +38875,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38479,7 +38886,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38490,7 +38897,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38501,7 +38908,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38512,7 +38919,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38523,7 +38930,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38534,7 +38941,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38545,7 +38952,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38556,7 +38963,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38567,7 +38974,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38578,7 +38985,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38589,7 +38996,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38600,7 +39007,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38611,7 +39018,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38622,7 +39029,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38633,7 +39040,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38644,7 +39051,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38655,7 +39062,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38666,7 +39073,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38677,7 +39084,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38688,7 +39095,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38699,7 +39106,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "vibrantcelebration.com": { + "domain": "vibrantcelebration.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38710,7 +39128,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38721,7 +39139,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38732,7 +39150,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38743,7 +39161,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38754,7 +39172,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38765,7 +39183,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "vividfrost.com": { + "domain": "vividfrost.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38776,7 +39205,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38787,7 +39216,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38798,7 +39227,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38809,7 +39238,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38820,7 +39249,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38831,7 +39260,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38842,7 +39271,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38853,7 +39282,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38864,7 +39293,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38875,7 +39304,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38886,7 +39315,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38897,7 +39326,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38908,7 +39337,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38919,7 +39348,18 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "wittyshack.com": { + "domain": "wittyshack.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38930,7 +39370,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38941,7 +39381,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38952,7 +39392,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38963,7 +39403,29 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "zestyhorizon.com": { + "domain": "zestyhorizon.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, + "fingerprinting": 1, + "cookies": 0.01, + "default": "block" + }, + "zestyrover.com": { + "domain": "zestyrover.com", + "owner": { + "name": "Leven Labs, Inc. DBA Admiral", + "displayName": "Admiral" + }, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38974,7 +39436,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -38985,7 +39447,7 @@ "name": "Leven Labs, Inc. DBA Admiral", "displayName": "Admiral" }, - "prevalence": 0.0151, + "prevalence": 0.0129, "fingerprinting": 1, "cookies": 0.01, "default": "block" @@ -48993,6 +49455,7 @@ "abstractedamount.com", "abstractedauthority.com", "acceptableauthority.com", + "accurateanimal.com", "accuratecoal.com", "acidpigs.com", "actoramusement.com", @@ -49088,6 +49551,7 @@ "calculatorstatement.com", "callousbrake.com", "calmcactus.com", + "calypsocapsule.com", "capablecup.com", "capriciouscorn.com", "captivatingcanyon.com", @@ -49107,6 +49571,8 @@ "ceciliavenus.com", "celestialquasar.com", "celestialspectra.com", + "chaireggnog.com", + "chairsdonkey.com", "chalkoil.com", "changeablecats.com", "chargecracker.com", @@ -49118,6 +49584,8 @@ "childlikeexample.com", "childlikeform.com", "chinsnakes.com", + "chipperisle.com", + "chivalrouscord.com", "chunkycactus.com", "circlelevel.com", "cleanhaircut.com", @@ -49125,6 +49593,7 @@ "cloisteredcurve.com", "closedcows.com", "coatfood.com", + "cobaltoverture.com", "coldbalance.com", "colossalclouds.com", "colossalcoat.com", @@ -49152,6 +49621,7 @@ "crabbychin.com", "cratecamera.com", "creatorcherry.com", + "creatorpassenger.com", "creaturecabbage.com", "crimsonmeadow.com", "critictruck.com", @@ -49204,8 +49674,11 @@ "drollwharf.com", "dustydime.com", "dustyhammer.com", + "eagerknight.com", + "echoinghaven.com", "effervescentcoral.com", "effervescentvista.com", + "effulgenttempest.com", "elasticchange.com", "elderlybean.com", "elusivebreeze.com", @@ -49215,6 +49688,7 @@ "encouragingthread.com", "endurablebulb.com", "energeticladybug.com", + "engineertrick.com", "enigmaticcanyon.com", "enigmaticvoyage.com", "enormousearth.com", @@ -49230,6 +49704,7 @@ "executeknowledge.com", "exhibitsneeze.com", "expansioneggnog.com", + "exquisiteartisanship.com", "exuberantedge.com", "fadedsnow.com", "fadewaves.com", @@ -49253,8 +49728,12 @@ "financefear.com", "firstfrogs.com", "fixedfold.com", + "flameuncle.com", "flimsycircle.com", "flimsythought.com", + "flourishingcollaboration.com", + "flourishinginnovation.com", + "flourishingpartnership.com", "flowerstreatment.com", "flowerycreature.com", "floweryfact.com", @@ -49284,9 +49763,12 @@ "giddycoat.com", "giraffepiano.com", "givevacation.com", + "gladysway.com", "gleamingcow.com", "glisteningguide.com", + "glitteringbrook.com", "gloriousbeef.com", + "goldfishgrowth.com", "gondolagnome.com", "gorgeousedge.com", "gracefulmilk.com", @@ -49337,6 +49819,7 @@ "importantmeat.com", "impossibleexpansion.com", "impulsejewel.com", + "impulselumber.com", "incompetentjoke.com", "inconclusiveaction.com", "inputicicle.com", @@ -49351,6 +49834,7 @@ "jubilanttempest.com", "jubilantwhisper.com", "kaputquill.com", + "keenquill.com", "knitstamp.com", "knottyswing.com", "laboredlocket.com", @@ -49360,6 +49844,7 @@ "leftliquid.com", "liftedknowledge.com", "lightenafterthought.com", + "lighttalon.com", "livelumber.com", "livelylaugh.com", "livelyreward.com", @@ -49379,6 +49864,7 @@ "lunchroomlock.com", "lustroushaven.com", "maddeningpowder.com", + "majesticwaterscape.com", "maliciousmusic.com", "marketspiders.com", "marriedbelief.com", @@ -49390,6 +49876,7 @@ "meatydime.com", "meddleplant.com", "melodiouschorus.com", + "melodiouscomposition.com", "meltmilk.com", "memopilot.com", "memorizematch.com", @@ -49435,6 +49922,7 @@ "oldfashionedoffer.com", "operationchicken.com", "optimallimit.com", + "opulentsylvan.com", "orientedargument.com", "outstandingincome.com", "outstandingsnails.com", @@ -49462,13 +49950,16 @@ "pleasantpump.com", "plotrabbit.com", "pluckypocket.com", + "pluckyzone.com", "pocketfaucet.com", "poeticpackage.com", "pointdigestion.com", "pointlesspocket.com", "pointlessprofit.com", + "polishedfolly.com", "politeplanes.com", "politicalporter.com", + "popplantation.com", "possibleboats.com", "possiblepencil.com", "potatoinvention.com", @@ -49484,7 +49975,9 @@ "profusesupport.com", "protestcopy.com", "psychedelicarithmetic.com", + "publicsofa.com", "puffypurpose.com", + "pulsatingmeadow.com", "pumpedpancake.com", "punyplant.com", "purposepipe.com", @@ -49519,6 +50012,8 @@ "regularplants.com", "regulatesleet.com", "rehabilitatereason.com", + "relationrest.com", + "rememberdiscussion.com", "repeatsweater.com", "replaceroute.com", "resonantbrush.com", @@ -49576,6 +50071,7 @@ "selfishsnake.com", "separatesort.com", "seraphicjubilee.com", + "serenecascade.com", "serenepebble.com", "serioussuit.com", "serpentshampoo.com", @@ -49679,6 +50175,7 @@ "stupendoussleet.com", "stupendoussnow.com", "stupidscene.com", + "sublimequartz.com", "succeedscene.com", "sugarfriction.com", "suggestionbridge.com", @@ -49700,6 +50197,7 @@ "tangycover.com", "tastelesstrees.com", "tastelesstrucks.com", + "tearfulglass.com", "tediousticket.com", "teenytinycellar.com", "teenytinyshirt.com", @@ -49715,6 +50213,7 @@ "thomastorch.com", "thoughtlessknot.com", "threetruck.com", + "thrivingmarketplace.com", "ticketaunt.com", "tidymitten.com", "tiredthroat.com", @@ -49763,12 +50262,14 @@ "verdantlabyrinth.com", "verdantloom.com", "verseballs.com", + "vibrantcelebration.com", "vibrantgale.com", "vibranthaven.com", "vibrantpact.com", "vibranttalisman.com", "virtualvincent.com", "vividcanopy.com", + "vividfrost.com", "vividmeadow.com", "vividplume.com", "volatileprofit.com", @@ -49787,15 +50288,18 @@ "whispermeeting.com", "wildcommittee.com", "wistfulwaste.com", + "wittyshack.com", "workoperation.com", "wretchedfloor.com", "wrongwound.com", "zephyrlabyrinth.com", "zestycrime.com", + "zestyhorizon.com", + "zestyrover.com", "zipperxray.com", "zlp6s.pw" ], - "prevalence": 0.0151, + "prevalence": 0.0129, "displayName": "Admiral" } }, @@ -50523,6 +51027,7 @@ "abstractedamount.com": "Leven Labs, Inc. DBA Admiral", "abstractedauthority.com": "Leven Labs, Inc. DBA Admiral", "acceptableauthority.com": "Leven Labs, Inc. DBA Admiral", + "accurateanimal.com": "Leven Labs, Inc. DBA Admiral", "accuratecoal.com": "Leven Labs, Inc. DBA Admiral", "acidpigs.com": "Leven Labs, Inc. DBA Admiral", "actoramusement.com": "Leven Labs, Inc. DBA Admiral", @@ -50618,6 +51123,7 @@ "calculatorstatement.com": "Leven Labs, Inc. DBA Admiral", "callousbrake.com": "Leven Labs, Inc. DBA Admiral", "calmcactus.com": "Leven Labs, Inc. DBA Admiral", + "calypsocapsule.com": "Leven Labs, Inc. DBA Admiral", "capablecup.com": "Leven Labs, Inc. DBA Admiral", "capriciouscorn.com": "Leven Labs, Inc. DBA Admiral", "captivatingcanyon.com": "Leven Labs, Inc. DBA Admiral", @@ -50637,6 +51143,8 @@ "ceciliavenus.com": "Leven Labs, Inc. DBA Admiral", "celestialquasar.com": "Leven Labs, Inc. DBA Admiral", "celestialspectra.com": "Leven Labs, Inc. DBA Admiral", + "chaireggnog.com": "Leven Labs, Inc. DBA Admiral", + "chairsdonkey.com": "Leven Labs, Inc. DBA Admiral", "chalkoil.com": "Leven Labs, Inc. DBA Admiral", "changeablecats.com": "Leven Labs, Inc. DBA Admiral", "chargecracker.com": "Leven Labs, Inc. DBA Admiral", @@ -50648,6 +51156,8 @@ "childlikeexample.com": "Leven Labs, Inc. DBA Admiral", "childlikeform.com": "Leven Labs, Inc. DBA Admiral", "chinsnakes.com": "Leven Labs, Inc. DBA Admiral", + "chipperisle.com": "Leven Labs, Inc. DBA Admiral", + "chivalrouscord.com": "Leven Labs, Inc. DBA Admiral", "chunkycactus.com": "Leven Labs, Inc. DBA Admiral", "circlelevel.com": "Leven Labs, Inc. DBA Admiral", "cleanhaircut.com": "Leven Labs, Inc. DBA Admiral", @@ -50655,6 +51165,7 @@ "cloisteredcurve.com": "Leven Labs, Inc. DBA Admiral", "closedcows.com": "Leven Labs, Inc. DBA Admiral", "coatfood.com": "Leven Labs, Inc. DBA Admiral", + "cobaltoverture.com": "Leven Labs, Inc. DBA Admiral", "coldbalance.com": "Leven Labs, Inc. DBA Admiral", "colossalclouds.com": "Leven Labs, Inc. DBA Admiral", "colossalcoat.com": "Leven Labs, Inc. DBA Admiral", @@ -50682,6 +51193,7 @@ "crabbychin.com": "Leven Labs, Inc. DBA Admiral", "cratecamera.com": "Leven Labs, Inc. DBA Admiral", "creatorcherry.com": "Leven Labs, Inc. DBA Admiral", + "creatorpassenger.com": "Leven Labs, Inc. DBA Admiral", "creaturecabbage.com": "Leven Labs, Inc. DBA Admiral", "crimsonmeadow.com": "Leven Labs, Inc. DBA Admiral", "critictruck.com": "Leven Labs, Inc. DBA Admiral", @@ -50734,8 +51246,11 @@ "drollwharf.com": "Leven Labs, Inc. DBA Admiral", "dustydime.com": "Leven Labs, Inc. DBA Admiral", "dustyhammer.com": "Leven Labs, Inc. DBA Admiral", + "eagerknight.com": "Leven Labs, Inc. DBA Admiral", + "echoinghaven.com": "Leven Labs, Inc. DBA Admiral", "effervescentcoral.com": "Leven Labs, Inc. DBA Admiral", "effervescentvista.com": "Leven Labs, Inc. DBA Admiral", + "effulgenttempest.com": "Leven Labs, Inc. DBA Admiral", "elasticchange.com": "Leven Labs, Inc. DBA Admiral", "elderlybean.com": "Leven Labs, Inc. DBA Admiral", "elusivebreeze.com": "Leven Labs, Inc. DBA Admiral", @@ -50745,6 +51260,7 @@ "encouragingthread.com": "Leven Labs, Inc. DBA Admiral", "endurablebulb.com": "Leven Labs, Inc. DBA Admiral", "energeticladybug.com": "Leven Labs, Inc. DBA Admiral", + "engineertrick.com": "Leven Labs, Inc. DBA Admiral", "enigmaticcanyon.com": "Leven Labs, Inc. DBA Admiral", "enigmaticvoyage.com": "Leven Labs, Inc. DBA Admiral", "enormousearth.com": "Leven Labs, Inc. DBA Admiral", @@ -50760,6 +51276,7 @@ "executeknowledge.com": "Leven Labs, Inc. DBA Admiral", "exhibitsneeze.com": "Leven Labs, Inc. DBA Admiral", "expansioneggnog.com": "Leven Labs, Inc. DBA Admiral", + "exquisiteartisanship.com": "Leven Labs, Inc. DBA Admiral", "exuberantedge.com": "Leven Labs, Inc. DBA Admiral", "fadedsnow.com": "Leven Labs, Inc. DBA Admiral", "fadewaves.com": "Leven Labs, Inc. DBA Admiral", @@ -50783,8 +51300,12 @@ "financefear.com": "Leven Labs, Inc. DBA Admiral", "firstfrogs.com": "Leven Labs, Inc. DBA Admiral", "fixedfold.com": "Leven Labs, Inc. DBA Admiral", + "flameuncle.com": "Leven Labs, Inc. DBA Admiral", "flimsycircle.com": "Leven Labs, Inc. DBA Admiral", "flimsythought.com": "Leven Labs, Inc. DBA Admiral", + "flourishingcollaboration.com": "Leven Labs, Inc. DBA Admiral", + "flourishinginnovation.com": "Leven Labs, Inc. DBA Admiral", + "flourishingpartnership.com": "Leven Labs, Inc. DBA Admiral", "flowerstreatment.com": "Leven Labs, Inc. DBA Admiral", "flowerycreature.com": "Leven Labs, Inc. DBA Admiral", "floweryfact.com": "Leven Labs, Inc. DBA Admiral", @@ -50814,9 +51335,12 @@ "giddycoat.com": "Leven Labs, Inc. DBA Admiral", "giraffepiano.com": "Leven Labs, Inc. DBA Admiral", "givevacation.com": "Leven Labs, Inc. DBA Admiral", + "gladysway.com": "Leven Labs, Inc. DBA Admiral", "gleamingcow.com": "Leven Labs, Inc. DBA Admiral", "glisteningguide.com": "Leven Labs, Inc. DBA Admiral", + "glitteringbrook.com": "Leven Labs, Inc. DBA Admiral", "gloriousbeef.com": "Leven Labs, Inc. DBA Admiral", + "goldfishgrowth.com": "Leven Labs, Inc. DBA Admiral", "gondolagnome.com": "Leven Labs, Inc. DBA Admiral", "gorgeousedge.com": "Leven Labs, Inc. DBA Admiral", "gracefulmilk.com": "Leven Labs, Inc. DBA Admiral", @@ -50867,6 +51391,7 @@ "importantmeat.com": "Leven Labs, Inc. DBA Admiral", "impossibleexpansion.com": "Leven Labs, Inc. DBA Admiral", "impulsejewel.com": "Leven Labs, Inc. DBA Admiral", + "impulselumber.com": "Leven Labs, Inc. DBA Admiral", "incompetentjoke.com": "Leven Labs, Inc. DBA Admiral", "inconclusiveaction.com": "Leven Labs, Inc. DBA Admiral", "inputicicle.com": "Leven Labs, Inc. DBA Admiral", @@ -50881,6 +51406,7 @@ "jubilanttempest.com": "Leven Labs, Inc. DBA Admiral", "jubilantwhisper.com": "Leven Labs, Inc. DBA Admiral", "kaputquill.com": "Leven Labs, Inc. DBA Admiral", + "keenquill.com": "Leven Labs, Inc. DBA Admiral", "knitstamp.com": "Leven Labs, Inc. DBA Admiral", "knottyswing.com": "Leven Labs, Inc. DBA Admiral", "laboredlocket.com": "Leven Labs, Inc. DBA Admiral", @@ -50890,6 +51416,7 @@ "leftliquid.com": "Leven Labs, Inc. DBA Admiral", "liftedknowledge.com": "Leven Labs, Inc. DBA Admiral", "lightenafterthought.com": "Leven Labs, Inc. DBA Admiral", + "lighttalon.com": "Leven Labs, Inc. DBA Admiral", "livelumber.com": "Leven Labs, Inc. DBA Admiral", "livelylaugh.com": "Leven Labs, Inc. DBA Admiral", "livelyreward.com": "Leven Labs, Inc. DBA Admiral", @@ -50909,6 +51436,7 @@ "lunchroomlock.com": "Leven Labs, Inc. DBA Admiral", "lustroushaven.com": "Leven Labs, Inc. DBA Admiral", "maddeningpowder.com": "Leven Labs, Inc. DBA Admiral", + "majesticwaterscape.com": "Leven Labs, Inc. DBA Admiral", "maliciousmusic.com": "Leven Labs, Inc. DBA Admiral", "marketspiders.com": "Leven Labs, Inc. DBA Admiral", "marriedbelief.com": "Leven Labs, Inc. DBA Admiral", @@ -50920,6 +51448,7 @@ "meatydime.com": "Leven Labs, Inc. DBA Admiral", "meddleplant.com": "Leven Labs, Inc. DBA Admiral", "melodiouschorus.com": "Leven Labs, Inc. DBA Admiral", + "melodiouscomposition.com": "Leven Labs, Inc. DBA Admiral", "meltmilk.com": "Leven Labs, Inc. DBA Admiral", "memopilot.com": "Leven Labs, Inc. DBA Admiral", "memorizematch.com": "Leven Labs, Inc. DBA Admiral", @@ -50965,6 +51494,7 @@ "oldfashionedoffer.com": "Leven Labs, Inc. DBA Admiral", "operationchicken.com": "Leven Labs, Inc. DBA Admiral", "optimallimit.com": "Leven Labs, Inc. DBA Admiral", + "opulentsylvan.com": "Leven Labs, Inc. DBA Admiral", "orientedargument.com": "Leven Labs, Inc. DBA Admiral", "outstandingincome.com": "Leven Labs, Inc. DBA Admiral", "outstandingsnails.com": "Leven Labs, Inc. DBA Admiral", @@ -50992,13 +51522,16 @@ "pleasantpump.com": "Leven Labs, Inc. DBA Admiral", "plotrabbit.com": "Leven Labs, Inc. DBA Admiral", "pluckypocket.com": "Leven Labs, Inc. DBA Admiral", + "pluckyzone.com": "Leven Labs, Inc. DBA Admiral", "pocketfaucet.com": "Leven Labs, Inc. DBA Admiral", "poeticpackage.com": "Leven Labs, Inc. DBA Admiral", "pointdigestion.com": "Leven Labs, Inc. DBA Admiral", "pointlesspocket.com": "Leven Labs, Inc. DBA Admiral", "pointlessprofit.com": "Leven Labs, Inc. DBA Admiral", + "polishedfolly.com": "Leven Labs, Inc. DBA Admiral", "politeplanes.com": "Leven Labs, Inc. DBA Admiral", "politicalporter.com": "Leven Labs, Inc. DBA Admiral", + "popplantation.com": "Leven Labs, Inc. DBA Admiral", "possibleboats.com": "Leven Labs, Inc. DBA Admiral", "possiblepencil.com": "Leven Labs, Inc. DBA Admiral", "potatoinvention.com": "Leven Labs, Inc. DBA Admiral", @@ -51014,7 +51547,9 @@ "profusesupport.com": "Leven Labs, Inc. DBA Admiral", "protestcopy.com": "Leven Labs, Inc. DBA Admiral", "psychedelicarithmetic.com": "Leven Labs, Inc. DBA Admiral", + "publicsofa.com": "Leven Labs, Inc. DBA Admiral", "puffypurpose.com": "Leven Labs, Inc. DBA Admiral", + "pulsatingmeadow.com": "Leven Labs, Inc. DBA Admiral", "pumpedpancake.com": "Leven Labs, Inc. DBA Admiral", "punyplant.com": "Leven Labs, Inc. DBA Admiral", "purposepipe.com": "Leven Labs, Inc. DBA Admiral", @@ -51049,6 +51584,8 @@ "regularplants.com": "Leven Labs, Inc. DBA Admiral", "regulatesleet.com": "Leven Labs, Inc. DBA Admiral", "rehabilitatereason.com": "Leven Labs, Inc. DBA Admiral", + "relationrest.com": "Leven Labs, Inc. DBA Admiral", + "rememberdiscussion.com": "Leven Labs, Inc. DBA Admiral", "repeatsweater.com": "Leven Labs, Inc. DBA Admiral", "replaceroute.com": "Leven Labs, Inc. DBA Admiral", "resonantbrush.com": "Leven Labs, Inc. DBA Admiral", @@ -51106,6 +51643,7 @@ "selfishsnake.com": "Leven Labs, Inc. DBA Admiral", "separatesort.com": "Leven Labs, Inc. DBA Admiral", "seraphicjubilee.com": "Leven Labs, Inc. DBA Admiral", + "serenecascade.com": "Leven Labs, Inc. DBA Admiral", "serenepebble.com": "Leven Labs, Inc. DBA Admiral", "serioussuit.com": "Leven Labs, Inc. DBA Admiral", "serpentshampoo.com": "Leven Labs, Inc. DBA Admiral", @@ -51209,6 +51747,7 @@ "stupendoussleet.com": "Leven Labs, Inc. DBA Admiral", "stupendoussnow.com": "Leven Labs, Inc. DBA Admiral", "stupidscene.com": "Leven Labs, Inc. DBA Admiral", + "sublimequartz.com": "Leven Labs, Inc. DBA Admiral", "succeedscene.com": "Leven Labs, Inc. DBA Admiral", "sugarfriction.com": "Leven Labs, Inc. DBA Admiral", "suggestionbridge.com": "Leven Labs, Inc. DBA Admiral", @@ -51230,6 +51769,7 @@ "tangycover.com": "Leven Labs, Inc. DBA Admiral", "tastelesstrees.com": "Leven Labs, Inc. DBA Admiral", "tastelesstrucks.com": "Leven Labs, Inc. DBA Admiral", + "tearfulglass.com": "Leven Labs, Inc. DBA Admiral", "tediousticket.com": "Leven Labs, Inc. DBA Admiral", "teenytinycellar.com": "Leven Labs, Inc. DBA Admiral", "teenytinyshirt.com": "Leven Labs, Inc. DBA Admiral", @@ -51245,6 +51785,7 @@ "thomastorch.com": "Leven Labs, Inc. DBA Admiral", "thoughtlessknot.com": "Leven Labs, Inc. DBA Admiral", "threetruck.com": "Leven Labs, Inc. DBA Admiral", + "thrivingmarketplace.com": "Leven Labs, Inc. DBA Admiral", "ticketaunt.com": "Leven Labs, Inc. DBA Admiral", "tidymitten.com": "Leven Labs, Inc. DBA Admiral", "tiredthroat.com": "Leven Labs, Inc. DBA Admiral", @@ -51293,12 +51834,14 @@ "verdantlabyrinth.com": "Leven Labs, Inc. DBA Admiral", "verdantloom.com": "Leven Labs, Inc. DBA Admiral", "verseballs.com": "Leven Labs, Inc. DBA Admiral", + "vibrantcelebration.com": "Leven Labs, Inc. DBA Admiral", "vibrantgale.com": "Leven Labs, Inc. DBA Admiral", "vibranthaven.com": "Leven Labs, Inc. DBA Admiral", "vibrantpact.com": "Leven Labs, Inc. DBA Admiral", "vibranttalisman.com": "Leven Labs, Inc. DBA Admiral", "virtualvincent.com": "Leven Labs, Inc. DBA Admiral", "vividcanopy.com": "Leven Labs, Inc. DBA Admiral", + "vividfrost.com": "Leven Labs, Inc. DBA Admiral", "vividmeadow.com": "Leven Labs, Inc. DBA Admiral", "vividplume.com": "Leven Labs, Inc. DBA Admiral", "volatileprofit.com": "Leven Labs, Inc. DBA Admiral", @@ -51317,11 +51860,14 @@ "whispermeeting.com": "Leven Labs, Inc. DBA Admiral", "wildcommittee.com": "Leven Labs, Inc. DBA Admiral", "wistfulwaste.com": "Leven Labs, Inc. DBA Admiral", + "wittyshack.com": "Leven Labs, Inc. DBA Admiral", "workoperation.com": "Leven Labs, Inc. DBA Admiral", "wretchedfloor.com": "Leven Labs, Inc. DBA Admiral", "wrongwound.com": "Leven Labs, Inc. DBA Admiral", "zephyrlabyrinth.com": "Leven Labs, Inc. DBA Admiral", "zestycrime.com": "Leven Labs, Inc. DBA Admiral", + "zestyhorizon.com": "Leven Labs, Inc. DBA Admiral", + "zestyrover.com": "Leven Labs, Inc. DBA Admiral", "zipperxray.com": "Leven Labs, Inc. DBA Admiral", "zlp6s.pw": "Leven Labs, Inc. DBA Admiral", "abtasty.com": "AB Tasty", diff --git a/DuckDuckGo/CrashReports/Model/CrashReport.swift b/DuckDuckGo/CrashReports/Model/CrashReport.swift index 773c66cd27..05df42936f 100644 --- a/DuckDuckGo/CrashReports/Model/CrashReport.swift +++ b/DuckDuckGo/CrashReports/Model/CrashReport.swift @@ -17,13 +17,17 @@ // import Foundation +import MetricKit -protocol CrashReport { +protocol CrashReportPresenting { + var content: String? { get } +} + +protocol CrashReport: CrashReportPresenting { static var fileExtension: String { get } var url: URL { get } - var content: String? { get } var contentData: Data? { get } } @@ -91,3 +95,10 @@ struct JSONCrashReport: CrashReport { } } + +@available(macOS 12.0, *) +extension MXDiagnosticPayload: CrashReportPresenting { + var content: String? { + jsonRepresentation().utf8String() + } +} diff --git a/DuckDuckGo/CrashReports/Model/CrashReportPromptPresenter.swift b/DuckDuckGo/CrashReports/Model/CrashReportPromptPresenter.swift index 3d4e17cd2f..313c6a1e95 100644 --- a/DuckDuckGo/CrashReports/Model/CrashReportPromptPresenter.swift +++ b/DuckDuckGo/CrashReports/Model/CrashReportPromptPresenter.swift @@ -31,9 +31,9 @@ final class CrashReportPromptPresenter { // swiftlint:enable force_cast } - func showPrompt(_ delegate: CrashReportPromptViewControllerDelegate, for crashReport: CrashReport) { - viewController.delegate = delegate + func showPrompt(for crashReport: CrashReportPresenting, userDidAllowToReport: @escaping () -> Void) { viewController.crashReport = crashReport + viewController.userDidAllowToReport = userDidAllowToReport windowController.showWindow(self) windowController.window?.center() diff --git a/DuckDuckGo/CrashReports/Model/CrashReportSender.swift b/DuckDuckGo/CrashReports/Model/CrashReportSender.swift deleted file mode 100644 index e6ac958fc3..0000000000 --- a/DuckDuckGo/CrashReports/Model/CrashReportSender.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// CrashReportSender.swift -// -// 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 - -final class CrashReportSender { - - static let reportServiceUrl = URL(string: "https://duckduckgo.com/crash.js")! - - private let session = URLSession(configuration: .ephemeral) - - func send(_ crashReport: CrashReport) { - guard let contentData = crashReport.contentData else { - assertionFailure("CrashReportSender: Can't get the content of the crash report") - return - } - var request = URLRequest(url: Self.reportServiceUrl) - request.setValue("text/plain", forHTTPHeaderField: "Content-Type") - request.setValue("ddg_mac", forHTTPHeaderField: "User-Agent") - request.httpMethod = "POST" - request.httpBody = contentData - - session.dataTask(with: request) { (_, _, error) in - if error != nil { - assertionFailure("CrashReportSender: Failed to send the crash reprot") - } - }.resume() - } - -} diff --git a/DuckDuckGo/CrashReports/Model/CrashReporter.swift b/DuckDuckGo/CrashReports/Model/CrashReporter.swift index 39288b6043..f8e73f87e6 100644 --- a/DuckDuckGo/CrashReports/Model/CrashReporter.swift +++ b/DuckDuckGo/CrashReports/Model/CrashReporter.swift @@ -16,19 +16,20 @@ // limitations under the License. // +import Common +import Crashes import Foundation +import PixelKit final class CrashReporter { private let reader = CrashReportReader() - private lazy var sender = CrashReportSender() + private lazy var sender = CrashReportSender(platform: .macOS, log: .default) private lazy var promptPresenter = CrashReportPromptPresenter() @UserDefaultsWrapper(key: .lastCrashReportCheckDate, defaultValue: nil) private var lastCheckDate: Date? - private var latestCrashReport: CrashReport? - func checkForNewReports() { #if !DEBUG @@ -47,31 +48,19 @@ final class CrashReporter { return } - Pixel.fire(.crash) - - latestCrashReport = latest - promptPresenter.showPrompt(self, for: latest) - -#endif - - } - -} - -extension CrashReporter: CrashReportPromptViewControllerDelegate { + PixelKit.fire(GeneralPixel.crash) - func crashReportPromptViewController(_ crashReportPromptViewController: CrashReportPromptViewController, - userDidAllowToReport: Bool) { - guard userDidAllowToReport else { - return + promptPresenter.showPrompt(for: latest) { + guard let contentData = latest.contentData else { + assertionFailure("CrashReporter: Can't get the content of the crash report") + return + } + Task { + await self.sender.send(contentData) + } } - guard let latestCrashReport = latestCrashReport else { - assertionFailure("CrashReporter: The latest crash report is nil") - return - } +#endif - sender.send(latestCrashReport) } - } diff --git a/DuckDuckGo/CrashReports/View/CrashReportPromptViewController.swift b/DuckDuckGo/CrashReports/View/CrashReportPromptViewController.swift index f8977d640b..4b21d7a222 100644 --- a/DuckDuckGo/CrashReports/View/CrashReportPromptViewController.swift +++ b/DuckDuckGo/CrashReports/View/CrashReportPromptViewController.swift @@ -18,13 +18,6 @@ import Cocoa -protocol CrashReportPromptViewControllerDelegate: AnyObject { - - func crashReportPromptViewController(_ crashReportPromptViewController: CrashReportPromptViewController, - userDidAllowToReport: Bool) - -} - final class CrashReportPromptViewController: NSViewController { @IBOutlet weak var titleLabel: NSTextField! @IBOutlet weak var dontSendButton: NSButton! @@ -33,8 +26,9 @@ final class CrashReportPromptViewController: NSViewController { @IBOutlet weak var descriptionLabel: NSTextField! @IBOutlet var textView: NSTextView! - weak var delegate: CrashReportPromptViewControllerDelegate? - var crashReport: CrashReport? { + var userDidAllowToReport: () -> Void = {} + + var crashReport: CrashReportPresenting? { didSet { updateView() } @@ -58,12 +52,11 @@ final class CrashReportPromptViewController: NSViewController { } @IBAction func sendAction(_ sender: Any) { - delegate?.crashReportPromptViewController(self, userDidAllowToReport: true) + userDidAllowToReport() view.window?.close() } @IBAction func dontSendAction(_ sender: Any) { - delegate?.crashReportPromptViewController(self, userDidAllowToReport: false) view.window?.close() } diff --git a/DuckDuckGo/DBP/DBPHomeViewController.swift b/DuckDuckGo/DBP/DBPHomeViewController.swift index f3b2cf95d0..cf9e05e900 100644 --- a/DuckDuckGo/DBP/DBPHomeViewController.swift +++ b/DuckDuckGo/DBP/DBPHomeViewController.swift @@ -33,8 +33,16 @@ public extension Notification.Name { final class DBPHomeViewController: NSViewController { private var presentedWindowController: NSWindowController? private let dataBrokerProtectionManager: DataBrokerProtectionManager + private let pixelHandler: EventMapping = DataBrokerProtectionPixelsHandler() + private var currentChildViewController: NSViewController? + private var observer: NSObjectProtocol? - lazy var dataBrokerProtectionViewController: DataBrokerProtectionViewController = { + private let prerequisiteVerifier: DataBrokerPrerequisitesStatusVerifier + private lazy var errorViewController: DataBrokerProtectionErrorViewController = { + DataBrokerProtectionErrorViewController() + }() + + private lazy var dataBrokerProtectionViewController: DataBrokerProtectionViewController = { let privacyConfigurationManager = PrivacyFeatures.contentBlocking.privacyConfigurationManager let features = ContentScopeFeatureToggles(emailProtection: false, emailProtectionIncontextSignup: false, @@ -63,8 +71,9 @@ final class DBPHomeViewController: NSViewController { }) }() - init(dataBrokerProtectionManager: DataBrokerProtectionManager) { + init(dataBrokerProtectionManager: DataBrokerProtectionManager, prerequisiteVerifier: DataBrokerPrerequisitesStatusVerifier = DefaultDataBrokerPrerequisitesStatusVerifier()) { self.dataBrokerProtectionManager = dataBrokerProtectionManager + self.prerequisiteVerifier = prerequisiteVerifier super.init(nibName: nil, bundle: nil) } @@ -79,32 +88,45 @@ final class DBPHomeViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() - if !dataBrokerProtectionManager.shouldAskForInviteCode() { - attachDataBrokerContainerView() - } + setupUI() + setupObserver() - if dataBrokerProtectionManager.dataManager.fetchProfile() != nil { - let dbpDateStore = DefaultWaitlistActivationDateStore(source: .dbp) - dbpDateStore.updateLastActiveDate() + do { + if try dataBrokerProtectionManager.dataManager.fetchProfile() != nil { + let dbpDateStore = DefaultWaitlistActivationDateStore(source: .dbp) + dbpDateStore.updateLastActiveDate() + } + } catch { + os_log("DBPHomeViewController error: viewDidLoad, error: %{public}@", log: .error, error.localizedDescription) + pixelHandler.fire(.generalError(error: error, functionOccurredIn: "DBPHomeViewController.viewDidLoad")) } } - private func attachDataBrokerContainerView() { - addChild(dataBrokerProtectionViewController) - view.addSubview(dataBrokerProtectionViewController.view) - } - override func viewDidAppear() { super.viewDidAppear() - if dataBrokerProtectionManager.shouldAskForInviteCode() { + if shouldAskForInviteCode() { presentInviteCodeFlow() } } override func viewDidLayout() { super.viewDidLayout() - dataBrokerProtectionViewController.view.frame = view.bounds + if let currentChildViewController = currentChildViewController { + currentChildViewController.view.frame = view.bounds + } + } + + private func setupUI() { + if !shouldAskForInviteCode() { + setupUIWithCurrentStatus() + } + } + + private func setupObserver() { + observer = NotificationCenter.default.addObserver(forName: NSApplication.didBecomeActiveNotification, object: nil, queue: nil) { [weak self] _ in + self?.setupUI() + } } private func presentInviteCodeFlow() { @@ -122,13 +144,54 @@ final class DBPHomeViewController: NSViewController { } parentWindowController.window?.beginSheet(newWindow) } + + private func setupUIWithCurrentStatus() { + setupUIWithStatus(prerequisiteVerifier.checkStatus()) + } + + private func setupUIWithStatus(_ status: DataBrokerPrerequisitesStatus) { + switch status { + case .invalidDirectory: + displayWrongDirectoryErrorUI() + pixelHandler.fire(.homeViewShowBadPathError) + case .invalidSystemPermission: + displayWrongPermissionsErrorUI() + pixelHandler.fire(.homeViewShowNoPermissionError) + case .valid: + displayDBPUI() + pixelHandler.fire(.homeViewShowWebUI) + } + } + + private func shouldAskForInviteCode() -> Bool { + prerequisiteVerifier.checkStatus() == .valid && dataBrokerProtectionManager.shouldAskForInviteCode() + } + + private func displayDBPUI() { + replaceChildController(dataBrokerProtectionViewController) + } + + private func replaceChildController(_ childViewController: NSViewController) { + if let child = currentChildViewController { + child.removeCompletely() + } + + addAndLayoutChild(childViewController) + self.currentChildViewController = childViewController + } + + deinit { + if let observer = observer { + NotificationCenter.default.removeObserver(observer) + } + } } extension DBPHomeViewController: DataBrokerProtectionInviteDialogsViewModelDelegate { func dataBrokerProtectionInviteDialogsViewModelDidReedemSuccessfully(_ viewModel: DataBrokerProtectionInviteDialogsViewModel) { presentedWindowController?.window?.close() presentedWindowController = nil - attachDataBrokerContainerView() + setupUIWithCurrentStatus() } func dataBrokerProtectionInviteDialogsViewModelDidCancel(_ viewModel: DataBrokerProtectionInviteDialogsViewModel) { @@ -138,71 +201,54 @@ extension DBPHomeViewController: DataBrokerProtectionInviteDialogsViewModelDeleg } } -public class DataBrokerProtectionPixelsHandler: EventMapping { - - // swiftlint:disable:next function_body_length - public init() { - super.init { event, _, _, _ in - switch event { - case .error(let error, _): - Pixel.fire(.debug(event: .pixelKitEvent(event), error: error)) - case .ipcServerOptOutAllBrokersCompletion(error: let error), - .ipcServerScanAllBrokersCompletion(error: let error), - .ipcServerRunQueuedOperationsCompletion(error: let error): - // We can't use .debug directly because it modifies the pixel name and clobbers the params - Pixel.fire(.pixelKitEvent(DebugEvent(event, error: error))) - case .parentChildMatches, - .optOutStart, - .optOutEmailGenerate, - .optOutCaptchaParse, - .optOutCaptchaSend, - .optOutCaptchaSolve, - .optOutSubmit, - .optOutEmailReceive, - .optOutEmailConfirm, - .optOutValidate, - .optOutFinish, - .optOutSubmitSuccess, - .optOutFillForm, - .optOutSuccess, - .optOutFailure, - .backgroundAgentStarted, - .backgroundAgentRunOperationsAndStartSchedulerIfPossible, - .backgroundAgentRunOperationsAndStartSchedulerIfPossibleNoSavedProfile, - .backgroundAgentRunOperationsAndStartSchedulerIfPossibleRunQueuedOperationsCallbackStartScheduler, - .backgroundAgentStartedStoppingDueToAnotherInstanceRunning, - .ipcServerRegister, - .ipcServerStartScheduler, - .ipcServerStopScheduler, - .ipcServerOptOutAllBrokers, - .ipcServerScanAllBrokers, - .ipcServerRunQueuedOperations, - .ipcServerRunAllOperations, - .scanSuccess, - .scanFailed, - .scanError, - .dataBrokerProtectionNotificationSentFirstScanComplete, - .dataBrokerProtectionNotificationOpenedFirstScanComplete, - .dataBrokerProtectionNotificationSentFirstRemoval, - .dataBrokerProtectionNotificationOpenedFirstRemoval, - .dataBrokerProtectionNotificationScheduled2WeeksCheckIn, - .dataBrokerProtectionNotificationOpened2WeeksCheckIn, - .dataBrokerProtectionNotificationSentAllRecordsRemoved, - .dataBrokerProtectionNotificationOpenedAllRecordsRemoved, - .dailyActiveUser, - .weeklyActiveUser, - .monthlyActiveUser, - .weeklyReportScanning, - .weeklyReportRemovals, - .scanningEventNewMatch, - .scanningEventReAppearance: - Pixel.fire(.pixelKitEvent(event)) - } +// MARK: - Error UI + +extension DBPHomeViewController { + private func displayWrongDirectoryErrorUI() { + let errorViewModel = DataBrokerProtectionErrorViewModel(title: UserText.dbpErrorPageBadPathTitle, + message: UserText.dbpErrorPageBadPathMessage, + ctaText: UserText.dbpErrorPageBadPathCTA, + ctaAction: { [weak self] in + self?.moveToApplicationFolder() + }) + + errorViewController.errorViewModel = errorViewModel + replaceChildController(errorViewController) + } + + private func displayWrongPermissionsErrorUI() { + let errorViewModel = DataBrokerProtectionErrorViewModel(title: UserText.dbpErrorPageNoPermissionTitle, + message: UserText.dbpErrorPageNoPermissionMessage, + ctaText: UserText.dbpErrorPageNoPermissionCTA, + ctaAction: { [weak self] in + self?.openLoginItemSettings() + }) + + errorViewController.errorViewModel = errorViewModel + replaceChildController(errorViewController) + } +} + +// MARK: - System configuration + +import ServiceManagement + +extension DBPHomeViewController { + func openLoginItemSettings() { + pixelHandler.fire(.homeViewCTAGrantPermissionClicked) + if #available(macOS 13.0, *) { + SMAppService.openSystemSettingsLoginItems() + } else { + let loginItemsURL = URL(string: "x-apple.systempreferences:com.apple.LoginItems-Settings.extension")! + NSWorkspace.shared.open(loginItemsURL) } } - override init(mapping: @escaping EventMapping.Mapping) { - fatalError("Use init()") + func moveToApplicationFolder() { + pixelHandler.fire(.homeViewCTAMoveApplicationClicked) + Task { @MainActor in + await AppLauncher(appBundleURL: Bundle.main.bundleURL).launchApp(withCommand: .moveAppToApplications) + } } } diff --git a/DuckDuckGo/DBP/DataBrokerPrerequisitesStatusVerifier.swift b/DuckDuckGo/DBP/DataBrokerPrerequisitesStatusVerifier.swift new file mode 100644 index 0000000000..f5f5c4d091 --- /dev/null +++ b/DuckDuckGo/DBP/DataBrokerPrerequisitesStatusVerifier.swift @@ -0,0 +1,50 @@ +// +// DataBrokerPrerequisitesStatusVerifier.swift +// +// 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 Combine +import DataBrokerProtection +import LoginItems + +enum DataBrokerPrerequisitesStatus { + case invalidDirectory + case invalidSystemPermission + case valid +} + +protocol DataBrokerPrerequisitesStatusVerifier: AnyObject { + func checkStatus() -> DataBrokerPrerequisitesStatus +} + +final class DefaultDataBrokerPrerequisitesStatusVerifier: DataBrokerPrerequisitesStatusVerifier { + private let statusChecker: DBPLoginItemStatusChecker + + init(statusChecker: DBPLoginItemStatusChecker = LoginItem.dbpBackgroundAgent) { + self.statusChecker = statusChecker + } + + func checkStatus() -> DataBrokerPrerequisitesStatus { + if !statusChecker.doesHaveNecessaryPermissions() { + return .invalidSystemPermission + } else if !statusChecker.isInCorrectDirectory() { + return .invalidDirectory + } else { + return .valid + } + } +} diff --git a/DuckDuckGo/DBP/DataBrokerProtectionAppEvents.swift b/DuckDuckGo/DBP/DataBrokerProtectionAppEvents.swift index b96ad16581..07a579367f 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionAppEvents.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionAppEvents.swift @@ -49,8 +49,8 @@ struct DataBrokerProtectionAppEvents { // If we don't have profileQueries it means there's no user profile saved in our DB // In this case, let's disable the agent and delete any left-over data because there's nothing for it to do - let profileQueries = await DataBrokerProtectionManager.shared.dataManager.fetchBrokerProfileQueryData(ignoresCache: true) - if profileQueries.count > 0 { + if let profileQueriesCount = try? DataBrokerProtectionManager.shared.dataManager.profileQueriesCount(), + profileQueriesCount > 0 { restartBackgroundAgent(loginItemsManager: loginItemsManager) } else { featureVisibility.disableAndDeleteForWaitlistUsers() @@ -81,9 +81,9 @@ struct DataBrokerProtectionAppEvents { if DataBrokerProtectionWaitlist().readyToAcceptTermsAndConditions { switch source { case .cardUI: - DataBrokerProtectionExternalWaitlistPixels.fire(pixel: .dataBrokerProtectionWaitlistCardUITapped, frequency: .dailyAndCount) + DataBrokerProtectionExternalWaitlistPixels.fire(pixel: GeneralPixel.dataBrokerProtectionWaitlistCardUITapped, frequency: .dailyAndCount) case .localPush: - DataBrokerProtectionExternalWaitlistPixels.fire(pixel: .dataBrokerProtectionWaitlistNotificationTapped, frequency: .dailyAndCount) + DataBrokerProtectionExternalWaitlistPixels.fire(pixel: GeneralPixel.dataBrokerProtectionWaitlistNotificationTapped, frequency: .dailyAndCount) } DataBrokerProtectionWaitlistViewControllerPresenter.show() @@ -96,12 +96,12 @@ struct DataBrokerProtectionAppEvents { private func sendActiveDataBrokerProtectionWaitlistUserPixel() { if DefaultDataBrokerProtectionFeatureVisibility().waitlistIsOngoing { - DataBrokerProtectionExternalWaitlistPixels.fire(pixel: .dataBrokerProtectionWaitlistUserActive, frequency: .dailyOnly) + DataBrokerProtectionExternalWaitlistPixels.fire(pixel: GeneralPixel.dataBrokerProtectionWaitlistUserActive, frequency: .daily) } } private func restartBackgroundAgent(loginItemsManager: LoginItemsManager) { - DataBrokerProtectionLoginItemPixels.fire(pixel: .dataBrokerResetLoginItemDaily, frequency: .dailyOnly) + DataBrokerProtectionLoginItemPixels.fire(pixel: GeneralPixel.dataBrokerResetLoginItemDaily, frequency: .daily) loginItemsManager.disableLoginItems([LoginItem.dbpBackgroundAgent]) loginItemsManager.enableLoginItems([LoginItem.dbpBackgroundAgent], log: .dbp) diff --git a/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift b/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift index 44bbfad4b1..b22ee8eac2 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionDebugMenu.swift @@ -48,6 +48,7 @@ final class DataBrokerProtectionDebugMenu: NSMenu { private let customURLLabelMenuItem = NSMenuItem(title: "") private let environmentMenu = NSMenu() + private let statusMenuIconMenu = NSMenuItem(title: "Show Status Menu Icon", action: #selector(DataBrokerProtectionDebugMenu.toggleShowStatusMenuItem)) private let webUISettings = DataBrokerProtectionWebUIURLSettings(.dbp) private let settings = DataBrokerProtectionSettings(defaults: .dbp) @@ -147,6 +148,8 @@ final class DataBrokerProtectionDebugMenu: NSMenu { NSMenuItem.separator() + statusMenuIconMenu.targetting(self) + NSMenuItem(title: "Show DB Browser", action: #selector(DataBrokerProtectionDebugMenu.showDatabaseBrowser)) .targetting(self) NSMenuItem(title: "Force Profile Removal", action: #selector(DataBrokerProtectionDebugMenu.showForceOptOutWindow)) @@ -172,6 +175,7 @@ final class DataBrokerProtectionDebugMenu: NSMenu { updateWaitlistItems() updateWebUIMenuItemsState() updateEnvironmentMenu() + updateShowStatusMenuIconMenu() } // MARK: - Menu functions @@ -204,9 +208,15 @@ final class DataBrokerProtectionDebugMenu: NSMenu { os_log("Running queued operations...", log: .dataBrokerProtection) let showWebView = sender.representedObject as? Bool ?? false - DataBrokerProtectionManager.shared.scheduler.runQueuedOperations(showWebView: showWebView) { error in - if let error = error { - os_log("Queued operations finished, error: %{public}@", log: .dataBrokerProtection, error.localizedDescription) + DataBrokerProtectionManager.shared.scheduler.runQueuedOperations(showWebView: showWebView) { errors in + if let errors = errors { + if let oneTimeError = errors.oneTimeError { + os_log("Queued operations finished, error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) + } + if let operationErrors = errors.operationErrors, + operationErrors.count != 0 { + os_log("Queued operations finished, operation errors count: %{public}d", log: .dataBrokerProtection, operationErrors.count) + } } else { os_log("Queued operations finished", log: .dataBrokerProtection) } @@ -217,9 +227,15 @@ final class DataBrokerProtectionDebugMenu: NSMenu { os_log("Running scan operations...", log: .dataBrokerProtection) let showWebView = sender.representedObject as? Bool ?? false - DataBrokerProtectionManager.shared.scheduler.scanAllBrokers(showWebView: showWebView) { error in - if let error = error { - os_log("Scan operations finished, error: %{public}@", log: .dataBrokerProtection, error.localizedDescription) + DataBrokerProtectionManager.shared.scheduler.startManualScan(showWebView: showWebView, startTime: Date()) { errors in + if let errors = errors { + if let oneTimeError = errors.oneTimeError { + os_log("scan operations finished, error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) + } + if let operationErrors = errors.operationErrors, + operationErrors.count != 0 { + os_log("scan operations finished, operation errors count: %{public}d", log: .dataBrokerProtection, operationErrors.count) + } } else { os_log("Scan operations finished", log: .dataBrokerProtection) } @@ -230,9 +246,15 @@ final class DataBrokerProtectionDebugMenu: NSMenu { os_log("Running Optout operations...", log: .dataBrokerProtection) let showWebView = sender.representedObject as? Bool ?? false - DataBrokerProtectionManager.shared.scheduler.optOutAllBrokers(showWebView: showWebView) { error in - if let error = error { - os_log("Optout operations finished, error: %{public}@", log: .dataBrokerProtection, error.localizedDescription) + DataBrokerProtectionManager.shared.scheduler.optOutAllBrokers(showWebView: showWebView) { errors in + if let errors = errors { + if let oneTimeError = errors.oneTimeError { + os_log("Optout operations finished, error: %{public}@", log: .dataBrokerProtection, oneTimeError.localizedDescription) + } + if let operationErrors = errors.operationErrors, + operationErrors.count != 0 { + os_log("Optout operations finished, operation errors count: %{public}d", log: .dataBrokerProtection, operationErrors.count) + } } else { os_log("Optout operations finished", log: .dataBrokerProtection) } @@ -348,6 +370,10 @@ final class DataBrokerProtectionDebugMenu: NSMenu { } } + @objc private func toggleShowStatusMenuItem() { + settings.showInMenuBar.toggle() + } + @objc func setSelectedEnvironment(_ menuItem: NSMenuItem) { let title = menuItem.title let selectedEnvironment: DataBrokerProtectionSettings.SelectedEnvironment @@ -430,6 +456,10 @@ final class DataBrokerProtectionDebugMenu: NSMenu { environmentMenu.items.first?.state = selectedEnvironment == .production ? .on: .off environmentMenu.items.last?.state = selectedEnvironment == .staging ? .on: .off } + + private func updateShowStatusMenuIconMenu() { + statusMenuIconMenu.state = settings.showInMenuBar ? .on : .off + } } extension DataBrokerProtectionDebugMenu: NSWindowDelegate { diff --git a/DuckDuckGo/DBP/DataBrokerProtectionExternalWaitlistPixels.swift b/DuckDuckGo/DBP/DataBrokerProtectionExternalWaitlistPixels.swift index 79a6d85bf5..f23a4884a5 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionExternalWaitlistPixels.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionExternalWaitlistPixels.swift @@ -17,6 +17,7 @@ // import Foundation +import PixelKit struct DataBrokerProtectionExternalWaitlistPixels { @@ -35,15 +36,11 @@ struct DataBrokerProtectionExternalWaitlistPixels { return (regionCode ?? "US") == "US" } - static func fire(pixel: Pixel.Event, frequency: DailyPixel.PixelFrequency) { + static func fire(pixel: PixelKitEventV2, frequency: PixelKit.Frequency) { if Self.isUserLocaleAllowed { let isInternalUser = NSApp.delegateTyped.internalUserDecider.isInternalUser - DailyPixel.fire(pixel: pixel, - frequency: frequency, - withAdditionalParameters: [ - "isInternalUser": isInternalUser.description - ] - ) + let parameters = ["isInternalUser": isInternalUser.description] + PixelKit.fire(pixel, frequency: frequency, withAdditionalParameters: parameters) } } } diff --git a/DuckDuckGo/DBP/DataBrokerProtectionFeatureDisabler.swift b/DuckDuckGo/DBP/DataBrokerProtectionFeatureDisabler.swift index b9ab9ac50a..83489b21bb 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionFeatureDisabler.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionFeatureDisabler.swift @@ -46,9 +46,13 @@ struct DataBrokerProtectionFeatureDisabler: DataBrokerProtectionFeatureDisabling scheduler.disableLoginItem() - dataManager.removeAllData() + do { + try dataManager.removeAllData() + } catch { + os_log("DataBrokerProtectionFeatureDisabler error: disableAndDelete, error: %{public}@", log: .error, error.localizedDescription) + } - DataBrokerProtectionLoginItemPixels.fire(pixel: .dataBrokerDisableAndDeleteDaily, frequency: .dailyOnly) + DataBrokerProtectionLoginItemPixels.fire(pixel: GeneralPixel.dataBrokerDisableAndDeleteDaily, frequency: .daily) NotificationCenter.default.post(name: .dbpWasDisabled, object: nil) } } diff --git a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemPixels.swift b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemPixels.swift index 30e2373a7f..6b10effcf1 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemPixels.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemPixels.swift @@ -17,19 +17,16 @@ // import Foundation +import PixelKit struct DataBrokerProtectionLoginItemPixels { - static func fire(pixel: Pixel.Event, frequency: DailyPixel.PixelFrequency) { + static func fire(pixel: PixelKitEventV2, frequency: PixelKit.Frequency) { DispatchQueue.main.async { // delegateTyped needs to be called in the main thread let isInternalUser = NSApp.delegateTyped.internalUserDecider.isInternalUser - DailyPixel.fire(pixel: pixel, - frequency: frequency, - withAdditionalParameters: [ - "isInternalUser": isInternalUser.description - ] - ) + let parameters = ["isInternalUser": isInternalUser.description] + PixelKit.fire(pixel, frequency: frequency, withAdditionalParameters: parameters) } } } diff --git a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift index feb254562a..50b75e9fac 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionLoginItemScheduler.swift @@ -36,12 +36,12 @@ final class DataBrokerProtectionLoginItemScheduler { // MARK: - Login Item Management func disableLoginItem() { - DataBrokerProtectionLoginItemPixels.fire(pixel: .dataBrokerDisableLoginItemDaily, frequency: .dailyOnly) + DataBrokerProtectionLoginItemPixels.fire(pixel: GeneralPixel.dataBrokerDisableLoginItemDaily, frequency: .daily) loginItemsManager.disableLoginItems([.dbpBackgroundAgent]) } func enableLoginItem() { - DataBrokerProtectionLoginItemPixels.fire(pixel: .dataBrokerEnableLoginItemDaily, frequency: .dailyOnly) + DataBrokerProtectionLoginItemPixels.fire(pixel: GeneralPixel.dataBrokerEnableLoginItemDaily, frequency: .daily) loginItemsManager.enableLoginItems([.dbpBackgroundAgent], log: .dbp) } } @@ -55,9 +55,11 @@ extension DataBrokerProtectionLoginItemScheduler: DataBrokerProtectionScheduler ipcScheduler.statusPublisher } - func scanAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) { + func startManualScan(showWebView: Bool, + startTime: Date, + completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { enableLoginItem() - ipcScheduler.scanAllBrokers(showWebView: showWebView, completion: completion) + ipcScheduler.startManualScan(showWebView: showWebView, startTime: startTime, completion: completion) } func startScheduler(showWebView: Bool) { @@ -69,7 +71,8 @@ extension DataBrokerProtectionLoginItemScheduler: DataBrokerProtectionScheduler ipcScheduler.stopScheduler() } - func optOutAllBrokers(showWebView: Bool, completion: ((Error?) -> Void)?) { + func optOutAllBrokers(showWebView: Bool, + completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { ipcScheduler.optOutAllBrokers(showWebView: showWebView, completion: completion) } @@ -77,9 +80,14 @@ extension DataBrokerProtectionLoginItemScheduler: DataBrokerProtectionScheduler ipcScheduler.runAllOperations(showWebView: showWebView) } - func runQueuedOperations(showWebView: Bool, completion: ((Error?) -> Void)?) { + func runQueuedOperations(showWebView: Bool, + completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { ipcScheduler.runQueuedOperations(showWebView: showWebView, completion: completion) } + + func getDebugMetadata(completion: @escaping (DBPBackgroundAgentMetadata?) -> Void) { + ipcScheduler.getDebugMetadata(completion: completion) + } } #endif diff --git a/DuckDuckGo/DBP/DataBrokerProtectionManager.swift b/DuckDuckGo/DBP/DataBrokerProtectionManager.swift index 29ce721418..f3b8705674 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionManager.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionManager.swift @@ -36,12 +36,17 @@ public final class DataBrokerProtectionManager { private let dataBrokerProtectionWaitlistDataSource: WaitlistActivationDateStore = DefaultWaitlistActivationDateStore(source: .dbp) lazy var dataManager: DataBrokerProtectionDataManager = { - let dataManager = DataBrokerProtectionDataManager(fakeBrokerFlag: fakeBrokerFlag) + let dataManager = DataBrokerProtectionDataManager(pixelHandler: pixelHandler, fakeBrokerFlag: fakeBrokerFlag) dataManager.delegate = self return dataManager }() - private lazy var ipcClient = DataBrokerProtectionIPCClient(machServiceName: Bundle.main.dbpBackgroundAgentBundleId, pixelHandler: pixelHandler) + private lazy var ipcClient: DataBrokerProtectionIPCClient = { + let loginItemStatusChecker = LoginItem.dbpBackgroundAgent + return DataBrokerProtectionIPCClient(machServiceName: Bundle.main.dbpBackgroundAgentBundleId, + pixelHandler: pixelHandler, + loginItemStatusChecker: loginItemStatusChecker) + }() lazy var scheduler: DataBrokerProtectionLoginItemScheduler = { diff --git a/DuckDuckGo/DBP/DataBrokerProtectionPixelsHandler.swift b/DuckDuckGo/DBP/DataBrokerProtectionPixelsHandler.swift new file mode 100644 index 0000000000..2f91fe97a0 --- /dev/null +++ b/DuckDuckGo/DBP/DataBrokerProtectionPixelsHandler.swift @@ -0,0 +1,122 @@ +// +// DataBrokerProtectionPixelsHandler.swift +// +// 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 DataBrokerProtection +import PixelKit +import Common + +public class DataBrokerProtectionPixelsHandler: EventMapping { + + // swiftlint:disable:next function_body_length + public init() { + super.init { event, _, _, _ in + switch event { + case .error(let error, _): + PixelKit.fire(DebugEvent(event, error: error)) + case .generalError(let error, _), + .secureVaultInitError(let error), + .secureVaultError(let error): + PixelKit.fire(DebugEvent(event, error: error)) + case .ipcServerStartSchedulerXPCError(error: let error), + .ipcServerStopSchedulerXPCError(error: let error), + .ipcServerScanAllBrokersXPCError(error: let error), + .ipcServerScanAllBrokersCompletedOnAgentWithError(error: let error), + .ipcServerScanAllBrokersCompletionCalledOnAppWithError(error: let error), + .ipcServerOptOutAllBrokersCompletion(error: let error), + .ipcServerRunQueuedOperationsCompletion(error: let error): + PixelKit.fire(DebugEvent(event, error: error), frequency: .dailyAndCount, includeAppVersionParameter: true) + case .ipcServerStartSchedulerCalledByApp, + .ipcServerStartSchedulerReceivedByAgent, + .ipcServerStopSchedulerCalledByApp, + .ipcServerStopSchedulerReceivedByAgent, + .ipcServerScanAllBrokersAttemptedToCallWithoutLoginItemPermissions, + .ipcServerScanAllBrokersAttemptedToCallInWrongDirectory, + .ipcServerScanAllBrokersCalledByApp, + .ipcServerScanAllBrokersReceivedByAgent, + .ipcServerScanAllBrokersCompletedOnAgentWithoutError, + .ipcServerScanAllBrokersCompletionCalledOnAppWithoutError, + .ipcServerScanAllBrokersInterruptedOnAgent, + .ipcServerScanAllBrokersCompletionCalledOnAppAfterInterruption: + PixelKit.fire(event, frequency: .dailyAndCount, includeAppVersionParameter: true) + case .parentChildMatches, + .optOutStart, + .optOutEmailGenerate, + .optOutCaptchaParse, + .optOutCaptchaSend, + .optOutCaptchaSolve, + .optOutSubmit, + .optOutEmailReceive, + .optOutEmailConfirm, + .optOutValidate, + .optOutFinish, + .optOutSubmitSuccess, + .optOutFillForm, + .optOutSuccess, + .optOutFailure, + .backgroundAgentStarted, + .backgroundAgentRunOperationsAndStartSchedulerIfPossible, + .backgroundAgentRunOperationsAndStartSchedulerIfPossibleNoSavedProfile, + .backgroundAgentRunOperationsAndStartSchedulerIfPossibleRunQueuedOperationsCallbackStartScheduler, + .backgroundAgentStartedStoppingDueToAnotherInstanceRunning, + .ipcServerOptOutAllBrokers, + .ipcServerRunQueuedOperations, + .ipcServerRunAllOperations, + .scanSuccess, + .scanFailed, + .scanError, + .dataBrokerProtectionNotificationSentFirstScanComplete, + .dataBrokerProtectionNotificationOpenedFirstScanComplete, + .dataBrokerProtectionNotificationSentFirstRemoval, + .dataBrokerProtectionNotificationOpenedFirstRemoval, + .dataBrokerProtectionNotificationScheduled2WeeksCheckIn, + .dataBrokerProtectionNotificationOpened2WeeksCheckIn, + .dataBrokerProtectionNotificationSentAllRecordsRemoved, + .dataBrokerProtectionNotificationOpenedAllRecordsRemoved, + .dailyActiveUser, + .weeklyActiveUser, + .monthlyActiveUser, + .weeklyReportScanning, + .weeklyReportRemovals, + .scanningEventNewMatch, + .scanningEventReAppearance, + .webUILoadingFailed, + .webUILoadingStarted, + .webUILoadingSuccess, + .emptyAccessTokenDaily, + .generateEmailHTTPErrorDaily, + .initialScanTotalDuration, + .initialScanSiteLoadDuration, + .initialScanPostLoadingDuration, + .initialScanPreStartDuration: + PixelKit.fire(event) + + case .homeViewShowNoPermissionError, + .homeViewShowWebUI, + .homeViewShowBadPathError, + .homeViewCTAMoveApplicationClicked, + .homeViewCTAGrantPermissionClicked: + PixelKit.fire(event, frequency: .dailyAndCount) + } + } + } + + override init(mapping: @escaping EventMapping.Mapping) { + fatalError("Use init()") + } +} diff --git a/DuckDuckGo/DBP/DataBrokerProtectionSubscriptionEventHandler.swift b/DuckDuckGo/DBP/DataBrokerProtectionSubscriptionEventHandler.swift index 08ec829fb1..57dd6d5c33 100644 --- a/DuckDuckGo/DBP/DataBrokerProtectionSubscriptionEventHandler.swift +++ b/DuckDuckGo/DBP/DataBrokerProtectionSubscriptionEventHandler.swift @@ -15,11 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#if DBP && SUBSCRIPTION +#if DBP import Foundation import Subscription import DataBrokerProtection +import PixelKit final class DataBrokerProtectionSubscriptionEventHandler { @@ -42,7 +43,7 @@ final class DataBrokerProtectionSubscriptionEventHandler { @objc private func handleAccountDidSignIn() { guard let token = accountManager.accessToken else { - Pixel.fire(.dataBrokerProtectionErrorWhenFetchingSubscriptionAuthTokenAfterSignIn) + PixelKit.fire(GeneralPixel.dataBrokerProtectionErrorWhenFetchingSubscriptionAuthTokenAfterSignIn) assertionFailure("[DBP Subscription] AccountManager signed in but token could not be retrieved") return } diff --git a/DuckDuckGo/DBP/ErrorView/DataBrokerProtectionErrorViewController.swift b/DuckDuckGo/DBP/ErrorView/DataBrokerProtectionErrorViewController.swift new file mode 100644 index 0000000000..fa628b686e --- /dev/null +++ b/DuckDuckGo/DBP/ErrorView/DataBrokerProtectionErrorViewController.swift @@ -0,0 +1,92 @@ +// +// DataBrokerProtectionErrorViewController.swift +// +// 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 SwiftUI + +final class DataBrokerProtectionErrorViewController: NSViewController { + private var errorSubview: NSView? + + var errorViewModel: DataBrokerProtectionErrorViewModel? { + didSet { + guard let errorViewModel = errorViewModel else { return } + + errorSubview?.removeFromSuperview() + + let errorView = DataBrokerProtectionErrorView(viewModel: errorViewModel) + errorSubview = NSHostingView(rootView: errorView) + + if let errorSubview = errorSubview { + view.addAndLayout(errorSubview) + } + } + } +} + +struct DataBrokerProtectionErrorView: View { + var viewModel: DataBrokerProtectionErrorViewModel + + var body: some View { + VStack(alignment: .center, spacing: 16) { + + HStack { + Image("DaxLockScreenLogo") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 32, height: 32) + + Text("Privacy Pro") + .font(.title) + .fontWeight(.light) + } + .padding(.bottom, 25) + + HStack { + Image("dbp-error-info") + .resizable() + .frame(width: 24, height: 24) + + Text(viewModel.title) + .font(.title) + .fontWeight(.light) + } + + Text(viewModel.message) + .font(.body) + .fontWeight(.light) + .multilineTextAlignment(.center) + .padding(.bottom, 10) + + Button(action: { + viewModel.ctaAction() + }) { + Text(viewModel.ctaText) + } + + Spacer() + }.padding() + .frame(maxWidth: 500) + } +} + +struct DataBrokerProtectionErrorViewModel { + let title: String + let message: String + let ctaText: String + let ctaAction: () -> Void +} diff --git a/DuckDuckGo/DBP/LoginItem+DataBrokerProtection.swift b/DuckDuckGo/DBP/LoginItem+DataBrokerProtection.swift index cdbfa623a9..d6fbfa761f 100644 --- a/DuckDuckGo/DBP/LoginItem+DataBrokerProtection.swift +++ b/DuckDuckGo/DBP/LoginItem+DataBrokerProtection.swift @@ -18,6 +18,7 @@ import Foundation import LoginItems +import DataBrokerProtection #if DBP @@ -27,4 +28,28 @@ extension LoginItem { } +extension LoginItem: DBPLoginItemStatusChecker { + + public func doesHaveNecessaryPermissions() -> Bool { + return status != .requiresApproval + } + + public func isInCorrectDirectory() -> Bool { + guard let appPath = Bundle.main.resourceURL?.deletingLastPathComponent() else { return false } + let dirPaths = NSSearchPathForDirectoriesInDomains(.applicationDirectory, .localDomainMask, true) + for path in dirPaths { + let filePath: URL + if #available(macOS 13.0, *) { + filePath = URL(filePath: path) + } else { + filePath = URL(fileURLWithPath: path) + } + if appPath.absoluteString.hasPrefix(filePath.absoluteString) { + return true + } + } + return false + } +} + #endif diff --git a/DuckDuckGo/DBP/RemoteMessaging/DataBrokerProtectionRemoteMessaging.swift b/DuckDuckGo/DBP/RemoteMessaging/DataBrokerProtectionRemoteMessaging.swift index 4359b535e0..b43994834b 100644 --- a/DuckDuckGo/DBP/RemoteMessaging/DataBrokerProtectionRemoteMessaging.swift +++ b/DuckDuckGo/DBP/RemoteMessaging/DataBrokerProtectionRemoteMessaging.swift @@ -18,6 +18,7 @@ import Foundation import Networking +import PixelKit #if DBP @@ -91,7 +92,7 @@ final class DefaultDataBrokerProtectionRemoteMessaging: DataBrokerProtectionRemo try self.messageStorage.store(messages: messages) self.updateLastRefreshDate() // Update last refresh date on success, otherwise let the app try again next time } catch { - Pixel.fire(.debug(event: .dataBrokerProtectionRemoteMessageStorageFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.dataBrokerProtectionRemoteMessageStorageFailed, error: error)) } case .failure(let error): // Ignore 403 errors, those happen when a file can't be found on S3 @@ -100,7 +101,7 @@ final class DefaultDataBrokerProtectionRemoteMessaging: DataBrokerProtectionRemo return } - Pixel.fire(.debug(event: .dataBrokerProtectionRemoteMessageFetchingFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.dataBrokerProtectionRemoteMessageFetchingFailed, error: error)) } } } diff --git a/DuckDuckGo/DataExport/CSVLoginExporter.swift b/DuckDuckGo/DataExport/CSVLoginExporter.swift index 26e9a3f0d2..90062966fe 100644 --- a/DuckDuckGo/DataExport/CSVLoginExporter.swift +++ b/DuckDuckGo/DataExport/CSVLoginExporter.swift @@ -18,6 +18,7 @@ import Foundation import BrowserServicesKit +import PixelKit final class CSVLoginExporter { @@ -49,7 +50,7 @@ final class CSVLoginExporter { } } } catch { - Pixel.fire(.debug(event: .secureVaultError, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.secureVaultError(error: error))) throw error } diff --git a/DuckDuckGo/DataImport/Bookmarks/Firefox/FirefoxBookmarksReader.swift b/DuckDuckGo/DataImport/Bookmarks/Firefox/FirefoxBookmarksReader.swift index fdf0029709..afef50085b 100644 --- a/DuckDuckGo/DataImport/Bookmarks/Firefox/FirefoxBookmarksReader.swift +++ b/DuckDuckGo/DataImport/Bookmarks/Firefox/FirefoxBookmarksReader.swift @@ -45,6 +45,8 @@ final class FirefoxBookmarksReader { case fetchAllFolders case copyTemporaryFile + + case couldNotFindBookmarksFile } var action: DataImportAction { .bookmarks } @@ -53,7 +55,7 @@ final class FirefoxBookmarksReader { var errorType: DataImport.ErrorType { switch type { - case .dbOpen: .noData + case .dbOpen, .couldNotFindBookmarksFile: .noData case .fetchRootEntries, .noRootEntries, .fetchTopLevelFolders, .fetchAllBookmarks, .fetchAllFolders: .dataCorrupted case .copyTemporaryFile: .other } @@ -72,6 +74,10 @@ final class FirefoxBookmarksReader { } func readBookmarks() -> DataImportResult { + guard FileManager.default.fileExists(atPath: firefoxPlacesDatabaseURL.path) else { + return .failure(ImportError(type: .couldNotFindBookmarksFile, underlyingError: nil)) + } + do { currentOperationType = .copyTemporaryFile return try firefoxPlacesDatabaseURL.withTemporaryFile { temporaryDatabaseURL in diff --git a/DuckDuckGo/DataImport/Bookmarks/Safari/SafariDataImporter.swift b/DuckDuckGo/DataImport/Bookmarks/Safari/SafariDataImporter.swift index 005fc26971..0f3daaef5d 100644 --- a/DuckDuckGo/DataImport/Bookmarks/Safari/SafariDataImporter.swift +++ b/DuckDuckGo/DataImport/Bookmarks/Safari/SafariDataImporter.swift @@ -17,7 +17,7 @@ // import AppKit -import Foundation +import PixelKit final class SafariDataImporter: DataImporter { @@ -114,7 +114,7 @@ final class SafariDataImporter: DataImporter { await faviconManager.handleFaviconsByDocumentUrl(faviconsByDocument) case .failure(let error): - Pixel.fire(.dataImportFailed(source: source, sourceVersion: profile.installedAppsMajorVersionDescription(), error: error)) + PixelKit.fire(GeneralPixel.dataImportFailed(source: source, sourceVersion: profile.installedAppsMajorVersionDescription(), error: error)) } } diff --git a/DuckDuckGo/DataImport/Logins/Chromium/ChromiumDataImporter.swift b/DuckDuckGo/DataImport/Logins/Chromium/ChromiumDataImporter.swift index a387ac7d34..1f920dd809 100644 --- a/DuckDuckGo/DataImport/Logins/Chromium/ChromiumDataImporter.swift +++ b/DuckDuckGo/DataImport/Logins/Chromium/ChromiumDataImporter.swift @@ -17,6 +17,7 @@ // import Foundation +import PixelKit internal class ChromiumDataImporter: DataImporter { @@ -139,7 +140,7 @@ internal class ChromiumDataImporter: DataImporter { await faviconManager.handleFaviconsByDocumentUrl(faviconsByDocument) case .failure(let error): - Pixel.fire(.dataImportFailed(source: source, sourceVersion: profile.installedAppsMajorVersionDescription(), error: error)) + PixelKit.fire(GeneralPixel.dataImportFailed(source: source, sourceVersion: profile.installedAppsMajorVersionDescription(), error: error)) } } diff --git a/DuckDuckGo/DataImport/Logins/Chromium/ChromiumKeychainPrompt.swift b/DuckDuckGo/DataImport/Logins/Chromium/ChromiumKeychainPrompt.swift index 4e473eada8..08872a1d78 100644 --- a/DuckDuckGo/DataImport/Logins/Chromium/ChromiumKeychainPrompt.swift +++ b/DuckDuckGo/DataImport/Logins/Chromium/ChromiumKeychainPrompt.swift @@ -17,6 +17,7 @@ // import Foundation +import PixelKit enum ChromiumKeychainPromptResult { case password(String) @@ -45,7 +46,7 @@ final class ChromiumKeychainPrompt: ChromiumKeychainPrompting { var dataFromKeychain: AnyObject? // Fire Pixel to help measure rate of password prompt denied actions - Pixel.fire(.passwordImportKeychainPrompt) + PixelKit.fire(GeneralPixel.passwordImportKeychainPrompt) let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataFromKeychain) diff --git a/DuckDuckGo/DataImport/Logins/Firefox/FirefoxDataImporter.swift b/DuckDuckGo/DataImport/Logins/Firefox/FirefoxDataImporter.swift index a6b87ee62b..5eb7ca6353 100644 --- a/DuckDuckGo/DataImport/Logins/Firefox/FirefoxDataImporter.swift +++ b/DuckDuckGo/DataImport/Logins/Firefox/FirefoxDataImporter.swift @@ -18,6 +18,7 @@ import Foundation import SecureStorage +import PixelKit internal class FirefoxDataImporter: DataImporter { @@ -139,7 +140,7 @@ internal class FirefoxDataImporter: DataImporter { await faviconManager.handleFaviconsByDocumentUrl(faviconsByDocument) case .failure(let error): - Pixel.fire(.dataImportFailed(source: source, sourceVersion: profile.installedAppsMajorVersionDescription(), error: error)) + PixelKit.fire(GeneralPixel.dataImportFailed(source: source, sourceVersion: profile.installedAppsMajorVersionDescription(), error: error)) } } diff --git a/DuckDuckGo/DataImport/Logins/Firefox/FirefoxLoginReader.swift b/DuckDuckGo/DataImport/Logins/Firefox/FirefoxLoginReader.swift index 3c354886cc..af702efd16 100644 --- a/DuckDuckGo/DataImport/Logins/Firefox/FirefoxLoginReader.swift +++ b/DuckDuckGo/DataImport/Logins/Firefox/FirefoxLoginReader.swift @@ -41,6 +41,8 @@ final class FirefoxLoginReader { case decryptUsername case decryptPassword + + case couldNotFindKeyDB } var action: DataImportAction { .passwords } @@ -49,7 +51,7 @@ final class FirefoxLoginReader { var errorType: DataImport.ErrorType { switch type { - case .couldNotFindLoginsFile, .couldNotReadLoginsFile: .noData + case .couldNotFindLoginsFile, .couldNotFindKeyDB, .couldNotReadLoginsFile: .noData case .key3readerStage1, .key3readerStage2, .key3readerStage3, .key4readerStage1, .key4readerStage2, .key4readerStage3, .decryptUsername, .decryptPassword: .decryptionError case .couldNotDetermineFormat: .dataCorrupted case .requiresPrimaryPassword: .other @@ -94,7 +96,7 @@ final class FirefoxLoginReader { func readLogins(dataFormat: DataFormat?) -> DataImportResult<[ImportedLoginCredential]> { var currentOperationType: ImportError.OperationType = .couldNotFindLoginsFile do { - let dataFormat = try dataFormat ?? detectLoginFormat() ?? { throw ImportError(type: .couldNotDetermineFormat, underlyingError: nil) }() + let dataFormat = try dataFormat ?? detectLoginFormat() ?? { throw ImportError(type: .couldNotFindKeyDB, underlyingError: nil) }() let keyData = try getEncryptionKey(dataFormat: dataFormat) let result = try reallyReadLogins(dataFormat: dataFormat, keyData: keyData, currentOperationType: ¤tOperationType) return .success(result) @@ -106,7 +108,7 @@ final class FirefoxLoginReader { } func getEncryptionKey() throws -> Data { - let dataFormat = try detectLoginFormat() ?? { throw ImportError(type: .couldNotDetermineFormat, underlyingError: nil) }() + let dataFormat = try detectLoginFormat() ?? { throw ImportError(type: .couldNotFindKeyDB, underlyingError: nil) }() return try getEncryptionKey(dataFormat: dataFormat) } diff --git a/DuckDuckGo/DataImport/Logins/SecureVault/SecureVaultLoginImporter.swift b/DuckDuckGo/DataImport/Logins/SecureVault/SecureVaultLoginImporter.swift index 17acb874e0..193806cef0 100644 --- a/DuckDuckGo/DataImport/Logins/SecureVault/SecureVaultLoginImporter.swift +++ b/DuckDuckGo/DataImport/Logins/SecureVault/SecureVaultLoginImporter.swift @@ -23,7 +23,7 @@ import SecureStorage final class SecureVaultLoginImporter: LoginImporter { func importLogins(_ logins: [ImportedLoginCredential], progressCallback: @escaping (Int) throws -> Void) throws -> DataImport.DataTypeSummary { - let vault = try AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) + let vault = try AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) var successful: [String] = [] var duplicates: [String] = [] diff --git a/DuckDuckGo/DataImport/Model/DataImportViewModel.swift b/DuckDuckGo/DataImport/Model/DataImportViewModel.swift index 1a2d1eef7b..7e6211da9d 100644 --- a/DuckDuckGo/DataImport/Model/DataImportViewModel.swift +++ b/DuckDuckGo/DataImport/Model/DataImportViewModel.swift @@ -18,8 +18,8 @@ import AppKit import Common -import Foundation import UniformTypeIdentifiers +import PixelKit struct DataImportViewModel { @@ -107,6 +107,11 @@ struct DataImportViewModel { self.dataType = dataType self.result = result } + + static func == (lhs: DataTypeImportResult, rhs: DataTypeImportResult) -> Bool { + lhs.dataType == rhs.dataType && + lhs.result.description == rhs.result.description + } } /// collected import summary for current import operation per selected import source @@ -248,7 +253,7 @@ struct DataImportViewModel { // switch to file import of the failed data type displaying successful import results nextScreen = .fileImport(dataType: dataType, summary: Set(summary.filter({ $0.value.isSuccess }).keys)) } - Pixel.fire(.dataImportFailed(source: importSource, sourceVersion: importSource.installedAppsMajorVersionDescription(selectedProfile: selectedProfile), error: error)) + PixelKit.fire(GeneralPixel.dataImportFailed(source: importSource, sourceVersion: importSource.installedAppsMajorVersionDescription(selectedProfile: selectedProfile), error: error)) } } @@ -286,7 +291,7 @@ struct DataImportViewModel { switch error { // chromium user denied keychain prompt error case let error as ChromiumLoginReader.ImportError where error.type == .userDeniedKeychainPrompt: - Pixel.fire(.passwordImportKeychainPromptDenied) + PixelKit.fire(GeneralPixel.passwordImportKeychainPromptDenied) // stay on the same screen return true @@ -310,7 +315,7 @@ struct DataImportViewModel { log("file read no permission for \(url.path)") if url != selectedProfile?.profileURL.appendingPathComponent(SafariDataImporter.bookmarksFileName) { - Pixel.fire(.dataImportFailed(source: importSource, sourceVersion: importSource.installedAppsMajorVersionDescription(selectedProfile: selectedProfile), error: importError)) + PixelKit.fire(GeneralPixel.dataImportFailed(source: importSource, sourceVersion: importSource.installedAppsMajorVersionDescription(selectedProfile: selectedProfile), error: importError)) } screen = .getReadPermission(url) return true @@ -322,16 +327,19 @@ struct DataImportViewModel { } /// Skip button press - @MainActor mutating func skipImport() { + @MainActor mutating func skipImportOrDismiss(using dismiss: @escaping () -> Void) { if let screen = screenForNextDataTypeRemainingToImport(after: screen.fileImportDataType) { // skip to next non-imported data type self.screen = screen - } else if selectedDataTypes.first(where: { error(for: $0) != nil }) != nil { + } else if selectedDataTypes.first(where: { + let error = error(for: $0) + return error != nil && error?.errorType != .noData + }) != nil { // errors occurred during import: show feedback screen self.screen = .feedback } else { - // display total summary - self.screen = .summary(selectedDataTypes) + // When we skip a manual import, and there are no next non-imported data types, we dismiss + self.dismiss(using: dismiss) } } @@ -671,7 +679,7 @@ extension DataImportViewModel { initiateImport() case .skip: - skipImport() + skipImportOrDismiss(using: dismiss) case .cancel: importTask?.cancel() diff --git a/DuckDuckGo/DataImport/View/DataImportNoDataView.swift b/DuckDuckGo/DataImport/View/DataImportNoDataView.swift index 84fb50a583..889daccbab 100644 --- a/DuckDuckGo/DataImport/View/DataImportNoDataView.swift +++ b/DuckDuckGo/DataImport/View/DataImportNoDataView.swift @@ -31,15 +31,13 @@ struct DataImportNoDataView: View { Text("We couldn‘t find any bookmarks.", comment: "Data import error message: Bookmarks weren‘t found.") .bold() - Text("Try importing bookmarks manually instead.", - comment: "Data import error subtitle: suggestion to import Bookmarks manually by selecting a CSV or HTML file.") + Text(UserText.importNoDataBookmarksSubtitle(from: source)) case .passwords: Text("We couldn‘t find any passwords.", comment: "Data import error message: Passwords weren‘t found.") .bold() - Text("Try importing passwords manually instead.", - comment: "Data import error subtitle: suggestion to import Passwords manually by selecting a CSV or HTML file.") + Text(UserText.importNoDataPasswordsSubtitle(from: source)) } } } diff --git a/DuckDuckGo/DataImport/View/DataImportSummaryView.swift b/DuckDuckGo/DataImport/View/DataImportSummaryView.swift index f9eddeecfb..b385a90c66 100644 --- a/DuckDuckGo/DataImport/View/DataImportSummaryView.swift +++ b/DuckDuckGo/DataImport/View/DataImportSummaryView.swift @@ -33,6 +33,8 @@ struct DataImportSummaryView: View { self.model = model } + private let zeroString = "0" + var body: some View { VStack(alignment: .leading, spacing: 8) { { @@ -61,7 +63,7 @@ struct DataImportSummaryView: View { } if summary.duplicate > 0 { HStack { - failureImage() + skippedImage() Text("Duplicate Bookmarks Skipped:", comment: "Data import summary format of how many duplicate bookmarks (%lld) were skipped during import.") + Text(" " as String) @@ -78,6 +80,15 @@ struct DataImportSummaryView: View { } } + case (.bookmarks, .failure(let error)) where error.errorType == .noData: + HStack { + skippedImage() + Text("Bookmarks:", + comment: "Data import summary format of how many bookmarks were successfully imported.") + + Text(" " as String) + + Text(zeroString).bold() + } + case (.bookmarks, .failure): HStack { failureImage() @@ -85,11 +96,21 @@ struct DataImportSummaryView: View { comment: "Data import summary message of failed bookmarks import.") } - case (.passwords, .failure): - HStack { - failureImage() - Text("Password import failed.", - comment: "Data import summary message of failed passwords import.") + case (.passwords, .failure(let error)): + if error.errorType == .noData { + HStack { + skippedImage() + Text("Passwords:", + comment: "Data import summary format of how many passwords were successfully imported.") + + Text(" " as String) + + Text(zeroString).bold() + } + } else { + HStack { + failureImage() + Text("Password import failed.", + comment: "Data import summary message of failed passwords import.") + } } case (.passwords, .success(let summary)): @@ -126,6 +147,11 @@ private func failureImage() -> some View { .frame(width: 16, height: 16) } +private func skippedImage() -> some View { + Image(.skipped) + .frame(width: 16, height: 16) +} + #if DEBUG #Preview { VStack { diff --git a/DuckDuckGo/DataImport/View/DataImportView.swift b/DuckDuckGo/DataImport/View/DataImportView.swift index 67a8dad11c..2302b54421 100644 --- a/DuckDuckGo/DataImport/View/DataImportView.swift +++ b/DuckDuckGo/DataImport/View/DataImportView.swift @@ -492,8 +492,7 @@ extension DataImportViewModel.ButtonType { profileURL: URL(fileURLWithPath: "/test/Profile 1")), .init(browser: .chrome, profileURL: URL(fileURLWithPath: "/test/Profile 2")), - ], validateProfileData: { _ in - { .init(logins: .available, bookmarks: .available) } // swiftlint:disable:this opening_brace + ], validateProfileData: { _ in { .init(logins: .available, bookmarks: .available) } // swiftlint:disable:this opening_brace }) } dataImporterFactory: { source, type, _, _ in return MockDataImporter(source: source, dataType: type) diff --git a/DuckDuckGo/DataImport/View/ReportFeedbackView.swift b/DuckDuckGo/DataImport/View/ReportFeedbackView.swift index dc35dc0745..86aa8da7c4 100644 --- a/DuckDuckGo/DataImport/View/ReportFeedbackView.swift +++ b/DuckDuckGo/DataImport/View/ReportFeedbackView.swift @@ -150,4 +150,4 @@ private struct InfoItemView: View { } return PreviewView() -} ()} +}()} diff --git a/DuckDuckGo/DeviceAuthentication/DeviceAuthenticationService.swift b/DuckDuckGo/DeviceAuthentication/DeviceAuthenticationService.swift index 307a1bc3bd..3cc09f250d 100644 --- a/DuckDuckGo/DeviceAuthentication/DeviceAuthenticationService.swift +++ b/DuckDuckGo/DeviceAuthentication/DeviceAuthenticationService.swift @@ -21,6 +21,7 @@ import Foundation enum DeviceAuthenticationResult { case success case failure + case noAuthAvailable var authenticated: Bool { return self == .success diff --git a/DuckDuckGo/DeviceAuthentication/LocalAuthenticationService.swift b/DuckDuckGo/DeviceAuthentication/LocalAuthenticationService.swift index 474d53c750..b7ddbe7416 100644 --- a/DuckDuckGo/DeviceAuthentication/LocalAuthenticationService.swift +++ b/DuckDuckGo/DeviceAuthentication/LocalAuthenticationService.swift @@ -24,6 +24,12 @@ final class LocalAuthenticationService: DeviceAuthenticationService { func authenticateDevice(reason: String, result: @escaping DeviceAuthenticationResultHandler) { let context = LAContext() + var error: NSError? + guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else { + result(.noAuthAvailable) + return + } + context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { authenticated, _ in DispatchQueue.main.async { let authenticationResult: DeviceAuthenticationResult = authenticated ? .success : .failure diff --git a/DuckDuckGo/Email/EmailManagerRequestDelegate.swift b/DuckDuckGo/Email/EmailManagerRequestDelegate.swift index 6b01002a03..43e96115fd 100644 --- a/DuckDuckGo/Email/EmailManagerRequestDelegate.swift +++ b/DuckDuckGo/Email/EmailManagerRequestDelegate.swift @@ -17,6 +17,7 @@ // import BrowserServicesKit +import PixelKit extension EmailManagerRequestDelegate { @@ -67,7 +68,7 @@ extension EmailManagerRequestDelegate { parameters["keychain_operation"] = "save" } - Pixel.fire(.debug(event: .emailAutofillKeychainError), withAdditionalParameters: parameters) + PixelKit.fire(DebugEvent(GeneralPixel.emailAutofillKeychainError), withAdditionalParameters: parameters) } } diff --git a/DuckDuckGo/ErrorPage/ErrorPageHTMLTemplate.swift b/DuckDuckGo/ErrorPage/ErrorPageHTMLTemplate.swift index af9d04103e..a288139546 100644 --- a/DuckDuckGo/ErrorPage/ErrorPageHTMLTemplate.swift +++ b/DuckDuckGo/ErrorPage/ErrorPageHTMLTemplate.swift @@ -19,6 +19,7 @@ import Foundation import ContentScopeScripts import WebKit +import Common struct ErrorPageHTMLTemplate { @@ -43,3 +44,130 @@ struct ErrorPageHTMLTemplate { } } + +struct SSLErrorPageHTMLTemplate { + let domain: String + let errorCode: Int + let tld = TLD() + + static var htmlTemplatePath: String { + guard let file = ContentScopeScripts.Bundle.path(forResource: "index", ofType: "html", inDirectory: "pages/sslerrorpage") else { + assertionFailure("HTML template not found") + return "" + } + return file + } + + func makeHTMLFromTemplate() -> String { + let sslError = SSLErrorType.forErrorCode(errorCode) + guard let html = try? String(contentsOfFile: Self.htmlTemplatePath) else { + assertionFailure("Should be able to load template") + return "" + } + let eTldPlus1 = tld.eTLDplus1(domain) ?? domain + let loadTimeData = createJSONString(header: sslError.header, body: sslError.body(for: domain), advancedButton: sslError.advancedButton, leaveSiteButton: sslError.leaveSiteButton, advancedInfoHeader: sslError.advancedInfoTitle, specificMessage: sslError.specificMessage(for: domain, eTldPlus1: eTldPlus1), advancedInfoBody: sslError.advancedInfoBody, visitSiteButton: sslError.visitSiteButton) + return html.replacingOccurrences(of: "$LOAD_TIME_DATA$", with: loadTimeData, options: .literal) + } + + private func createJSONString(header: String, body: String, advancedButton: String, leaveSiteButton: String, advancedInfoHeader: String, specificMessage: String, advancedInfoBody: String, visitSiteButton: String) -> String { + let innerDictionary: [String: Any] = [ + "header": header.escapedUnicodeHtmlString(), + "body": body.escapedUnicodeHtmlString(), + "advancedButton": advancedButton.escapedUnicodeHtmlString(), + "leaveSiteButton": leaveSiteButton.escapedUnicodeHtmlString(), + "advancedInfoHeader": advancedInfoHeader.escapedUnicodeHtmlString(), + "specificMessage": specificMessage.escapedUnicodeHtmlString(), + "advancedInfoBody": advancedInfoBody.escapedUnicodeHtmlString(), + "visitSiteButton": visitSiteButton.escapedUnicodeHtmlString() + ] + + let outerDictionary: [String: Any] = [ + "strings": innerDictionary + ] + + do { + let jsonData = try JSONSerialization.data(withJSONObject: outerDictionary, options: .prettyPrinted) + if let jsonString = String(data: jsonData, encoding: .utf8) { + return jsonString + } else { + return "Error: Could not encode jsonData to String." + } + } catch { + return "Error: \(error.localizedDescription)" + } + } + +} + +public enum SSLErrorType { + case expired + case wrongHost + case selfSigned + case invalid + + var header: String { + return UserText.sslErrorPageHeader + } + + func body(for domain: String) -> String { + let boldDomain = "\(domain)" + return UserText.sslErrorPageBody(boldDomain) + } + + var advancedButton: String { + return UserText.sslErrorPageAdvancedButton + } + + var leaveSiteButton: String { + return UserText.sslErrorPageLeaveSiteButton + } + + var visitSiteButton: String { + return UserText.sslErrorPageVisitSiteButton + } + + var advancedInfoTitle: String { + return UserText.sslErrorAdvancedInfoTitle + } + + var advancedInfoBody: String { + switch self { + case .expired: + return UserText.sslErrorAdvancedInfoBodyExpired + case .wrongHost: + return UserText.sslErrorAdvancedInfoBodyWrongHost + case .selfSigned: + return UserText.sslErrorAdvancedInfoBodyWrongHost + case .invalid: + return UserText.sslErrorAdvancedInfoBodyWrongHost + } + } + + func specificMessage(for domain: String, eTldPlus1: String) -> String { + let boldDomain = "\(domain)" + let boldETldPlus1 = "\(eTldPlus1)" + switch self { + case .expired: + return UserText.sslErrorCertificateExpiredMessage(boldDomain) + case .wrongHost: + return UserText.sslErrorCertificateWrongHostMessage(boldDomain, eTldPlus1: boldETldPlus1) + case .selfSigned: + return UserText.sslErrorCertificateSelfSignedMessage(boldDomain) + case .invalid: + return UserText.sslErrorCertificateSelfSignedMessage(boldDomain) + } + } + + static func forErrorCode(_ errorCode: Int) -> Self { + switch Int32(errorCode) { + case errSSLCertExpired: + return .expired + case errSSLHostNameMismatch: + return .wrongHost + case errSSLXCertChainInvalid: + return .selfSigned + default: + return .invalid + } + } +} diff --git a/DuckDuckGo/ErrorPage/SSLErrorPageUserScript.swift b/DuckDuckGo/ErrorPage/SSLErrorPageUserScript.swift new file mode 100644 index 0000000000..1f3487834e --- /dev/null +++ b/DuckDuckGo/ErrorPage/SSLErrorPageUserScript.swift @@ -0,0 +1,77 @@ +// +// SSLErrorPageUserScript.swift +// +// 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 UserScript + +final class SSLErrorPageUserScript: NSObject, Subfeature { + enum MessageName: String, CaseIterable { + case leaveSite + case visitSite + } + + public let messageOriginPolicy: MessageOriginPolicy = .all + public let featureName: String = "sslErrorPage" + + var isEnabled: Bool = false + var failingURL: URL? + + weak var broker: UserScriptMessageBroker? + weak var delegate: SSLErrorPageUserScriptDelegate? + + func with(broker: UserScriptMessageBroker) { + self.broker = broker + } + + @MainActor + func handler(forMethodNamed methodName: String) -> Subfeature.Handler? { + guard isEnabled else { return nil } + switch MessageName(rawValue: methodName) { + case .leaveSite: + return handleLeaveSiteAction + case .visitSite: + return handleVisitSiteAction + default: + assertionFailure("SSLErrorPageUserScript: Failed to parse User Script message: \(methodName)") + return nil + } + } + + @MainActor + func handleLeaveSiteAction(params: Any, message: UserScriptMessage) -> Encodable? { + delegate?.leaveSite() + return nil + } + + @MainActor + func handleVisitSiteAction(params: Any, message: UserScriptMessage) -> Encodable? { + delegate?.visitSite() + return nil + } + + // MARK: - UserValuesNotification + + struct UserValuesNotification: Encodable { + let userValuesNotification: UserValues + } +} + +protocol SSLErrorPageUserScriptDelegate: AnyObject { + func leaveSite() + func visitSite() +} diff --git a/DuckDuckGo/Favicons/Services/FaviconStore.swift b/DuckDuckGo/Favicons/Services/FaviconStore.swift index 7e2826c27e..2376d29162 100644 --- a/DuckDuckGo/Favicons/Services/FaviconStore.swift +++ b/DuckDuckGo/Favicons/Services/FaviconStore.swift @@ -20,6 +20,7 @@ import Cocoa import CoreData import Combine import Common +import PixelKit protocol FaviconStoring { @@ -230,7 +231,7 @@ fileprivate extension Favicon { let documentUrl = faviconMO.documentUrlEncrypted as? URL, let dateCreated = faviconMO.dateCreated, let relation = Favicon.Relation(rawValue: Int(faviconMO.relation)) else { - Pixel.fire(.debug(event: .faviconDecryptionFailedUnique), limitTo: .dailyFirst) + PixelKit.fire(DebugEvent(GeneralPixel.faviconDecryptionFailedUnique), frequency: .daily) assertionFailure("Favicon: Failed to init Favicon from FaviconManagedObject") return nil } diff --git a/DuckDuckGo/FeatureFlagging/Model/FeatureFlag.swift b/DuckDuckGo/FeatureFlagging/Model/FeatureFlag.swift index 8b784addef..32c34a8b9b 100644 --- a/DuckDuckGo/FeatureFlagging/Model/FeatureFlag.swift +++ b/DuckDuckGo/FeatureFlagging/Model/FeatureFlag.swift @@ -21,6 +21,7 @@ import BrowserServicesKit public enum FeatureFlag: String { case debugMenu + case sslCertificatesBypass /// Add experimental atb parameter to SERP queries for internal users to display Privacy Reminder /// https://app.asana.com/0/1199230911884351/1205979030848528/f @@ -34,6 +35,8 @@ extension FeatureFlag: FeatureFlagSourceProviding { return .internalOnly case .appendAtbToSerpQueries: return .internalOnly + case .sslCertificatesBypass: + return .remoteReleasable(.subfeature(sslCertificatesSubfeature.allowBypass)) } } } diff --git a/DuckDuckGo/Feedback/Model/FeedbackSender.swift b/DuckDuckGo/Feedback/Model/FeedbackSender.swift index 3e032d36aa..09be2ef5a7 100644 --- a/DuckDuckGo/Feedback/Model/FeedbackSender.swift +++ b/DuckDuckGo/Feedback/Model/FeedbackSender.swift @@ -19,6 +19,7 @@ import Common import Foundation import Networking +import PixelKit final class FeedbackSender { @@ -43,7 +44,7 @@ final class FeedbackSender { request.fetch { _, error in if let error = error { os_log("FeedbackSender: Failed to submit feedback %s", type: .error, error.localizedDescription) - Pixel.fire(.debug(event: .feedbackReportingFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.feedbackReportingFailed, error: error)) } } } diff --git a/DuckDuckGo/Feedback/View/FeedbackViewController.swift b/DuckDuckGo/Feedback/View/FeedbackViewController.swift index ff45c1a7e9..6bec572e75 100644 --- a/DuckDuckGo/Feedback/View/FeedbackViewController.swift +++ b/DuckDuckGo/Feedback/View/FeedbackViewController.swift @@ -75,7 +75,7 @@ final class FeedbackViewController: NSViewController { var currentTab: Tab? var currentTabUrl: URL? { - guard let url = currentTab?.content.url else { + guard let url = currentTab?.content.urlForWebView else { return nil } diff --git a/DuckDuckGo/FileDownload/Extensions/WKWebView+Download.swift b/DuckDuckGo/FileDownload/Extensions/WKWebView+Download.swift index ad211f4eba..757f50f845 100644 --- a/DuckDuckGo/FileDownload/Extensions/WKWebView+Download.swift +++ b/DuckDuckGo/FileDownload/Extensions/WKWebView+Download.swift @@ -24,11 +24,7 @@ import WebKit extension WKWebView { var suggestedFilename: String? { - guard let title = self.title?.replacingOccurrences(of: "[~#@*+%{}<>\\[\\]|\"\\_^\\/:\\\\]", - with: "_", - options: .regularExpression), - !title.isEmpty - else { + guard let title = self.title?.replacingInvalidFileNameCharacters(), !title.isEmpty else { return url?.suggestedFilename } return title.appending(".html") diff --git a/UnitTests/FileDownload/Helpers/DownloadListStoreMock.swift b/DuckDuckGo/FileDownload/Model/DownloadListStoreMock.swift similarity index 92% rename from UnitTests/FileDownload/Helpers/DownloadListStoreMock.swift rename to DuckDuckGo/FileDownload/Model/DownloadListStoreMock.swift index 28001ba4e1..edae68b750 100644 --- a/UnitTests/FileDownload/Helpers/DownloadListStoreMock.swift +++ b/DuckDuckGo/FileDownload/Model/DownloadListStoreMock.swift @@ -17,12 +17,12 @@ // import Foundation -@testable import DuckDuckGo_Privacy_Browser +#if DEBUG final class DownloadListStoreMock: DownloadListStoring { var fetchBlock: ((@escaping @MainActor (Result<[DownloadListItem], Error>) -> Void) -> Void)? - func fetch(completionHandler: @escaping @MainActor (Result<[DuckDuckGo_Privacy_Browser.DownloadListItem], any Error>) -> Void) { + func fetch(completionHandler: @escaping @MainActor (Result<[DownloadListItem], any Error>) -> Void) { fetchBlock?(completionHandler) } @@ -42,3 +42,4 @@ final class DownloadListStoreMock: DownloadListStoring { } } +#endif diff --git a/DuckDuckGo/FileDownload/Model/DownloadViewModel.swift b/DuckDuckGo/FileDownload/Model/DownloadViewModel.swift index cdcdadf330..d22e8a9e6e 100644 --- a/DuckDuckGo/FileDownload/Model/DownloadViewModel.swift +++ b/DuckDuckGo/FileDownload/Model/DownloadViewModel.swift @@ -75,7 +75,7 @@ final class DownloadViewModel { } func update(with item: DownloadListItem) { - self.localURL = item.destinationURL + self.localURL = item.tempURL == nil ? item.destinationURL : nil // only return destination file URL for completed downloads self.filename = item.fileName let oldState = self.state let newState = State(item: item, shouldAnimateOnAppear: state.shouldAnimateOnAppear ?? true) diff --git a/DuckDuckGo/FileDownload/Model/FilePresenter.swift b/DuckDuckGo/FileDownload/Model/FilePresenter.swift index be8d94e8a6..1770935af2 100644 --- a/DuckDuckGo/FileDownload/Model/FilePresenter.swift +++ b/DuckDuckGo/FileDownload/Model/FilePresenter.swift @@ -23,7 +23,6 @@ import Foundation private protocol FilePresenterDelegate: AnyObject { var logger: FilePresenterLogger { get } var url: URL? { get } - var primaryPresentedItemURL: URL? { get } func presentedItemDidMove(to newURL: URL) func accommodatePresentedItemDeletion() throws func accommodatePresentedItemEviction() throws @@ -57,12 +56,14 @@ internal class FilePresenter { final let presentedItemOperationQueue: OperationQueue fileprivate final weak var delegate: FilePresenterDelegate? - init(presentedItemOperationQueue: OperationQueue) { + init(presentedItemOperationQueue: OperationQueue, delegate: FilePresenterDelegate) { self.presentedItemOperationQueue = presentedItemOperationQueue + self.delegate = delegate } + final var fallbackPresentedItemURL: URL? final var presentedItemURL: URL? { - guard let delegate else { return nil } + guard let delegate else { return fallbackPresentedItemURL } FilePresenter.dispatchSourceQueue.async { // prevent owning FilePresenter deallocation inside the presentedItemURL getter withExtendedLifetime(delegate) {} @@ -72,12 +73,10 @@ internal class FilePresenter { } final func presentedItemDidMove(to newURL: URL) { - assert(delegate != nil) delegate?.presentedItemDidMove(to: newURL) } func accommodatePresentedItemDeletion(completionHandler: @escaping @Sendable ((any Error)?) -> Void) { - assert(delegate != nil) do { try delegate?.accommodatePresentedItemDeletion() completionHandler(nil) @@ -87,9 +86,8 @@ internal class FilePresenter { } func accommodatePresentedItemEviction(completionHandler: @escaping @Sendable ((any Error)?) -> Void) { - assert(delegate != nil) do { - try delegate?.accommodatePresentedItemEviction() + try delegate?.accommodatePresentedItemEviction() completionHandler(nil) } catch { completionHandler(error) @@ -100,74 +98,138 @@ internal class FilePresenter { final private class DelegatingRelatedFilePresenter: DelegatingFilePresenter { - var primaryPresentedItemURL: URL? { - let url = delegate?.primaryPresentedItemURL - return url + let primaryPresentedItemURL: URL? + + init(primaryPresentedItemURL: URL?, presentedItemOperationQueue: OperationQueue, delegate: FilePresenterDelegate) { + self.primaryPresentedItemURL = primaryPresentedItemURL + super.init(presentedItemOperationQueue: presentedItemOperationQueue, delegate: delegate) } } fileprivate let lock = NSLock() - private var innerPresenter: DelegatingFilePresenter? + private var innerPresenters = [DelegatingFilePresenter]() private var dispatchSourceCancellable: AnyCancellable? fileprivate let logger: any FilePresenterLogger - let primaryPresentedItemURL: URL? - - private var _url: URL? + private var urlController: SecurityScopedFileURLController? final var url: URL? { lock.withLock { - _url + urlController?.url } } private func setURL(_ newURL: URL?) { - guard let oldValue = lock.withLock({ () -> URL?? in - let oldValue = _url - guard oldValue != newURL else { return URL??.none } - _url = newURL - return oldValue - }) else { return } + guard let oldValue = lock.withLock({ _setURL(newURL) }) else { return } didSetURL(newURL, oldValue: oldValue) } + // inside locked scope + private func _setURL(_ newURL: URL?) -> URL?? /* returns old value (URL?) if new value was updated */ { + let oldValue = urlController?.url + guard oldValue != newURL else { return URL??.none } + guard let newURL else { + urlController = nil + return newURL + } + + // if the new url is pointing to the same path (only letter case has changed) - keep its sandbox extension in a new Controller + if let urlController, let oldValue, + oldValue.resolvingSymlinksInPath().path == newURL.resolvingSymlinksInPath().path, + urlController.isManagingSecurityScope { + urlController.updateUrlKeepingSandboxExtensionRetainCount(newURL) + } else { + urlController = SecurityScopedFileURLController(url: newURL, logger: logger) + } + + return oldValue + } + private var urlSubject = PassthroughSubject() final var urlPublisher: AnyPublisher { urlSubject.prepend(url).eraseToAnyPublisher() } - init(url: URL, primaryItemURL: URL? = nil, logger: FilePresenterLogger = OSLog.disabled, createIfNeededCallback: ((URL) throws -> URL)? = nil) throws { - self._url = url - self.primaryPresentedItemURL = primaryItemURL + /// - Parameter url: represented file URL access to which is coordinated by the File Presenter. + /// - Parameter consumeUnbalancedStartAccessingResource: assume the `url` is already accessible (e.g. after choosing the file using Open Panel). + /// would cause an unbalanced `stopAccessingSecurityScopedResource` call on the File Presenter deallocation. + /// - Note: see https://stackoverflow.com/questions/25627628/sandboxed-mac-app-exhausting-security-scoped-url-resources + init(url: URL, consumeUnbalancedStartAccessingResource: Bool = false, logger: FilePresenterLogger = OSLog.disabled, createIfNeededCallback: ((URL) throws -> URL)? = nil) throws { + self.urlController = SecurityScopedFileURLController(url: url, manageSecurityScope: consumeUnbalancedStartAccessingResource, logger: logger) + self.logger = logger - let innerPresenter: DelegatingFilePresenter - if primaryItemURL != nil { - innerPresenter = DelegatingRelatedFilePresenter(presentedItemOperationQueue: FilePresenter.presentedItemOperationQueue) + do { + try setupInnerPresenter(for: url, primaryItemURL: nil, createIfNeededCallback: createIfNeededCallback) + logger.log("🗄️ added file presenter for \"\(url.path)\"") + } catch { + removeFilePresenters() + throw error + } + } + + /// - Parameter url: represented file URL access to which is coordinated by the File Presenter. + /// - Parameter primaryItemURL: URL to a main file resource access to which has been granted. + /// Used to grant out-of-sandbox access to `url` representing a “related” resource like “download.duckload” where the `primaryItemURL` would point to “download.zip”. + /// - Note: the related (“duckload”) file extension should be registered in the Info.plist with `NSIsRelatedItemType` flag set to `true`. + /// - Note: when presenting a related item the security scoped resource access will always be stopped on the File Presenter deallocation + /// - Parameter consumeUnbalancedStartAccessingResource: assume the `url` is already accessible (e.g. after choosing the file using Open Panel). + /// would cause an unbalanced `stopAccessingSecurityScopedResource` call on the File Presenter deallocation. + init(url: URL, primaryItemURL: URL, logger: FilePresenterLogger = OSLog.disabled, createIfNeededCallback: ((URL) throws -> URL)? = nil) throws { + self.urlController = SecurityScopedFileURLController(url: url, logger: logger) + self.logger = logger + + do { + try setupInnerPresenter(for: url, primaryItemURL: primaryItemURL, createIfNeededCallback: createIfNeededCallback) + logger.log("🗄️ added file presenter for \"\(url.path) primary item: \"\(primaryItemURL.path)\"") + } catch { + removeFilePresenters() + throw error + } + } + + private func setupInnerPresenter(for url: URL, primaryItemURL: URL?, createIfNeededCallback: ((URL) throws -> URL)?) throws { + let innerPresenter = if let primaryItemURL { + DelegatingRelatedFilePresenter(primaryPresentedItemURL: primaryItemURL, presentedItemOperationQueue: FilePresenter.presentedItemOperationQueue, delegate: self) } else { - innerPresenter = DelegatingFilePresenter(presentedItemOperationQueue: FilePresenter.presentedItemOperationQueue) + DelegatingFilePresenter(presentedItemOperationQueue: FilePresenter.presentedItemOperationQueue, delegate: self) } - self.innerPresenter = innerPresenter - innerPresenter.delegate = self + self.innerPresenters = [innerPresenter] + NSFileCoordinator.addFilePresenter(innerPresenter) if !FileManager.default.fileExists(atPath: url.path) { - if let createFile = createIfNeededCallback { - logger.log("🗄️💥 creating file for presenter at \"\(url.path)\"") - self._url = try coordinateWrite(at: url, using: createFile) - - // re-add File Presenter for the updated URL + guard let createFile = createIfNeededCallback else { + throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: url.path]) + } + logger.log("🗄️💥 creating file for presenter at \"\(url.path)\"") + // create new file at the presented URL using the provided callback and update URL if needed + _=self._setURL( + try coordinateWrite(at: url, using: createFile) + ) + + if primaryItemURL == nil { + // Remove and re-add the file presenter for regular item presenters. NSFileCoordinator.removeFilePresenter(innerPresenter) NSFileCoordinator.addFilePresenter(innerPresenter) - - } else { - throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: url.path]) } } - addFSODispatchSource(for: url) + // to correctly handle file move events for a “related” item presenters we need to use a secondary presenter + if primaryItemURL != nil { + // set permanent original url without tracking file movements + // to correctly release the sandbox extension when the “related” presenter is removed + innerPresenter.fallbackPresentedItemURL = url + innerPresenter.delegate = nil + + let innerPresenter2 = DelegatingFilePresenter(presentedItemOperationQueue: FilePresenter.presentedItemOperationQueue, delegate: self) + NSFileCoordinator.addFilePresenter(innerPresenter2) + innerPresenters.append(innerPresenter2) + } - logger.log("🗄️ added file presenter for \"\(url.path)\"\(primaryPresentedItemURL != nil ? " primary item: \"\(primaryPresentedItemURL!.path)\"" : "")") + try coordinateRead(at: url, with: .withoutChanges) { url in + addFSODispatchSource(for: url) + } } private func addFSODispatchSource(for url: URL) { @@ -187,7 +249,7 @@ internal class FilePresenter { self.logger.log("🗄️⚠️ file delete event handler: \"\(url.path)\"") var resolvedBookmarkData: URL? { var isStale = false - guard let presenter = self as? SandboxFilePresenter, + guard let presenter = self as? BookmarkFilePresenter, let bookmarkData = presenter.fileBookmarkData, let url = try? URL(resolvingBookmarkData: bookmarkData, bookmarkDataIsStale: &isStale) else { if FileManager().fileExists(atPath: url.path) { return url } // file still exists but with different letter case ? @@ -212,25 +274,36 @@ internal class FilePresenter { dispatchSource.resume() } - private func removeFilePresenter() { - if let innerPresenter { - logger.log("🗄️ removing file presenter for \"\(url?.path ?? "")\"") + private func removeFilePresenters() { + for (idx, innerPresenter) in innerPresenters.enumerated() { + // innerPresenter delegate won‘t be available at this point when called from `deinit`, + // so set the final url here to correctly remove the presenter. + if innerPresenter.fallbackPresentedItemURL == nil { + innerPresenter.fallbackPresentedItemURL = urlController?.url + } + logger.log("🗄️ removing file presenter \(idx) for \"\(innerPresenter.presentedItemURL?.path ?? "")\"") NSFileCoordinator.removeFilePresenter(innerPresenter) - self.innerPresenter = nil } + if innerPresenters.count > 1 { + // ”related” item File Presenters make an unbalanced sandbox extension retain, + // release the actual file URL sandbox extension by calling an extra `stopAccessingSecurityScopedResource` + urlController?.url.consumeUnbalancedStartAccessingSecurityScopedResource() + } + innerPresenters = [] } fileprivate func didSetURL(_ newValue: URL?, oldValue: URL?) { - assert(newValue != oldValue) + assert(newValue == nil || newValue != oldValue) logger.log("🗄️ did update url from \"\(oldValue?.path ?? "")\" to \"\(newValue?.path ?? "")\"") urlSubject.send(newValue) } deinit { - removeFilePresenter() + removeFilePresenters() } } + extension FilePresenter: FilePresenterDelegate { func presentedItemDidMove(to newURL: URL) { @@ -240,8 +313,9 @@ extension FilePresenter: FilePresenterDelegate { func accommodatePresentedItemDeletion() throws { logger.log("🗄️ accommodatePresentedItemDeletion (\"\(url?.path ?? "")\")") + // should go before resetting the URL to correctly remove File Presenter + removeFilePresenters() setURL(nil) - removeFilePresenter() } func accommodatePresentedItemEviction() throws { @@ -254,9 +328,7 @@ extension FilePresenter: FilePresenterDelegate { /// Maintains File Bookmark Data for presented resource URL /// and manages its sandbox security scope access calling `stopAccessingSecurityScopedResource` on deinit /// balanced with preceding `startAccessingSecurityScopedResource` -final class SandboxFilePresenter: FilePresenter { - - private let securityScopedURL: URL? +final class BookmarkFilePresenter: FilePresenter { private var _fileBookmarkData: Data? final var fileBookmarkData: Data? { @@ -271,21 +343,31 @@ final class SandboxFilePresenter: FilePresenter { } /// - Parameter url: represented file URL access to which is coordinated by the File Presenter. - /// - Parameter primaryItemURL: URL to a main file resource access to which has been granted. - /// Used to grant out-of-sandbox access to `url` representing a “secondary” resource like “download.duckload” where the `primaryItemURL` would point to “download.zip”. - /// - Note: the secondary (“duckload”) file extension should be registered in the Info.plist with `NSIsRelatedItemType` flag set to `true`. /// - Parameter consumeUnbalancedStartAccessingResource: assume the `url` is already accessible (e.g. after choosing the file using Open Panel). /// would cause an unbalanced `stopAccessingSecurityScopedResource` call on the File Presenter deallocation. - init(url: URL, primaryItemURL: URL? = nil, consumeUnbalancedStartAccessingResource: Bool = false, logger: FilePresenterLogger = OSLog.disabled, createIfNeededCallback: ((URL) throws -> URL)? = nil) throws { + override init(url: URL, consumeUnbalancedStartAccessingResource: Bool = false, logger: FilePresenterLogger = OSLog.disabled, createIfNeededCallback: ((URL) throws -> URL)? = nil) throws { - if consumeUnbalancedStartAccessingResource || url.startAccessingSecurityScopedResource() == true { - self.securityScopedURL = url - logger.log("🏝️ \(consumeUnbalancedStartAccessingResource ? "consuming unbalanced startAccessingResource for" : "started resource access for") \"\(url.path)\"") - } else { - self.securityScopedURL = nil - logger.log("🏖️ didn‘t start resource access for \"\(url.path)\"") + try super.init(url: url, consumeUnbalancedStartAccessingResource: consumeUnbalancedStartAccessingResource, logger: logger, createIfNeededCallback: createIfNeededCallback) + + do { + try self.coordinateRead(at: url, with: .withoutChanges) { url in + logger.log("📒 updating bookmark data for \"\(url.path)\"") + self._fileBookmarkData = try url.bookmarkData(options: .withSecurityScope) + } + } catch { + logger.log("📕 bookmark data retreival failed for \"\(url.path)\": \(error)") + throw error } + } + /// - Parameter url: represented file URL access to which is coordinated by the File Presenter. + /// - Parameter primaryItemURL: URL to a main file resource access to which has been granted. + /// Used to grant out-of-sandbox access to `url` representing a “related” resource like “download.duckload” where the `primaryItemURL` would point to “download.zip”. + /// - Note: the related (“duckload”) file extension should be registered in the Info.plist with `NSIsRelatedItemType` flag set to `true`. + /// - Note: when presenting a related item the security scoped resource access will always be stopped on the File Presenter deallocation + /// - Parameter consumeUnbalancedStartAccessingResource: assume the `url` is already accessible (e.g. after choosing the file using Open Panel). + /// would cause an unbalanced `stopAccessingSecurityScopedResource` call on the File Presenter deallocation. + override init(url: URL, primaryItemURL: URL, logger: FilePresenterLogger = OSLog.disabled, createIfNeededCallback: ((URL) throws -> URL)? = nil) throws { try super.init(url: url, primaryItemURL: primaryItemURL, logger: logger, createIfNeededCallback: createIfNeededCallback) do { @@ -305,15 +387,8 @@ final class SandboxFilePresenter: FilePresenter { var isStale = false logger.log("📒 resolving url from bookmark data") let url = try URL(resolvingBookmarkData: fileBookmarkData, options: .withSecurityScope, bookmarkDataIsStale: &isStale) - if url.startAccessingSecurityScopedResource() == true { - self.securityScopedURL = url - logger.log("🏝️ started resource access for \"\(url.path)\"\(isStale ? " (stale)" : "")") - } else { - self.securityScopedURL = nil - logger.log("🏖️ didn‘t start resource access for \"\(url.path)\"\(isStale ? " (stale)" : "")") - } - try super.init(url: url, logger: logger) + try super.init(url: url, consumeUnbalancedStartAccessingResource: true, logger: logger) if isStale { DispatchQueue.global().async { [weak self] in @@ -346,25 +421,18 @@ final class SandboxFilePresenter: FilePresenter { fileBookmarkDataSubject.send(fileBookmarkData) } - deinit { - if let securityScopedURL { - logger.log("🗄️ stopAccessingSecurityScopedResource \"\(securityScopedURL.path)\"") - securityScopedURL.stopAccessingSecurityScopedResource() - } - } - } extension FilePresenter { func coordinateRead(at url: URL? = nil, with options: NSFileCoordinator.ReadingOptions = [], using reader: (URL) throws -> T) throws -> T { - guard let innerPresenter, let url = url ?? self.url else { throw CocoaError(.fileNoSuchFile) } + guard let innerPresenter = innerPresenters.last, let url = url ?? self.url else { throw CocoaError(.fileNoSuchFile) } return try NSFileCoordinator(filePresenter: innerPresenter).coordinateRead(at: url, with: options, using: reader) } func coordinateWrite(at url: URL? = nil, with options: NSFileCoordinator.WritingOptions = [], using writer: (URL) throws -> T) throws -> T { - guard let innerPresenter, let url = url ?? self.url else { throw CocoaError(.fileNoSuchFile) } + guard let innerPresenter = innerPresenters.last, let url = url ?? self.url else { throw CocoaError(.fileNoSuchFile) } // temporarily disable DispatchSource file removal events dispatchSourceCancellable?.cancel() @@ -377,7 +445,7 @@ extension FilePresenter { } public func coordinateMove(from url: URL? = nil, to: URL, with options2: NSFileCoordinator.WritingOptions = .forReplacing, using move: (URL, URL) throws -> T) throws -> T { - guard let innerPresenter, let url = url ?? self.url else { throw CocoaError(.fileNoSuchFile) } + guard let innerPresenter = innerPresenters.last, let url = url ?? self.url else { throw CocoaError(.fileNoSuchFile) } return try NSFileCoordinator(filePresenter: innerPresenter).coordinateMove(from: url, to: to, with: options2, using: move) } @@ -425,33 +493,3 @@ extension NSFileCoordinator { } } - -#if DEBUG -extension NSURL { - - private static var stopAccessingSecurityScopedResourceCallback: ((URL) -> Void)? - - private static let originalStopAccessingSecurityScopedResource = { - class_getInstanceMethod(NSURL.self, #selector(NSURL.stopAccessingSecurityScopedResource))! - }() - private static let swizzledStopAccessingSecurityScopedResource = { - class_getInstanceMethod(NSURL.self, #selector(NSURL.swizzled_stopAccessingSecurityScopedResource))! - }() - private static let swizzleStopAccessingSecurityScopedResourceOnce: Void = { - method_exchangeImplementations(originalStopAccessingSecurityScopedResource, swizzledStopAccessingSecurityScopedResource) - }() - - static func swizzleStopAccessingSecurityScopedResource(with stopAccessingSecurityScopedResourceCallback: ((URL) -> Void)?) { - _=swizzleStopAccessingSecurityScopedResourceOnce - self.stopAccessingSecurityScopedResourceCallback = stopAccessingSecurityScopedResourceCallback - } - - @objc private dynamic func swizzled_stopAccessingSecurityScopedResource() { - if let stopAccessingSecurityScopedResourceCallback = Self.stopAccessingSecurityScopedResourceCallback { - stopAccessingSecurityScopedResourceCallback(self as URL) - } - self.swizzled_stopAccessingSecurityScopedResource() // call original - } - -} -#endif diff --git a/DuckDuckGo/FileDownload/Model/NSURL+sandboxExtensionRetainCount.m b/DuckDuckGo/FileDownload/Model/NSURL+sandboxExtensionRetainCount.m new file mode 100644 index 0000000000..8a312c2fb0 --- /dev/null +++ b/DuckDuckGo/FileDownload/Model/NSURL+sandboxExtensionRetainCount.m @@ -0,0 +1,40 @@ +// +// NSURL+sandboxExtensionRetainCount.m +// +// 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 + +// Macro for adding quotes +#define STRINGIFY(X) STRINGIFY2(X) +#define STRINGIFY2(X) #X + +#import STRINGIFY(SWIFT_OBJC_INTERFACE_HEADER_NAME) + +@implementation NSURL (sandboxExtensionRetainCount) + +/** + * This method will be automatically called at app launch time to swizzle `startAccessingSecurityScopedResource` and + * `stopAccessingSecurityScopedResource` methods to accurately reflect the current number of start and stop calls + * stored in the associated `NSURL.sandboxExtensionRetainCount` value. + * + * See SecurityScopedFileURLController.swift + */ ++ (void)initialize { + [self swizzleStartStopAccessingSecurityScopedResourceOnce]; +} + +@end diff --git a/DuckDuckGo/FileDownload/Model/SecurityScopedFileURLController.swift b/DuckDuckGo/FileDownload/Model/SecurityScopedFileURLController.swift new file mode 100644 index 0000000000..bec94e02ac --- /dev/null +++ b/DuckDuckGo/FileDownload/Model/SecurityScopedFileURLController.swift @@ -0,0 +1,182 @@ +// +// SecurityScopedFileURLController.swift +// +// 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 + +/// Manages security-scoped resource access to a file URL. +/// +/// This class is designed to consume unbalanced `startAccessingSecurityScopedResource` calls and ensure proper +/// resource cleanup by calling `stopAccessingSecurityScopedResource` the appropriate number of times +/// to end the resource access securely. +/// +/// - Note: Used in conjunction with NSURL extension swizzling the `startAccessingSecurityScopedResource` and +/// `stopAccessingSecurityScopedResource` methods to accurately reflect the current number of start and stop calls. +/// The number is reflected in the associated `URL.sandboxExtensionRetainCount` value. +final class SecurityScopedFileURLController { + + fileprivate let logger: any FilePresenterLogger + + private(set) var url: URL + let isManagingSecurityScope: Bool + + /// Initializes a new instance of `SecurityScopedFileURLController` with the provided URL and security-scoped resource handling options. + /// + /// - Parameters: + /// - url: The URL of the file to manage. + /// - manageSecurityScope: A Boolean value indicating whether the controller should manage the URL security scope access (i.e. call stop and end accessing resource methods). + /// - logger: An optional logger instance for logging file operations. Defaults to disabled. + /// - Note: when `manageSecurityScope` is `true` access to the represented URL will be stopped for the whole app on the controller deallocation. + init(url: URL, manageSecurityScope: Bool = true, logger: any FilePresenterLogger = OSLog.disabled) { + assert(url.isFileURL) +#if APPSTORE + let didStartAccess = manageSecurityScope && url.startAccessingSecurityScopedResource() +#else + let didStartAccess = false +#endif + self.url = url + self.isManagingSecurityScope = didStartAccess + self.logger = logger + logger.log("\(didStartAccess ? "🧪 " : "")SecurityScopedFileURLController.init: \(url.sandboxExtensionRetainCount) – \"\(url.path)\"") + } + + func updateUrlKeepingSandboxExtensionRetainCount(_ newURL: URL) { + guard newURL as NSURL !== url as NSURL else { return } + + for _ in 0.. Bool { + if self.swizzled_startAccessingSecurityScopedResource() /* call original */ { + sandboxExtensionRetainCount += 1 + return true + } + return false + } + + @objc private dynamic func swizzled_stopAccessingSecurityScopedResource() { + self.swizzled_stopAccessingSecurityScopedResource() // call original + + var sandboxExtensionRetainCount = self.sandboxExtensionRetainCount + if sandboxExtensionRetainCount > 0 { + sandboxExtensionRetainCount -= 1 + self.sandboxExtensionRetainCount = sandboxExtensionRetainCount + } + } + + private static let sandboxExtensionRetainCountKey = UnsafeRawPointer(bitPattern: "sandboxExtensionRetainCountKey".hashValue)! + fileprivate(set) var sandboxExtensionRetainCount: Int { + get { + (objc_getAssociatedObject(self, Self.sandboxExtensionRetainCountKey) as? NSNumber)?.intValue ?? 0 + } + set { + objc_setAssociatedObject(self, Self.sandboxExtensionRetainCountKey, NSNumber(value: newValue), .OBJC_ASSOCIATION_RETAIN) +#if DEBUG + if newValue > 0 { + NSURL.activeSecurityScopedUrlUsages.insert(.init(url: self)) + } else { + NSURL.activeSecurityScopedUrlUsages.remove(.init(url: self)) + } +#endif + } + } + +#if DEBUG + struct SecurityScopedUrlUsage: Hashable { + let url: NSURL + // hash url as object address + func hash(into hasher: inout Hasher) { + hasher.combine(ObjectIdentifier(url)) + } + static func == (lhs: Self, rhs: Self) -> Bool { + lhs.url === rhs.url + } + } + static var activeSecurityScopedUrlUsages: Set = [] +#endif + +} + +extension URL { + + /// The number of times the security-scoped resource associated with the URL has been accessed + /// using `startAccessingSecurityScopedResource` without a corresponding call to + /// `stopAccessingSecurityScopedResource`. This property provides a count of active accesses + /// to the security-scoped resource, helping manage resource cleanup and ensure proper + /// handling of security-scoped resources. + /// + /// - Note: Accessing this property requires NSURL extension swizzling of `startAccessingSecurityScopedResource` + /// and `stopAccessingSecurityScopedResource` methods to accurately track the count. + var sandboxExtensionRetainCount: Int { + (self as NSURL).sandboxExtensionRetainCount + } + + func consumeUnbalancedStartAccessingSecurityScopedResource() { + (self as NSURL).sandboxExtensionRetainCount += 1 + } + +} diff --git a/DuckDuckGo/FileDownload/Model/WebKitDownloadTask.swift b/DuckDuckGo/FileDownload/Model/WebKitDownloadTask.swift index a39f173fa1..db56c4d535 100644 --- a/DuckDuckGo/FileDownload/Model/WebKitDownloadTask.swift +++ b/DuckDuckGo/FileDownload/Model/WebKitDownloadTask.swift @@ -22,6 +22,7 @@ import Foundation import Navigation import UniformTypeIdentifiers import WebKit +import PixelKit protocol WebKitDownloadTaskDelegate: AnyObject { func fileDownloadTaskNeedsDestinationURL(_ task: WebKitDownloadTask, suggestedFilename: String, suggestedFileType: UTType?) async -> (URL?, UTType?) @@ -116,6 +117,7 @@ final class WebKitDownloadTask: NSObject, ProgressReporting, @unchecked Sendable @MainActor private var itemReplacementDirectory: URL? @MainActor private var itemReplacementDirectoryFSOCancellable: AnyCancellable? @MainActor private var tempFileUrlCancellable: AnyCancellable? + @MainActor private(set) var selectedDestinationURL: URL? var originalRequest: URLRequest? { download.originalRequest @@ -226,6 +228,13 @@ final class WebKitDownloadTask: NSObject, ProgressReporting, @unchecked Sendable do { let fm = FileManager() guard let destinationURL else { throw URLError(.cancelled) } + // in case we‘re overwriting the URL – increment the access counter for the duration of the method + let accessStarted = destinationURL.startAccessingSecurityScopedResource() + defer { + if accessStarted { + destinationURL.stopAccessingSecurityScopedResource() + } + } os_log(.debug, log: log, "download task callback: creating temp directory for \"\(destinationURL.path)\"") switch cleanupStyle { @@ -266,7 +275,7 @@ final class WebKitDownloadTask: NSObject, ProgressReporting, @unchecked Sendable self.download.cancel() self.finish(with: .failure(.failedToCompleteDownloadTask(underlyingError: error, resumeData: nil, isRetryable: false))) - Pixel.fire(.debug(event: .fileGetDownloadLocationFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.fileGetDownloadLocationFailed, error: error)) } return nil } @@ -326,22 +335,22 @@ final class WebKitDownloadTask: NSObject, ProgressReporting, @unchecked Sendable self.download.cancel() self.finish(with: .failure(.failedToCompleteDownloadTask(underlyingError: error, resumeData: nil, isRetryable: false))) - Pixel.fire(.debug(event: .fileDownloadCreatePresentersFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.fileDownloadCreatePresentersFailed, error: error)) } } /// opens File Presenters for destination file and temp file private nonisolated func filePresenters(for destinationURL: URL, tempURL: URL) async throws -> (tempFile: FilePresenter, destinationFile: FilePresenter) { var destinationURL = destinationURL - let duckloadURL = destinationURL.deletingPathExtension().appendingPathExtension(Self.downloadExtension) - let fm = FileManager.default + var duckloadURL = destinationURL.deletingPathExtension().appendingPathExtension(Self.downloadExtension) + let fm = FileManager() // 🧙‍♂️ now we‘re doing do some magique here 🧙‍♂️ // -------------------------------------- os_log(.debug, log: log, "🧙‍♂️ magique.start: \"\(destinationURL.path)\" (\"\(duckloadURL.path)\") directory writable: \(fm.isWritableFile(atPath: destinationURL.deletingLastPathComponent().path))") // 1. create our final destination file (let‘s say myfile.zip) and setup a File Presenter for it // doing this we preserve access to the file until it‘s actually downloaded - let destinationFilePresenter = try SandboxFilePresenter(url: destinationURL, consumeUnbalancedStartAccessingResource: true, logger: log) { url in + let destinationFilePresenter = try BookmarkFilePresenter(url: destinationURL, consumeUnbalancedStartAccessingResource: true, logger: log) { url in try fm.createFile(atPath: url.path, contents: nil) ? url : { throw CocoaError(.fileWriteNoPermission, userInfo: [NSFilePathErrorKey: url.path]) }() @@ -353,45 +362,76 @@ final class WebKitDownloadTask: NSObject, ProgressReporting, @unchecked Sendable // 2. mark the file as hidden until it‘s downloaded to not to confuse user // and prevent from unintentional opening of the empty file - var resourceValues = URLResourceValues() - resourceValues.isHidden = true - try destinationURL.setResourceValues(resourceValues) - os_log(.debug, log: log, "🧙‍♂️ \"\(destinationURL.path)\" hidden, moving temp file from \"\(tempURL.path)\" to \"\(duckloadURL.path)\"") + try destinationURL.setFileHidden(true) + os_log(.debug, log: log, "🧙‍♂️ \"\(destinationURL.path)\" hidden") - // 3. then we move the temporary download file to the destination directory (myfile.zip.duckload) + // 3. then we move the temporary download file to the destination directory (myfile.duckload) // this is doable in sandboxed builds by using “Related Items” i.e. using a file URL with an extra // `.duckload` extension appended and “Primary Item” pointing to the sandbox-accessible destination URL // the `.duckload` document type is registered in the Info.plist with `NSIsRelatedItemType` flag // // - after the file is downloaded we‘ll replace the destination file with the `.duckload` file if fm.fileExists(atPath: duckloadURL.path) { - // remove the `.duckload` item if already exists + // `.duckload` already exists do { - try FilePresenter(url: duckloadURL, primaryItemURL: destinationURL).coordinateWrite(with: .forDeleting) { duckloadURL in - try fm.removeItem(at: duckloadURL) - } + try chooseAlternativeDuckloadFileNameOrRemove(&duckloadURL, destinationURL: destinationURL) } catch { // that‘s ok, we‘ll keep using the original temp file - os_log(.error, log: log, "❗️ could not remove \"\(duckloadURL.path)\" \(error)") + os_log(.error, log: log, "❗️ can‘t resolve duckload file exists: \"\(duckloadURL.path)\": \(error)") + duckloadURL = tempURL } } - // now move the temp file to `.duckload` instantiating a File Presenter with it - let tempFilePresenter = try SandboxFilePresenter(url: duckloadURL, primaryItemURL: destinationURL, logger: log) { [log] duckloadURL in - do { - try fm.moveItem(at: tempURL, to: duckloadURL) - } catch { - // fallback: move failed, keep the temp file in the original location - os_log(.error, log: log, "🙁 fallback with \(error), will use \(tempURL.path)") - Pixel.fire(.debug(event: .fileAccessRelatedItemFailed, error: error)) - return tempURL + + let tempFilePresenter = if duckloadURL == tempURL { + // we won‘t use a `.duckload` file for this download, the file will be left in the temp location instead + try BookmarkFilePresenter(url: duckloadURL, logger: log) + } else { + // now move the temp file to `.duckload` instantiating a File Presenter with it + try BookmarkFilePresenter(url: duckloadURL, primaryItemURL: destinationURL, logger: log) { [log] duckloadURL in + do { + try fm.moveItem(at: tempURL, to: duckloadURL) + return duckloadURL + } catch { + // fallback: move failed, keep the temp file in the original location + os_log(.error, log: log, "🙁 fallback with \(error), will use \(tempURL.path)") + PixelKit.fire(DebugEvent(GeneralPixel.fileAccessRelatedItemFailed, error: error)) + return tempURL + } } - return duckloadURL } os_log(.debug, log: log, "🧙‍♂️ \"\(duckloadURL.path)\" (\"\(tempFilePresenter.url?.path ?? "")\") ready") return (tempFile: tempFilePresenter, destinationFile: destinationFilePresenter) } + private func chooseAlternativeDuckloadFileNameOrRemove(_ duckloadURL: inout URL, destinationURL: URL) throws { + let fm = FileManager() + // are we using the `.duckload` file for some other download (with different extension)? + if NSFileCoordinator.filePresenters.first(where: { $0.presentedItemURL?.resolvingSymlinksInPath() == duckloadURL.resolvingSymlinksInPath() }) != nil { + // if the downloads directory is writable without extra permission – try choosing another `.duckload` filename + if fm.isWritableFile(atPath: duckloadURL.deletingLastPathComponent().path) { + // append `.duckload` to the destination file name with extension + let destinationPathExtension = destinationURL.pathExtension + let pathExtension = destinationPathExtension.isEmpty ? Self.downloadExtension : destinationPathExtension + "." + Self.downloadExtension + duckloadURL = duckloadURL.deletingPathExtension().appendingPathExtension(pathExtension) + + // choose non-existent path + duckloadURL = try fm.withNonExistentUrl(for: duckloadURL, incrementingIndexIfExistsUpTo: 1000, pathExtension: pathExtension) { url in + try Data().write(to: url) + return url + } + } else { + // continue keeping the temp file in the temp dir + throw CocoaError(.fileWriteFileExists) + } + } + + os_log(.debug, log: log, "removing temp file \"\(duckloadURL.path)\"") + try FilePresenter(url: duckloadURL, primaryItemURL: destinationURL).coordinateWrite(with: .forDeleting) { duckloadURL in + try fm.removeItem(at: duckloadURL) + } + } + private nonisolated func reuseFilePresenters(tempFile: FilePresenter, destination: FilePresenter, tempURL: URL) async throws -> (tempFile: FilePresenter, destinationFile: FilePresenter) { // if the download is “resumed” as a new download (replacing the destination file) - // use the existing `.duckload` file and move the temp file in its place @@ -560,7 +600,7 @@ extension WebKitDownloadTask: WKDownloadDelegate { progress.totalUnitCount = response.expectedContentLength } - var suggestedFilename = suggestedFilename + var suggestedFilename = (suggestedFilename.removingPercentEncoding ?? suggestedFilename).replacingInvalidFileNameCharacters() // sometimes suggesteFilename has an extension appended to already present URL file extension // e.g. feed.xml.rss for www.domain.com/rss.xml if let urlSuggestedFilename = response.url?.suggestedFilename, @@ -587,6 +627,7 @@ extension WebKitDownloadTask: WKDownloadDelegate { return nil } + self.selectedDestinationURL = destinationURL return await prepareChosenDestinationURL(destinationURL, fileType: suggestedFileType, cleanupStyle: cleanupStyle) } @@ -646,7 +687,7 @@ extension WebKitDownloadTask: WKDownloadDelegate { self.finish(with: .success(destinationFile)) } catch { - Pixel.fire(.debug(event: .fileMoveToDownloadsFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.fileMoveToDownloadsFailed, error: error)) os_log(.error, log: log, "fileMoveToDownloadsFailed: \(error)") self.finish(with: .failure(.failedToCompleteDownloadTask(underlyingError: error, resumeData: nil, isRetryable: false))) } @@ -697,20 +738,7 @@ extension WebKitDownloadTask { override var description: String { guard Thread.isMainThread else { #if DEBUG - os_log(""" - - - ------------------------------------------------------------------------------------------------------ - BREAK: - ------------------------------------------------------------------------------------------------------ - - ❗️accessing WebKitDownloadTask.description from non-main thread - - Hit Continue (^⌘Y) to continue program execution - ------------------------------------------------------------------------------------------------------ - - """, type: .fault) - raise(SIGINT) + breakByRaisingSigInt("❗️accessing WebKitDownloadTask.description from non-main thread") #endif return "" } diff --git a/DuckDuckGo/FileDownload/Services/DownloadListCoordinator.swift b/DuckDuckGo/FileDownload/Services/DownloadListCoordinator.swift index a7d0b3e1d3..55763a2c5c 100644 --- a/DuckDuckGo/FileDownload/Services/DownloadListCoordinator.swift +++ b/DuckDuckGo/FileDownload/Services/DownloadListCoordinator.swift @@ -20,6 +20,7 @@ import Combine import Common import Foundation import Navigation +import PixelKit @MainActor private func getFirstAvailableWebView() -> WKWebView? { @@ -54,7 +55,7 @@ final class DownloadListCoordinator { enum UpdateKind { case added case removed - case updated + case updated(oldValue: DownloadListItem) } typealias Update = (kind: UpdateKind, item: DownloadListItem) private let updatesSubject = PassthroughSubject() @@ -152,9 +153,9 @@ final class DownloadListCoordinator { // locate destination file let destinationPresenterResult = Result { if let destinationFileBookmarkData = item.destinationFileBookmarkData { - try SandboxFilePresenter(fileBookmarkData: destinationFileBookmarkData, logger: log) + try BookmarkFilePresenter(fileBookmarkData: destinationFileBookmarkData, logger: log) } else if let destinationURL = item.destinationURL { - try SandboxFilePresenter(url: destinationURL, logger: log) + try BookmarkFilePresenter(url: destinationURL, logger: log) } else { nil } @@ -163,9 +164,9 @@ final class DownloadListCoordinator { // locate temp download file var tempFilePresenterResult = Result { if let tempFileBookmarkData = item.tempFileBookmarkData { - try SandboxFilePresenter(fileBookmarkData: tempFileBookmarkData, logger: log) + try BookmarkFilePresenter(fileBookmarkData: tempFileBookmarkData, logger: log) } else if let tempURL = item.tempURL { - try SandboxFilePresenter(url: tempURL, logger: log) + try BookmarkFilePresenter(url: tempURL, logger: log) } else { nil } @@ -223,10 +224,10 @@ final class DownloadListCoordinator { case .downloading(destination: let destination, tempFile: let tempFile): self.addItemIfNeededAndSubscribe(to: (destination, tempFile), for: item) case .downloaded(let destination): - let updatedItem = self.downloadTask(task, withId: item.identifier, completedWith: .finished) + let updatedItem = self.downloadTask(task, withOriginalItem: item, completedWith: .finished) self.subscribeToPresenters((destination: destination, tempFile: nil), of: updatedItem ?? item) case .failed(destination: let destination, tempFile: let tempFile, resumeData: _, error: let error): - let updatedItem = self.downloadTask(task, withId: item.identifier, completedWith: .failure(error)) + let updatedItem = self.downloadTask(task, withOriginalItem: item, completedWith: .failure(error)) self.subscribeToPresenters((destination: destination, tempFile: tempFile), of: updatedItem ?? item) } } @@ -250,7 +251,7 @@ final class DownloadListCoordinator { Publishers.CombineLatest( presenters.destination?.urlPublisher ?? Just(nil).eraseToAnyPublisher(), - (presenters.destination as? SandboxFilePresenter)?.fileBookmarkDataPublisher ?? Just(nil).eraseToAnyPublisher() + (presenters.destination as? BookmarkFilePresenter)?.fileBookmarkDataPublisher ?? Just(nil).eraseToAnyPublisher() ) .scan((oldURL: nil, newURL: nil, fileBookmarkData: nil)) { (oldURL: $0.newURL, newURL: $1.0, fileBookmarkData: $1.1) } .sink { [weak self] oldURL, newURL, fileBookmarkData in @@ -279,7 +280,7 @@ final class DownloadListCoordinator { Publishers.CombineLatest( presenters.tempFile?.urlPublisher ?? Just(nil).eraseToAnyPublisher(), - (presenters.tempFile as? SandboxFilePresenter)?.fileBookmarkDataPublisher ?? Just(nil).eraseToAnyPublisher() + (presenters.tempFile as? BookmarkFilePresenter)?.fileBookmarkDataPublisher ?? Just(nil).eraseToAnyPublisher() ) .scan((oldURL: nil, newURL: nil, fileBookmarkData: nil)) { (oldURL: $0.newURL, newURL: $1.0, fileBookmarkData: $1.1) } .sink { [weak self] oldURL, newURL, fileBookmarkData in @@ -341,19 +342,25 @@ final class DownloadListCoordinator { } @MainActor - private func downloadTask(_ task: WebKitDownloadTask, withId identifier: UUID, completedWith result: Subscribers.Completion) -> DownloadListItem? { - os_log(.debug, log: log, "coordinator: task did finish \(identifier) \(task) with .\(result)") + private func downloadTask(_ task: WebKitDownloadTask, withOriginalItem initialItem: DownloadListItem, completedWith result: Subscribers.Completion) -> DownloadListItem? { + os_log(.debug, log: log, "coordinator: task did finish \(initialItem.identifier) \(task) with .\(result)") self.downloadTaskCancellables[task] = nil - // item will be really updated (completed) only if it was added before in `addItemOrUpdateFilePresenter` (when state switched to .downloading) - // if it has failed without starting - it won‘t be added or updated here - return updateItem(withId: identifier) { item in + return updateItem(withId: initialItem.identifier) { item in if item?.isBurner ?? false { item = nil return } + if item == nil, + case .failure(let failure) = result, !failure.isCancelled, + let fileName = task.selectedDestinationURL?.lastPathComponent { + // add instantly failed downloads to the list (not user-cancelled) + item = initialItem + item?.fileName = fileName + } + item?.progress = nil if case .failure(let error) = result { item?.error = error @@ -379,8 +386,8 @@ final class DownloadListCoordinator { case (.none, .some(let item)): self.updatesSubject.send((.added, item)) store.save(item) - case (.some, .some(let item)): - self.updatesSubject.send((.updated, item)) + case (.some(let oldValue), .some(let item)): + self.updatesSubject.send((.updated(oldValue: oldValue), item)) store.save(item) case (.some(let item), .none): item.progress?.cancel() @@ -446,10 +453,9 @@ final class DownloadListCoordinator { @MainActor func downloads(sortedBy keyPath: KeyPath, ascending: Bool) -> [DownloadListItem] { - let comparator: (T, T) -> Bool = ascending ? (<) : (>) - return items.values.sorted(by: { - comparator($0[keyPath: keyPath], $1[keyPath: keyPath]) - }) + return items.values.sorted { + ascending ? ($0[keyPath: keyPath] < $1[keyPath: keyPath]) : ($0[keyPath: keyPath] > $1[keyPath: keyPath]) + } } var updates: AnyPublisher { @@ -477,7 +483,7 @@ final class DownloadListCoordinator { } } catch { assertionFailure("Resume data coding failed: \(error)") - Pixel.fire(.debug(event: .downloadResumeDataCodingFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.downloadResumeDataCodingFailed, error: error)) } webView.resumeDownload(fromResumeData: resumeData, diff --git a/DuckDuckGo/FileDownload/Services/DownloadListStore.swift b/DuckDuckGo/FileDownload/Services/DownloadListStore.swift index cec1d0e0da..9af9ffb38a 100644 --- a/DuckDuckGo/FileDownload/Services/DownloadListStore.swift +++ b/DuckDuckGo/FileDownload/Services/DownloadListStore.swift @@ -21,6 +21,7 @@ import Common import CoreData import Foundation import UniformTypeIdentifiers +import PixelKit protocol DownloadListStoring { @@ -191,7 +192,7 @@ extension DownloadListItem { let modified = managedObject.modified, let url = managedObject.urlEncrypted as? URL else { - Pixel.fire(.debug(event: .downloadListItemDecryptionFailedUnique), limitTo: .dailyFirst) + PixelKit.fire(DebugEvent(GeneralPixel.downloadListItemDecryptionFailedUnique), frequency: .daily) assertionFailure("DownloadListItem: Failed to init from ManagedObject") return nil } diff --git a/DuckDuckGo/FileDownload/View/Downloads.storyboard b/DuckDuckGo/FileDownload/View/Downloads.storyboard deleted file mode 100644 index 41e5511da3..0000000000 --- a/DuckDuckGo/FileDownload/View/Downloads.storyboard +++ /dev/null @@ -1,483 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/DuckDuckGo/FileDownload/View/DownloadsCellView.swift b/DuckDuckGo/FileDownload/View/DownloadsCellView.swift index ad3ed7bdd5..2c3f803924 100644 --- a/DuckDuckGo/FileDownload/View/DownloadsCellView.swift +++ b/DuckDuckGo/FileDownload/View/DownloadsCellView.swift @@ -22,6 +22,11 @@ import UniformTypeIdentifiers final class DownloadsCellView: NSTableCellView { + fileprivate enum Constants { + static let width: CGFloat = 420 + static let height: CGFloat = 60 + } + enum DownloadError: Error { case urlNotSet case fileRemoved @@ -38,13 +43,22 @@ final class DownloadsCellView: NSTableCellView { } } - @IBOutlet var titleLabel: NSTextField! - @IBOutlet var detailLabel: NSTextField! - @IBOutlet var progressView: CircularProgressView! - @IBOutlet var cancelButton: MouseOverButton! - @IBOutlet var revealButton: MouseOverButton! - @IBOutlet var restartButton: MouseOverButton! - @IBOutlet var separator: NSBox! + private let fileIconView = NSImageView() + private let titleLabel = NSTextField() + private let detailLabel = NSTextField() + + private let progressView = CircularProgressView() + private let cancelButton = MouseOverButton(image: .cancelDownload, + target: nil, + action: #selector(DownloadsViewController.cancelDownloadAction)) + private let revealButton = MouseOverButton(image: .revealDownload, + target: nil, + action: #selector(DownloadsViewController.revealDownloadAction)) + private let restartButton = MouseOverButton(image: .restartDownload, + target: nil, + action: #selector(DownloadsViewController.restartDownloadAction)) + + private let separator = NSBox() private var buttonOverCancellables = Set() private var cancellables = Set() @@ -82,7 +96,149 @@ final class DownloadsCellView: NSTableCellView { } } - override func awakeFromNib() { + init(identifier: NSUserInterfaceItemIdentifier) { + super.init(frame: CGRect(x: 0, y: 0, width: Constants.width, height: Constants.height)) + self.identifier = identifier + + setupUI() + subscribeToMouseOverEvents() + } + + required init?(coder: NSCoder) { + fatalError("\(Self.self): Bad initializer") + } + + // swiftlint:disable:next function_body_length + private func setupUI() { + self.imageView = fileIconView + self.wantsLayer = true + + addSubview(fileIconView) + addSubview(titleLabel) + addSubview(detailLabel) + addSubview(cancelButton) + addSubview(revealButton) + addSubview(restartButton) + addSubview(progressView) + addSubview(separator) + + fileIconView.translatesAutoresizingMaskIntoConstraints = false + fileIconView.setContentHuggingPriority(.init(rawValue: 251), for: .horizontal) + fileIconView.setContentHuggingPriority(.init(rawValue: 251), for: .vertical) + fileIconView.imageScaling = .scaleProportionallyDown + + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.isEditable = false + titleLabel.isBordered = false + titleLabel.isSelectable = false + titleLabel.drawsBackground = false + titleLabel.font = .systemFont(ofSize: 13) + titleLabel.textColor = .controlTextColor + titleLabel.lineBreakMode = .byTruncatingMiddle + titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + titleLabel.setContentHuggingPriority(.defaultHigh, for: .vertical) + titleLabel.setContentHuggingPriority(.init(rawValue: 251), for: .horizontal) + + detailLabel.translatesAutoresizingMaskIntoConstraints = false + detailLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + detailLabel.isEditable = false + detailLabel.isBordered = false + detailLabel.isSelectable = false + detailLabel.drawsBackground = false + detailLabel.font = .systemFont(ofSize: 13) + detailLabel.textColor = .secondaryLabelColor + detailLabel.lineBreakMode = .byClipping + detailLabel.setContentHuggingPriority(.defaultHigh, for: .vertical) + detailLabel.setContentHuggingPriority(.init(rawValue: 251), for: .horizontal) + + progressView.translatesAutoresizingMaskIntoConstraints = false + + cancelButton.translatesAutoresizingMaskIntoConstraints = false + cancelButton.setContentHuggingPriority(.defaultHigh, for: .horizontal) + cancelButton.setContentHuggingPriority(.defaultHigh, for: .vertical) + cancelButton.bezelStyle = .shadowlessSquare + cancelButton.isBordered = false + cancelButton.imagePosition = .imageOnly + cancelButton.imageScaling = .scaleProportionallyDown + cancelButton.cornerRadius = 4 + cancelButton.backgroundInset = CGPoint(x: 2, y: 2) + cancelButton.mouseDownColor = .buttonMouseDown + cancelButton.mouseOverColor = .buttonMouseOver + + revealButton.translatesAutoresizingMaskIntoConstraints = false + revealButton.setContentHuggingPriority(.defaultHigh, for: .horizontal) + revealButton.setContentHuggingPriority(.defaultHigh, for: .vertical) + revealButton.alignment = .center + revealButton.bezelStyle = .shadowlessSquare + revealButton.isBordered = false + revealButton.imagePosition = .imageOnly + revealButton.imageScaling = .scaleProportionallyDown + revealButton.cornerRadius = 4 + revealButton.backgroundInset = CGPoint(x: 2, y: 2) + revealButton.mouseDownColor = .buttonMouseDown + revealButton.mouseOverColor = .buttonMouseOver + + restartButton.translatesAutoresizingMaskIntoConstraints = false + restartButton.setContentHuggingPriority(.defaultHigh, for: .horizontal) + restartButton.setContentHuggingPriority(.defaultHigh, for: .vertical) + restartButton.alignment = .center + restartButton.bezelStyle = .shadowlessSquare + restartButton.isBordered = false + restartButton.imagePosition = .imageOnly + restartButton.imageScaling = .scaleProportionallyDown + restartButton.cornerRadius = 4 + restartButton.backgroundInset = CGPoint(x: 2, y: 2) + restartButton.mouseDownColor = .buttonMouseDown + restartButton.mouseOverColor = .buttonMouseOver + + separator.boxType = .separator + separator.translatesAutoresizingMaskIntoConstraints = false + + setupLayout() + } + + private func setupLayout() { + NSLayoutConstraint.activate([ + fileIconView.heightAnchor.constraint(equalToConstant: 32), + fileIconView.widthAnchor.constraint(equalToConstant: 32), + fileIconView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 7), + fileIconView.centerYAnchor.constraint(equalTo: centerYAnchor), + + titleLabel.heightAnchor.constraint(equalToConstant: 16), + titleLabel.leadingAnchor.constraint(equalTo: fileIconView.trailingAnchor, constant: 6), + titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 12), + detailLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor), + + cancelButton.heightAnchor.constraint(equalToConstant: 32), + cancelButton.widthAnchor.constraint(equalToConstant: 32), + cancelButton.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 8), + cancelButton.leadingAnchor.constraint(equalTo: detailLabel.trailingAnchor, constant: 8), + cancelButton.centerYAnchor.constraint(equalTo: centerYAnchor), + trailingAnchor.constraint(equalTo: cancelButton.trailingAnchor, constant: 4), + + revealButton.widthAnchor.constraint(equalToConstant: 32), + revealButton.heightAnchor.constraint(equalToConstant: 32), + revealButton.centerYAnchor.constraint(equalTo: cancelButton.centerYAnchor), + revealButton.centerXAnchor.constraint(equalTo: cancelButton.centerXAnchor), + + restartButton.widthAnchor.constraint(equalToConstant: 32), + restartButton.heightAnchor.constraint(equalToConstant: 32), + restartButton.centerXAnchor.constraint(equalTo: revealButton.centerXAnchor), + restartButton.centerYAnchor.constraint(equalTo: revealButton.centerYAnchor), + + progressView.widthAnchor.constraint(equalToConstant: 27), + progressView.heightAnchor.constraint(equalToConstant: 27), + progressView.centerXAnchor.constraint(equalTo: cancelButton.centerXAnchor), + progressView.centerYAnchor.constraint(equalTo: cancelButton.centerYAnchor), + + separator.topAnchor.constraint(equalTo: detailLabel.bottomAnchor, constant: 12), + separator.leadingAnchor.constraint(equalTo: leadingAnchor), + trailingAnchor.constraint(equalTo: separator.trailingAnchor), + bottomAnchor.constraint(equalTo: separator.bottomAnchor), + ]) + } + + private func subscribeToMouseOverEvents() { cancelButton.$isMouseOver.sink { [weak self] isMouseOver in self?.onButtonMouseOverChange?(isMouseOver) }.store(in: &buttonOverCancellables) @@ -163,8 +319,10 @@ final class DownloadsCellView: NSTableCellView { .store(in: &cancellables) } - private static let fileRemovedTitleAttributes: [NSAttributedString.Key: Any] = [.strikethroughStyle: 1, - .foregroundColor: NSColor.disabledControlTextColor] + private static let fileRemovedTitleAttributes: [NSAttributedString.Key: Any] = [ + .strikethroughStyle: 1, + .foregroundColor: NSColor.disabledControlTextColor + ] private func updateFilename(_ filename: String, state: DownloadViewModel.State) { // hide progress with animation on completion/failure @@ -357,3 +515,56 @@ extension DownloadsCellView.DownloadError: LocalizedError { } } + +#if DEBUG +@available(macOS 14.0, *) +#Preview { + DownloadsCellView.PreviewView() +} +@available(macOS 14.0, *) +let previewDownloadListItems = [ + DownloadListItem(identifier: .init(), added: .now, modified: .now, downloadURL: .empty, websiteURL: nil, fileName: "Indefinite progress download with long filename for clipping.zip", progress: Progress(totalUnitCount: -1), isBurner: false, destinationURL: URL(fileURLWithPath: "\(#file)"), destinationFileBookmarkData: nil, tempURL: URL(fileURLWithPath: "\(#file)"), tempFileBookmarkData: nil, error: nil), + DownloadListItem(identifier: .init(), added: .now, modified: .now, downloadURL: .empty, websiteURL: nil, fileName: "Active download.pdf", progress: Progress(totalUnitCount: 100, completedUnitCount: 42), isBurner: false, destinationURL: URL(fileURLWithPath: "\(#file)"), destinationFileBookmarkData: nil, tempURL: URL(fileURLWithPath: "\(#file)"), tempFileBookmarkData: nil, error: nil), + DownloadListItem(identifier: .init(), added: .now, modified: .now, downloadURL: .empty, websiteURL: nil, fileName: "Completed download.dmg", progress: nil, isBurner: false, destinationURL: URL(fileURLWithPath: "\(#file)"), destinationFileBookmarkData: nil, tempURL: nil, tempFileBookmarkData: nil, error: nil), + DownloadListItem(identifier: .init(), added: .now, modified: .now, downloadURL: .empty, websiteURL: nil, fileName: "Non-retryable download.txt", progress: nil, isBurner: false, destinationURL: URL(fileURLWithPath: "\(#file)"), destinationFileBookmarkData: nil, tempURL: URL(fileURLWithPath: "\(#file)"), tempFileBookmarkData: nil, error: nil), + DownloadListItem(identifier: .init(), added: .now, modified: .now, downloadURL: .empty, websiteURL: nil, fileName: "Retryable download.rtf", progress: nil, isBurner: false, destinationURL: URL(fileURLWithPath: "\(#file)"), destinationFileBookmarkData: nil, tempURL: URL(fileURLWithPath: "\(#file)"), tempFileBookmarkData: nil, error: FileDownloadError(URLError(.networkConnectionLost, userInfo: ["isRetryable": true]) as NSError)), +] +@available(macOS 14.0, *) +extension DownloadsCellView { + final class PreviewView: NSView { + + init() { + super.init(frame: .zero) + translatesAutoresizingMaskIntoConstraints = true + + let cells = [ + DownloadsCellView(identifier: .init("")), + DownloadsCellView(identifier: .init("")), + DownloadsCellView(identifier: .init("")), + DownloadsCellView(identifier: .init("")), + DownloadsCellView(identifier: .init("")), + ] + + for (idx, cell) in cells.enumerated() { + cell.widthAnchor.constraint(equalToConstant: 420).isActive = true + cell.heightAnchor.constraint(equalToConstant: 60).isActive = true + let item = previewDownloadListItems[idx] + cell.objectValue = DownloadViewModel(item: item) + } + + let stackView = NSStackView(views: cells as [NSView]) + stackView.orientation = .vertical + stackView.spacing = 1 + addAndLayout(stackView) + + widthAnchor.constraint(equalToConstant: 420).isActive = true + heightAnchor.constraint(equalToConstant: CGFloat((60 + 1) * cells.count)).isActive = true + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + } +} +#endif diff --git a/DuckDuckGo/FileDownload/View/DownloadsPopover.swift b/DuckDuckGo/FileDownload/View/DownloadsPopover.swift index 31bc627e2f..b41bf222c3 100644 --- a/DuckDuckGo/FileDownload/View/DownloadsPopover.swift +++ b/DuckDuckGo/FileDownload/View/DownloadsPopover.swift @@ -38,7 +38,7 @@ final class DownloadsPopover: NSPopover { // swiftlint:enable force_cast private func setupContentController() { - let controller = DownloadsViewController.create() + let controller = DownloadsViewController() contentViewController = controller } diff --git a/DuckDuckGo/FileDownload/View/DownloadsViewController.swift b/DuckDuckGo/FileDownload/View/DownloadsViewController.swift index fb33a0788d..ddc8c1aeb5 100644 --- a/DuckDuckGo/FileDownload/View/DownloadsViewController.swift +++ b/DuckDuckGo/FileDownload/View/DownloadsViewController.swift @@ -20,58 +20,157 @@ import Cocoa import Combine protocol DownloadsViewControllerDelegate: AnyObject { - func clearDownloadsActionTriggered() - } final class DownloadsViewController: NSViewController { static let preferredContentSize = CGSize(width: 420, height: 500) - static func create() -> Self { - let storyboard = NSStoryboard(name: "Downloads", bundle: nil) - // swiftlint:disable force_cast - let controller = storyboard.instantiateInitialController() as! Self - controller.loadView() - // swiftlint:enable force_cast - return controller - } - - @IBOutlet weak var openItem: NSMenuItem! - @IBOutlet weak var showInFinderItem: NSMenuItem! - @IBOutlet weak var copyDownloadLinkItem: NSMenuItem! - @IBOutlet weak var openWebsiteItem: NSMenuItem! - @IBOutlet weak var removeFromListItem: NSMenuItem! - @IBOutlet weak var stopItem: NSMenuItem! - @IBOutlet weak var restartItem: NSMenuItem! - @IBOutlet weak var clearAllItem: NSMenuItem! - - @IBOutlet weak var titleLabel: NSTextField! + private lazy var titleLabel = NSTextField(string: UserText.downloadsDialogTitle) - @IBOutlet var openDownloadsFolderButton: NSButton! - @IBOutlet var clearDownloadsButton: NSButton! + private lazy var openDownloadsFolderButton = MouseOverButton(image: .openDownloadsFolder, target: self, action: #selector(openDownloadsFolderAction)) + private lazy var clearDownloadsButton = MouseOverButton(image: .clearDownloads, target: self, action: #selector(clearDownloadsAction)) - @IBOutlet var contextMenu: NSMenu! - @IBOutlet var tableView: NSTableView! - @IBOutlet var tableViewHeightConstraint: NSLayoutConstraint? + private lazy var scrollView = NSScrollView() + private lazy var tableView = NSTableView() + private var tableViewHeightConstraint: NSLayoutConstraint! private var cellIndexToUnselect: Int? weak var delegate: DownloadsViewControllerDelegate? - var viewModel = DownloadListViewModel() - var downloadsCancellable: AnyCancellable? + private let viewModel: DownloadListViewModel + private var downloadsCancellable: AnyCancellable? - override func viewDidLoad() { - super.viewDidLoad() + init(viewModel: DownloadListViewModel? = nil) { + self.viewModel = viewModel ?? DownloadListViewModel() + super.init(nibName: nil, bundle: nil) + } - setupDragAndDrop() - setUpStrings() + required init?(coder: NSCoder) { + self.viewModel = DownloadListViewModel() + super.init(coder: coder) + } + override func loadView() { // swiftlint:disable:this function_body_length + view = NSView() + + view.addSubview(titleLabel) + view.addSubview(openDownloadsFolderButton) + view.addSubview(clearDownloadsButton) + view.addSubview(scrollView) + + titleLabel.isSelectable = false + titleLabel.isEditable = false + titleLabel.isBordered = false + titleLabel.setContentHuggingPriority(.defaultHigh, for: .vertical) + titleLabel.setContentHuggingPriority(.init(rawValue: 251), for: .horizontal) + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.drawsBackground = false + titleLabel.font = .preferredFont(forTextStyle: .title3) + titleLabel.textColor = .labelColor + + openDownloadsFolderButton.translatesAutoresizingMaskIntoConstraints = false + openDownloadsFolderButton.alignment = .center + openDownloadsFolderButton.bezelStyle = .shadowlessSquare + openDownloadsFolderButton.isBordered = false + openDownloadsFolderButton.imagePosition = .imageOnly + openDownloadsFolderButton.imageScaling = .scaleProportionallyDown openDownloadsFolderButton.toolTip = UserText.openDownloadsFolderTooltip + openDownloadsFolderButton.cornerRadius = 4 + openDownloadsFolderButton.backgroundInset = CGPoint(x: 2, y: 2) + openDownloadsFolderButton.normalTintColor = .button + openDownloadsFolderButton.mouseDownColor = .buttonMouseDown + openDownloadsFolderButton.mouseOverColor = .buttonMouseOver + + clearDownloadsButton.translatesAutoresizingMaskIntoConstraints = false + clearDownloadsButton.alignment = .center + clearDownloadsButton.bezelStyle = .shadowlessSquare + clearDownloadsButton.isBordered = false + clearDownloadsButton.imagePosition = .imageOnly + clearDownloadsButton.imageScaling = .scaleProportionallyDown clearDownloadsButton.toolTip = UserText.clearDownloadHistoryTooltip + clearDownloadsButton.cornerRadius = 4 + clearDownloadsButton.backgroundInset = CGPoint(x: 2, y: 2) + clearDownloadsButton.normalTintColor = .button + clearDownloadsButton.mouseDownColor = .buttonMouseDown + clearDownloadsButton.mouseOverColor = .buttonMouseOver + + scrollView.autohidesScrollers = true + scrollView.borderType = .noBorder + scrollView.hasHorizontalScroller = false + scrollView.translatesAutoresizingMaskIntoConstraints = false + scrollView.usesPredominantAxisScrolling = false + scrollView.automaticallyAdjustsContentInsets = false + + let clipView = NSClipView() + clipView.documentView = tableView + + clipView.autoresizingMask = [.width, .height] + clipView.drawsBackground = false + clipView.frame = CGRect(x: 0, y: 0, width: 420, height: 440) + + tableView.addTableColumn(NSTableColumn()) + + tableView.headerView = nil + tableView.backgroundColor = .clear + tableView.gridColor = .clear + tableView.style = .fullWidth + tableView.rowHeight = 60 + tableView.setContentHuggingPriority(.defaultHigh, for: .vertical) + tableView.allowsMultipleSelection = false + tableView.doubleAction = #selector(DownloadsViewController.doubleClickAction) + tableView.target = self + tableView.delegate = self + tableView.dataSource = self + tableView.menu = setUpContextMenu() + + scrollView.contentView = clipView + + let separator = NSBox() + separator.boxType = .separator + separator.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(separator) + + setupLayout(separator: separator) + } + + private func setupLayout(separator: NSBox) { + tableViewHeightConstraint = scrollView.heightAnchor.constraint(equalToConstant: 440) + + NSLayoutConstraint.activate([ + titleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 12), + titleLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 12), + + openDownloadsFolderButton.widthAnchor.constraint(equalToConstant: 32), + openDownloadsFolderButton.heightAnchor.constraint(equalToConstant: 32), + openDownloadsFolderButton.leadingAnchor.constraint(greaterThanOrEqualTo: titleLabel.trailingAnchor, constant: 8), + openDownloadsFolderButton.centerYAnchor.constraint(equalTo: titleLabel.centerYAnchor), + + clearDownloadsButton.widthAnchor.constraint(equalToConstant: 32), + clearDownloadsButton.heightAnchor.constraint(equalToConstant: 32), + clearDownloadsButton.leadingAnchor.constraint(equalTo: openDownloadsFolderButton.trailingAnchor), + view.trailingAnchor.constraint(equalTo: clearDownloadsButton.trailingAnchor, constant: 11), + clearDownloadsButton.centerYAnchor.constraint(equalTo: openDownloadsFolderButton.centerYAnchor), + + view.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor), + view.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor), + scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 44), + scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + + separator.centerXAnchor.constraint(equalTo: view.centerXAnchor), + separator.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -2), + separator.topAnchor.constraint(equalTo: view.topAnchor, constant: 43), + + tableViewHeightConstraint + ]) + } + + override func viewDidLoad() { + super.viewDidLoad() preferredContentSize = Self.preferredContentSize + setupDragAndDrop() } override func viewWillAppear() { @@ -116,16 +215,21 @@ final class DownloadsViewController: NSViewController { downloadsCancellable = nil } - private func setUpStrings() { - titleLabel.stringValue = UserText.downloadsDialogTitle - openItem.title = UserText.downloadsOpenItem - showInFinderItem.title = UserText.downloadsShowInFinderItem - copyDownloadLinkItem.title = UserText.downloadsCopyLinkItem - openWebsiteItem.title = UserText.downloadsOpenWebsiteItem - removeFromListItem.title = UserText.downloadsRemoveFromListItem - stopItem.title = UserText.downloadsStopItem - restartItem.title = UserText.downloadsRestartItem - clearAllItem.title = UserText.downloadsClearAllItem + private func setUpContextMenu() -> NSMenu { + let menu = NSMenu { + NSMenuItem(title: UserText.downloadsOpenItem, action: #selector(openDownloadAction), target: self) + NSMenuItem(title: UserText.downloadsShowInFinderItem, action: #selector(revealDownloadAction), target: self) + NSMenuItem.separator() + NSMenuItem(title: UserText.downloadsCopyLinkItem, action: #selector(copyDownloadLinkAction), target: self) + NSMenuItem(title: UserText.downloadsOpenWebsiteItem, action: #selector(openOriginatingWebsiteAction), target: self) + NSMenuItem.separator() + NSMenuItem(title: UserText.downloadsRemoveFromListItem, action: #selector(removeDownloadAction), target: self) + NSMenuItem(title: UserText.downloadsStopItem, action: #selector(cancelDownloadAction), target: self) + NSMenuItem(title: UserText.downloadsRestartItem, action: #selector(restartDownloadAction), target: self) + NSMenuItem(title: UserText.downloadsClearAllItem, action: #selector(clearDownloadsAction), target: self) + } + menu.delegate = self + return menu } private func index(for sender: Any) -> Int? { @@ -156,63 +260,64 @@ final class DownloadsViewController: NSViewController { // MARK: User Actions - @IBAction func openDownloadsFolderAction(_ sender: Any) { + @objc func openDownloadsFolderAction(_ sender: Any) { let prefs = DownloadsPreferences.shared + let downloads = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask)[0] var url: URL? var itemToSelect: URL? if prefs.alwaysRequestDownloadLocation { - url = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first + url = prefs.lastUsedCustomDownloadLocation + // reveal the last completed download if let lastDownloaded = viewModel.items.first/* last added */(where: { // should still exist - $0.localURL != nil && FileManager.default.fileExists(atPath: $0.localURL!.deletingLastPathComponent().path) + if let url = $0.localURL, FileManager.default.fileExists(atPath: url.path) { true } else { false } }), let lastDownloadedURL = lastDownloaded.localURL, - // if no downloads are from the default Downloads folder - open the last downloaded item folder !viewModel.items.contains(where: { $0.localURL?.deletingLastPathComponent().path == url?.path }) || url == nil { url = lastDownloadedURL.deletingLastPathComponent() // select last downloaded item itemToSelect = lastDownloadedURL - } /* else fallback to default User‘s Downloads */ + } /* else fallback to the last location chosen in the Save Panel */ } else { // open preferred downlod location - url = prefs.effectiveDownloadLocation ?? FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first + url = prefs.effectiveDownloadLocation } - guard let url else { return } + let folder = url ?? downloads + + _=NSWorkspace.shared.selectFile(itemToSelect?.path, inFileViewerRootedAtPath: folder.path) + // hack for the sandboxed environment: + // when we have no permission to open a folder we don‘t have access to + // try to guess a file that would most probably exist and reveal it: it‘s the ".DS_Store" file + || NSWorkspace.shared.selectFile(folder.appendingPathComponent(".DS_Store").path, inFileViewerRootedAtPath: folder.path) + // fallback to default Downloads folder + || NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: downloads.path) self.dismiss() - NSWorkspace.shared.selectFile(itemToSelect?.path, inFileViewerRootedAtPath: url.path) } - @IBAction func clearDownloadsAction(_ sender: Any) { + @objc func clearDownloadsAction(_ sender: Any) { viewModel.cleanupInactiveDownloads() self.dismiss() delegate?.clearDownloadsActionTriggered() } - @IBAction func openDownloadedFileAction(_ sender: Any) { - guard let index = index(for: sender), - let url = viewModel.items[safe: index]?.localURL - else { return } - NSWorkspace.shared.open(url) - } - - @IBAction func cancelDownloadAction(_ sender: Any) { + @objc func cancelDownloadAction(_ sender: Any) { guard let index = index(for: sender) else { return } viewModel.cancelDownload(at: index) } - @IBAction func removeDownloadAction(_ sender: Any) { + @objc func removeDownloadAction(_ sender: Any) { guard let index = index(for: sender) else { return } viewModel.removeDownload(at: index) } - @IBAction func revealDownloadAction(_ sender: Any) { + @objc func revealDownloadAction(_ sender: Any) { guard let index = index(for: sender), let url = viewModel.items[safe: index]?.localURL else { return } @@ -220,7 +325,7 @@ final class DownloadsViewController: NSViewController { NSWorkspace.shared.activateFileViewerSelecting([url]) } - func openDownloadAction(_ sender: Any) { + @objc func openDownloadAction(_ sender: Any) { guard let index = index(for: sender), let url = viewModel.items[safe: index]?.localURL else { return } @@ -228,12 +333,12 @@ final class DownloadsViewController: NSViewController { NSWorkspace.shared.open(url) } - @IBAction func restartDownloadAction(_ sender: Any) { + @objc func restartDownloadAction(_ sender: Any) { guard let index = index(for: sender) else { return } viewModel.restartDownload(at: index) } - @IBAction func copyDownloadLinkAction(_ sender: Any) { + @objc func copyDownloadLinkAction(_ sender: Any) { guard let index = index(for: sender), let url = viewModel.items[safe: index]?.url else { return } @@ -241,7 +346,7 @@ final class DownloadsViewController: NSViewController { NSPasteboard.general.copy(url) } - @IBAction func openOriginatingWebsiteAction(_ sender: Any) { + @objc func openOriginatingWebsiteAction(_ sender: Any) { guard let index = index(for: sender), let url = viewModel.items[safe: index]?.websiteURL else { return } @@ -250,7 +355,7 @@ final class DownloadsViewController: NSViewController { WindowControllersManager.shared.show(url: url, source: .historyEntry, newTab: true) } - @IBAction func doubleClickAction(_ sender: Any) { + @objc func doubleClickAction(_ sender: Any) { if index(for: sender) != nil { openDownloadAction(sender) } else { @@ -279,7 +384,7 @@ extension DownloadsViewController: NSMenuDelegate { for menuItem in menu.items { switch menuItem.action { - case #selector(openDownloadedFileAction(_:)), + case #selector(openDownloadAction(_:)), #selector(revealDownloadAction(_:)): if case .complete(.some(let url)) = item.state, FileManager.default.fileExists(atPath: url.path) { @@ -322,20 +427,17 @@ extension DownloadsViewController: NSTableViewDataSource, NSTableViewDelegate { } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { - let identifier: NSUserInterfaceItemIdentifier if viewModel.items.isEmpty { - identifier = .noDownloadsCell + return tableView.makeView(withIdentifier: .init(NoDownloadsCellView.className()), owner: self) as? NoDownloadsCellView + ?? NoDownloadsCellView(identifier: .init(NoDownloadsCellView.className())) + } else if viewModel.items.indices.contains(row) { - identifier = .downloadCell + return tableView.makeView(withIdentifier: .init(DownloadsCellView.className()), owner: self) as? DownloadsCellView + ?? DownloadsCellView(identifier: .init(DownloadsCellView.className())) } else { - identifier = .openDownloadsCell + return tableView.makeView(withIdentifier: .init(OpenDownloadsCellView.className()), owner: self) as? OpenDownloadsCellView + ?? OpenDownloadsCellView(identifier: .init(OpenDownloadsCellView.className())) } - let cell = tableView.makeView(withIdentifier: identifier, owner: nil) - if identifier == .downloadCell { - cell?.menu = contextMenu - } - - return cell } func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool { @@ -380,27 +482,15 @@ extension DownloadsViewController: NSTableViewDataSource, NSTableViewDelegate { } -private extension NSUserInterfaceItemIdentifier { - static let downloadCell = NSUserInterfaceItemIdentifier(rawValue: "cell") - static let noDownloadsCell = NSUserInterfaceItemIdentifier(rawValue: "NoDownloads") - static let openDownloadsCell = NSUserInterfaceItemIdentifier(rawValue: "OpenDownloads") -} - -final class NoDownloadViewCell: NSTableCellView { - @IBOutlet weak var openFolderButton: LinkButton! - @IBOutlet weak var titleLabel: NSTextField! - - override func awakeFromNib() { - titleLabel.stringValue = UserText.downloadsNoRecentDownload - openFolderButton.title = UserText.downloadsOpenDownloadsFolder - } -} - -final class OpenDownloadViewCell: NSTableCellView { - @IBOutlet weak var openFolderButton: LinkButton! +#if DEBUG +@available(macOS 14.0, *) +#Preview(traits: .fixedLayout(width: DownloadsViewController.preferredContentSize.width, height: DownloadsViewController.preferredContentSize.height)) { { - override func awakeFromNib() { - openFolderButton.title = UserText.downloadsOpenDownloadsFolder + let store = DownloadListStoreMock() + store.fetchBlock = { completion in + completion(.success(previewDownloadListItems)) } - -} + let viewModel = DownloadListViewModel(coordinator: DownloadListCoordinator(store: store)) + return DownloadsViewController(viewModel: viewModel) +}() } +#endif diff --git a/DuckDuckGo/FileDownload/View/NoDownloadsCellView.swift b/DuckDuckGo/FileDownload/View/NoDownloadsCellView.swift new file mode 100644 index 0000000000..9796154c32 --- /dev/null +++ b/DuckDuckGo/FileDownload/View/NoDownloadsCellView.swift @@ -0,0 +1,82 @@ +// +// NoDownloadsCellView.swift +// +// 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 AppKit + +final class NoDownloadsCellView: NSTableCellView { + + fileprivate enum Constants { + static let width: CGFloat = 420 + static let height: CGFloat = 60 + } + + private let titleLabel = NSTextField(string: UserText.downloadsNoRecentDownload) + private let openFolderButton = LinkButton(title: UserText.downloadsOpenDownloadsFolder, + target: nil, + action: #selector(DownloadsViewController.openDownloadsFolderAction)) + + init(identifier: NSUserInterfaceItemIdentifier) { + super.init(frame: CGRect(x: 0, y: 0, width: Constants.width, height: Constants.height)) + self.identifier = identifier + + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("\(Self.self): Bad initializer") + } + + private func setupUI() { + addSubview(titleLabel) + addSubview(openFolderButton) + + titleLabel.translatesAutoresizingMaskIntoConstraints = false + titleLabel.isEditable = false + titleLabel.isBordered = false + titleLabel.isSelectable = false + titleLabel.drawsBackground = false + titleLabel.font = .systemFont(ofSize: 13) + titleLabel.textColor = .secondaryLabelColor + titleLabel.lineBreakMode = .byTruncatingMiddle + + openFolderButton.translatesAutoresizingMaskIntoConstraints = false + openFolderButton.bezelStyle = .shadowlessSquare + openFolderButton.isBordered = false + openFolderButton.alignment = .center + openFolderButton.font = .systemFont(ofSize: 13) + openFolderButton.contentTintColor = .linkColor + + NSLayoutConstraint.activate([ + titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 12), + titleLabel.centerXAnchor.constraint(equalTo: centerXAnchor), + + openFolderButton.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, + constant: 4), + openFolderButton.centerXAnchor.constraint(equalTo: centerXAnchor), + ]) + } + +} + +@available(macOS 14.0, *) +#Preview(traits: .fixedLayout(width: NoDownloadsCellView.Constants.width, + height: NoDownloadsCellView.Constants.height)) { + PreviewViewController(showWindowTitle: false) { + NoDownloadsCellView(identifier: .init("")) + } +} diff --git a/DuckDuckGo/FileDownload/View/OpenDownloadsCellView.swift b/DuckDuckGo/FileDownload/View/OpenDownloadsCellView.swift new file mode 100644 index 0000000000..fbfed592da --- /dev/null +++ b/DuckDuckGo/FileDownload/View/OpenDownloadsCellView.swift @@ -0,0 +1,67 @@ +// +// OpenDownloadsCellView.swift +// +// 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 AppKit + +final class OpenDownloadsCellView: NSTableCellView { + + fileprivate enum Constants { + static let width: CGFloat = 420 + static let height: CGFloat = 60 + } + + private let openFolderButton = LinkButton(title: UserText.downloadsOpenDownloadsFolder, + target: nil, + action: #selector(DownloadsViewController.openDownloadsFolderAction)) + + init(identifier: NSUserInterfaceItemIdentifier) { + super.init(frame: CGRect(x: 0, y: 0, width: Constants.width, height: Constants.height)) + self.identifier = identifier + + setupUI() + } + + required init?(coder: NSCoder) { + fatalError("\(Self.self): Bad initializer") + } + + private func setupUI() { + addSubview(openFolderButton) + + openFolderButton.translatesAutoresizingMaskIntoConstraints = false + openFolderButton.bezelStyle = .shadowlessSquare + openFolderButton.isBordered = false + openFolderButton.alignment = .center + openFolderButton.font = .systemFont(ofSize: 13) + openFolderButton.contentTintColor = .linkColor + + NSLayoutConstraint.activate([ + openFolderButton.centerYAnchor.constraint(equalTo: centerYAnchor), + openFolderButton.centerXAnchor.constraint(equalTo: centerXAnchor), + ]) + } + +} + +@available(macOS 14.0, *) +#Preview(traits: .fixedLayout(width: OpenDownloadsCellView.Constants.width, + height: OpenDownloadsCellView.Constants.height)) { + PreviewViewController(showWindowTitle: false) { + OpenDownloadsCellView(identifier: .init("")) + } +} diff --git a/DuckDuckGo/Fire/Model/Fire.swift b/DuckDuckGo/Fire/Model/Fire.swift index a783f6b9ad..b5e9f9725c 100644 --- a/DuckDuckGo/Fire/Model/Fire.swift +++ b/DuckDuckGo/Fire/Model/Fire.swift @@ -400,7 +400,7 @@ final class Fire { // MARK: - Favicons private func autofillDomains() -> Set { - guard let vault = try? secureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared), + guard let vault = try? secureVaultFactory.makeVault(reporter: SecureVaultReporter.shared), let accounts = try? vault.accounts() else { return [] } diff --git a/DuckDuckGo/Fire/Model/TabCleanupPreparer.swift b/DuckDuckGo/Fire/Model/TabCleanupPreparer.swift index 798ebc2f7c..30314266da 100644 --- a/DuckDuckGo/Fire/Model/TabCleanupPreparer.swift +++ b/DuckDuckGo/Fire/Model/TabCleanupPreparer.swift @@ -17,6 +17,7 @@ // import Foundation +import PixelKit protocol TabDataClearing { func prepareForDataClearing(caller: TabCleanupPreparer) @@ -65,7 +66,7 @@ final class TabCleanupPreparer: NSObject, WKNavigationDelegate { } func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { - Pixel.fire(.debug(event: .blankNavigationOnBurnFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.blankNavigationOnBurnFailed, error: error)) processedTabs += 1 notifyIfDone() diff --git a/DuckDuckGo/Fire/View/FireViewController.swift b/DuckDuckGo/Fire/View/FireViewController.swift index 1b82d96eb8..fee0006b48 100644 --- a/DuckDuckGo/Fire/View/FireViewController.swift +++ b/DuckDuckGo/Fire/View/FireViewController.swift @@ -17,7 +17,7 @@ // import Cocoa -@preconcurrency import Lottie +import Lottie import Combine @MainActor diff --git a/DuckDuckGo/Fire/ViewModel/FirePopoverViewModel.swift b/DuckDuckGo/Fire/ViewModel/FirePopoverViewModel.swift index b10b728212..1221497f5f 100644 --- a/DuckDuckGo/Fire/ViewModel/FirePopoverViewModel.swift +++ b/DuckDuckGo/Fire/ViewModel/FirePopoverViewModel.swift @@ -20,6 +20,7 @@ import Cocoa import BrowserServicesKit import Common import History +import PixelKit @MainActor final class FirePopoverViewModel { @@ -188,7 +189,7 @@ final class FirePopoverViewModel { // MARK: - Burning func burn() { - Pixel.fire(.fireButtonFirstBurn, limitTo: .dailyFirst) + PixelKit.fire(GeneralPixel.fireButtonFirstBurn, frequency: .daily) switch (clearingOption, areAllSelected) { case (.currentTab, _): @@ -197,7 +198,7 @@ final class FirePopoverViewModel { assertionFailure("No tab selected") return } - Pixel.fire(.fireButton(option: .tab)) + PixelKit.fire(GeneralPixel.fireButton(option: .tab)) let burningEntity = Fire.BurningEntity.tab(tabViewModel: tabViewModel, selectedDomains: selectedDomains, parentTabCollectionViewModel: tabCollectionViewModel) @@ -207,17 +208,17 @@ final class FirePopoverViewModel { assertionFailure("FirePopoverViewModel: TabCollectionViewModel is not present") return } - Pixel.fire(.fireButton(option: .window)) + PixelKit.fire(GeneralPixel.fireButton(option: .window)) let burningEntity = Fire.BurningEntity.window(tabCollectionViewModel: tabCollectionViewModel, selectedDomains: selectedDomains) fireViewModel.fire.burnEntity(entity: burningEntity) case (.allData, true): - Pixel.fire(.fireButton(option: .allSites)) + PixelKit.fire(GeneralPixel.fireButton(option: .allSites)) fireViewModel.fire.burnAll() case (.allData, false): - Pixel.fire(.fireButton(option: .allSites)) + PixelKit.fire(GeneralPixel.fireButton(option: .allSites)) fireViewModel.fire.burnEntity(entity: .allWindows(mainWindowControllers: WindowControllersManager.shared.mainWindowControllers, selectedDomains: selectedDomains)) } diff --git a/DuckDuckGo/Fireproofing/Extensions/FireproofingURLExtensions.swift b/DuckDuckGo/Fireproofing/Extensions/FireproofingURLExtensions.swift index d75068166c..da4b9df331 100644 --- a/DuckDuckGo/Fireproofing/Extensions/FireproofingURLExtensions.swift +++ b/DuckDuckGo/Fireproofing/Extensions/FireproofingURLExtensions.swift @@ -52,7 +52,7 @@ extension URL { ] var canFireproof: Bool { - guard let host = self.host else { return false } + guard let host = self.host, self.navigationalScheme?.isHypertextScheme == true else { return false } return (host != Self.cookieDomain) } diff --git a/DuckDuckGo/History/Services/EncryptedHistoryStore.swift b/DuckDuckGo/History/Services/EncryptedHistoryStore.swift index 361ab26a81..a62dc501ce 100644 --- a/DuckDuckGo/History/Services/EncryptedHistoryStore.swift +++ b/DuckDuckGo/History/Services/EncryptedHistoryStore.swift @@ -21,6 +21,7 @@ import Foundation import CoreData import Combine import History +import PixelKit final class EncryptedHistoryStore: HistoryStoring { @@ -91,7 +92,7 @@ final class EncryptedHistoryStore: HistoryStoring { } os_log("%d items cleaned from history", log: .history, entriesToDelete.count) } catch { - Pixel.fire(.debug(event: .historyRemoveFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historyRemoveFailed, error: error)) self.context.reset() return .failure(error) } @@ -100,7 +101,7 @@ final class EncryptedHistoryStore: HistoryStoring { do { try context.save() } catch { - Pixel.fire(.debug(event: .historyRemoveFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historyRemoveFailed, error: error)) context.reset() return .failure(error) } @@ -117,7 +118,7 @@ final class EncryptedHistoryStore: HistoryStoring { let history = BrowsingHistory(historyEntries: historyEntries) return .success(history) } catch { - Pixel.fire(.debug(event: .historyReloadFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historyReloadFailed, error: error)) return .failure(error) } } @@ -133,7 +134,7 @@ final class EncryptedHistoryStore: HistoryStoring { } try context.save() } catch { - Pixel.fire(.debug(event: .historyCleanEntriesFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historyCleanEntriesFailed, error: error)) context.reset() return .failure(error) } @@ -149,7 +150,7 @@ final class EncryptedHistoryStore: HistoryStoring { try context.save() return .success(()) } catch { - Pixel.fire(.debug(event: .historyCleanVisitsFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historyCleanVisitsFailed, error: error)) context.reset() return .failure(error) } @@ -174,7 +175,8 @@ final class EncryptedHistoryStore: HistoryStoring { do { fetchedObjects = try self.context.fetch(fetchRequest) } catch { - Pixel.fire(.debug(event: .historySaveFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historySaveFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historySaveFailedDaily, error: error), frequency: .legacyDaily) promise(.failure(error)) return } @@ -202,14 +204,16 @@ final class EncryptedHistoryStore: HistoryStoring { context: self.context) switch insertionResult { case .failure(let error): - Pixel.fire(.debug(event: .historySaveFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historySaveFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historySaveFailedDaily, error: error), frequency: .legacyDaily) context.reset() promise(.failure(error)) case .success(let visitMOs): do { try self.context.save() } catch { - Pixel.fire(.debug(event: .historySaveFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historySaveFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historySaveFailedDaily, error: error), frequency: .legacyDaily) context.reset() promise(.failure(HistoryStoreError.savingFailed)) return @@ -259,7 +263,7 @@ final class EncryptedHistoryStore: HistoryStoring { context: NSManagedObjectContext) -> Result { let insertedObject = NSEntityDescription.insertNewObject(forEntityName: VisitManagedObject.className(), into: context) guard let visitMO = insertedObject as? VisitManagedObject else { - Pixel.fire(.debug(event: .historyInsertVisitFailed)) + PixelKit.fire(DebugEvent(GeneralPixel.historyInsertVisitFailed)) context.reset() return .failure(HistoryStoreError.savingFailed) } @@ -307,7 +311,7 @@ final class EncryptedHistoryStore: HistoryStoring { context.delete(visit) } } catch { - Pixel.fire(.debug(event: .historyRemoveVisitsFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historyRemoveVisitsFailed, error: error)) return .failure(error) } } @@ -315,7 +319,7 @@ final class EncryptedHistoryStore: HistoryStoring { do { try context.save() } catch { - Pixel.fire(.debug(event: .historyRemoveVisitsFailed, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.historyRemoveVisitsFailed, error: error)) context.reset() return .failure(error) } @@ -343,7 +347,7 @@ fileprivate extension HistoryEntry { guard let url = historyEntryMO.urlEncrypted as? URL, let identifier = historyEntryMO.identifier, let lastVisit = historyEntryMO.lastVisit else { - Pixel.fire(.debug(event: .historyEntryDecryptionFailedUnique), limitTo: .dailyFirst) + PixelKit.fire(DebugEvent(GeneralPixel.historyEntryDecryptionFailedUnique), frequency: .daily) assertionFailure("HistoryEntry: Failed to init HistoryEntry from HistoryEntryManagedObject") return nil } diff --git a/DuckDuckGo/HomePage/Model/DataImportStatusProviding.swift b/DuckDuckGo/HomePage/Model/DataImportStatusProviding.swift index 7c729d99ad..17efd1a64d 100644 --- a/DuckDuckGo/HomePage/Model/DataImportStatusProviding.swift +++ b/DuckDuckGo/HomePage/Model/DataImportStatusProviding.swift @@ -19,6 +19,7 @@ import Foundation import Bookmarks import BrowserServicesKit +import PixelKit protocol DataImportStatusProviding { var didImport: Bool { get } @@ -30,7 +31,7 @@ final class BookmarksAndPasswordsImportStatusProvider: DataImportStatusProviding let secureVault: (any AutofillSecureVault)? let bookmarkManager: BookmarkManager - init(secureVault: (any AutofillSecureVault)? = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared), + init(secureVault: (any AutofillSecureVault)? = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared), bookmarkManager: BookmarkManager = LocalBookmarkManager.shared) { self.secureVault = secureVault self.bookmarkManager = bookmarkManager @@ -80,7 +81,7 @@ final class BookmarksAndPasswordsImportStatusProvider: DataImportStatusProviding let identitiesDates = try secureVault.identities().map(\.created) dates.append(contentsOf: identitiesDates) } catch { - Pixel.fire(.debug(event: .secureVaultError, error: error)) + PixelKit.fire(DebugEvent(GeneralPixel.secureVaultError(error: error))) } guard dates.count >= 2 else { return false diff --git a/DuckDuckGo/HomePage/Model/HomePageContinueSetUpModel.swift b/DuckDuckGo/HomePage/Model/HomePageContinueSetUpModel.swift index 41c8bc3075..b99a4a2949 100644 --- a/DuckDuckGo/HomePage/Model/HomePageContinueSetUpModel.swift +++ b/DuckDuckGo/HomePage/Model/HomePageContinueSetUpModel.swift @@ -20,11 +20,10 @@ import AppKit import BrowserServicesKit import Common import Foundation +import PixelKit -#if NETWORK_PROTECTION import NetworkProtection import NetworkProtectionUI -#endif extension HomePage.Models { @@ -41,38 +40,18 @@ extension HomePage.Models { let deleteActionTitle = UserText.newTabSetUpRemoveItemAction let privacyConfigurationManager: PrivacyConfigurationManaging let homePageRemoteMessaging: HomePageRemoteMessaging + let permanentSurveyManager: SurveyManager - var isDay0SurveyEnabled: Bool { - let newTabContinueSetUpSettings = privacyConfigurationManager.privacyConfig.settings(for: .newTabContinueSetUp) - if let day0SurveyString = newTabContinueSetUpSettings["surveyCardDay0"] as? String { - if day0SurveyString == "enabled" { - return true - } - } - return false - } - var isDay14SurveyEnabled: Bool { - let newTabContinueSetUpSettings = privacyConfigurationManager.privacyConfig.settings(for: .newTabContinueSetUp) - if let day14SurveyString = newTabContinueSetUpSettings["surveyCardDay14"] as? String { - if day14SurveyString == "enabled" { - return true - } - } - return false - } var duckPlayerURL: String { let duckPlayerSettings = privacyConfigurationManager.privacyConfig.settings(for: .duckPlayer) return duckPlayerSettings["tryDuckPlayerLink"] as? String ?? "https://www.youtube.com/watch?v=yKWIA-Pys4c" } - var day0SurveyURL: String = "https://selfserve.decipherinc.com/survey/selfserve/32ab/240300?list=1" - var day14SurveyURL: String = "https://selfserve.decipherinc.com/survey/selfserve/32ab/240300?list=2" private let defaultBrowserProvider: DefaultBrowserProvider private let dataImportProvider: DataImportStatusProviding private let tabCollectionViewModel: TabCollectionViewModel private let emailManager: EmailManager private let duckPlayerPreferences: DuckPlayerPreferencesPersistor - private let randomNumberGenerator: RandomNumberGenerating @UserDefaultsWrapper(key: .homePageShowAllFeatures, defaultValue: false) var shouldShowAllFeatures: Bool { @@ -93,30 +72,15 @@ extension HomePage.Models { @UserDefaultsWrapper(key: .homePageShowEmailProtection, defaultValue: true) private var shouldShowEmailProtectionSetting: Bool - @UserDefaultsWrapper(key: .homePageShowSurveyDay0, defaultValue: true) - private var shouldShowSurveyDay0: Bool - - @UserDefaultsWrapper(key: .homePageUserInteractedWithSurveyDay0, defaultValue: false) - private var userInteractedWithSurveyDay0: Bool + @UserDefaultsWrapper(key: .homePageShowPermanentSurvey, defaultValue: true) + private var shouldShowPermanentSurvey: Bool @UserDefaultsWrapper(key: .shouldShowDBPWaitlistInvitedCardUI, defaultValue: false) private var shouldShowDBPWaitlistInvitedCardUI: Bool - @UserDefaultsWrapper(key: .homePageShowSurveyDay14, defaultValue: true) - private var shouldShowSurveyDay14: Bool - @UserDefaultsWrapper(key: .homePageIsFirstSession, defaultValue: true) private var isFirstSession: Bool - @UserDefaultsWrapper(key: .homePageShowSurveyDay0in10Percent, defaultValue: nil) - private var isPartOfSurveyDay0On10Percent: Bool? - - @UserDefaultsWrapper(key: .homePageShowSurveyDay14in10Percent, defaultValue: nil) - private var isPartOfSurveyDay14On10Percent: Bool? - - @UserDefaultsWrapper(key: .firstLaunchDate, defaultValue: Calendar.current.date(byAdding: .month, value: -1, to: Date())!) - private var firstLaunchDate: Date - var isMoreOrLessButtonNeeded: Bool { return featuresMatrix.count > itemsRowCountWhenCollapsed } @@ -125,10 +89,6 @@ extension HomePage.Models { return !featuresMatrix.isEmpty } - lazy var statisticsStore: StatisticsStore = LocalStatisticsStore() - - lazy var waitlistBetaThankYouPresenter = WaitlistThankYouPromptPresenter() - lazy var listOfFeatures = isFirstSession ? firstRunFeatures : randomisedFeatures private var featuresMatrix: [[FeatureType]] = [[]] { @@ -146,7 +106,7 @@ extension HomePage.Models { duckPlayerPreferences: DuckPlayerPreferencesPersistor, homePageRemoteMessaging: HomePageRemoteMessaging, privacyConfigurationManager: PrivacyConfigurationManaging = AppPrivacyFeatures.shared.contentBlocking.privacyConfigurationManager, - randomNumberGenerator: RandomNumberGenerating = RandomNumberGenerator()) { + permanentSurveyManager: SurveyManager = PermanentSurveyManager()) { self.defaultBrowserProvider = defaultBrowserProvider self.dataImportProvider = dataImportProvider self.tabCollectionViewModel = tabCollectionViewModel @@ -154,7 +114,7 @@ extension HomePage.Models { self.duckPlayerPreferences = duckPlayerPreferences self.homePageRemoteMessaging = homePageRemoteMessaging self.privacyConfigurationManager = privacyConfigurationManager - self.randomNumberGenerator = randomNumberGenerator + self.permanentSurveyManager = permanentSurveyManager refreshFeaturesMatrix() @@ -162,12 +122,11 @@ extension HomePage.Models { NotificationCenter.default.addObserver(self, selector: #selector(windowDidBecomeKey(_:)), name: NSWindow.didBecomeKeyNotification, object: nil) } - // swiftlint:disable:next cyclomatic_complexity @MainActor func performAction(for featureType: FeatureType) { switch featureType { case .defaultBrowser: do { - Pixel.fire(.defaultRequestedFromHomepageSetupView) + PixelKit.fire(GeneralPixel.defaultRequestedFromHomepageSetupView) try defaultBrowserProvider.presentDefaultBrowserPrompt() } catch { defaultBrowserProvider.openSystemPreferences() @@ -182,10 +141,8 @@ extension HomePage.Models { case .emailProtection: let tab = Tab(content: .url(EmailUrls().emailProtectionLink, source: .ui), shouldLoadInBackground: true) tabCollectionViewModel.append(tab: tab) - case .surveyDay0: - visitSurvey(day: .day0) - case .surveyDay14: - visitSurvey(day: .day14) + case .permanentSurvey: + visitSurvey() case .networkProtectionRemoteMessage(let message): handle(remoteMessage: message) case .dataBrokerProtectionRemoteMessage(let message): @@ -194,18 +151,9 @@ extension HomePage.Models { #if DBP DataBrokerProtectionAppEvents().handleWaitlistInvitedNotification(source: .cardUI) #endif - case .vpnThankYou: - guard let window = NSApp.keyWindow, - case .normal = NSApp.runType else { return } - waitlistBetaThankYouPresenter.presentVPNThankYouPrompt(in: window) - case .pirThankYou: - guard let window = NSApp.keyWindow, - case .normal = NSApp.runType else { return } - waitlistBetaThankYouPresenter.presentPIRThankYouPrompt(in: window) } } - // swiftlint:disable:next cyclomatic_complexity func removeItem(for featureType: FeatureType) { switch featureType { case .defaultBrowser: @@ -216,31 +164,22 @@ extension HomePage.Models { shouldShowDuckPlayerSetting = false case .emailProtection: shouldShowEmailProtectionSetting = false - case .surveyDay0: - shouldShowSurveyDay0 = false - case .surveyDay14: - shouldShowSurveyDay14 = false + case .permanentSurvey: + shouldShowPermanentSurvey = false case .networkProtectionRemoteMessage(let message): -#if NETWORK_PROTECTION homePageRemoteMessaging.networkProtectionRemoteMessaging.dismiss(message: message) - Pixel.fire(.networkProtectionRemoteMessageDismissed(messageID: message.id)) -#endif + PixelKit.fire(GeneralPixel.networkProtectionRemoteMessageDismissed(messageID: message.id)) case .dataBrokerProtectionRemoteMessage(let message): #if DBP homePageRemoteMessaging.dataBrokerProtectionRemoteMessaging.dismiss(message: message) - Pixel.fire(.dataBrokerProtectionRemoteMessageDismissed(messageID: message.id)) + PixelKit.fire(GeneralPixel.dataBrokerProtectionRemoteMessageDismissed(messageID: message.id)) #endif case .dataBrokerProtectionWaitlistInvited: shouldShowDBPWaitlistInvitedCardUI = false - case .vpnThankYou: - waitlistBetaThankYouPresenter.didDismissVPNThankYouCard() - case .pirThankYou: - waitlistBetaThankYouPresenter.didDismissPIRThankYouCard() } refreshFeaturesMatrix() } - // swiftlint:disable:next cyclomatic_complexity function_body_length func refreshFeaturesMatrix() { var features: [FeatureType] = [] #if DBP @@ -250,67 +189,42 @@ extension HomePage.Models { for message in homePageRemoteMessaging.dataBrokerProtectionRemoteMessaging.presentableRemoteMessages() { features.append(.dataBrokerProtectionRemoteMessage(message)) - DailyPixel.fire( - pixel: .dataBrokerProtectionRemoteMessageDisplayed(messageID: message.id), - frequency: .dailyOnly - ) + PixelKit.fire(GeneralPixel.dataBrokerProtectionRemoteMessageDisplayed(messageID: message.id), frequency: .daily) } #endif -#if NETWORK_PROTECTION for message in homePageRemoteMessaging.networkProtectionRemoteMessaging.presentableRemoteMessages() { - features.append(.networkProtectionRemoteMessage(message)) - DailyPixel.fire( - pixel: .networkProtectionRemoteMessageDisplayed(messageID: message.id), - frequency: .dailyOnly - ) + PixelKit.fire(GeneralPixel.networkProtectionRemoteMessageDisplayed(messageID: message.id), frequency: .daily) } -#endif - if waitlistBetaThankYouPresenter.canShowVPNCard { - features.append(.vpnThankYou) - } + appendFeatureCards(&features) - if waitlistBetaThankYouPresenter.canShowPIRCard { - features.append(.pirThankYou) + featuresMatrix = features.chunked(into: itemsPerRow) + } + + private func appendFeatureCards(_ features: inout [FeatureType]) { + for feature in listOfFeatures where shouldAppendFeature(feature: feature) { + features.append(feature) } + } - for feature in listOfFeatures { - switch feature { - case .defaultBrowser: - if shouldMakeDefaultCardBeVisible { - features.append(feature) - } - case .importBookmarksAndPasswords: - if shouldImportCardBeVisible { - features.append(feature) - } - case .duckplayer: - if shouldDuckPlayerCardBeVisible { - features.append(feature) - } - case .emailProtection: - if shouldEmailProtectionCardBeVisible { - features.append(feature) - } - case .surveyDay0: - if shouldSurveyDay0BeVisible { - features.append(feature) - userInteractedWithSurveyDay0 = true - } - case .surveyDay14: - if shouldSurveyDay14BeVisible { - features.append(feature) - } - case .networkProtectionRemoteMessage, - .dataBrokerProtectionRemoteMessage, - .dataBrokerProtectionWaitlistInvited, - .vpnThankYou, - .pirThankYou: - break // Do nothing, these messages get appended first - } + private func shouldAppendFeature(feature: FeatureType) -> Bool { + switch feature { + case .defaultBrowser: + return shouldMakeDefaultCardBeVisible + case .importBookmarksAndPasswords: + return shouldImportCardBeVisible + case .duckplayer: + return shouldDuckPlayerCardBeVisible + case .emailProtection: + return shouldEmailProtectionCardBeVisible + case .permanentSurvey: + return shouldPermanentSurveyBeVisible + case .networkProtectionRemoteMessage, + .dataBrokerProtectionRemoteMessage, + .dataBrokerProtectionWaitlistInvited: + return false // These are handled separately } - featuresMatrix = features.chunked(into: itemsPerRow) } // Helper Functions @@ -384,70 +298,22 @@ extension HomePage.Models { !emailManager.isSignedIn } - private var shouldSurveyDay0BeVisible: Bool { - let oneDayAgo = Calendar.current.date(byAdding: .weekday, value: -1, to: Date())! - return isDay0SurveyEnabled && - shouldShowSurveyDay0 && - firstLaunchDate >= oneDayAgo && - Bundle.main.preferredLocalizations.first == "en" && - isPartOfSurveyDay0On10Percent ?? calculateIfIn10percent(day: .day0) - } - - private var shouldSurveyDay14BeVisible: Bool { - let fourteenDaysAgo = Calendar.current.date(byAdding: .weekday, value: -14, to: Date())! - let fifteenDaysAgo = Calendar.current.date(byAdding: .weekday, value: -15, to: Date())! - return isDay14SurveyEnabled && - shouldShowSurveyDay0 && - shouldShowSurveyDay14 && - !userInteractedWithSurveyDay0 && - firstLaunchDate >= fifteenDaysAgo && - firstLaunchDate <= fourteenDaysAgo && - Bundle.main.preferredLocalizations.first == "en" && - isPartOfSurveyDay14On10Percent ?? calculateIfIn10percent(day: .day14) - } - - private func calculateIfIn10percent(day: SurveyDay) -> Bool { - let randomNumber0To99 = randomNumberGenerator.random(in: 0..<100) - let isInSurvey10Percent = randomNumber0To99 < 10 - switch day { - case .day0: - isPartOfSurveyDay0On10Percent = isInSurvey10Percent - case .day14: - isPartOfSurveyDay14On10Percent = isInSurvey10Percent - } - return isInSurvey10Percent + private var shouldPermanentSurveyBeVisible: Bool { + return shouldShowPermanentSurvey && + permanentSurveyManager.isSurveyAvailable } - private enum SurveyDay { - case day0 - case day14 - } + @MainActor private func visitSurvey() { + guard let url = permanentSurveyManager.url else { return } - @MainActor private func visitSurvey(day: SurveyDay) { - var surveyURLString: String - switch day { - case .day0: - surveyURLString = day0SurveyURL - case .day14: - surveyURLString = day14SurveyURL - } - - if let url = URL(string: surveyURLString) { - let tab = Tab(content: .url(url, source: .ui), shouldLoadInBackground: true) - tabCollectionViewModel.append(tab: tab) - switch day { - case .day0: - shouldShowSurveyDay0 = false - case .day14: - shouldShowSurveyDay14 = false - } - } + let tab = Tab(content: .url(url, source: .ui), shouldLoadInBackground: true) + tabCollectionViewModel.append(tab: tab) + shouldShowPermanentSurvey = false } @MainActor private func handle(remoteMessage: NetworkProtectionRemoteMessage) { -#if NETWORK_PROTECTION guard let actionType = remoteMessage.action.actionType else { - Pixel.fire(.networkProtectionRemoteMessageDismissed(messageID: remoteMessage.id)) + PixelKit.fire(GeneralPixel.networkProtectionRemoteMessageDismissed(messageID: remoteMessage.id)) homePageRemoteMessaging.networkProtectionRemoteMessaging.dismiss(message: remoteMessage) refreshFeaturesMatrix() return @@ -460,20 +326,19 @@ extension HomePage.Models { if let surveyURL = remoteMessage.presentableSurveyURL() { let tab = Tab(content: .url(surveyURL, source: .ui), shouldLoadInBackground: true) tabCollectionViewModel.append(tab: tab) - Pixel.fire(.networkProtectionRemoteMessageOpened(messageID: remoteMessage.id)) + PixelKit.fire(GeneralPixel.networkProtectionRemoteMessageOpened(messageID: remoteMessage.id)) // Dismiss the message after the user opens the URL, even if they just close the tab immediately afterwards. homePageRemoteMessaging.networkProtectionRemoteMessaging.dismiss(message: remoteMessage) refreshFeaturesMatrix() } } -#endif } @MainActor private func handle(remoteMessage: DataBrokerProtectionRemoteMessage) { #if DBP guard let actionType = remoteMessage.action.actionType else { - Pixel.fire(.dataBrokerProtectionRemoteMessageDismissed(messageID: remoteMessage.id)) + PixelKit.fire(GeneralPixel.dataBrokerProtectionRemoteMessageDismissed(messageID: remoteMessage.id)) homePageRemoteMessaging.dataBrokerProtectionRemoteMessaging.dismiss(message: remoteMessage) refreshFeaturesMatrix() return @@ -486,7 +351,7 @@ extension HomePage.Models { if let surveyURL = remoteMessage.presentableSurveyURL() { let tab = Tab(content: .url(surveyURL, source: .ui), shouldLoadInBackground: true) tabCollectionViewModel.append(tab: tab) - Pixel.fire(.dataBrokerProtectionRemoteMessageOpened(messageID: remoteMessage.id)) + PixelKit.fire(GeneralPixel.dataBrokerProtectionRemoteMessageOpened(messageID: remoteMessage.id)) // Dismiss the message after the user opens the URL, even if they just close the tab immediately afterwards. homePageRemoteMessaging.dataBrokerProtectionRemoteMessaging.dismiss(message: remoteMessage) @@ -504,20 +369,17 @@ extension HomePage.Models { // We ignore the `networkProtectionRemoteMessage` case here to avoid it getting accidentally included - it has special handling and will get // included elsewhere. static var allCases: [HomePage.Models.FeatureType] { - [.duckplayer, .emailProtection, .defaultBrowser, .importBookmarksAndPasswords, .surveyDay0, .surveyDay14] + [.duckplayer, .emailProtection, .defaultBrowser, .importBookmarksAndPasswords, .permanentSurvey] } case duckplayer case emailProtection case defaultBrowser case importBookmarksAndPasswords - case surveyDay0 - case surveyDay14 + case permanentSurvey case networkProtectionRemoteMessage(NetworkProtectionRemoteMessage) case dataBrokerProtectionRemoteMessage(DataBrokerProtectionRemoteMessage) case dataBrokerProtectionWaitlistInvited - case vpnThankYou - case pirThankYou var title: String { switch self { @@ -529,20 +391,14 @@ extension HomePage.Models { return UserText.newTabSetUpDuckPlayerCardTitle case .emailProtection: return UserText.newTabSetUpEmailProtectionCardTitle - case .surveyDay0: - return UserText.newTabSetUpSurveyDay0CardTitle - case .surveyDay14: - return UserText.newTabSetUpSurveyDay14CardTitle + case .permanentSurvey: + return PermanentSurveyManager.title case .networkProtectionRemoteMessage(let message): return message.cardTitle case .dataBrokerProtectionRemoteMessage(let message): return message.cardTitle case .dataBrokerProtectionWaitlistInvited: return "Personal Information Removal" - case .vpnThankYou: - return "Thanks for testing DuckDuckGo VPN!" - case .pirThankYou: - return "Thanks for testing Personal Information Removal!" } } @@ -556,20 +412,14 @@ extension HomePage.Models { return UserText.newTabSetUpDuckPlayerSummary case .emailProtection: return UserText.newTabSetUpEmailProtectionSummary - case .surveyDay0: - return UserText.newTabSetUpSurveyDay0Summary - case .surveyDay14: - return UserText.newTabSetUpSurveyDay14Summary + case .permanentSurvey: + return PermanentSurveyManager.body case .networkProtectionRemoteMessage(let message): return message.cardDescription case .dataBrokerProtectionRemoteMessage(let message): return message.cardDescription case .dataBrokerProtectionWaitlistInvited: return "You're invited to try Personal Information Removal beta!" - case .vpnThankYou: - return "To keep using it, subscribe to DuckDuckGo Privacy Pro." - case .pirThankYou: - return "To keep using it, subscribe to DuckDuckGo Privacy Pro." } } @@ -583,20 +433,14 @@ extension HomePage.Models { return UserText.newTabSetUpDuckPlayerAction case .emailProtection: return UserText.newTabSetUpEmailProtectionAction - case .surveyDay0: - return UserText.newTabSetUpSurveyDay0Action - case .surveyDay14: - return UserText.newTabSetUpSurveyDay14Action + case .permanentSurvey: + return PermanentSurveyManager.actionTitle case .networkProtectionRemoteMessage(let message): return message.action.actionTitle case .dataBrokerProtectionRemoteMessage(let message): return message.action.actionTitle case .dataBrokerProtectionWaitlistInvited: return "Get Started" - case .vpnThankYou: - return "See Special Offer For Testers" - case .pirThankYou: - return "See Special Offer For Testers" } } @@ -612,20 +456,14 @@ extension HomePage.Models { return .cleanTube128.resized(to: iconSize)! case .emailProtection: return .inbox128.resized(to: iconSize)! - case .surveyDay0: - return .qandA128.resized(to: iconSize)! - case .surveyDay14: - return .qandA128.resized(to: iconSize)! + case .permanentSurvey: + return .survey128.resized(to: iconSize)! case .networkProtectionRemoteMessage: return .vpnEnded.resized(to: iconSize)! case .dataBrokerProtectionRemoteMessage: return .dbpInformationRemover.resized(to: iconSize)! case .dataBrokerProtectionWaitlistInvited: return .dbpInformationRemover.resized(to: iconSize)! - case .vpnThankYou: - return .vpnEnded.resized(to: iconSize)! - case .pirThankYou: - return .dbpInformationRemover.resized(to: iconSize)! } } } @@ -649,32 +487,23 @@ extension HomePage.Models { struct HomePageRemoteMessaging { static func defaultMessaging() -> HomePageRemoteMessaging { -#if NETWORK_PROTECTION && DBP +#if DBP return HomePageRemoteMessaging( networkProtectionRemoteMessaging: DefaultNetworkProtectionRemoteMessaging(), networkProtectionUserDefaults: .netP, dataBrokerProtectionRemoteMessaging: DefaultDataBrokerProtectionRemoteMessaging(), dataBrokerProtectionUserDefaults: .dbp ) -#elseif NETWORK_PROTECTION +#else return HomePageRemoteMessaging( networkProtectionRemoteMessaging: DefaultNetworkProtectionRemoteMessaging(), networkProtectionUserDefaults: .netP ) -#elseif DBP - return HomePageRemoteMessaging( - dataBrokerProtectionRemoteMessaging: DefaultDataBrokerProtectionRemoteMessaging(), - dataBrokerProtectionUserDefaults: .dbp - ) -#else - return HomePageRemoteMessaging() #endif } -#if NETWORK_PROTECTION let networkProtectionRemoteMessaging: NetworkProtectionRemoteMessaging let networkProtectionUserDefaults: UserDefaults -#endif #if DBP let dataBrokerProtectionRemoteMessaging: DataBrokerProtectionRemoteMessaging @@ -683,12 +512,12 @@ struct HomePageRemoteMessaging { } -public protocol RandomNumberGenerating { - func random(in range: Range) -> Int -} - -struct RandomNumberGenerator: RandomNumberGenerating { - func random(in range: Range) -> Int { - return Int.random(in: range) +extension AppVersion { + public var majorAndMinorOSVersion: String { + let components = osVersion.split(separator: ".") + guard components.count >= 2 else { + return majorVersionNumber + } + return "\(components[0]).\(components[1])" } } diff --git a/DuckDuckGo/HomePage/Model/HomePageRecentlyVisitedModel.swift b/DuckDuckGo/HomePage/Model/HomePageRecentlyVisitedModel.swift index 2e627932cc..a22162f63e 100644 --- a/DuckDuckGo/HomePage/Model/HomePageRecentlyVisitedModel.swift +++ b/DuckDuckGo/HomePage/Model/HomePageRecentlyVisitedModel.swift @@ -28,7 +28,7 @@ final class RecentlyVisitedModel: ObservableObject { let f = RelativeDateTimeFormatter() f.unitsStyle = .abbreviated return f - } () + }() private let fire: Fire diff --git a/DuckDuckGo/HomePage/Model/PermanentSurveyManager.swift b/DuckDuckGo/HomePage/Model/PermanentSurveyManager.swift new file mode 100644 index 0000000000..529b3ddf51 --- /dev/null +++ b/DuckDuckGo/HomePage/Model/PermanentSurveyManager.swift @@ -0,0 +1,141 @@ +// +// PermanentSurveyManager.swift +// +// 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 BrowserServicesKit +import Common +import AppKit + +protocol SurveyManager { + var isSurveyAvailable: Bool { get } + var url: URL? { get } + static var title: String { get } + static var body: String { get } + static var actionTitle: String { get } +} + +final class PermanentSurveyManager: SurveyManager { + static var title: String = "Help Us Improve" + static var body: String = "Take our short survey and help us build the best browser." + static var actionTitle: String = "Share Your Thoughts" + + @UserDefaultsWrapper(key: .firstLaunchDate, defaultValue: Calendar.current.date(byAdding: .month, value: -1, to: Date())!) + private var firstLaunchDate: Date + + @UserDefaultsWrapper(key: .homePageUserInSurveyShare, defaultValue: nil) + private var isUserRegisteredInSurveyShare: Bool? + + private let surveySettings: [String: Any]? + private let userDecider: InternalUserDecider + private let randomNumberGenerator: RandomNumberGenerating + + lazy var statisticsStore: StatisticsStore = LocalStatisticsStore() + + init(privacyConfigurationManager: PrivacyConfigurationManaging = AppPrivacyFeatures.shared.contentBlocking.privacyConfigurationManager, + randomNumberGenerator: RandomNumberGenerating = RandomNumberGenerator()) { + let newTabContinueSetUpSettings = privacyConfigurationManager.privacyConfig.settings(for: .newTabContinueSetUp) + self.surveySettings = newTabContinueSetUpSettings["permanentSurvey"] as? [String: Any] + self.userDecider = NSApp.delegateTyped.internalUserDecider + self.randomNumberGenerator = randomNumberGenerator + } + + public var isSurveyAvailable: Bool { + let firstSurveyDayDate = Calendar.current.date(byAdding: .weekday, value: -firstDay, to: Date())! + let lastSurveyDayDate = Calendar.current.date(byAdding: .weekday, value: -lastDay, to: Date())! + let rightLocale = isLocalized ? true : Bundle.main.preferredLocalizations.first == "en" + + return + isEnabled && + firstLaunchDate >= lastSurveyDayDate && + firstLaunchDate <= firstSurveyDayDate && + rightLocale && + isUserInSurveyShare(sharePercentage) + } + + public var url: URL? { + guard let urlString = surveySettings?["url"] as? String else { return nil } + guard let url = URL(string: urlString) else { return nil } + + var components = URLComponents(url: url, resolvingAgainstBaseURL: true) + var newQueryItems: [URLQueryItem] = [] + if let atb = self.statisticsStore.atb { + newQueryItems.append(URLQueryItem(name: "atb", value: atb)) + } + if let variant = statisticsStore.variant { + newQueryItems.append(URLQueryItem(name: "v", value: variant)) + } + newQueryItems.append(URLQueryItem(name: "ddg", value: AppVersion.shared.versionNumber)) + newQueryItems.append(URLQueryItem(name: "macos", value: AppVersion.shared.majorAndMinorOSVersion)) + let oldQueryItems = components?.queryItems ?? [] + components?.queryItems = oldQueryItems + newQueryItems + + return components?.url ?? url + } + + private func isUserInSurveyShare(_ share: Int) -> Bool { + if isUserRegisteredInSurveyShare ?? false { + return true + } + let randomNumber0To99 = randomNumberGenerator.random(in: 0..<100) + isUserRegisteredInSurveyShare = randomNumber0To99 < share + return isUserRegisteredInSurveyShare! + } + + private var isEnabled: Bool { + if let state = surveySettings?["state"] as? String { + if state == "enabled" { + return true + } + if state == "internal" && userDecider.isInternalUser { + return true + } + } + return false + } + + private var isLocalized: Bool { + if let state = surveySettings?["localization"] as? String { + if state == "enabled" { + return true + } + } + return false + } + + private var firstDay: Int { + return surveySettings?["firstDay"] as? Int ?? 0 + } + + private var lastDay: Int { + return surveySettings?["lastDay"] as? Int ?? 365 + } + + private var sharePercentage: Int { + return surveySettings?["sharePercentage"] as? Int ?? 0 + } +} + +public protocol RandomNumberGenerating { + func random(in range: Range) -> Int +} + +struct RandomNumberGenerator: RandomNumberGenerating { + func random(in range: Range) -> Int { + return Int.random(in: range) + } +} diff --git a/DuckDuckGo/HomePage/View/FavoritesView.swift b/DuckDuckGo/HomePage/View/FavoritesView.swift index 52e7f585d1..39f74b58cf 100644 --- a/DuckDuckGo/HomePage/View/FavoritesView.swift +++ b/DuckDuckGo/HomePage/View/FavoritesView.swift @@ -324,12 +324,12 @@ struct Favorite: View { .link { model.open(bookmark) }.contextMenu(ContextMenu(menuItems: { - Button(UserText.openInNewTab, action: { model.openInNewTab(bookmark) }) - Button(UserText.openInNewWindow, action: { model.openInNewWindow(bookmark) }) + Button(UserText.openInNewTab, action: { model.openInNewTab(bookmark) }).accessibilityIdentifier("HomePage.Views.openInNewTab") + Button(UserText.openInNewWindow, action: { model.openInNewWindow(bookmark) }).accessibilityIdentifier("HomePage.Views.openInNewWindow") Divider() - Button(UserText.edit, action: { model.edit(bookmark) }) - Button(UserText.removeFavorite, action: { model.removeFavorite(bookmark) }) - Button(UserText.deleteBookmark, action: { model.deleteBookmark(bookmark) }) + Button(UserText.edit, action: { model.edit(bookmark) }).accessibilityIdentifier("HomePage.Views.editBookmark") + Button(UserText.removeFavorite, action: { model.removeFavorite(bookmark) }).accessibilityIdentifier("HomePage.Views.removeFavorite") + Button(UserText.deleteBookmark, action: { model.deleteBookmark(bookmark) }).accessibilityIdentifier("HomePage.Views.deleteBookmark") })) } @@ -344,13 +344,13 @@ extension HomePage.Models.FavoriteModel { var favoriteView: some View { switch favoriteType { case .bookmark(let bookmark): - HomePage.Views.Favorite(bookmark: bookmark) + HomePage.Views.Favorite(bookmark: bookmark)?.accessibilityIdentifier("HomePage.Models.FavoriteModel.\(bookmark.title)") case .addButton: - HomePage.Views.FavoritesGridAddButton() + HomePage.Views.FavoritesGridAddButton().accessibilityIdentifier("HomePage.Models.FavoriteModel.addButton") case .ghostButton: - HomePage.Views.FavoritesGridGhostButton() + HomePage.Views.FavoritesGridGhostButton().accessibilityIdentifier("HomePage.Models.FavoriteModel.ghostButton") } } } diff --git a/DuckDuckGo/HomePage/View/HomePageViewController.swift b/DuckDuckGo/HomePage/View/HomePageViewController.swift index 96fb2aca47..9769333182 100644 --- a/DuckDuckGo/HomePage/View/HomePageViewController.swift +++ b/DuckDuckGo/HomePage/View/HomePageViewController.swift @@ -20,6 +20,7 @@ import Cocoa import Combine import SwiftUI import History +import PixelKit @MainActor final class HomePageViewController: NSViewController { @@ -106,8 +107,8 @@ final class HomePageViewController: NSViewController { override func viewWillAppear() { super.viewWillAppear() - if OnboardingViewModel.isOnboardingFinished && Pixel.isNewUser { - Pixel.fire(.newTabInitial, limitTo: .initial) + if OnboardingViewModel.isOnboardingFinished && AppDelegate.isNewUser { + PixelKit.fire(GeneralPixel.newTabInitial, frequency: .legacyInitial) } subscribeToHistory() } @@ -158,7 +159,7 @@ final class HomePageViewController: NSViewController { func createDefaultBrowserModel() -> HomePage.Models.DefaultBrowserModel { return .init(isDefault: DefaultBrowserPreferences.shared.isDefault, wasClosed: defaultBrowserDismissed, requestSetDefault: { [weak self] in - Pixel.fire(.defaultRequestedFromHomepage) + PixelKit.fire(GeneralPixel.defaultRequestedFromHomepage) let defaultBrowserPreferencesModel = DefaultBrowserPreferences.shared defaultBrowserPreferencesModel.becomeDefault { [weak self] isDefault in _ = defaultBrowserPreferencesModel diff --git a/DuckDuckGo/Info.plist b/DuckDuckGo/Info.plist index a521153891..095900fb99 100644 --- a/DuckDuckGo/Info.plist +++ b/DuckDuckGo/Info.plist @@ -9,42 +9,444 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDocumentTypes - - - CFBundleTypeExtensions - - html - htm - shtml - xht - xhtml - - CFBundleTypeIconFile - document.icns - CFBundleTypeName - HTML Document - CFBundleTypeOSTypes - - HTML - - CFBundleTypeRole - Viewer - LSHandlerRank - Default - - - CFBundleTypeExtensions - - duckload - - CFBundleTypeName - Incomplete download - CFBundleTypeRole - Editor - NSIsRelatedItemType - - - + + + CFBundleTypeExtensions + + html + htm + shtml + xht + xhtml + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + HTML Document + CFBundleTypeOSTypes + + HTML + + CFBundleTypeRole + Viewer + LSHandlerRank + Default + + + CFBundleTypeExtensions + + txt + text + log + + CFBundleTypeMIMETypes + + text/plain + + LSItemContentTypes + + public.text + + CFBundleTypeOSTypes + + TEXT + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + Text document + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + webarchive + + CFBundleTypeMIMETypes + + application/x-webarchive + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + Web archive + CFBundleTypeRole + Viewer + LSHandlerRank + Default + + + CFBundleTypeExtensions + + duckload + + CFBundleTypeName + Incomplete download + CFBundleTypeRole + Editor + NSIsRelatedItemType + + LSHandlerRank + Owner + + + CFBundleTypeExtensions + + pdf + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + PDF Document + CFBundleTypeMIMETypes + + application/pdf + + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + png + + CFBundleTypeMIMETypes + + image/png + + LSItemContentTypes + + public.png + + CFBundleTypeOSTypes + + PNGf + + CFBundleTypeIconFile + document.icns + CFBundleTypeName + PNG image + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + jpg + jpeg + jp2 + jpeg2 + + CFBundleTypeMIMETypes + + image/jpeg + image/jp2 + image/jpeg2000 + + CFBundleTypeOSTypes + + JPEG + jp2 + + LSItemContentTypes + + public.jpeg + public.jpeg-2000 + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + JPEG image + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + gif + giff + + CFBundleTypeMIMETypes + + image/gif + + CFBundleTypeOSTypes + + GIFf + + LSItemContentTypes + + com.compuserve.gif + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + GIF image + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + svg + + CFBundleTypeMIMETypes + + image/svg+xml + + LSItemContentTypes + + public.svg-image + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + SVG image + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + tiff + tif + + CFBundleTypeMIMETypes + + image/tiff + + CFBundleTypeOSTypes + + TIFF + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + TIFF image + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + ico + + CFBundleTypeMIMETypes + + image/x-icon + image/icon + image/ico + + CFBundleTypeOSTypes + + ICO + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + Windows icon + CFBundleTypeRole + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + bmp + + CFBundleTypeMIMETypes + + image/bmp + image/x-bitmap + image/x-bmp + image/x-ms-bitmap + image/x-ms-bmp + + LSItemContentTypes + + com.microsoft.bmp + + CFBundleTypeName + BMP Image + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + LSRoleHandlerScheme + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + xml + rss + atom + + CFBundleTypeMIMETypes + + text/xml + application/xml + application/rss+xml + application/atom+xml + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + XML document + CFBundleTypeRole + Viewer + LSHandlerRank + Default + + + CFBundleTypeExtensions + + json + + CFBundleTypeMIMETypes + + text/json + application/json + + LSItemContentTypes + + public.json + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + JSON document + CFBundleTypeRole + Viewer + LSHandlerRank + Default + + + CFBundleTypeExtensions + + flac + m4a + mp3 + mpg + wav + aac + amr + mp4 + mpeg + + CFBundleTypeMIMETypes + + audio/flac + audio/x-flac + audio/m4a + audio/mp4 + audio/mp3 + audio/mpeg + audio/mpeg3 + audio/qcp + audio/qcelp + audio/vnd.qcelp + audio/vnd.qcp + audio/vnd.wave + audio/x-wav + audio/x-aac + audio/aac + audio/x-amr + audio/amr + audio/x-m4a + audio/x-mp3 + audio/x-mp4 + audio/x-mpeg + audio/x-mpeg3 + audio/x-mpg + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + Audio File + LSRoleHandlerScheme + Viewer + LSHandlerRank + Alternate + + + CFBundleTypeExtensions + + 3gp + avi + m4v + mov + mp4 + + CFBundleTypeMIMETypes + + video/3gp + video/3gpp + video/avi + video/x-msvideo + video/x-m4v + video/mp4 + video/x-quicktime + video/quicktime + + LSItemContentTypes + + public.movie + + CFBundleTypeIconFile + document.icns + CFBundleTypeIconSystemGenerated + YES + CFBundleTypeName + Video File + LSRoleHandlerScheme + Viewer + LSHandlerRank + Alternate + + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/DuckDuckGo/InfoPlist.xcstrings b/DuckDuckGo/InfoPlist.xcstrings index e4f7972ce7..28e181ef08 100644 --- a/DuckDuckGo/InfoPlist.xcstrings +++ b/DuckDuckGo/InfoPlist.xcstrings @@ -363,4 +363,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/DuckDuckGo/Localizable.xcstrings b/DuckDuckGo/Localizable.xcstrings index faac3cb31a..f65592de5a 100644 --- a/DuckDuckGo/Localizable.xcstrings +++ b/DuckDuckGo/Localizable.xcstrings @@ -317,6 +317,7 @@ } }, "••••••••••••" : { + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -480,6 +481,58 @@ } } }, + "1." : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "1." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "1." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "1." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "1." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "1." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "1." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "1." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "1." + } + } + } + }, "about.app_name" : { "comment" : "Application name to be displayed in the About dialog", "extractionState" : "extracted_with_value", @@ -768,6 +821,7 @@ }, "Add Folder" : { "comment" : "Add Folder popover: Create folder button", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -1114,6 +1168,7 @@ }, "Address:" : { "comment" : "Add Bookmark dialog bookmark url field heading", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -2358,6 +2413,66 @@ } } }, + "auto.clear" : { + "comment" : "Header of a section in Settings. The setting configures clearing data automatically after quitting the app.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisch löschen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Auto-Clear" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Borrado automático" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Effacement automatique" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancellazione automatica" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatisch wissen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatyczne czyszczenie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limpeza automática" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Автоочистка" + } + } + } + }, "autoconsent.checkbox.title" : { "comment" : "Autoconsent settings checkbox title", "extractionState" : "extracted_with_value", @@ -3678,6 +3793,66 @@ } } }, + "autofill.hide-card-cvv" : { + "comment" : "Tooltip for the Autofill panel's Hide CVV button", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "CVV ausblenden" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Hide CVV" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ocultar CVV" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Masquer CVV" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nascondi CVV" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "CVV verbergen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ukryj CVV" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ocultar CVV" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Скрыть CVV-код" + } + } + } + }, "autofill.hide-password" : { "comment" : "Tooltip for the Autofill panel's Hide Password button", "extractionState" : "extracted_with_value", @@ -5298,6 +5473,66 @@ } } }, + "autofill.show-card-cvv" : { + "comment" : "Tooltip for the Autofill panel's Show CVV button", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "CVV anzeigen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Show CVV" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mostrar CVV" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Afficher CVV" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mostra CVV" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "CVV weergeven" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pokaż CVV" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mostrar CVV" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Показать CVV-код" + } + } + } + }, "autofill.show-password" : { "comment" : "Tooltip for the Autofill panel's Show Password button", "extractionState" : "extracted_with_value", @@ -5478,6 +5713,66 @@ } } }, + "automatically.clear.data" : { + "comment" : "Label after the checkbox in Settings which configures clearing data automatically after quitting the app.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tabs und Browserdaten automatisch löschen, wenn DuckDuckGo beendet wird" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Automatically clear tabs and browsing data when DuckDuckGo quits" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Borra automáticamente las pestañas y los datos de navegación cuando se cierra DuckDuckGo" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Effacer automatiquement les onglets et les données de navigation lorsque DuckDuckGo se ferme" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancella automaticamente schede e dati di navigazione quando chiudi DuckDuckGo" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tabbladen en browsegegevens automatisch wissen wanneer DuckDuckGo stopt" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Automatycznie czyść karty i dane przeglądania przy wychodzeniu z DuckDuckGo" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limpar automaticamente os separadores e os dados de navegação quando o DuckDuckGo fecha" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Автоматически закрывает вкладки и стирает данные о посещении сайтов при завершении работы DuckDuckGo." + } + } + } + }, "Birthday" : { "comment" : "Title of the section of the Identities manager where the user can add/modify a date of birth", "localizations" : { @@ -6130,6 +6425,186 @@ } } }, + "bitwarden.incompatible" : { + "comment" : "Message that warns user that specific Bitwarden app vesions are not compatible with this app", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Die folgenden Bitwarden-Versionen sind mit DuckDuckGo inkompatibel: v2024.3.0, v2024.3.2, v2024.4.0, v2024.4.1. Bitte kehre zu einer älteren Version zurück, indem du die folgenden Schritte ausführst:" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The following Bitwarden versions are incompatible with DuckDuckGo: v2024.3.0, v2024.3.2, v2024.4.0, v2024.4.1. Please revert to an older version by following these steps:" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Las siguientes versiones de Bitwarden son incompatibles con DuckDuckGo: v2024.3.0, v2024.3.2, v2024.4.0, v2024.4.1. Vuelve a una versión anterior siguiendo estos pasos:" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Les versions suivantes de Bitwarden sont incompatibles avec DuckDuckGo : v2024.3.0, v2024.3.2, v2024.4.0 et v2024.4.1. Veuillez revenir à une version antérieure en procédant comme suit :" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le seguenti versioni di Bitwarden non sono compatibili con DuckDuckGo: v2024.3.0, v2024.3.2, v2024.4.0, v2024.4.1. È necessario tornare a una versione precedente seguendo questi passaggi:" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "De volgende versies van Bitwarden zijn niet compatibel met DuckDuckGo: v2024.3.0, v2024.3.2, v2024.4.0, v2024.4.1. Volg deze stappen om terug te gaan naar een oudere versie:" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Następujące wersje Bitwarden są niezgodne z DuckDuckGo: v2024.3.0, v2024.3.2, v2024.4.0, v2024.4.1. Przywróć starszą wersję, wykonując następujące czynności:" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "As seguintes versões do Bitwarden são incompatíveis com o DuckDuckGo: v2024.3.0, v2024.3.2, v2024.4.0 e v2024.4.1. Reverte para uma versão mais antiga seguindo estes passos:" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "С DuckDuckGo несовместимы следующие версии Bitwarden: 2024.3.0, 2024.3.2, 2024.4.0, 2024.4.1. Вернитесь к более старой версии, выполнив следующие действия:" + } + } + } + }, + "bitwarden.incompatible.step.1" : { + "comment" : "First step to downgrade Bitwarden", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "V2014.2.1 herunterladen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Download v2014.2.1" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descargar v2014.2.1" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Télécharger v2014.2.1" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Scarica la versione v2014.2.1" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Download v2014.2.1" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pobierz v2014.2.1" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Transfere a versão v2014.2.1" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Скачайте версию 2014.2.1" + } + } + } + }, + "bitwarden.incompatible.step.2" : { + "comment" : "Second step to downgrade Bitwarden", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "2. Öffne die heruntergeladene DMG-Datei und ziehe die Bitwarden-Anwendung auf den Ordner „/Applications“." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "2. Open the downloaded DMG file and drag the Bitwarden application to\nthe /Applications folder." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "2. Abre el archivo DMG descargado y arrastra la aplicación Bitwarden a\nla carpeta /Applications." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "2. Ouvrez le fichier DMG téléchargé et faites glisser l'application Bitwarden vers\nle dossier /Applications." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "2. Apri il file DMG scaricato e trascina l'applicazione Bitwarden nella\n/cartella Applications." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "2. Open het gedownloade DMG-bestand en sleep de Bitwarden-app naar\n de map /Applications." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "2. Otwórz pobrany plik DMG i przeciągnij aplikację Bitwarden do\nfolderu /Applications." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "2. Abre o ficheiro DMG transferido e arrasta a aplicação Bitwarden para\na pasta /Applications." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "2. Откройте загруженный файл DMG и перетащите приложение Bitwarden в стандартную папку «Программы»." + } + } + } + }, "bitwarden.install" : { "comment" : "Button to install Bitwarden app", "extractionState" : "extracted_with_value", @@ -7151,6 +7626,7 @@ }, "Bookmark Added" : { "comment" : "Bookmark Added popover title", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -7308,6 +7784,66 @@ } } }, + "bookmark.all.tabs" : { + "comment" : "Menu item for bookmarking all the open tabs", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle Tabs mit Lesezeichen versehen…" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Bookmark All Tabs…" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Añadir todas las pestañas a marcadores…" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter tous les onglets aux signets…" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Crea un segnalibro con tutte le schede…" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle tabbladen toevoegen als bladwijzer…" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dodaj wszystkie karty do zakładek…" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Marcar todos os separadores…" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добавить все вкладки в закладки…" + } + } + } + }, "bookmark.dialog.add" : { "comment" : "Button to confim a bookmark creation", "extractionState" : "extracted_with_value", @@ -7435,55 +7971,55 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Diese Seite als Lesezeichen markieren" + "value" : "Diese Seite mit einem Lesezeichen versehen…" } }, "en" : { "stringUnit" : { "state" : "new", - "value" : "Bookmark This Page" + "value" : "Bookmark This Page…" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "Marcar esta página" + "value" : "Marcar esta página…" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Ajouter cette page aux signets" + "value" : "Ajouter cette page aux signets…" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "Crea un segnalibro per questa pagina" + "value" : "Crea un segnalibro per questa pagina…" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Bladwijzer toevoegen aan deze pagina" + "value" : "Bladwijzer toevoegen voor deze pagina…" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Dodaj tę stronę do zakładek" + "value" : "Dodaj tę stronę do zakładek…" } }, "pt" : { "stringUnit" : { "state" : "translated", - "value" : "Marcar esta página" + "value" : "Marcar esta página…" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Сохранить в закладках" + "value" : "Сохранить страницу в закладках…" } } } @@ -8494,308 +9030,608 @@ } } }, - "bookmarks.dialog.action.addBookmark" : { - "comment" : "CTA title for adding a Bookmark", - "extractionState" : "extracted_with_value", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Lesezeichen hinzufügen" - } - }, - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Add Bookmark" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Añadir marcador" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Ajouter un signet" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Aggiungi ai segnalibri" - } - }, - "nl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Bladwijzer toevoegen" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Dodaj zakładkę" - } - }, - "pt" : { - "stringUnit" : { - "state" : "translated", - "value" : "Adicionar marcador" - } - }, - "ru" : { - "stringUnit" : { - "state" : "translated", - "value" : "Добавить закладку" - } - } - } - }, - "bookmarks.dialog.action.addFolder" : { - "comment" : "CTA title for adding a Folder", + "bookmarks.dialog.action.addAllBookmarks" : { + "comment" : "CTA title for saving multiple Bookmarks at once", "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Ordner hinzufügen" + "value" : "Lesezeichen speichern" } }, "en" : { "stringUnit" : { "state" : "new", - "value" : "Add Folder" + "value" : "Save Bookmarks" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "Añadir carpeta" + "value" : "Guardar marcadores" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Ajouter le dossier" + "value" : "Enregistrer les signets" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "Aggiungi cartella" + "value" : "Salva segnalibri" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Map toevoegen" + "value" : "Bladwijzers opslaan" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Dodaj folder" + "value" : "Zapisz zakładki" } }, "pt" : { "stringUnit" : { "state" : "translated", - "value" : "Adicionar pasta" + "value" : "Guardar marcadores" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Добавить папку" + "value" : "Сохранение закладок" } } } }, - "bookmarks.dialog.field.location" : { - "comment" : "Location field label for Bookmark folder", - "extractionState" : "extracted_with_value", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Standort" - } - }, - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Location" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Ubicación" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Localisation" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Posizione" - } - }, - "nl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Locatie" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Lokalizacja" - } - }, - "pt" : { - "stringUnit" : { - "state" : "translated", - "value" : "Localização" - } - }, - "ru" : { - "stringUnit" : { - "state" : "translated", - "value" : "Местоположение" - } - } - } - }, - "bookmarks.dialog.field.name" : { - "comment" : "Name field label for Bookmark or Folder", - "extractionState" : "extracted_with_value", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Name" - } - }, - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Name" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nombre" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nom" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nome" - } - }, - "nl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Naam" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nazwa" - } - }, - "pt" : { - "stringUnit" : { - "state" : "translated", - "value" : "Nome" - } - }, - "ru" : { - "stringUnit" : { - "state" : "translated", - "value" : "Название" - } - } - } - }, - "bookmarks.dialog.field.url" : { - "comment" : "URL field label for Bookmar", + "bookmarks.dialog.action.addBookmark" : { + "comment" : "CTA title for adding a Bookmark", "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "URL" + "value" : "Lesezeichen hinzufügen" } }, "en" : { "stringUnit" : { "state" : "new", - "value" : "URL" + "value" : "Add Bookmark" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "URL" + "value" : "Añadir marcador" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "URL" + "value" : "Ajouter un signet" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "URL" + "value" : "Aggiungi ai segnalibri" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "URL" + "value" : "Bladwijzer toevoegen" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Adres URL" + "value" : "Dodaj zakładkę" } }, "pt" : { "stringUnit" : { "state" : "translated", - "value" : "URL" + "value" : "Adicionar marcador" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "URL" + "value" : "Добавить закладку" } } } }, - "bookmarks.dialog.folder.title.add" : { - "comment" : "Bookmark folder creation dialog title", + "bookmarks.dialog.action.addFolder" : { + "comment" : "CTA title for adding a Folder", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ordner hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Add Folder" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Añadir carpeta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter le dossier" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aggiungi cartella" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Map toevoegen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dodaj folder" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar pasta" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добавить папку" + } + } + } + }, + "bookmarks.dialog.allTabs.message.add" : { + "comment" : "Bookmark creation for all open tabs dialog title", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Diese Lesezeichen werden in einem neuen Ordner gespeichert:" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "These bookmarks will be saved in a new folder:" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estos marcadores se guardarán en una nueva carpeta:" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ces signets seront enregistrés dans un nouveau dossier:" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Questi segnalibri verranno salvati in una nuova cartella:" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deze bladwijzers worden opgeslagen in een nieuwe map:" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Te zakładki zostaną zapisane w nowym folderze:" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Estes marcadores serão guardados numa nova pasta:" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Эти закладки будут сохранены в новой папке:" + } + } + } + }, + "bookmarks.dialog.allTabs.title.add" : { + "comment" : "Title of dialog to bookmark all open tabs. E.g. 'Bookmark Open Tabs (42)'", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Offene Tabs mit Lesezeichen versehen (%d)" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Bookmark Open Tabs (%d)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Añadir pestañas abiertas (%d)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter les onglets ouverts (%d) aux signets" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aggiungere ai segnalibri le schede aperte (%d)" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d geopende tabbladen toevoegen als bladwijzer" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dodaj otwarte karty (%d) do zakładek" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Marcar separadores abertos (%d)" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добавить открытые вкладки (%d) в закладки" + } + } + } + }, + "bookmarks.dialog.field.folderName" : { + "comment" : "Folder name field label for Bookmarks folder", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ordnername" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Folder Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre de la carpeta" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom du dossier" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nome della cartella" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Naam van de map" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nazwa folderu" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nome da pasta" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Название папки" + } + } + } + }, + "bookmarks.dialog.field.folderName.value" : { + "comment" : "The suggested name of the folder that will contain the bookmark tabs. Eg. 2024-02-12 - Tabs (42)", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ – Tabs (%2$d)" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ - Tabs (%2$d)" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - Pestañas (%2$d)" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - Onglets (%2$d)" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - Schede (%2$d)" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - Tabbladen (%2$d)" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - Karty (%2$d)" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - Separadores (%2$d)" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - Вкладки (%2$d)" + } + } + } + }, + "bookmarks.dialog.field.location" : { + "comment" : "Location field label for Bookmark folder", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Standort" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Location" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ubicación" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Localisation" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Posizione" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Locatie" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lokalizacja" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Localização" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Местоположение" + } + } + } + }, + "bookmarks.dialog.field.name" : { + "comment" : "Name field label for Bookmark or Folder", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Name" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Name" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nombre" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nom" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nome" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Naam" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nazwa" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nome" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Название" + } + } + } + }, + "bookmarks.dialog.field.url" : { + "comment" : "URL field label for Bookmar", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "URL" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "URL" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "URL" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "URL" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "URL" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "URL" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adres URL" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "URL" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "URL" + } + } + } + }, + "bookmarks.dialog.folder.title.add" : { + "comment" : "Bookmark folder creation dialog title", "extractionState" : "extracted_with_value", "localizations" : { "de" : { @@ -8921,7 +9757,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Lesezeichen hinzufügen" + "value" : "Add Bookmark" } }, "en" : { @@ -8933,43 +9769,43 @@ "es" : { "stringUnit" : { "state" : "translated", - "value" : "Añadir marcador" + "value" : "Add Bookmark" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Ajouter un signet" + "value" : "Add Bookmark" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "Aggiungi ai segnalibri" + "value" : "Add Bookmark" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Bladwijzer toevoegen" + "value" : "Add Bookmark" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Dodaj zakładkę" + "value" : "Add Bookmark" } }, "pt" : { "stringUnit" : { "state" : "translated", - "value" : "Adicionar marcador" + "value" : "Add Bookmark" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Добавить закладку" + "value" : "Add Bookmark" } } } @@ -9041,7 +9877,7 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Lesezeichen bearbeiten" + "value" : "Edit Bookmark" } }, "en" : { @@ -9053,43 +9889,43 @@ "es" : { "stringUnit" : { "state" : "translated", - "value" : "Editar marcador" + "value" : "Edit Bookmark" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Modifier le signet" + "value" : "Edit Bookmark" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "Modifica segnalibro" + "value" : "Edit Bookmark" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Bladwijzer bewerken" + "value" : "Edit Bookmark" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Edytuj zakładkę" + "value" : "Edit Bookmark" } }, "pt" : { "stringUnit" : { "state" : "translated", - "value" : "Editar marcador" + "value" : "Edit Bookmark" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Редактировать закладку" + "value" : "Edit Bookmark" } } } @@ -10573,6 +11409,126 @@ } } }, + "clear.and.quit" : { + "comment" : "Button to clear data and quit the application", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Löschen und Beenden" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Clear and Quit" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Borrar y salir" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Effacer et quitter" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancella ed esci" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wissen en stoppen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wyczyść i wyjdź" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limpar e sair" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Очистить и выйти" + } + } + } + }, + "close.all.other.tabs" : { + "comment" : "Menu item", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle anderen Tabs schließen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Close All Other Tabs" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cerrar todas las demás pestañas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fermer tous les autres onglets" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chiudi tutte le altre schede" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alle andere tabbladen sluiten" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zamknij wszystkie inne karty" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fechar todos os outros separadores" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Закрыть все остальные вкладки" + } + } + } + }, "close.other.tabs" : { "comment" : "Menu item", "extractionState" : "extracted_with_value", @@ -10813,6 +11769,66 @@ } } }, + "close.tabs.to.the.left" : { + "comment" : "Menu item", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tabs auf der linken Seite schließen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Close Tabs to the Left" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cerrar las pestañas a la izquierda" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fermer les onglets à gauche" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chiudi le schede a sinistra" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tabbladen links sluiten" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zamknij karty po lewej stronie" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fechar separadores à esquerda" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Закрыть вкладки слева" + } + } + } + }, "close.tabs.to.the.right" : { "comment" : "Menu item", "extractionState" : "extracted_with_value", @@ -11106,6 +12122,126 @@ } } }, + "context.menu.new.tab.mode.at.end" : { + "comment" : "Preferences > Tabs > At end of list", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rechts neben anderen Tabs hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Add to the right of other tabs" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Añadir a la derecha de otras pestañas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter à droite des autres onglets" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aggiungi a destra di altre schede" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toevoegen aan de rechterkant van andere tabbladen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dodaj po prawej stronie innych kart" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar à direita dos outros separadores" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добавить справа от остальных вкладок" + } + } + } + }, + "context.menu.new.tab.mode.next.to.current" : { + "comment" : "Preferences > Tabs > Next to current tab", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rechts neben dem aktuellen Tab hinzufügen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Add to the right of the current tab" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Añadir a la derecha de la pestaña actual" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ajouter à droite de l'onglet actuel" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aggiungi a destra della scheda attuale" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toevoegen aan de rechterkant van het huidige tabblad" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dodaj po prawej stronie bieżącej karty" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Adicionar à direita do separador atual" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добавить справа от текущей вкладки" + } + } + } + }, "copy" : { "comment" : "Copy button", "extractionState" : "extracted_with_value", @@ -11168,6 +12304,7 @@ }, "Copy" : { "comment" : "Command", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -12407,6 +13544,7 @@ }, "Delete" : { "comment" : "Command", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -12691,6 +13829,66 @@ } } }, + "disable.auto.clear.to.enable.session.restore" : { + "comment" : "Information label in Settings. It tells user that to enable session restoration setting they have to disable burn on quit. Auto-Clear should match the string with 'auto.clear' key", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deaktiviere das automatische Löschen beim Beenden, um die Sitzungswiederherstellung einzuschalten." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Disable auto-clear on quit to turn on session restore." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desactiva el borrado automático al salir para activar Restaurar sesión." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Désactivez l'effacement automatique à la fermeture pour activer la restauration de session." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Disabilita la cancellazione automatica all'uscita per attivare il ripristino della sessione." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Schakel automatisch wissen uit wanneer u stopt om het herstellen van de sessie in te schakelen." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wyłącz automatyczne czyszczenie przy wychodzeniu, aby włączyć przywracanie sesji." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Desativa a limpeza automática ao sair para ativar a restauração da sessão." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Чтобы активировать восстановление сеанса, отключите автоочистку данных при выходе." + } + } + } + }, "disable.email.protection.mesage" : { "comment" : "Message for alert shown when user disables email protection", "extractionState" : "extracted_with_value", @@ -14543,66 +15741,6 @@ } } }, - "downloads.restart.item" : { - "comment" : "Contextual menu item in downloads manager to restart the download", - "extractionState" : "extracted_with_value", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Stopp" - } - }, - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Stop" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Detener" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Arrêter" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Interrompi" - } - }, - "nl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Stoppen" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Zatrzymaj" - } - }, - "pt" : { - "stringUnit" : { - "state" : "translated", - "value" : "Parar" - } - }, - "ru" : { - "stringUnit" : { - "state" : "translated", - "value" : "Остановить" - } - } - } - }, "downloads.show-in-finder.item" : { "comment" : "Contextual menu item in downloads manager to show the downloaded file in Finder", "extractionState" : "extracted_with_value", @@ -15663,6 +16801,7 @@ }, "Edit…" : { "comment" : "Command", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -19948,6 +21087,7 @@ }, "Hide" : { "comment" : "Main Menu > View > Home Button > None item\n Preferences > Home Button > None item", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -24263,6 +25403,126 @@ } } }, + "import.nodata.bookmarks.subtitle" : { + "comment" : "Data import error subtitle: suggestion to import Bookmarks manually by selecting a CSV or HTML file. The placeholder here represents the source browser, e.g Firefox.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wenn du %@ Lesezeichen hast, versuche stattdessen, sie manuell zu importieren." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "If you have %@ bookmarks, try importing them manually instead." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Si tienes %@ marcadores, intenta importarlos manualmente." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Si vous avez %@ signets, essayez plutôt de les importer manuellement." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Se hai %@ segnalibri, prova a importarli manualmente." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Als je %@ bladwijzers hebt, probeer ze dan handmatig te importeren." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jeśli masz zakładki %@, spróbuj zaimportować je ręcznie." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Se tens favoritos do %@, tenta importá-los manualmente." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Если у вас есть %@-файл с закладками, попробуйте импортировать его вручную." + } + } + } + }, + "import.nodata.passwords.subtitle" : { + "comment" : "Data import error subtitle: suggestion to import passwords manually by selecting a CSV or HTML file. The placeholder here represents the source browser, e.g Firefox.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wenn du %@ Passwörter hast, versuche stattdessen, sie manuell zu importieren." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "If you have %@ passwords, try importing them manually instead." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Si tiene %@ contraseñas, intenta importarlas manualmente." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Si vous avez %@ mots de passe, essayez plutôt de les importer manuellement." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Se hai %@ password, prova a importarle manualmente." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Als je %@ wachtwoorden hebt, probeer ze dan handmatig te importeren." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jeśli masz hasła %@, spróbuj zaimportować je ręcznie." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Se tens palavras-passe do %@, tenta importá-las manualmente." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Если у вас есть %@-файл с паролями, попробуйте импортировать его вручную." + } + } + } + }, "import.onePassword.app.version.info" : { "comment" : "Instructions how to find an installed 1Password password manager app version.\n%1$s, %2$s - app name (1Password)", "extractionState" : "extracted_with_value", @@ -30136,12 +31396,12 @@ }, "newTab.setup.survey.day.0.action" : { "comment" : "Action title of the Day 0 survey of the Set Up section in the home page", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Teile deine Gedanken" + "value" : "Sign Up To Participate" } }, "en" : { @@ -30152,56 +31412,56 @@ }, "es" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Comparte tus ideas" + "state" : "translated", + "value" : "Sign Up To Participate" } }, "fr" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Partagez votre avis" + "state" : "translated", + "value" : "Sign Up To Participate" } }, "it" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Comunicaci la tua opinione" + "state" : "translated", + "value" : "Sign Up To Participate" } }, "nl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Deel je gedachten" + "state" : "translated", + "value" : "Sign Up To Participate" } }, "pl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Podziel się przemyśleniami" + "state" : "translated", + "value" : "Sign Up To Participate" } }, "pt" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Partilha as tuas opiniões" + "state" : "translated", + "value" : "Sign Up To Participate" } }, "ru" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Поделиться соображениями" + "state" : "translated", + "value" : "Sign Up To Participate" } } } }, "newTab.setup.survey.day.0.summary" : { "comment" : "Summary of the card on the new tab page that invites users to partecipate to a survey", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Nimm an unserer kurzen Umfrage teil und hilf uns, den besten Browser zu entwickeln." + "value" : "Join an interview with a member of our research team to help us build the best browser." } }, "en" : { @@ -30212,56 +31472,56 @@ }, "es" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Responde a nuestra breve encuesta y ayúdanos a crear el mejor navegador." + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." } }, "fr" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Répondez à notre courte enquête et aidez-nous à créer le meilleur navigateur." + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." } }, "it" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Rispondi al nostro breve sondaggio e aiutaci a creare il browser migliore." + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." } }, "nl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Vul onze korte enquête in en help ons de beste browser te bouwen." + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." } }, "pl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Weź udział w krótkiej ankiecie i pomóż nam opracować najlepszą przeglądarkę." + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." } }, "pt" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Responde ao nosso curto inquérito e ajuda-nos a criar o melhor navegador." + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." } }, "ru" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Пройдите короткий опрос и помогите DuckDuckGo стать лучшим из браузеров." + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." } } } }, "newTab.setup.survey.day.0.title" : { "comment" : "Title of the Day 0 durvey of the Set Up section in the home page", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Sag uns, was dich hierher gebracht hat" + "value" : "Share Your Thoughts With Us" } }, "en" : { @@ -30272,44 +31532,44 @@ }, "es" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Cuéntanos qué te ha traído hasta aquí" + "state" : "translated", + "value" : "Share Your Thoughts With Us" } }, "fr" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Dites-nous ce qui vous amène ici" + "state" : "translated", + "value" : "Share Your Thoughts With Us" } }, "it" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Raccontaci cosa ti ha portato qui" + "state" : "translated", + "value" : "Share Your Thoughts With Us" } }, "nl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Vertel ons wat je hier heeft gebracht" + "state" : "translated", + "value" : "Share Your Thoughts With Us" } }, "pl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Powiedz nam, co Cię tu sprowadziło" + "state" : "translated", + "value" : "Share Your Thoughts With Us" } }, "pt" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Diz-nos o que te trouxe aqui" + "state" : "translated", + "value" : "Share Your Thoughts With Us" } }, "ru" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Что привело вас к нам" + "state" : "translated", + "value" : "Share Your Thoughts With Us" } } } @@ -30496,12 +31756,12 @@ }, "newTab.setup.survey.day.14.action" : { "comment" : "Action title of the Day 14 survey of the Set Up section in the home page", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Hilf uns, uns zu verbessern" + "value" : "Sign Up To Participate" } }, "en" : { @@ -30509,25 +31769,121 @@ "state" : "new", "value" : "Sign Up To Participate" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign Up To Participate" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign Up To Participate" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign Up To Participate" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign Up To Participate" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign Up To Participate" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign Up To Participate" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sign Up To Participate" + } } } }, "newTab.setup.survey.day.14.summary" : { "comment" : "Summary of the card on the new tab page that invites users to partecipate to a survey", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." + } + }, "en" : { "stringUnit" : { "state" : "new", "value" : "Join an interview with a member of our research team to help us build the best browser." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Join an interview with a member of our research team to help us build the best browser." + } } } }, "newTab.setup.survey.day.14.title" : { "comment" : "Title of the Day 14 durvey of the Set Up section in the home page", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Share Your Thoughts With Us" + } + }, "en" : { "stringUnit" : { "state" : "new", @@ -30537,43 +31893,43 @@ "es" : { "stringUnit" : { "state" : "translated", - "value" : "Ayúdanos a mejorar" + "value" : "Share Your Thoughts With Us" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Aidez-nous à nous améliorer" + "value" : "Share Your Thoughts With Us" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "Aiutaci a migliorare" + "value" : "Share Your Thoughts With Us" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Help ons om te verbeteren" + "value" : "Share Your Thoughts With Us" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Pomóż nam we wprowadzaniu ulepszeń" + "value" : "Share Your Thoughts With Us" } }, "pt" : { "stringUnit" : { "state" : "translated", - "value" : "Ajuda-nos a melhorar" + "value" : "Share Your Thoughts With Us" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Помогите нам стать лучше" + "value" : "Share Your Thoughts With Us" } } } @@ -30820,7 +32176,7 @@ }, "no.access.to.selected.folder" : { "comment" : "Alert presented to user if the app doesn't have rights to access selected folder", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -30880,7 +32236,7 @@ }, "no.access.to.selected.folder.header" : { "comment" : "Header of the alert dialog informing user about failed download", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -34811,7 +36167,7 @@ } }, "Passwords:" : { - "comment" : "Data import summary format of how many passwords (%lld) were successfully imported.", + "comment" : "Data import summary format of how many passwords were successfully imported.", "localizations" : { "de" : { "stringUnit" : { @@ -42536,6 +43892,246 @@ } } }, + "preferences-tabs.new.tab.position.title" : { + "comment" : "Title for new tab positioning", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beim Erstellen eines neuen Tabs" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "When creating a new tab" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Al crear una nueva pestaña" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lors de la création d'un nouvel onglet" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quando si crea una nuova scheda" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bij het maken van een nieuw tabblad" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podczas tworzenia nowej karty" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ao criar um novo separador" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "При создании новой вкладки" + } + } + } + }, + "preferences-tabs.prefer.new.tabs.to.windows" : { + "comment" : "Option to prefer opening new tabs instead of windows when opening links", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Links nach Möglichkeit in neuen Tabs statt in neuen Fenstern öffnen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Open links in new tabs instead of new windows whenever possible" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abrir enlaces en nuevas pestañas en lugar de nuevas ventanas siempre que sea posible" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ouvrir les liens dans de nouveaux onglets plutôt que dans de nouvelles fenêtres si possible" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apri i collegamenti in nuove schede anziché in nuove finestre quando possibile" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Links waar mogelijk openen in nieuwe tabbladen in plaats van in nieuwe vensters" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otwieraj linki w nowych kartach zamiast w nowych oknach, gdy tylko jest to możliwe" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abrir links em separadores novos em vez de novas janelas sempre que possível" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "По возможности открывать ссылки в новых вкладках, а не окнах" + } + } + } + }, + "preferences-tabs.switch.tab.when.opened" : { + "comment" : "Option to switch to a new tab/window when it is opened", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Beim Öffnen von Links sofort zu einem neuen Tab oder Fenster wechseln" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "When opening links, switch to the new tab or window immediately" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Al abrir enlaces, cambiar a la nueva pestaña o ventana inmediatamente" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "À l'ouverture des liens, basculer immédiatement sur le nouvel onglet ou la nouvelle fenêtre" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quando apri i collegamenti, passa immediatamente alla nuova scheda o finestra" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meteen overschakelen naar het nieuwe tabblad of venster bij het openen van links" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otwierając linki, natychmiast przełącz na nową kartę lub nowe okno" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ao abrir links, mudar imediatamente para o novo separador ou janela" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "При открытии ссылки сразу переключаться на ее вкладку или окно" + } + } + } + }, + "preferences-tabs.title" : { + "comment" : "Title for tabs section in settings", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tabs" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Tabs" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pestañas" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Onglets" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Schede" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tabbladen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Karty" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Separadores" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вкладки" + } + } + } + }, "preferences.about" : { "comment" : "Title of the option to show the About screen", "extractionState" : "extracted_with_value", @@ -45416,6 +47012,58 @@ } } }, + "Privacy Pro" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Pro" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Pro" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Pro" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Pro" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Pro" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Pro" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Pro" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy Pro" + } + } + } + }, "private.search.explenation" : { "comment" : "feature explanation in settings", "extractionState" : "extracted_with_value", @@ -45536,115 +47184,121 @@ } } }, - "Recently Closed" : { - "comment" : "Main Menu History item", + "quit.without.clearing" : { + "comment" : "Button to quit the application without clearing data", + "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Kürzlich geschlossen" + "value" : "Beenden ohne Löschen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Quit Without Clearing" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "Cerrado recientemente" + "value" : "Salir sin borrar" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Récemment clôturé" + "value" : "Quitter sans effacer" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "Chiusa di recente" + "value" : "Esci senza cancellare" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Onlangs gesloten" + "value" : "Stoppen zonder wissen" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Niedawno zamknięte" + "value" : "Wyjdź bez czyszczenia" } }, "pt" : { "stringUnit" : { "state" : "translated", - "value" : "Fechados recentemente" + "value" : "Sair sem limpar" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Недавно закрытые" + "value" : "Выйти без очистки" } } } }, - "Reload Page" : { - "comment" : "Main Menu View item", + "Recently Closed" : { + "comment" : "Main Menu History item", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Seite neu laden" + "value" : "Kürzlich geschlossen" } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "Volver a cargar página" + "value" : "Cerrado recientemente" } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Recharger la page" + "value" : "Récemment clôturé" } }, "it" : { "stringUnit" : { "state" : "translated", - "value" : "Ricarica pagina" + "value" : "Chiusa di recente" } }, "nl" : { "stringUnit" : { "state" : "translated", - "value" : "Pagina opnieuw laden" + "value" : "Onlangs gesloten" } }, "pl" : { "stringUnit" : { "state" : "translated", - "value" : "Załaduj ponownie stronę" + "value" : "Niedawno zamknięte" } }, "pt" : { "stringUnit" : { "state" : "translated", - "value" : "Recarregar página" + "value" : "Fechados recentemente" } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "Перезагрузить страницу" + "value" : "Недавно закрытые" } } } }, - "reload.page" : { - "comment" : "Context menu item", - "extractionState" : "extracted_with_value", + "Reload Page" : { + "comment" : "Main Menu View item", "localizations" : { "de" : { "stringUnit" : { @@ -45652,12 +47306,66 @@ "value" : "Seite neu laden" } }, - "en" : { - "stringUnit" : { - "state" : "new", - "value" : "Reload Page" - } - }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Volver a cargar página" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recharger la page" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ricarica pagina" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pagina opnieuw laden" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Załaduj ponownie stronę" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recarregar página" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Перезагрузить страницу" + } + } + } + }, + "reload.page" : { + "comment" : "Context menu item", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seite neu laden" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Reload Page" + } + }, "es" : { "stringUnit" : { "state" : "translated", @@ -45704,6 +47412,7 @@ }, "Remove" : { "comment" : "Remove bookmark button title", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -47683,6 +49392,7 @@ }, "Show left of the back button" : { "comment" : "Preferences > Home Button > left position item", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -47736,6 +49446,7 @@ }, "Show Left of the Back Button" : { "comment" : "Main Menu > View > Home Button > left position item", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -48001,6 +49712,7 @@ }, "Show right of the reload button" : { "comment" : "Preferences > Home Button > right position item", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -48054,6 +49766,7 @@ }, "Show Right of the Reload Button" : { "comment" : "Main Menu > View > Home Button > right position item", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -48158,6 +49871,66 @@ } } }, + "show.data.clearing.settings" : { + "comment" : "Button in Settings. It navigates user to Data Clearing Settings. The Data Clearing string should match the string with the preferences.data-clearing key", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Einstellungen zum Löschen von Daten öffnen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Open Data Clearing Settings" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abrir configuración de borrado de datos" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ouvrir les paramètres d'effacement des données" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Apri Impostazioni cancellazione dati" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Instellingen voor het wissen van open gegevens" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otwórz ustawienia czyszczenia danych" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abrir Definições de limpeza de dados" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Открыть настройки очистки данных" + } + } + } + }, "show.folder.contents" : { "comment" : "Menu item that shows the content of a folder ", "extractionState" : "extracted_with_value", @@ -48483,6 +50256,726 @@ } } }, + "ssl.error.certificate.expired.message" : { + "comment" : "Describes an SSL error where a website's security certificate is expired. '%1$@' is a placeholder for the website's domain.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Das Sicherheitszertifikat für %1$@ ist abgelaufen." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The security certificate for %1$@ is expired." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El certificado de seguridad de %1$@ ha caducado." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le certificat de sécurité de %1$@ a expiré." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il certificato di sicurezza per %1$@ è scaduto." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Het beveiligingscertificaat voor %1$@ is verlopen." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Certyfikat zabezpieczeń dla %1$@ wygasł." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O certificado de segurança de %1$@ expirou." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Срок действия сертификата безопасности сайта %1$@ истек." + } + } + } + }, + "ssl.error.page.advanced.button" : { + "comment" : "Button shown in an error page that warns users of security risks on a website due to SSL issues. The buttons allows the user to see advanced options on click.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erweitert …" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Advanced…" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avanzadas..." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Options avancées" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avanzate…" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geavanceerd ..." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zaawansowane..." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avançado…" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дополнительно..." + } + } + } + }, + "ssl.error.page.advanced.info.body.expired" : { + "comment" : "Body of the text of the Advanced info shown in an error page that warns users of security risks on a website due to SSL issues.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Es ist möglich, dass die Website falsch konfiguriert ist, ein Angreifer deine Verbindung kompromittiert hat oder deine Systemuhr falsch ist." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "It’s possible that the website is misconfigured, that an attacker has compromised your connection, or that your system clock is incorrect." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Es posible que el sitio web esté mal configurado, que un atacante haya comprometido tu conexión o que el reloj del sistema no sea correcto." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il est possible que le site soit mal configuré, qu'un pirate ait compromis votre connexion ou que l'horloge de votre système soit incorrecte." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "È possibile che il sito web non sia configurato correttamente, che un aggressore abbia compromesso la tua connessione o che l'orologio del tuo sistema non sia corretto." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mogelijk is de website verkeerd geconfigureerd, heeft een aanvaller je verbinding gecompromitteerd of staat de klok van je systeem niet goed." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Możliwe, że witryna jest błędnie skonfigurowana, osoba atakująca naruszyła połączenie lub ustawienie zegara systemowego jest nieprawidłowe." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "É possível que o site esteja mal configurado, que um invasor tenha comprometido a tua ligação ou que o teu relógio do sistema esteja incorreto." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Возможно, неверно задана конфигурация сайта, соединение перехвачено злоумышленником либо неправильно настроены системные часы." + } + } + } + }, + "ssl.error.page.advanced.info.body.wrong.host" : { + "comment" : "Body of the text of the Advanced info shown in an error page that warns users of security risks on a website due to SSL issues.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Möglicherweise ist die Website falsch konfiguriert oder ein Angreifer hat deine Verbindung kompromittiert." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "It’s possible that the website is misconfigured or that an attacker has compromised your connection." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Es posible que el sitio web esté mal configurado o que un atacante haya comprometido tu conexión." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il est possible que le site soit mal configuré ou qu'un pirate ait compromis votre connexion." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "È possibile che il sito web non sia configurato correttamente o che un malintenzionato abbia compromesso la tua connessione." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Mogelijk is de website verkeerd geconfigureerd of heeft een aanvaller je verbinding gecompromitteerd." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Możliwe, że witryna jest błędnie skonfigurowana lub osoba atakująca naruszyła połączenie." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "É possível que o site esteja mal configurado ou que um invasor tenha comprometido a tua ligação." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Возможно, неверно задана конфигурация сайта либо ваше соединение перехвачено злоумышленником." + } + } + } + }, + "ssl.error.page.advanced.info.title" : { + "comment" : "Title of the Advanced info section shown in an error page that warns users of security risks on a website due to SSL issues.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "DuckDuckGo warnt dich, wenn eine Website ein ungültiges Zertifikat hat." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "DuckDuckGo warns you when a website has an invalid certificate." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "DuckDuckGo te avisa cuando un sitio web tiene un certificado no válido." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "DuckDuckGo vous avertit lorsque le certificat d'un site Web n'est pas valide." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "DuckDuckGo ti avverte quando un sito web ha un certificato non valido." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "DuckDuckGo waarschuwt je wanneer een website een ongeldig certificaat heeft." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "DuckDuckGo ostrzega gdy witryna internetowa ma nieprawidłowy certyfikat." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O DuckDuckGo avisa-te quando um site tem um certificado inválido." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "DuckDuckGo предупредит вас, если у сайта окажется недействительный сертификат." + } + } + } + }, + "ssl.error.page.body" : { + "comment" : "Error description shown in an error page that warns users of security risks on a website due to SSL issues. %1$@ represent the site domain.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Das Zertifikat für diese Website ist ungültig. Möglicherweise stellst du eine Verbindung zu einem Server her, der vorgibt, %1$@ zu sein, wodurch deine vertraulichen Daten in Gefahr sein könnten." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The certificate for this site is invalid. You might be connecting to a server that is pretending to be %1$@ which could put your confidential information at risk." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El certificado de este sitio no es válido. Puede que te estés conectando a un servidor que se hace pasar por %1$@, lo que podría poner en riesgo tu información confidencial." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le certificat de ce site n'est pas valide. Vous vous connectez peut-être à un serveur qui se fait passer pour %1$@, ce qui pourrait mettre vos informations confidentielles en danger." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il certificato di questo sito non è valido. Potresti collegarti a un server che finge di essere %1$@ e che potrebbe mettere a rischio le tue informazioni riservate." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Het certificaat voor deze website is ongeldig. Mogelijk maak je verbinding met een server die zich voordoet als %1$@, waardoor je vertrouwelijke informatie in gevaar kan komen." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Certyfikat tej witryny jest nieprawidłowy. Być może łączysz się z serwerem podszywającym się pod %1$@, co może narazić poufne informacje na niebezpieczeństwo." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O certificado deste site é inválido. Podes estar a estabelecer ligação a um servidor que finge ser %1$@, o que pode colocar as tuas informações confidenciais em risco." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сертификат этого сайта недействителен. Возможно, вы пытаетесь подключиться к серверу, который выдает себя за %1$@, что ставит под угрозу вашу конфиденциальную информацию." + } + } + } + }, + "ssl.error.page.header" : { + "comment" : "Title shown in an error page that warn users of security risks on a website due to SSL issues", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warnung: Diese Website ist möglicherweise unsicher" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Warning: This site may be insecure" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Advertencia: este sitio puede ser inseguro" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avertissement : ce site n'est peut-être pas sécurisé" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attenzione: questo sito potrebbe non essere sicuro" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Waarschuwing: Deze website is mogelijk onveilig" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ostrzeżenie: ta witryna może być niebezpieczna" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aviso: este site pode ser inseguro" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Внимание! Возможно, сайт небезопасен" + } + } + } + }, + "ssl.error.page.leave.site.button" : { + "comment" : "Button shown in an error page that warns users of security risks on a website due to SSL issues. The buttons allows the user to leave the website and navigate to previous page.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Diese Website verlassen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Leave This Site" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Salir de este sitio" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Quitter ce site" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esci da questo sito" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deze website verlaten" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opuść tę stronę" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Deixar este site" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Покинуть сайт" + } + } + } + }, + "ssl.error.page.tab.title" : { + "comment" : "Title shown in an error page tab that warn users of security risks on a website due to SSL issues", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warnung: Website ist möglicherweise unsicher" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Warning: Site May Be Insecure" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Advertencia: el sitio puede ser inseguro" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avertissement : le site n'est peut-être pas sécurisé" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attenzione: il sito potrebbe non essere sicuro" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Waarschuwing: Website mogelijk onveilig" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ostrzeżenie: witryna może być niebezpieczna" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aviso: o site pode ser inseguro" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Внимание! Возможно, сайт небезопасен" + } + } + } + }, + "ssl.error.page.visit.site.button" : { + "comment" : "Button shown in an error page that warns users of security risks on a website due to SSL issues. The buttons allows the user to visit the website anyway despite the risks.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Risiko akzeptieren und Website besuchen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Accept Risk and Visit Site" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aceptar el riesgo y visitar el sitio" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Accepter le risque et visiter le site" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Accetta il rischio e visita il sito" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Risico accepteren en site bezoeken" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zaakceptuj ryzyko i odwiedź witrynę" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aceitar o risco e visitar o site" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Принять риск и перейти на сайт" + } + } + } + }, + "ssl.error.self.signed.message" : { + "comment" : "Warns the user that the site's security certificate is self-signed and not trusted. '%1$@' is the site's domain.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Das Sicherheitszertifikat für %1$@ wird vom Betriebssystem deines Geräts als nicht vertrauenswürdig eingestuft." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The security certificate for %1$@ is not trusted by your device's operating system." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El sistema operativo del dispositivo no confía en el certificado de seguridad de %1$@." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le certificat de sécurité de %1$@ n'est pas approuvé par le système d'exploitation de votre appareil." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il certificato di sicurezza di %1$@ non è considerato attendibile dal sistema operativo del tuo dispositivo." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Het besturingssysteem van je apparaat vertrouwt het beveiligingscertificaat voor %1$@ niet." + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Certyfikat bezpieczeństwa %1$@ nie jest zaufany przez system operacyjny urządzenia." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O sistema operativo do teu dispositivo não confia no certificado de segurança de %1$@." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Операционная система вашего устройства не доверяет сертификату безопасности сайта %1$@." + } + } + } + }, + "ssl.error.wrong.host.message" : { + "comment" : "Explains an SSL error when a site's certificate doesn't match its domain. '%1$@' is the site's domain.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Das Sicherheitszertifikat für %1$@ stimmt nicht mit *.%2$@ überein." + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The security certificate for %1$@ does not match *.%2$@." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El certificado de seguridad de %1$@ no coincide con *.%2$@." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Le certificat de sécurité de %1$@ ne correspond pas à *.%2$@." + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Il certificato di protezione per %1$@ non corrisponde a *.%2$@." + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Het beveiligingscertificaat voor %1$@ komt niet overeen met *.%2$@. " + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Certyfikat zabezpieczeń %1$@ nie jest zgodny z *.%2$@." + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "O certificado de segurança de %1$@ não corresponde a *.%2$@." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сертификат безопасности сайта %1$@ не подходит для домена *.%2$@." + } + } + } + }, "Start Speaking" : { "comment" : "Main Menu Edit-Speech item", "localizations" : { @@ -48822,6 +51315,66 @@ } } }, + "tab.empty.title" : { + "comment" : "Title for an empty tab without a title", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ohne Titel" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Untitled" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sin título" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sans titre" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Senza titolo" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Naamloos" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bez tytułu" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sem título" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Без названия" + } + } + } + }, "tab.error.title" : { "comment" : "Tab error title", "extractionState" : "extracted_with_value", @@ -50949,6 +53502,7 @@ }, "Try importing bookmarks manually instead." : { "comment" : "Data import error subtitle: suggestion to import Bookmarks manually by selecting a CSV or HTML file.", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -51002,6 +53556,7 @@ }, "Try importing passwords manually instead." : { "comment" : "Data import error subtitle: suggestion to import Passwords manually by selecting a CSV or HTML file.", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -51466,6 +54021,186 @@ } } }, + "warn.before.quit" : { + "comment" : "Label after the checkbox in Settings which configures a warning before clearing data on the application termination.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warne mich, dass Tabs und Daten beim Beenden gelöscht werden" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Warn me that tabs and data will be cleared when quitting" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Advertirme de que las pestañas y los datos se borrarán al salir" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "M'avertir que les onglets et les données seront effacés à la fermeture" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avvisa prima di cancellare schede e dati all'uscita" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Waarschuwen dat tabbladen en gegevens worden gewist bij het afsluiten" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ostrzegaj, że karty i dane zostaną wyczyszczone przy wychodzeniu" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avisar-me que os separadores e os dados serão limpos ao sair" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Показывать предупреждение о сбросе вкладок и данных при выходе" + } + } + } + }, + "warn.before.quit.dialog.checkbox.message" : { + "comment" : "A label after checkbox to configure the warning before clearing data on the application termination.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Jedes Mal warnen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Warn me every time" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Advertirme cada vez" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Toujours me prévenir" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avvisa ogni volta" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Elke keer waarschuwen" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ostrzegaj za każdym razem" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avisar-me sempre" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Предупреждать каждый раз" + } + } + } + }, + "warn.before.quit.dialog.header" : { + "comment" : "A header of warning before clearing data on the application termination.", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tabs und Browserdaten löschen und DuckDuckGo beenden?" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Clear tabs and browsing data and quit DuckDuckGo?" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Borrar pestañas y datos de navegación y salir de DuckDuckGo?" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Effacer les onglets et les données de navigation et quitter DuckDuckGo ?" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancellare le schede e i dati di navigazione e uscire da DuckDuckGo?" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tabbladen en browsergegevens wissen en DuckDuckGo afsluiten?" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wyczyścić karty i dane przeglądania i wyjść z DuckDuckGo?" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Limpar separadores e dados de navegação e sair do DuckDuckGo?" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Очистить вкладки и данные и выйти из DuckDuckGo?" + } + } + } + }, "We couldn‘t find any bookmarks." : { "comment" : "Data import error message: Bookmarks weren‘t found.", "localizations" : { diff --git a/DuckDuckGo/LoginItems/LoginItemsManager.swift b/DuckDuckGo/LoginItems/LoginItemsManager.swift index e0a44a4fb4..076c75f2b8 100644 --- a/DuckDuckGo/LoginItems/LoginItemsManager.swift +++ b/DuckDuckGo/LoginItems/LoginItemsManager.swift @@ -19,10 +19,15 @@ import Common import Foundation import LoginItems +import PixelKit + +protocol LoginItemsManaging { + func throwingEnableLoginItems(_ items: Set, log: OSLog) throws +} /// Class to manage the login items for the VPN and DBP /// -final class LoginItemsManager { +final class LoginItemsManager: LoginItemsManaging { private enum Action: String { case enable case disable @@ -42,6 +47,20 @@ final class LoginItemsManager { } } + /// Throwing version of enableLoginItems + /// + func throwingEnableLoginItems(_ items: Set, log: OSLog) throws { + for item in items { + do { + try item.enable() + os_log("🟢 Enabled successfully %{public}@", log: log, String(describing: item)) + } catch let error as NSError { + handleError(for: item, action: .enable, error: error) + throw error + } + } + } + func restartLoginItems(_ items: Set, log: OSLog) { for item in items { do { @@ -66,17 +85,12 @@ final class LoginItemsManager { } private func handleError(for item: LoginItem, action: Action, error: NSError) { - let event = Pixel.Event.Debug.loginItemUpdateError( - loginItemBundleID: item.agentBundleID, - action: "enable", - buildType: AppVersion.shared.buildType, - osVersion: AppVersion.shared.osVersion - ) - DailyPixel.fire(pixel: .debug(event: event, error: error), frequency: .dailyAndCount) - - os_log("🔴 Could not enable %{public}@: %{public}@", - item.debugDescription, - error.debugDescription) + let event = GeneralPixel.loginItemUpdateError(loginItemBundleID: item.agentBundleID, + action: "enable", + buildType: AppVersion.shared.buildType, + osVersion: AppVersion.shared.osVersion) + PixelKit.fire(DebugEvent(event, error: error), frequency: .dailyAndCount) + os_log("🔴 Could not enable %{public}@: %{public}@", item.debugDescription, error.debugDescription) } // MARK: - Debug Interactions diff --git a/DuckDuckGo/MainWindow/MainViewController.swift b/DuckDuckGo/MainWindow/MainViewController.swift index 17c166e932..118116eaad 100644 --- a/DuckDuckGo/MainWindow/MainViewController.swift +++ b/DuckDuckGo/MainWindow/MainViewController.swift @@ -20,11 +20,8 @@ import Cocoa import Carbon.HIToolbox import Combine import Common - -#if NETWORK_PROTECTION import NetworkProtection import NetworkProtectionIPC -#endif final class MainViewController: NSViewController { private lazy var mainView = MainView(frame: NSRect(x: 0, y: 0, width: 600, height: 660)) @@ -35,6 +32,7 @@ final class MainViewController: NSViewController { let findInPageViewController: FindInPageViewController let fireViewController: FireViewController let bookmarksBarViewController: BookmarksBarViewController + private let bookmarksBarVisibilityManager: BookmarksBarVisibilityManager let tabCollectionViewModel: TabCollectionViewModel let isBurner: Bool @@ -63,8 +61,8 @@ final class MainViewController: NSViewController { self.isBurner = tabCollectionViewModel.isBurner tabBarViewController = TabBarViewController.create(tabCollectionViewModel: tabCollectionViewModel) + bookmarksBarVisibilityManager = BookmarksBarVisibilityManager(selectedTabPublisher: tabCollectionViewModel.$selectedTabViewModel.eraseToAnyPublisher()) -#if NETWORK_PROTECTION let networkProtectionPopoverManager: NetPPopoverManager = { #if DEBUG guard case .normal = NSApp.runType else { @@ -95,14 +93,12 @@ final class MainViewController: NSViewController { serverInfoObserver: ipcClient.ipcServerInfoObserver, connectionErrorObserver: ipcClient.ipcConnectionErrorObserver, connectivityIssuesObserver: connectivityIssuesObserver, - controllerErrorMessageObserver: controllerErrorMessageObserver + controllerErrorMessageObserver: controllerErrorMessageObserver, + dataVolumeObserver: ipcClient.ipcDataVolumeObserver ) }() navigationBarViewController = NavigationBarViewController.create(tabCollectionViewModel: tabCollectionViewModel, isBurner: isBurner, networkProtectionPopoverManager: networkProtectionPopoverManager, networkProtectionStatusReporter: networkProtectionStatusReporter, autofillPopoverPresenter: autofillPopoverPresenter) -#else - navigationBarViewController = NavigationBarViewController.create(tabCollectionViewModel: tabCollectionViewModel, isBurner: isBurner, autofillPopoverPresenter: AutofillPopoverPresenter) -#endif browserTabViewController = BrowserTabViewController(tabCollectionViewModel: tabCollectionViewModel, bookmarkManager: bookmarkManager) findInPageViewController = FindInPageViewController.create() @@ -131,7 +127,7 @@ final class MainViewController: NSViewController { listenToKeyDownEvents() subscribeToMouseTrackingArea() subscribeToSelectedTabViewModel() - subscribeToAppSettingsNotifications() + subscribeToBookmarkBarVisibility() subscribeToFirstResponder() mainView.findInPageContainerView.applyDropShadow() @@ -178,9 +174,6 @@ final class MainViewController: NSViewController { resizeNavigationBar(isHomePage: tabCollectionViewModel.selectedTabViewModel?.tab.content == .newtab, animated: false) - - let bookmarksBarVisible = AppearancePreferences.shared.showBookmarksBar - updateBookmarksBarViewVisibility(visible: bookmarksBarVisible) } updateDividerColor(isShowingHomePage: tabCollectionViewModel.selectedTabViewModel?.tab.content == .newtab) @@ -196,12 +189,8 @@ final class MainViewController: NSViewController { updateReloadMenuItem() updateStopMenuItem() browserTabViewController.windowDidBecomeKey() - presentWaitlistThankYouPromptIfNecessary() -#if NETWORK_PROTECTION - sendActiveNetworkProtectionWaitlistUserPixel() refreshNetworkProtectionMessages() -#endif #if DBP DataBrokerProtectionAppEvents().windowDidBecomeMain() @@ -228,13 +217,11 @@ final class MainViewController: NSViewController { } } -#if NETWORK_PROTECTION private let networkProtectionMessaging = DefaultNetworkProtectionRemoteMessaging() func refreshNetworkProtectionMessages() { networkProtectionMessaging.fetchRemoteMessages() } -#endif #if DBP private let dataBrokerProtectionMessaging = DefaultDataBrokerProtectionRemoteMessaging() @@ -316,21 +303,30 @@ final class MainViewController: NSViewController { } private func subscribeToTitleChange(of selectedTabViewModel: TabViewModel?) { - guard let window = self.view.window else { return } - selectedTabViewModel?.$title + guard let selectedTabViewModel else { return } + + // Only subscribe once the view is added to the window. + let windowPublisher = view.publisher(for: \.window).filter({ $0 != nil }).prefix(1).asVoid() + + windowPublisher + .combineLatest(selectedTabViewModel.$title) { $1 } .map { $0.truncated(length: MainMenu.Constants.maxTitleLength) } .receive(on: DispatchQueue.main) - .assign(to: \.title, onWeaklyHeld: window) + .sink { [weak self] title in + self?.view.window?.title = title + } .store(in: &tabViewModelCancellables) } - private func subscribeToAppSettingsNotifications() { - bookmarksBarVisibilityChangedCancellable = NotificationCenter.default - .publisher(for: AppearancePreferences.Notifications.showBookmarksBarSettingChanged) - .sink { [weak self] _ in - self?.updateBookmarksBarViewVisibility(visible: AppearancePreferences.shared.showBookmarksBar) + private func subscribeToBookmarkBarVisibility() { + bookmarksBarVisibilityChangedCancellable = bookmarksBarVisibilityManager + .$isBookmarksBarVisible + .removeDuplicates() + .receive(on: DispatchQueue.main) + .sink { [weak self] isBookmarksBarVisible in + self?.updateBookmarksBarViewVisibility(visible: isBookmarksBarVisible) } } @@ -347,7 +343,6 @@ final class MainViewController: NSViewController { defer { lastTabContent = content } resizeNavigationBar(isHomePage: content == .newtab, animated: content == .newtab && lastTabContent != .newtab) - updateBookmarksBar(content) adjustFirstResponder(selectedTabViewModel: selectedTabViewModel, tabContent: content) } .store(in: &self.tabViewModelCancellables) @@ -367,14 +362,6 @@ final class MainViewController: NSViewController { } } - private func updateBookmarksBar(_ content: Tab.TabContent, _ prefs: AppearancePreferences = AppearancePreferences.shared) { - if content.isUrl && prefs.bookmarksBarAppearance == .newTabOnly { - updateBookmarksBarViewVisibility(visible: false) - } else if prefs.showBookmarksBar { - updateBookmarksBarViewVisibility(visible: true) - } - } - private func subscribeToFindInPage(of selectedTabViewModel: TabViewModel?) { selectedTabViewModel?.findInPage? .$isVisible @@ -450,24 +437,6 @@ final class MainViewController: NSViewController { NSApp.mainMenuTyped.stopMenuItem.isEnabled = selectedTabViewModel.isLoading } -#if NETWORK_PROTECTION - private func sendActiveNetworkProtectionWaitlistUserPixel() { - if DefaultNetworkProtectionVisibility().waitlistIsOngoing { - DailyPixel.fire(pixel: .networkProtectionWaitlistUserActive, frequency: .dailyOnly) - } - } -#endif - - func presentWaitlistThankYouPromptIfNecessary() { - guard let window = self.view.window else { - assertionFailure("Couldn't get main view controller's window") - return - } - - let presenter = WaitlistThankYouPromptPresenter() - presenter.presentThankYouPromptIfNecessary(in: window) - } - // MARK: - First responder func adjustFirstResponder(selectedTabViewModel: TabViewModel? = nil, tabContent: Tab.TabContent? = nil, force: Bool = false) { diff --git a/DuckDuckGo/Menus/HistoryMenu.swift b/DuckDuckGo/Menus/HistoryMenu.swift index b99c7a867f..42fd97d990 100644 --- a/DuckDuckGo/Menus/HistoryMenu.swift +++ b/DuckDuckGo/Menus/HistoryMenu.swift @@ -53,7 +53,9 @@ final class HistoryMenu: NSMenu { reopenLastClosedMenuItem recentlyClosedMenuItem reopenAllWindowsFromLastSessionMenuItem - NSMenuItem.separator() + + clearAllHistorySeparator + clearAllHistoryMenuItem } reopenMenuItemKeyEquivalentManager.reopenLastClosedMenuItem = reopenLastClosedMenuItem diff --git a/DuckDuckGo/Menus/MainMenu.swift b/DuckDuckGo/Menus/MainMenu.swift index 2e6c0d2639..66e026dc1d 100644 --- a/DuckDuckGo/Menus/MainMenu.swift +++ b/DuckDuckGo/Menus/MainMenu.swift @@ -24,15 +24,9 @@ import OSLog // swiftlint:disable:this enforce_os_log_wrapper import SwiftUI import WebKit import Configuration - -#if NETWORK_PROTECTION import NetworkProtection -#endif - -#if SUBSCRIPTION import Subscription import SubscriptionUI -#endif // swiftlint:disable:next type_body_length @MainActor final class MainMenu: NSMenu { @@ -72,7 +66,7 @@ import SubscriptionUI var forwardMenuItem: NSMenuItem { historyMenu.forwardMenuItem } // MARK: Bookmarks - let manageBookmarksMenuItem = NSMenuItem(title: UserText.mainMenuHistoryManageBookmarks, action: #selector(MainViewController.showManageBookmarks)) + let manageBookmarksMenuItem = NSMenuItem(title: UserText.mainMenuHistoryManageBookmarks, action: #selector(MainViewController.showManageBookmarks)).withAccessibilityIdentifier("MainMenu.manageBookmarksMenuItem") var bookmarksMenuToggleBookmarksBarMenuItem = NSMenuItem(title: "BookmarksBarMenuPlaceholder", action: #selector(MainViewController.toggleBookmarksBarFromMenu), keyEquivalent: "B") let importBookmarksMenuItem = NSMenuItem(title: UserText.importBookmarks, action: #selector(AppDelegate.openImportBrowserDataWindow)) let bookmarksMenu = NSMenu(title: UserText.bookmarks) @@ -85,9 +79,7 @@ import SubscriptionUI let toggleBookmarksShortcutMenuItem = NSMenuItem(title: UserText.mainMenuViewShowBookmarksShortcut, action: #selector(MainViewController.toggleBookmarksShortcut), keyEquivalent: "K") let toggleDownloadsShortcutMenuItem = NSMenuItem(title: UserText.mainMenuViewShowDownloadsShortcut, action: #selector(MainViewController.toggleDownloadsShortcut), keyEquivalent: "J") -#if NETWORK_PROTECTION let toggleNetworkProtectionShortcutMenuItem = NSMenuItem(title: UserText.showNetworkProtectionShortcut, action: #selector(MainViewController.toggleNetworkProtectionShortcut), keyEquivalent: "N") -#endif // MARK: Window let windowsMenu = NSMenu(title: UserText.mainMenuWindow) @@ -270,9 +262,7 @@ import SubscriptionUI toggleBookmarksShortcutMenuItem toggleDownloadsShortcutMenuItem -#if NETWORK_PROTECTION toggleNetworkProtectionShortcutMenuItem -#endif NSMenuItem.separator() @@ -301,6 +291,7 @@ import SubscriptionUI func buildBookmarksMenu() -> NSMenuItem { NSMenuItem(title: UserText.bookmarks).submenu(bookmarksMenu.buildItems { NSMenuItem(title: UserText.bookmarkThisPage, action: #selector(MainViewController.bookmarkThisPage), keyEquivalent: "d") + NSMenuItem(title: UserText.bookmarkAllTabs, action: #selector(MainViewController.bookmarkAllOpenTabs), keyEquivalent: [.command, .shift, "d"]) manageBookmarksMenuItem bookmarksMenuToggleBookmarksBarMenuItem NSMenuItem.separator() @@ -313,6 +304,7 @@ import SubscriptionUI .submenu(favoritesMenu.buildItems { NSMenuItem(title: UserText.mainMenuHistoryFavoriteThisPage, action: #selector(MainViewController.favoriteThisPage)) .withImage(.favorite) + .withAccessibilityIdentifier("MainMenu.favoriteThisPage") NSMenuItem.separator() }) .withImage(.favorite) @@ -328,6 +320,7 @@ import SubscriptionUI NSMenuItem(title: UserText.zoom, action: #selector(NSWindow.performZoom)) NSMenuItem.separator() + NSMenuItem(title: UserText.duplicateTab, action: #selector(MainViewController.duplicateTab)) NSMenuItem(title: UserText.pinTab, action: #selector(MainViewController.pinOrUnpinTab)) NSMenuItem(title: UserText.moveTabToNewWindow, action: #selector(MainViewController.moveTabToNewWindow)) NSMenuItem(title: UserText.mainMenuWindowMergeAllWindows, action: #selector(NSWindow.mergeAllWindows)) @@ -398,10 +391,8 @@ import SubscriptionUI override func update() { super.update() -#if NETWORK_PROTECTION // To be safe, hide the NetP shortcut menu item by default. toggleNetworkProtectionShortcutMenuItem.isHidden = true -#endif updateHomeButtonMenuItem() updateBookmarksBarMenuItem() @@ -549,14 +540,12 @@ import SubscriptionUI toggleBookmarksShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .bookmarks) toggleDownloadsShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .downloads) -#if NETWORK_PROTECTION if DefaultNetworkProtectionVisibility().isVPNVisible() { toggleNetworkProtectionShortcutMenuItem.isHidden = false toggleNetworkProtectionShortcutMenuItem.title = LocalPinningManager.shared.shortcutTitle(for: .networkProtection) } else { toggleNetworkProtectionShortcutMenuItem.isHidden = true } -#endif } } @@ -567,8 +556,16 @@ import SubscriptionUI // swiftlint:disable:next function_body_length private func setupDebugMenu() -> NSMenu { let debugMenu = NSMenu(title: "Debug") { - NSMenuItem(title: "Open Vanilla Browser", action: #selector(MainViewController.openVanillaBrowser)) + NSMenuItem(title: "Open Vanilla Browser", action: #selector(MainViewController.openVanillaBrowser)).withAccessibilityIdentifier("MainMenu.openVanillaBrowser") NSMenuItem.separator() + NSMenuItem(title: "Tab") { + NSMenuItem(title: "Append Tabs") { + NSMenuItem(title: "10 Tabs", action: #selector(MainViewController.addDebugTabs(_:)), representedObject: 10) + NSMenuItem(title: "50 Tabs", action: #selector(MainViewController.addDebugTabs(_:)), representedObject: 50) + NSMenuItem(title: "100 Tabs", action: #selector(MainViewController.addDebugTabs(_:)), representedObject: 100) + NSMenuItem(title: "150 Tabs", action: #selector(MainViewController.addDebugTabs(_:)), representedObject: 150) + } + } NSMenuItem(title: "Reset Data") { NSMenuItem(title: "Reset Default Browser Prompt", action: #selector(MainViewController.resetDefaultBrowserPrompt)) NSMenuItem(title: "Reset Default Grammar Checks", action: #selector(MainViewController.resetDefaultGrammarChecks)) @@ -577,17 +574,16 @@ import SubscriptionUI NSMenuItem(title: "Reset Pinned Tabs", action: #selector(MainViewController.resetPinnedTabs)) NSMenuItem(title: "Reset YouTube Overlay Interactions", action: #selector(MainViewController.resetDuckPlayerOverlayInteractions)) NSMenuItem(title: "Reset MakeDuckDuckYours user settings", action: #selector(MainViewController.resetMakeDuckDuckGoYoursUserSettings)) - NSMenuItem(title: "Survey 10% on", action: #selector(MainViewController.in10PercentSurveyOn)) - NSMenuItem(title: "Survey 10% off", action: #selector(MainViewController.in10PercentSurveyOff)) + NSMenuItem(title: "Permanent Survey share on", action: #selector(MainViewController.inPermanentSurveyShareOn(_:))) + NSMenuItem(title: "Permanent Survey share off", action: #selector(MainViewController.inPermanentSurveyShareOff(_:))) NSMenuItem(title: "Change Activation Date") { NSMenuItem(title: "Today", action: #selector(MainViewController.changeInstallDateToToday), keyEquivalent: "N") - NSMenuItem(title: "Less Than a 1 days Ago", action: #selector(MainViewController.changeInstallDateToLessThan1DayAgo(_:))) - NSMenuItem(title: "More Than 1 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan1DayAgoButLessThan14(_:))) - NSMenuItem(title: "More Than 14 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan14DaysAgoButLessThan15(_:))) - NSMenuItem(title: "More Than 15 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan15DaysAgo(_:))) + NSMenuItem(title: "Less Than a 5 days Ago", action: #selector(MainViewController.changeInstallDateToLessThan5DayAgo(_:))) + NSMenuItem(title: "More Than 5 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan5DayAgoButLessThan9(_:))) + NSMenuItem(title: "More Than 9 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan9DaysAgo(_:))) } NSMenuItem(title: "Reset Email Protection InContext Signup Prompt", action: #selector(MainViewController.resetEmailProtectionInContextPrompt)) - NSMenuItem(title: "Reset Daily Pixels", action: #selector(MainViewController.resetDailyPixels)) + NSMenuItem(title: "Reset Pixels Storage", action: #selector(MainViewController.resetDailyPixels)) }.withAccessibilityIdentifier("MainMenu.resetData") NSMenuItem(title: "UI Triggers") { NSMenuItem(title: "Show Save Credentials Popover", action: #selector(MainViewController.showSaveCredentialsPopover)) @@ -616,16 +612,13 @@ import SubscriptionUI .submenu(DataBrokerProtectionDebugMenu()) #endif -#if NETWORK_PROTECTION if case .normal = NSApp.runType { NSMenuItem(title: "VPN") .submenu(NetworkProtectionDebugMenu()) } -#endif NSMenuItem(title: "Trigger Fatal Error", action: #selector(MainViewController.triggerFatalError)) -#if SUBSCRIPTION let currentEnvironmentWrapper = UserDefaultsWrapper(key: .subscriptionEnvironment, defaultValue: SubscriptionPurchaseEnvironment.ServiceEnvironment.default) let isInternalTestingWrapper = UserDefaultsWrapper(key: .subscriptionInternalTesting, defaultValue: false) @@ -644,7 +637,6 @@ import SubscriptionUI }, subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs) ) -#endif NSMenuItem(title: "Logging").submenu(setupLoggingMenu()) } diff --git a/DuckDuckGo/Menus/MainMenuActions.swift b/DuckDuckGo/Menus/MainMenuActions.swift index 51141f5da2..eca7f8004d 100644 --- a/DuckDuckGo/Menus/MainMenuActions.swift +++ b/DuckDuckGo/Menus/MainMenuActions.swift @@ -215,7 +215,7 @@ extension AppDelegate { savePanel.beginSheetModal(for: window) { response in guard response == .OK, let selectedURL = savePanel.url else { return } - let vault = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) + let vault = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) let exporter = CSVLoginExporter(secureVault: vault!) do { try exporter.exportVaultLogins(to: selectedURL) @@ -392,7 +392,7 @@ extension MainViewController { } navigationBarViewController.view.window?.makeKeyAndOrderFront(nil) } - navigationBarViewController.toggleDownloadsPopover(keepButtonVisible: false) + navigationBarViewController.toggleDownloadsPopover(keepButtonVisible: sender is NSMenuItem /* keep button visible for some time on Cmd+J */) } @objc func toggleBookmarksBarFromMenu(_ sender: Any) { @@ -422,9 +422,7 @@ extension MainViewController { } @objc func toggleNetworkProtectionShortcut(_ sender: Any) { -#if NETWORK_PROTECTION LocalPinningManager.shared.togglePinning(for: .networkProtection) -#endif } // MARK: - History @@ -509,6 +507,11 @@ extension MainViewController { .openBookmarkPopover(setFavorite: false, accessPoint: .init(sender: sender, default: .moreMenu)) } + @objc func bookmarkAllOpenTabs(_ sender: Any) { + let websitesInfo = tabCollectionViewModel.tabs.compactMap(WebsiteInfo.init) + BookmarksDialogViewFactory.makeBookmarkAllOpenTabsView(websitesInfo: websitesInfo).show() + } + @objc func favoriteThisPage(_ sender: Any) { guard let tabIndex = getActiveTabAndIndex()?.index else { return } if tabCollectionViewModel.selectedTabIndex != tabIndex { @@ -603,6 +606,12 @@ extension MainViewController { WindowsManager.openNewWindow(with: tab) } + @objc func duplicateTab(_ sender: Any?) { + guard let (_, index) = getActiveTabAndIndex() else { return } + + tabCollectionViewModel.duplicateTab(at: index) + } + @objc func pinOrUnpinTab(_ sender: Any?) { guard let (_, selectedTabIndex) = getActiveTabAndIndex() else { return } @@ -652,6 +661,14 @@ extension MainViewController { // MARK: - Debug + @objc func addDebugTabs(_ sender: AnyObject) { + let numberOfTabs = sender.representedObject as? Int ?? 1 + (1...numberOfTabs).forEach { _ in + let tab = Tab(content: .url(.duckDuckGo, credential: nil, source: .ui)) + tabCollectionViewModel.append(tab: tab) + } + } + @objc func resetDefaultBrowserPrompt(_ sender: Any?) { UserDefaultsWrapper.clear(.defaultBrowserDismissed) } @@ -666,7 +683,7 @@ extension MainViewController { } @objc func resetSecureVaultData(_ sender: Any?) { - let vault = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) + let vault = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) let accounts = (try? vault?.accounts()) ?? [] for accountID in accounts.compactMap(\.id) { @@ -715,9 +732,7 @@ extension MainViewController { UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowImport.rawValue) UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowDuckPlayer.rawValue) UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowEmailProtection.rawValue) - UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0.rawValue) - UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14.rawValue) - UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue) + UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowPermanentSurvey.rawValue) } @objc func internalUserState(_ sender: Any?) { @@ -742,47 +757,40 @@ extension MainViewController { UserDefaults.netP.networkProtectionEntitlementsExpired = false // Clear pixel data - DailyPixel.clearLastFireDate(pixel: .privacyProFeatureEnabled) - Pixel.shared?.clearRepetitions(for: .privacyProBetaUserThankYouDBP) - Pixel.shared?.clearRepetitions(for: .privacyProBetaUserThankYouVPN) + PixelKit.shared?.clearFrequencyHistoryFor(pixel: PrivacyProPixel.privacyProFeatureEnabled) + PixelKit.shared?.clearFrequencyHistoryFor(pixel: PrivacyProPixel.privacyProBetaUserThankYouDBP) + PixelKit.shared?.clearFrequencyHistoryFor(pixel: PrivacyProPixel.privacyProBetaUserThankYouVPN) } @objc func resetDailyPixels(_ sender: Any?) { - UserDefaults.standard.removePersistentDomain(forName: DailyPixel.Constant.dailyPixelStorageIdentifier) + PixelKit.shared?.clearFrequencyHistoryForAllPixels() } - @objc func in10PercentSurveyOn(_ sender: Any?) { - UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14in10Percent.rawValue) - UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0in10Percent.rawValue) + @objc func inPermanentSurveyShareOn(_ sender: Any?) { + UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageUserInSurveyShare.rawValue) } - @objc func in10PercentSurveyOff(_ sender: Any?) { - UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14in10Percent.rawValue) - UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0in10Percent.rawValue) + @objc func inPermanentSurveyShareOff(_ sender: Any?) { + UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInSurveyShare.rawValue) } @objc func changeInstallDateToToday(_ sender: Any?) { UserDefaults.standard.set(Date(), forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) } - @objc func changeInstallDateToLessThan1DayAgo(_ sender: Any?) { - let lessThanOneDaysAgo = Calendar.current.date(byAdding: .hour, value: -23, to: Date()) - UserDefaults.standard.set(lessThanOneDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) - } - - @objc func changeInstallDateToMoreThan1DayAgoButLessThan14(_ sender: Any?) { - let between1And4DaysAgo = Calendar.current.date(byAdding: .day, value: -13, to: Date()) - UserDefaults.standard.set(between1And4DaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) + @objc func changeInstallDateToLessThan5DayAgo(_ sender: Any?) { + let lessThanFiveDaysAgo = Calendar.current.date(byAdding: .day, value: -4, to: Date()) + UserDefaults.standard.set(lessThanFiveDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) } - @objc func changeInstallDateToMoreThan14DaysAgoButLessThan15(_ sender: Any?) { - let twentyEightDaysAgo = Calendar.current.date(byAdding: .day, value: -14, to: Date()) - UserDefaults.standard.set(twentyEightDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) + @objc func changeInstallDateToMoreThan5DayAgoButLessThan9(_ sender: Any?) { + let between5And9DaysAgo = Calendar.current.date(byAdding: .day, value: -5, to: Date()) + UserDefaults.standard.set(between5And9DaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) } - @objc func changeInstallDateToMoreThan15DaysAgo(_ sender: Any?) { - let twentyEightDaysAgo = Calendar.current.date(byAdding: .day, value: -16, to: Date()) - UserDefaults.standard.set(twentyEightDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) + @objc func changeInstallDateToMoreThan9DaysAgo(_ sender: Any?) { + let nineDaysAgo = Calendar.current.date(byAdding: .day, value: -9, to: Date()) + UserDefaults.standard.set(nineDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) } @objc func showSaveCredentialsPopover(_ sender: Any?) { @@ -930,8 +938,8 @@ extension MainViewController: NSMenuItemValidation { case #selector(findInPage), #selector(findInPageNext), #selector(findInPagePrevious): - return activeTabViewModel?.canReload == true // must have content loaded - && view.window?.isKeyWindow == true // disable in full screen + return activeTabViewModel?.canFindInPage == true // must have content loaded + && view.window?.isKeyWindow == true // disable in video full screen case #selector(findInPageDone): return getActiveTabAndIndex()?.tab.findInPage?.isActive == true @@ -949,6 +957,8 @@ extension MainViewController: NSMenuItemValidation { case #selector(MainViewController.bookmarkThisPage(_:)), #selector(MainViewController.favoriteThisPage(_:)): return activeTabViewModel?.canBeBookmarked == true + case #selector(MainViewController.bookmarkAllOpenTabs(_:)): + return tabCollectionViewModel.canBookmarkAllOpenTabs() case #selector(MainViewController.openBookmark(_:)), #selector(MainViewController.showManageBookmarks(_:)): return true @@ -1047,7 +1057,7 @@ extension AppDelegate: NSMenuItemValidation { } private var areTherePasswords: Bool { - let vault = try? AutofillSecureVaultFactory.makeVault(errorReporter: SecureVaultErrorReporter.shared) + let vault = try? AutofillSecureVaultFactory.makeVault(reporter: SecureVaultReporter.shared) guard let vault else { return false } diff --git a/DuckDuckGo/NavigationBar/PinningManager.swift b/DuckDuckGo/NavigationBar/PinningManager.swift index d2cc6ef6bb..37eceb098c 100644 --- a/DuckDuckGo/NavigationBar/PinningManager.swift +++ b/DuckDuckGo/NavigationBar/PinningManager.swift @@ -17,20 +17,14 @@ // import Foundation - -#if NETWORK_PROTECTION import NetworkProtection -#endif enum PinnableView: String { case autofill case bookmarks case downloads case homeButton - -#if NETWORK_PROTECTION case networkProtection -#endif } protocol PinningManager { @@ -45,11 +39,7 @@ protocol PinningManager { final class LocalPinningManager: PinningManager { -#if NETWORK_PROTECTION static let shared = LocalPinningManager(networkProtectionFeatureActivation: NetworkProtectionKeychainTokenStore()) -#else - static let shared = LocalPinningManager() -#endif static let pinnedViewChangedNotificationViewTypeKey = "pinning.pinnedViewChanged.viewType" @@ -59,13 +49,11 @@ final class LocalPinningManager: PinningManager { @UserDefaultsWrapper(key: .manuallyToggledPinnedViews, defaultValue: []) private var manuallyToggledPinnedViewsStrings: [String] -#if NETWORK_PROTECTION private let networkProtectionFeatureActivation: NetworkProtectionFeatureActivation init(networkProtectionFeatureActivation: NetworkProtectionFeatureActivation) { self.networkProtectionFeatureActivation = networkProtectionFeatureActivation } -#endif func togglePinning(for view: PinnableView) { flagAsManuallyToggled(view) @@ -122,10 +110,8 @@ final class LocalPinningManager: PinningManager { case .bookmarks: return isPinned(.bookmarks) ? UserText.hideBookmarksShortcut : UserText.showBookmarksShortcut case .downloads: return isPinned(.downloads) ? UserText.hideDownloadsShortcut : UserText.showDownloadsShortcut case .homeButton: return "" -#if NETWORK_PROTECTION case .networkProtection: return isPinned(.networkProtection) ? UserText.hideNetworkProtectionShortcut : UserText.showNetworkProtectionShortcut -#endif } } diff --git a/DuckDuckGo/NavigationBar/View/AddressBarButtonsViewController.swift b/DuckDuckGo/NavigationBar/View/AddressBarButtonsViewController.swift index f4f0248735..975217aa58 100644 --- a/DuckDuckGo/NavigationBar/View/AddressBarButtonsViewController.swift +++ b/DuckDuckGo/NavigationBar/View/AddressBarButtonsViewController.swift @@ -52,6 +52,7 @@ final class AddressBarButtonsViewController: NSViewController { return permissionAuthorizationPopover ?? { let popover = PermissionAuthorizationPopover() self.permissionAuthorizationPopover = popover + popover.setAccessibilityIdentifier("AddressBarButtonsViewController.permissionAuthorizationPopover") return popover }() } @@ -282,13 +283,13 @@ final class AddressBarButtonsViewController: NSViewController { private func updateBookmarkButtonVisibility() { guard view.window?.isPopUpWindow == false else { return } - bookmarkButton.setAccessibilityIdentifier("Bookmarks Button") + bookmarkButton.setAccessibilityIdentifier("AddressBarButtonsViewController.bookmarkButton") let hasEmptyAddressBar = textFieldValue?.isEmpty ?? true - var showBookmarkButton: Bool { + var shouldShowBookmarkButton: Bool { guard let tabViewModel, tabViewModel.canBeBookmarked else { return false } var isUrlBookmarked = false - if let url = tabViewModel.tab.content.url, + if let url = tabViewModel.tab.content.userEditableUrl, bookmarkManager.isUrlBookmarked(url: url) { isUrlBookmarked = true } @@ -296,7 +297,7 @@ final class AddressBarButtonsViewController: NSViewController { return clearButton.isHidden && !hasEmptyAddressBar && (isMouseOverNavigationBar || bookmarkPopover?.isShown == true || isUrlBookmarked) } - bookmarkButton.isHidden = !showBookmarkButton + bookmarkButton.isShown = shouldShowBookmarkButton } private func updateZoomButtonVisibility() { @@ -324,7 +325,7 @@ final class AddressBarButtonsViewController: NSViewController { zoomButton.isHidden = !shouldShowZoom } - func openBookmarkPopover(setFavorite: Bool, accessPoint: Pixel.Event.AccessPoint) { + func openBookmarkPopover(setFavorite: Bool, accessPoint: GeneralPixel.AccessPoint) { let result = bookmarkForCurrentUrl(setFavorite: setFavorite, accessPoint: accessPoint) guard let bookmark = result.bookmark else { assertionFailure("Failed to get a bookmark for the popover") @@ -333,7 +334,7 @@ final class AddressBarButtonsViewController: NSViewController { let bookmarkPopover = bookmarkPopoverCreatingIfNeeded() if !bookmarkPopover.isShown { - bookmarkButton.isHidden = false + bookmarkButton.isShown = true bookmarkPopover.isNew = result.isNew bookmarkPopover.bookmark = bookmark bookmarkPopover.show(positionedBelow: bookmarkButton) @@ -353,7 +354,7 @@ final class AddressBarButtonsViewController: NSViewController { }() if query.permissions.contains(.camera) - || (query.permissions.contains(.microphone) && microphoneButton.isHidden && !cameraButton.isHidden) { + || (query.permissions.contains(.microphone) && microphoneButton.isHidden && cameraButton.isShown) { button = cameraButton } else { assert(query.permissions.count == 1) @@ -376,9 +377,7 @@ final class AddressBarButtonsViewController: NSViewController { return } } - guard !button.isHidden, - !permissionButtons.isHidden - else { return } + guard button.isShown, permissionButtons.isShown else { return } (popover.contentViewController as? PermissionAuthorizationViewController)?.query = query popover.show(relativeTo: button.bounds, of: button, preferredEdge: .maxY) @@ -423,7 +422,7 @@ final class AddressBarButtonsViewController: NSViewController { func updateButtons() { stopAnimationsAfterFocus() - clearButton.isHidden = !(isTextFieldEditorFirstResponder && !(textFieldValue?.isEmpty ?? true)) + clearButton.isShown = isTextFieldEditorFirstResponder && !textFieldValue.isEmpty updatePrivacyEntryPointButton() updateImageButton() @@ -458,7 +457,7 @@ final class AddressBarButtonsViewController: NSViewController { permissions.microphone = tabViewModel.usedPermissions.microphone } - let url = tabViewModel.tab.content.url ?? .empty + let url = tabViewModel.tab.content.urlForWebView ?? .empty let domain = url.isFileURL ? .localhost : (url.host ?? "") PermissionContextMenu(permissions: permissions.map { ($0, $1) }, domain: domain, delegate: self) @@ -477,7 +476,7 @@ final class AddressBarButtonsViewController: NSViewController { return } - let url = tabViewModel.tab.content.url ?? .empty + let url = tabViewModel.tab.content.urlForWebView ?? .empty let domain = url.isFileURL ? .localhost : (url.host ?? "") PermissionContextMenu(permissions: [(.microphone, state)], domain: domain, delegate: self) @@ -496,7 +495,7 @@ final class AddressBarButtonsViewController: NSViewController { return } - let url = tabViewModel.tab.content.url ?? .empty + let url = tabViewModel.tab.content.urlForWebView ?? .empty let domain = url.isFileURL ? .localhost : (url.host ?? "") PermissionContextMenu(permissions: [(.geolocation, state)], domain: domain, delegate: self) @@ -520,7 +519,7 @@ final class AddressBarButtonsViewController: NSViewController { $0.append( (.popups, .requested($1)) ) } } else { - let url = tabViewModel.tab.content.url ?? .empty + let url = tabViewModel.tab.content.urlForWebView ?? .empty domain = url.isFileURL ? .localhost : (url.host ?? "") permissions = [(.popups, state)] } @@ -544,7 +543,7 @@ final class AddressBarButtonsViewController: NSViewController { } permissions = [(permissionType, state)] - let url = tabViewModel.tab.content.url ?? .empty + let url = tabViewModel.tab.content.urlForWebView ?? .empty let domain = url.isFileURL ? .localhost : (url.host ?? "") PermissionContextMenu(permissions: permissions, domain: domain, delegate: self) @@ -600,7 +599,13 @@ final class AddressBarButtonsViewController: NSViewController { } private func setupAnimationViews() { - func addAndLayoutAnimationViewIfNeeded(animationView: LottieAnimationView?, animationName: String, renderingEngine: Lottie.RenderingEngineOption = .automatic) -> LottieAnimationView { + + func addAndLayoutAnimationViewIfNeeded(animationView: LottieAnimationView?, + animationName: String, + // Default use of .mainThread to prevent high WindowServer Usage + // Pending Fix with newer Lottie versions + // https://app.asana.com/0/1177771139624306/1207024603216659/f + renderingEngine: Lottie.RenderingEngineOption = .mainThread) -> LottieAnimationView { if let animationView = animationView, animationView.identifier?.rawValue == animationName { return animationView } @@ -730,15 +735,15 @@ final class AddressBarButtonsViewController: NSViewController { } private func updatePermissionButtons() { - permissionButtons.isHidden = isTextFieldEditorFirstResponder - || isAnyTrackerAnimationPlaying - || (tabViewModel?.isShowingErrorPage ?? true) + guard let tabViewModel else { return } + + permissionButtons.isShown = !isTextFieldEditorFirstResponder + && !isAnyTrackerAnimationPlaying + && !tabViewModel.isShowingErrorPage defer { showOrHidePermissionPopoverIfNeeded() } - guard let tabViewModel else { return } - geolocationButton.buttonState = tabViewModel.usedPermissions.geolocation let (camera, microphone) = PermissionState?.combineCamera(tabViewModel.usedPermissions.camera, @@ -773,16 +778,19 @@ final class AddressBarButtonsViewController: NSViewController { } private func updateBookmarkButtonImage(isUrlBookmarked: Bool = false) { - if let url = tabViewModel?.tab.content.url, - isUrlBookmarked || bookmarkManager.isUrlBookmarked(url: url) { + if let url = tabViewModel?.tab.content.userEditableUrl, + isUrlBookmarked || bookmarkManager.isUrlBookmarked(url: url) + { bookmarkButton.image = .bookmarkFilled bookmarkButton.mouseOverTintColor = NSColor.bookmarkFilledTint bookmarkButton.toolTip = UserText.editBookmarkTooltip + bookmarkButton.setAccessibilityValue("Bookmarked") } else { bookmarkButton.mouseOverTintColor = nil bookmarkButton.image = .bookmark bookmarkButton.contentTintColor = nil bookmarkButton.toolTip = UserText.addBookmarkTooltip + bookmarkButton.setAccessibilityValue("Unbookmarked") } } @@ -807,22 +815,25 @@ final class AddressBarButtonsViewController: NSViewController { private func updatePrivacyEntryPointButton() { guard let tabViewModel else { return } - let urlScheme = tabViewModel.tab.content.url?.scheme - let isHypertextUrl = urlScheme == "http" || urlScheme == "https" + let url = tabViewModel.tab.content.userEditableUrl + let isNewTabOrOnboarding = [.newtab, .onboarding].contains(tabViewModel.tab.content) + let isHypertextUrl = url?.navigationalScheme?.isHypertextScheme == true && url?.isDuckPlayer == false let isEditingMode = controllerMode?.isEditing ?? false let isTextFieldValueText = textFieldValue?.isText ?? false - let isLocalUrl = tabViewModel.tab.content.url?.isLocalURL ?? false + let isLocalUrl = url?.isLocalURL ?? false // Privacy entry point button - privacyEntryPointButton.isHidden = isEditingMode - || isTextFieldEditorFirstResponder - || !isHypertextUrl - || tabViewModel.isShowingErrorPage - || isTextFieldValueText - || isLocalUrl - imageButtonWrapper.isHidden = view.window?.isPopUpWindow == true - || !privacyEntryPointButton.isHidden - || isAnyTrackerAnimationPlaying + privacyEntryPointButton.isShown = !isEditingMode + && !isTextFieldEditorFirstResponder + && isHypertextUrl + && !tabViewModel.isShowingErrorPage + && !isTextFieldValueText + && !isLocalUrl + + imageButtonWrapper.isShown = view.window?.isPopUpWindow != true + && (isHypertextUrl || isTextFieldEditorFirstResponder || isEditingMode || isNewTabOrOnboarding) + && privacyEntryPointButton.isHidden + && !isAnyTrackerAnimationPlaying } private func updatePrivacyEntryPointIcon() { @@ -833,15 +844,16 @@ final class AddressBarButtonsViewController: NSViewController { guard !isAnyShieldAnimationPlaying else { return } switch tabViewModel.tab.content { - case .url(let url, _, _): + case .url(let url, _, _), .identityTheftRestoration(let url), .subscription(let url): guard let host = url.host else { break } let isNotSecure = url.scheme == URL.NavigationalScheme.http.rawValue + let isCertificateValid = tabViewModel.tab.isCertificateValid ?? true let configuration = ContentBlocking.shared.privacyConfigurationManager.privacyConfig let isUnprotected = configuration.isUserUnprotected(domain: host) - let isShieldDotVisible = isNotSecure || isUnprotected + let isShieldDotVisible = isNotSecure || isUnprotected || !isCertificateValid privacyEntryPointButton.image = isShieldDotVisible ? .shieldDot : .shield @@ -860,8 +872,7 @@ final class AddressBarButtonsViewController: NSViewController { let trackerAnimationImageProvider = TrackerAnimationImageProvider() private func animateTrackers() { - guard !privacyEntryPointButton.isHidden, - let tabViewModel else { return } + guard privacyEntryPointButton.isShown, let tabViewModel else { return } switch tabViewModel.tab.content { case .url(let url, _, _): @@ -871,7 +882,7 @@ final class AddressBarButtonsViewController: NSViewController { } var animationView: LottieAnimationView - if url.scheme == "http" { + if url.navigationalScheme == .http { animationView = shieldDotAnimationView } else { animationView = shieldAnimationView @@ -915,7 +926,7 @@ final class AddressBarButtonsViewController: NSViewController { shieldAnimations: Bool = true, badgeAnimations: Bool = true) { func stopAnimation(_ animationView: LottieAnimationView) { - if animationView.isAnimationPlaying || !animationView.isHidden { + if animationView.isAnimationPlaying || animationView.isShown { animationView.isHidden = true animationView.stop() } @@ -957,9 +968,9 @@ final class AddressBarButtonsViewController: NSViewController { } } - private func bookmarkForCurrentUrl(setFavorite: Bool, accessPoint: Pixel.Event.AccessPoint) -> (bookmark: Bookmark?, isNew: Bool) { + private func bookmarkForCurrentUrl(setFavorite: Bool, accessPoint: GeneralPixel.AccessPoint) -> (bookmark: Bookmark?, isNew: Bool) { guard let tabViewModel, - let url = tabViewModel.tab.content.url else { + let url = tabViewModel.tab.content.userEditableUrl else { assertionFailure("No URL for bookmarking") return (nil, false) } diff --git a/DuckDuckGo/NavigationBar/View/AddressBarTextField.swift b/DuckDuckGo/NavigationBar/View/AddressBarTextField.swift index 84fbb30576..25cc50a039 100644 --- a/DuckDuckGo/NavigationBar/View/AddressBarTextField.swift +++ b/DuckDuckGo/NavigationBar/View/AddressBarTextField.swift @@ -22,6 +22,7 @@ import Combine import Common import Suggestions import Subscription +import BrowserServicesKit final class AddressBarTextField: NSTextField { @@ -233,7 +234,7 @@ final class AddressBarTextField: NSTextField { case .suggestion(let suggestionViewModel): let suggestion = suggestionViewModel.suggestion switch suggestion { - case .website, .bookmark, .historyEntry: + case .website, .bookmark, .historyEntry, .internalPage: restoreValue(Value(stringValue: suggestionViewModel.autocompletionString, userTyped: true)) case .phrase(phrase: let phase): restoreValue(Value.text(phase, userTyped: false)) @@ -259,7 +260,7 @@ final class AddressBarTextField: NSTextField { switch self.value { case .suggestion(let suggestionViewModel): switch suggestionViewModel.suggestion { - case .phrase, .website, .bookmark, .historyEntry: return false + case .phrase, .website, .bookmark, .historyEntry, .internalPage: return false case .unknown: return true } case .text(_, userTyped: true), .url(_, _, userTyped: true): return false @@ -275,7 +276,7 @@ final class AddressBarTextField: NSTextField { guard let selectedTabViewModel = selectedTabViewModel ?? tabCollectionViewModel.selectedTabViewModel else { return } let addressBarString = addressBarString ?? selectedTabViewModel.addressBarString - let isSearch = selectedTabViewModel.tab.content.url?.isDuckDuckGoSearch ?? false + let isSearch = selectedTabViewModel.tab.content.userEditableUrl?.isDuckDuckGoSearch ?? false self.value = Value(stringValue: addressBarString, userTyped: false, isSearch: isSearch) clearUndoManager() } @@ -332,9 +333,10 @@ final class AddressBarTextField: NSTextField { } #if APPSTORE - if providedUrl.isFileURL, let window = self.window { - let alert = NSAlert.cannotOpenFileAlert() - alert.beginSheetModal(for: window) { response in + if providedUrl.isFileURL, !providedUrl.isWritableLocation(), // is sandbox extension available for the file? + let window = self.window { + + NSAlert.cannotOpenFileAlert().beginSheetModal(for: window) { response in switch response { case .alertSecondButtonReturn: WindowControllersManager.shared.show(url: URL.ddgLearnMore, source: .ui, newTab: false) @@ -344,10 +346,10 @@ final class AddressBarTextField: NSTextField { return } } + return } #endif -#if SUBSCRIPTION if DefaultSubscriptionFeatureAvailability().isFeatureAvailable { if providedUrl.isChild(of: URL.subscriptionBaseURL) || providedUrl.isChild(of: URL.identityTheftRestoration) { self.updateValue(selectedTabViewModel: nil, addressBarString: nil) // reset @@ -355,7 +357,6 @@ final class AddressBarTextField: NSTextField { return } } -#endif self.window?.makeFirstResponder(nil) selectedTabViewModel.tab.setUrl(providedUrl, source: .userEntered(userEnteredValue, downloadRequested: downloadRequested)) @@ -418,7 +419,8 @@ final class AddressBarTextField: NSTextField { switch suggestion { case .bookmark(title: _, url: let url, isFavorite: _, allowedInTopHits: _), .historyEntry(title: _, url: let url, allowedInTopHits: _), - .website(url: let url): + .website(url: let url), + .internalPage(title: _, url: let url): finalUrl = url userEnteredValue = url.absoluteString case .phrase(phrase: let phrase), @@ -802,7 +804,8 @@ extension AddressBarTextField { self = Suffix.visit(host: host) case .bookmark(title: _, url: let url, isFavorite: _, allowedInTopHits: _), - .historyEntry(title: _, url: let url, allowedInTopHits: _): + .historyEntry(title: _, url: let url, allowedInTopHits: _), + .internalPage(title: _, url: let url): if let title = suggestionViewModel.title, !title.isEmpty, suggestionViewModel.autocompletionString != title { @@ -856,6 +859,11 @@ extension AddressBarTextField { } } +extension AddressBarTextField.Value? { + var isEmpty: Bool { + self?.isEmpty ?? true + } +} // MARK: - NSTextFieldDelegate extension AddressBarTextField: NSTextFieldDelegate { diff --git a/DuckDuckGo/NavigationBar/View/AddressBarViewController.swift b/DuckDuckGo/NavigationBar/View/AddressBarViewController.swift index 04cd4cb362..7976bb9dc6 100644 --- a/DuckDuckGo/NavigationBar/View/AddressBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/AddressBarViewController.swift @@ -168,12 +168,7 @@ final class AddressBarViewController: NSViewController { return true } - // If the webview doesn't have content it doesn't handle becoming the first responder properly - if tabViewModel?.tab.webView.url != nil { - tabViewModel?.tab.webView.makeMeFirstResponder() - } else { - view.superview?.becomeFirstResponder() - } + view.window?.makeFirstResponder(nil) return true } @@ -230,9 +225,9 @@ final class AddressBarViewController: NSViewController { passiveTextField.stringValue = "" return } - tabViewModel.$passiveAddressBarString + tabViewModel.$passiveAddressBarAttributedString .receive(on: DispatchQueue.main) - .assign(to: \.stringValue, onWeaklyHeld: passiveTextField) + .assign(to: \.attributedStringValue, onWeaklyHeld: passiveTextField) .store(in: &tabViewModelCancellables) } @@ -244,9 +239,9 @@ final class AddressBarViewController: NSViewController { func shouldShowLoadingIndicator(for tabViewModel: TabViewModel, isLoading: Bool, error: Error?) -> Bool { if isLoading, - let url = tabViewModel.tab.content.url, - [.http, .https].contains(url.navigationalScheme), - url.isDuckDuckGoSearch == false, + let url = tabViewModel.tab.content.urlForWebView, + url.navigationalScheme?.isHypertextScheme == true, + !url.isDuckDuckGoSearch, !url.isDuckPlayer, error == nil { return true } else { @@ -264,7 +259,7 @@ final class AddressBarViewController: NSViewController { .sink { [weak self] value in guard tabViewModel.isLoading, let progressIndicator = self?.progressIndicator, - progressIndicator.isShown + progressIndicator.isProgressShown else { return } progressIndicator.increaseProgress(to: value) @@ -279,7 +274,7 @@ final class AddressBarViewController: NSViewController { if shouldShowLoadingIndicator(for: tabViewModel, isLoading: isLoading, error: error) { progressIndicator.show(progress: tabViewModel.progress, startTime: tabViewModel.loadingStartTime) - } else if progressIndicator.isShown { + } else if progressIndicator.isProgressShown { progressIndicator.finishAndHide() } } @@ -369,7 +364,7 @@ final class AddressBarViewController: NSViewController { case .suggestion(let suggestionViewModel): switch suggestionViewModel.suggestion { case .phrase, .unknown: self.mode = .editing(isUrl: false) - case .website, .bookmark, .historyEntry: self.mode = .editing(isUrl: true) + case .website, .bookmark, .historyEntry, .internalPage: self.mode = .editing(isUrl: true) } } } @@ -496,12 +491,16 @@ extension AddressBarViewController { return event } + private static let maxClickReleaseDistanceToResignFirstResponder: CGFloat = 4 + func mouseUp(with event: NSEvent) -> NSEvent? { // click (same position down+up) outside of the field: resign first responder guard event.window === self.view.window, self.view.window?.firstResponder === addressBarTextField.currentEditor(), - self.clickPoint == event.locationInWindow - else { return event } + let clickPoint, + clickPoint.distance(to: event.locationInWindow) <= Self.maxClickReleaseDistanceToResignFirstResponder else { + return event + } self.view.window?.makeFirstResponder(nil) diff --git a/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift b/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift index 4598e190e4..847452c63c 100644 --- a/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift +++ b/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift @@ -20,18 +20,14 @@ import Cocoa import Combine import Common import BrowserServicesKit - -#if NETWORK_PROTECTION +import PixelKit import NetworkProtection -#endif - -#if SUBSCRIPTION import Subscription -#endif protocol OptionsButtonMenuDelegate: AnyObject { func optionsButtonMenuRequestedBookmarkThisPage(_ sender: NSMenuItem) + func optionsButtonMenuRequestedBookmarkAllOpenTabs(_ sender: NSMenuItem) func optionsButtonMenuRequestedBookmarkPopover(_ menu: NSMenu) func optionsButtonMenuRequestedBookmarkManagementInterface(_ menu: NSMenu) func optionsButtonMenuRequestedBookmarkImportInterface(_ menu: NSMenu) @@ -46,10 +42,8 @@ protocol OptionsButtonMenuDelegate: AnyObject { #if DBP func optionsButtonMenuRequestedDataBrokerProtection(_ menu: NSMenu) #endif -#if SUBSCRIPTION func optionsButtonMenuRequestedSubscriptionPurchasePage(_ menu: NSMenu) func optionsButtonMenuRequestedIdentityTheftRestoration(_ menu: NSMenu) -#endif } @MainActor @@ -64,15 +58,12 @@ final class MoreOptionsMenu: NSMenu { private lazy var sharingMenu: NSMenu = SharingMenu(title: UserText.shareMenuItem) private lazy var accountManager = AccountManager(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs)) -#if NETWORK_PROTECTION private let networkProtectionFeatureVisibility: NetworkProtectionFeatureVisibility -#endif required init(coder: NSCoder) { fatalError("MoreOptionsMenu: Bad initializer") } -#if NETWORK_PROTECTION init(tabCollectionViewModel: TabCollectionViewModel, emailManager: EmailManager = EmailManager(), passwordManagerCoordinator: PasswordManagerCoordinator, @@ -95,28 +86,6 @@ final class MoreOptionsMenu: NSMenu { setupMenuItems() } -#else - init(tabCollectionViewModel: TabCollectionViewModel, - emailManager: EmailManager = EmailManager(), - passwordManagerCoordinator: PasswordManagerCoordinator, - sharingMenu: NSMenu? = nil, - internalUserDecider: InternalUserDecider) { - - self.tabCollectionViewModel = tabCollectionViewModel - self.emailManager = emailManager - self.passwordManagerCoordinator = passwordManagerCoordinator - self.internalUserDecider = internalUserDecider - - super.init(title: "") - - if let sharingMenu { - self.sharingMenu = sharingMenu - } - self.emailManager.requestDelegate = self - - setupMenuItems() - } -#endif let zoomMenuItem = NSMenuItem(title: UserText.zoom, action: nil, keyEquivalent: "") @@ -202,6 +171,10 @@ final class MoreOptionsMenu: NSMenu { actionDelegate?.optionsButtonMenuRequestedBookmarkThisPage(sender) } + @objc func bookmarkAllOpenTabs(_ sender: NSMenuItem) { + actionDelegate?.optionsButtonMenuRequestedBookmarkAllOpenTabs(sender) + } + @objc func openBookmarks(_ sender: NSMenuItem) { actionDelegate?.optionsButtonMenuRequestedBookmarkPopover(self) } @@ -250,7 +223,6 @@ final class MoreOptionsMenu: NSMenu { actionDelegate?.optionsButtonMenuRequestedAppearancePreferences(self) } -#if SUBSCRIPTION @objc func openSubscriptionPurchasePage(_ sender: NSMenuItem) { actionDelegate?.optionsButtonMenuRequestedSubscriptionPurchasePage(self) } @@ -258,7 +230,6 @@ final class MoreOptionsMenu: NSMenu { @objc func openIdentityTheftRestoration(_ sender: NSMenuItem) { actionDelegate?.optionsButtonMenuRequestedIdentityTheftRestoration(self) } -#endif @objc func findInPage(_ sender: NSMenuItem) { tabCollectionViewModel.selectedTabViewModel?.showFindInPage() @@ -298,7 +269,7 @@ final class MoreOptionsMenu: NSMenu { .targetting(self) .withImage(.bookmarks) .withSubmenu(bookmarksSubMenu) - + .withAccessibilityIdentifier("MoreOptionsMenu.openBookmarks") addItem(withTitle: UserText.downloads, action: #selector(openDownloads), keyEquivalent: "j") .targetting(self) .withImage(.downloads) @@ -317,15 +288,11 @@ final class MoreOptionsMenu: NSMenu { private func addSubscriptionItems() { var items: [NSMenuItem] = [] -#if SUBSCRIPTION if DefaultSubscriptionFeatureAvailability().isFeatureAvailable && !accountManager.isUserAuthenticated { items.append(contentsOf: makeInactiveSubscriptionItems()) } else { items.append(contentsOf: makeActiveSubscriptionItems()) // this adds NETP and DBP only if conditionally enabled } -#else - items.append(contentsOf: makeActiveSubscriptionItems()) // this adds NETP and DBP only if conditionally enabled -#endif if !items.isEmpty { items.forEach { addItem($0) } @@ -337,39 +304,27 @@ final class MoreOptionsMenu: NSMenu { private func makeActiveSubscriptionItems() -> [NSMenuItem] { var items: [NSMenuItem] = [] -#if SUBSCRIPTION let subscriptionFeatureAvailability = DefaultSubscriptionFeatureAvailability() -#endif + let networkProtectionItem: NSMenuItem -#if NETWORK_PROTECTION - if networkProtectionFeatureVisibility.isNetworkProtectionBetaVisible() { - let networkProtectionItem: NSMenuItem + networkProtectionItem = makeNetworkProtectionItem() - networkProtectionItem = makeNetworkProtectionItem() - - items.append(networkProtectionItem) -#if SUBSCRIPTION - if subscriptionFeatureAvailability.isFeatureAvailable && accountManager.isUserAuthenticated { - Task { - let isMenuItemEnabled: Bool + items.append(networkProtectionItem) - switch await accountManager.hasEntitlement(for: .networkProtection) { - case let .success(result): - isMenuItemEnabled = result - case .failure: - isMenuItemEnabled = false - } + if subscriptionFeatureAvailability.isFeatureAvailable && accountManager.isUserAuthenticated { + Task { + let isMenuItemEnabled: Bool - networkProtectionItem.isEnabled = isMenuItemEnabled + switch await accountManager.hasEntitlement(for: .networkProtection) { + case let .success(result): + isMenuItemEnabled = result + case .failure: + isMenuItemEnabled = false } - } -#endif - DailyPixel.fire(pixel: .networkProtectionWaitlistEntryPointMenuItemDisplayed, frequency: .dailyAndCount, includeAppVersionParameter: true) - } else { - networkProtectionFeatureVisibility.disableForWaitlistUsers() + networkProtectionItem.isEnabled = isMenuItemEnabled + } } -#endif // NETWORK_PROTECTION #if DBP let dbpVisibility = DefaultDataBrokerProtectionFeatureVisibility() @@ -381,8 +336,7 @@ final class MoreOptionsMenu: NSMenu { .withImage(.dbpIcon) items.append(dataBrokerProtectionItem) -#if SUBSCRIPTION - if subscriptionFeatureAvailability.isFeatureAvailable && accountManager.isUserAuthenticated { + if subscriptionFeatureAvailability.isFeatureAvailable && accountManager.isUserAuthenticated { Task { let isMenuItemEnabled: Bool @@ -396,16 +350,14 @@ final class MoreOptionsMenu: NSMenu { dataBrokerProtectionItem.isEnabled = isMenuItemEnabled } } -#endif - DataBrokerProtectionExternalWaitlistPixels.fire(pixel: .dataBrokerProtectionWaitlistEntryPointMenuItemDisplayed, frequency: .dailyAndCount) + DataBrokerProtectionExternalWaitlistPixels.fire(pixel: GeneralPixel.dataBrokerProtectionWaitlistEntryPointMenuItemDisplayed, frequency: .dailyAndCount) } else { DefaultDataBrokerProtectionFeatureVisibility().disableAndDeleteForWaitlistUsers() } #endif // DBP -#if SUBSCRIPTION if accountManager.isUserAuthenticated { let identityTheftRestorationItem = NSMenuItem(title: UserText.identityTheftRestorationOptionsMenuItem, action: #selector(openIdentityTheftRestoration), @@ -414,7 +366,7 @@ final class MoreOptionsMenu: NSMenu { .withImage(.itrIcon) items.append(identityTheftRestorationItem) - if subscriptionFeatureAvailability.isFeatureAvailable && accountManager.isUserAuthenticated { + if subscriptionFeatureAvailability.isFeatureAvailable && accountManager.isUserAuthenticated { Task { let isMenuItemEnabled: Bool @@ -429,12 +381,10 @@ final class MoreOptionsMenu: NSMenu { } } } -#endif return items } -#if SUBSCRIPTION private func makeInactiveSubscriptionItems() -> [NSMenuItem] { let shouldHidePrivacyProDueToNoProducts = SubscriptionPurchaseEnvironment.current == .appStore && SubscriptionPurchaseEnvironment.canPurchase == false if shouldHidePrivacyProDueToNoProducts { @@ -449,13 +399,13 @@ final class MoreOptionsMenu: NSMenu { return [privacyProItem] } -#endif private func addPageItems() { - guard let url = tabCollectionViewModel.selectedTabViewModel?.tab.content.url else { return } + guard let tabViewModel = tabCollectionViewModel.selectedTabViewModel, + let url = tabViewModel.tab.content.userEditableUrl else { return } + let oldItemsCount = items.count if url.canFireproof, let host = url.host { - let isFireproof = FireproofDomains.shared.isFireproof(fireproofDomain: host) let title = isFireproof ? UserText.removeFireproofing : UserText.fireproofSite let image: NSImage = isFireproof ? .burn : .fireproof @@ -463,28 +413,33 @@ final class MoreOptionsMenu: NSMenu { addItem(withTitle: title, action: #selector(toggleFireproofing(_:)), keyEquivalent: "") .targetting(self) .withImage(image) - } - addItem(withTitle: UserText.findInPageMenuItem, action: #selector(findInPage(_:)), keyEquivalent: "f") - .targetting(self) - .withImage(.findSearch) - .withAccessibilityIdentifier("MoreOptionsMenu.findInPage") - - addItem(withTitle: UserText.shareMenuItem, action: nil, keyEquivalent: "") - .targetting(self) - .withImage(.share) - .withSubmenu(sharingMenu) + if tabViewModel.canFindInPage { + addItem(withTitle: UserText.findInPageMenuItem, action: #selector(findInPage(_:)), keyEquivalent: "f") + .targetting(self) + .withImage(.findSearch) + .withAccessibilityIdentifier("MoreOptionsMenu.findInPage") + } - addItem(withTitle: UserText.printMenuItem, action: #selector(doPrint(_:)), keyEquivalent: "") - .targetting(self) - .withImage(.print) + if tabViewModel.canReload { + addItem(withTitle: UserText.shareMenuItem, action: nil, keyEquivalent: "") + .targetting(self) + .withImage(.share) + .withSubmenu(sharingMenu) + } - addItem(NSMenuItem.separator()) + if tabViewModel.canPrint { + addItem(withTitle: UserText.printMenuItem, action: #selector(doPrint(_:)), keyEquivalent: "") + .targetting(self) + .withImage(.print) + } + if items.count > oldItemsCount { + addItem(NSMenuItem.separator()) + } } -#if NETWORK_PROTECTION private func makeNetworkProtectionItem() -> NSMenuItem { let networkProtectionItem = NSMenuItem(title: "", action: #selector(showNetworkProtectionStatus(_:)), keyEquivalent: "") .targetting(self) @@ -494,7 +449,6 @@ final class MoreOptionsMenu: NSMenu { return networkProtectionItem } -#endif } @@ -570,7 +524,7 @@ final class EmailOptionsButtonSubMenu: NSMenu { let pixelParameters = self.emailManager.emailPixelParameters self.emailManager.updateLastUseDate() - Pixel.fire(.emailUserCreatedAlias, withAdditionalParameters: pixelParameters) + PixelKit.fire(GeneralPixel.emailUserCreatedAlias, withAdditionalParameters: pixelParameters) NSPasteboard.general.copy(address) NotificationCenter.default.post(name: NSNotification.Name.privateEmailCopiedToClipboard, object: nil) @@ -675,9 +629,16 @@ final class BookmarksSubMenu: NSMenu { let bookmarkPageItem = addItem(withTitle: UserText.bookmarkThisPage, action: #selector(MoreOptionsMenu.bookmarkPage(_:)), keyEquivalent: "d") .withModifierMask([.command]) .targetting(target) + .withAccessibilityIdentifier("MoreOptionsMenu.bookmarkPage") bookmarkPageItem.isEnabled = tabCollectionViewModel.selectedTabViewModel?.canBeBookmarked == true + let bookmarkAllTabsItem = addItem(withTitle: UserText.bookmarkAllTabs, action: #selector(MoreOptionsMenu.bookmarkAllOpenTabs(_:)), keyEquivalent: "d") + .withModifierMask([.command, .shift]) + .targetting(target) + + bookmarkAllTabsItem.isEnabled = tabCollectionViewModel.canBookmarkAllOpenTabs() + addItem(NSMenuItem.separator()) addItem(withTitle: UserText.bookmarksShowToolbarPanel, action: #selector(MoreOptionsMenu.openBookmarks(_:)), keyEquivalent: "") diff --git a/DuckDuckGo/NavigationBar/View/NavigationBar.storyboard b/DuckDuckGo/NavigationBar/View/NavigationBar.storyboard index 541cc8a532..20efa231aa 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBar.storyboard +++ b/DuckDuckGo/NavigationBar/View/NavigationBar.storyboard @@ -739,6 +739,7 @@ +