diff --git a/.github/workflows/branch-flow.yml b/.github/workflows/branch-flow.yml index ccfb351e13..3b454eb14e 100644 --- a/.github/workflows/branch-flow.yml +++ b/.github/workflows/branch-flow.yml @@ -12,7 +12,7 @@ jobs: timeout-minutes: 5 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Branch flow audit self-test run: bash scripts/test-branch-flow-audit.sh diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml index 859aff68dc..4030e8f327 100644 --- a/.github/workflows/codecov.yml +++ b/.github/workflows/codecov.yml @@ -13,9 +13,14 @@ on: jobs: build: runs-on: macOS-latest + permissions: + contents: read + id-token: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Branch flow audit run: | @@ -30,6 +35,16 @@ jobs: bash ./scripts/test-todo-debt-audit.sh bash ./scripts/audit-todo-debt.sh + - name: TestFlight publication evidence + run: | + bash ./scripts/test-testflight-publication-readiness-audit.sh + bash ./scripts/audit-testflight-publication-readiness.sh + + - name: Codecov executable coverage contract + run: | + bash ./scripts/test-codecov-coverage-contract.sh + bash ./scripts/audit-codecov-coverage-contract.sh + - name: Iroha mobile SDK release asset contract env: GH_TOKEN: ${{ github.token }} @@ -53,7 +68,7 @@ jobs: - name: Upload shared-features delta report if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: shared-features-delta-report path: build/reports/shared-features-delta-report.json @@ -145,6 +160,7 @@ jobs: esac echo "Using destination: $DESTINATION" LOG_FILE="$PWD/build/codecov-xcodebuild.log" + RESULT_BUNDLE="$PWD/build/CodecovTests.xcresult" mkdir -p "$PWD/build" if ! xcodebuild \ -workspace fearless.xcworkspace \ @@ -152,6 +168,8 @@ jobs: -clonedSourcePackagesDirPath "$SP_DIR" \ -disableAutomaticPackageResolution \ -destination "$DESTINATION" \ + -enableCodeCoverage YES \ + -resultBundlePath "$RESULT_BUNDLE" \ build test | tee "$LOG_FILE" | xcpretty --test; then echo "Build/Test failed. Key errors from $LOG_FILE:" >&2 if command -v rg >/dev/null 2>&1; then @@ -161,9 +179,31 @@ jobs: fi exit 1 fi + COVERAGE_PROFILE="$( + find "$HOME/Library/Developer/Xcode/DerivedData" \ + -type f -name '*.profdata' -print -quit + )" + if [[ -z "$COVERAGE_PROFILE" ]]; then + echo "Tests passed but Xcode produced no coverage profile." >&2 + exit 1 + fi + xcrun llvm-profdata show "$COVERAGE_PROFILE" >/dev/null || { + echo "Xcode produced an unreadable coverage profile: $COVERAGE_PROFILE" >&2 + exit 1 + } + test -d "$RESULT_BUNDLE" || { + echo "Xcode did not produce the required result bundle." >&2 + exit 1 + } - name: Upload coverage to Codecov - run: bash <(curl -s https://codecov.io/bash) -J 'fearless' + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 + with: + fail_ci_if_error: true + plugins: xcode + swift_project: fearless + use_oidc: true + version: v11.3.1 jenkins-pr-merge: name: continuous-integration/jenkins/pr-merge diff --git a/.github/workflows/ios-release-safety.yml b/.github/workflows/ios-release-safety.yml new file mode 100644 index 0000000000..42c364b357 --- /dev/null +++ b/.github/workflows/ios-release-safety.yml @@ -0,0 +1,68 @@ +name: iOS Release Safety + +on: + pull_request: + push: + branches: + - master + - "release/**" + - "hotfix/**" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ios-release-safety-${{ github.ref }} + cancel-in-progress: true + +jobs: + release-contracts: + name: release-contracts + runs-on: macos-15 + timeout-minutes: 20 + steps: + - name: Check out exact commit + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + fetch-depth: 1 + + - name: Require clean exact checkout + run: | + set -euo pipefail + test -z "$(git status --porcelain=v1 --untracked-files=all)" + git rev-parse --verify HEAD + + - name: Run release gate contract suites + run: | + set -euo pipefail + bash scripts/test-ios-release-identity-audit.sh + bash scripts/test-ios-release-archive-signing-contract.sh + bash scripts/test-ios-signed-release-artifact-audit.sh + bash scripts/test-coredata-release-gate.sh + bash scripts/test-coredata-simulator-rehearsal.sh + bash scripts/storage/test-user-storage-compatibility-model-audit.sh + + - name: Reject silent x86 Release omissions + run: | + set -euo pipefail + if rg -n 'Skipping Release simulator tests|Release simulator tests were skipped' scripts/test-matrix.sh; then + echo "Release matrix still contains a green skip path." >&2 + exit 1 + fi + + required-context: + name: ios-release-safety + runs-on: ubuntu-latest + needs: release-contracts + if: always() + steps: + - name: Require release contract success + env: + RESULT: ${{ needs.release-contracts.result }} + run: | + set -euo pipefail + [[ "$RESULT" == "success" ]] || { + echo "iOS release safety contracts did not pass: $RESULT" >&2 + exit 1 + } diff --git a/Jenkinsfile b/Jenkinsfile index 2a00a2f508..7fba9342a5 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -48,7 +48,8 @@ def ghStatusFallback(String context, String state, String description) { // Ensure SPM and shared-features patches are applied before the main pipeline. // This resolves Web3 API drift (Data.bytes) and IrohaCrypto modulemap issues prior to archive. -node('mac-fearless') { +try { + node('mac-fearless') { stage('Bootstrap CI deps') { checkout scm sh label: 'Bootstrap Pods/SPM/LFS + apply shared-features fixes', script: 'bash scripts/ci/bootstrap.sh' @@ -78,17 +79,113 @@ node('mac-fearless') { scripts/test-matrix.sh fearless.tests "$DESTINATION" ''' ghNotifySafe context: 'jenkins/ios-tests', status: 'SUCCESS', description: 'All tests passed' - ghNotifySafe context: 'continuous-integration/jenkins/pr-merge', status: 'SUCCESS', description: 'Jenkins PR merge build passed' ghStatusFallback('jenkins/ios-tests', 'success', 'All tests passed') - ghStatusFallback('continuous-integration/jenkins/pr-merge', 'success', 'Jenkins PR merge build passed') } catch (e) { ghNotifySafe context: 'jenkins/ios-tests', status: 'FAILURE', description: 'Unit tests failed' - ghNotifySafe context: 'continuous-integration/jenkins/pr-merge', status: 'FAILURE', description: 'Jenkins PR merge build failed' ghStatusFallback('jenkins/ios-tests', 'failure', 'Unit tests failed') - ghStatusFallback('continuous-integration/jenkins/pr-merge', 'failure', 'Jenkins PR merge build failed') throw e } } -} -appPipeline.runPipeline('fearless') + ghNotifySafe context: 'jenkins/ios-release-safety', status: 'PENDING', description: 'Running release safety gates' + ghStatusFallback('jenkins/ios-release-safety', 'pending', 'Running release safety gates') + stage('iOS Release Safety Contracts') { + sh label: 'Run fail-closed release gate contract tests', script: ''' + set -euo pipefail + bash scripts/test-ios-release-identity-audit.sh + bash scripts/test-ios-signed-release-artifact-audit.sh + bash scripts/test-coredata-release-gate.sh + bash scripts/test-coredata-simulator-rehearsal.sh + bash scripts/storage/test-user-storage-compatibility-model-audit.sh + ''' + } + + // Jenkins multibranch PR jobs expose BRANCH_NAME as PR-. Bind the + // gate to both direct release branches and the repository's allowed hotfix / + // release promotion paths so a PR cannot bypass the exact Release evidence. + def directReleaseBranch = ( + env.BRANCH_NAME == 'master' || + env.BRANCH_NAME?.startsWith('release/') || + env.BRANCH_NAME?.startsWith('hotfix/') + ) + def releasePullRequest = ( + env.CHANGE_ID && + ( + ( + env.CHANGE_TARGET == 'develop' && + env.CHANGE_BRANCH?.startsWith('hotfix/') + ) || + ( + env.CHANGE_TARGET == 'master' && + ( + env.CHANGE_BRANCH == 'develop' || + env.CHANGE_BRANCH?.startsWith('release/') || + env.CHANGE_BRANCH?.startsWith('hotfix/') + ) + ) + ) + ) + def releaseBranch = directReleaseBranch || releasePullRequest + if (releaseBranch) { + stage('Exact Core Data Release Gate') { + sh label: 'Require arm64 and exact 412-test Release inventory', script: ''' + set -euo pipefail + [[ "$(uname -m)" == "arm64" ]] || { + echo "Exact Release gate requires dispatch to an arm64 macOS agent." >&2 + exit 78 + } + IOS_EXPECTED_BUILD_NUMBER=2026.7.28 \ + IOS_RELEASE_SOURCE_PACKAGES_DIR="$PWD/SourcePackages" \ + bash scripts/ci/audit-ios-release-identity.sh + bash scripts/storage/audit-user-storage-compatibility-models.sh + bash scripts/ci/run-coredata-release-gate.sh --stage core + ''' + } + } + + if (env.IOS_RELEASE_CANDIDATE == '1') { + stage('Copied-phone Release Evidence') { + sh label: 'Require immutable copied-phone fixture stage', script: ''' + set -euo pipefail + : "${FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE:?release candidate requires the copied-phone fixture}" + : "${FEARLESS_CORE_DATA_SIMULATOR_UDID:?release candidate requires an explicit Simulator UDID}" + bash scripts/ci/run-coredata-release-gate.sh \ + --stage copied-phone \ + --simulator-udid "$FEARLESS_CORE_DATA_SIMULATOR_UDID" \ + --fixture "$FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE" + ''' + } + } + } + + appPipeline.runPipeline('fearless') + + // A required context must not turn green until every custom gate and the + // shared application pipeline have completed. The fallback needs a node + // because it uses curl through the shell. + ghNotifySafe context: 'jenkins/ios-release-safety', status: 'SUCCESS', description: 'All iOS release safety gates passed' + ghNotifySafe context: 'continuous-integration/jenkins/pr-merge', status: 'SUCCESS', description: 'Jenkins PR merge build passed' + node('mac-fearless') { + stage('Finalize Required GitHub Statuses') { + ghStatusFallback('jenkins/ios-release-safety', 'success', 'All iOS release safety gates passed') + ghStatusFallback('continuous-integration/jenkins/pr-merge', 'success', 'Jenkins PR merge build passed') + } + } +} catch (e) { + // Post plugin failures first. If a macOS executor cannot be reacquired for + // the API fallback, the required contexts remain failed or pending, never + // stale green. + ghNotifySafe context: 'jenkins/ios-release-safety', status: 'FAILURE', description: 'iOS release safety or pipeline failed' + ghNotifySafe context: 'continuous-integration/jenkins/pr-merge', status: 'FAILURE', description: 'Jenkins PR merge build failed' + try { + node('mac-fearless') { + stage('Report Required GitHub Status Failure') { + ghStatusFallback('jenkins/ios-release-safety', 'failure', 'iOS release safety or pipeline failed') + ghStatusFallback('continuous-integration/jenkins/pr-merge', 'failure', 'Jenkins PR merge build failed') + } + } + } catch (statusError) { + echo "Could not run GitHub status API fallback: ${statusError.message}" + } + throw e +} diff --git a/config/testflight-publication-readiness.json b/config/testflight-publication-readiness.json new file mode 100644 index 0000000000..9015b38b9c --- /dev/null +++ b/config/testflight-publication-readiness.json @@ -0,0 +1,80 @@ +{ + "schemaVersion": 1, + "platform": "ios", + "distributionChannel": "testflight-external-public-link", + "assessedAtUTC": "2026-07-26T13:26:11Z", + "evidenceBoundary": { + "contract": "tracked-sanitized-publication-snapshot", + "observationMethod": "authenticated-app-store-connect-and-unauthenticated-public-link-in-safari", + "rawAttestationsTracked": false, + "rawAttestationsLocation": "ignored-build-output", + "currentStateRevalidationRequired": true + }, + "artifact": { + "sourceCommit": "f56b7b896344cfded39456217097747ef9efeacf", + "bundleIdentifier": "jp.co.soramitsu.fearlesswallet", + "marketingVersion": "4.2.0", + "buildNumber": "2026.7.26", + "preUploadArchiveTreeSHA256": "301f19a4f1232fb05719d85b825ac081196fa5fb6988b58011b7569a4bd9e6fa", + "executableSHA256": "cf0318792fc361bbd8704b21b6e1a08c4d81897f23492e4a807eab7f22403568", + "signedArchiveAuditReceiptSHA256": "1dbf38740b38403dde9cc7d4b1710cd28fdd5dc6f6f25990a7102020f11d1abc", + "preservedDataArchiveRehearsalResultSHA256": "418d22cdd9e673ddfa1f47a49c666df11a740aac6737f6ef2b0328fa1b6a8641" + }, + "upload": { + "status": "success", + "uploadedAtUTC": "2026-07-26T13:16:00Z", + "postUploadArchiveTreeSHA256": "a483a372fe8fd19761d3b0324427c4cf55a4553b4ed7433b34b78517f292cea7", + "postUploadArchiveInfoPlistSHA256": "e82ff42b4b47713d1094c420dd7d1abfbfdfe7e7b80c972909936ad64e1e4756", + "postUploadAttestationSHA256": "6ede1d8fb981be149a82d69313be0ebc1838291e27d0ecf1c1576c95350b1af9", + "xcodeMutation": "Distributions-only", + "reconstructedPreUploadArchiveTreeMatched": true, + "embeddedAppSignatureVerified": true + }, + "testFlight": { + "processingStatus": "testing", + "externalTestingActive": true, + "externalGroup": { + "name": "Public Beta Test", + "id": "9410949d-b468-40e5-b2f4-24055e65d270", + "testerCount": 122, + "buildCount": 2, + "containsBuild": true, + "publicLinkTesterCount": 120, + "publicLinkTesterLimit": 500 + }, + "publicLink": { + "enabled": true, + "shareableToAnyoneWithLink": true, + "url": "https://testflight.apple.com/join/012KzFyD", + "urlSHA256": "d6599b1b9c0f7e77d9dd80d9185da67c1d864be5df9a7bbf360f245b099a000c", + "landingPageResolved": true, + "landingPageApplicationName": "Fearless Wallet: DeFi Wallet", + "testFlightDeepLinkPresent": true + }, + "whatToTestSHA256": "d5d0c2063934c4ca7dd8bb82af038d79909738c93cf96c11ab63bca8c0b7f272", + "automaticTesterNotification": true, + "publicationAttestationSHA256": "84e53d78316cf46cc1956d04e86782241d6e575da90fef109acaaf44cb368d4c" + }, + "symbolication": { + "status": "degraded-third-party-symbolication", + "runtimeInstallLaunchOrMigrationImpact": false, + "mainApplicationDSYMPresent": true, + "runtimeFrameworkMissingVendorDSYM": "MPQRCoreSDK.framework", + "staticStubFrameworkWarnings": [ + "blake2lib.framework", + "libed25519.framework", + "sr25519lib.framework" + ], + "productionFollowUpRequired": true + }, + "readiness": { + "status": "blocked", + "publicationVerified": true, + "externalTestingActive": true, + "exactAppleDeliveredInstallVerified": false, + "preservedDataPostInstallRehearsalVerified": false, + "releaseEnabled": false, + "blockerCode": "testflight-exact-build-preserved-data-install-pending", + "requiredAction": "Update in place through TestFlight without deleting or clearing app data, then repeat the five-cold-launch and store-integrity rehearsal." + } +} diff --git a/config/todo-debt-baseline.tsv b/config/todo-debt-baseline.tsv index ccd3438865..7c23a6060b 100644 --- a/config/todo-debt-baseline.tsv +++ b/config/todo-debt-baseline.tsv @@ -4,12 +4,9 @@ fearless/Common/Crypto/Data+Keccak.swift // TODO: move to library fearless/Common/Extension/Foundation/NSPredicate+Filter.swift // TODO: Remove fearless/Common/Extension/Foundation/NSPredicate+Validation.swift // TODO: Add deriviationPathHardSoftNumeric? fearless/Common/Extension/Foundation/NSPredicate+Validation.swift // TODO: Add deriviationPathHardSoftNumericPassword? -fearless/Common/Extension/Storage/CDAccountItem+CoreDataDecodable.swift // TODO: Fix logic fearless/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeHotBootSnapshotFactory.swift // TODO: think about it fearless/Common/Services/ChainRegistry/RuntimeProviderPool/RuntimeSnapshotOperationFactory.swift // TODO: think about it fearless/Common/Services/ExtrinsicService/ExtrinsicOperationFactory.swift method: "author_submitAndWatchExtrinsic", // TODO: add to fearless utils -fearless/Common/Storage/Migration/UserStorage/MultiassetV2MigrationPolicy.swift // TODO: tech debt -fearless/Common/Storage/Migration/UserStorage/StorageMigrator+Sync.swift // TODO: Move this logic to app loading state fearless/Modules/AddAccount/Interactors/AddAccount+AccountConfirmInteractor.swift // TODO: Check how to convert this to chain account import fearless/Modules/Export/ExportMnemonic/ExportMnemonicPresenter.swift // TODO: Support custom accounts fearless/Modules/PolkaswapFlow/PolkaswapAdjustment/PolkaswapAdjustmentPresenter.swift // TODO: - need think about this diff --git a/docs/release-checklist.md b/docs/release-checklist.md index e5498c391e..697eaef0fc 100644 --- a/docs/release-checklist.md +++ b/docs/release-checklist.md @@ -31,6 +31,13 @@ Use this checklist for every release PR from `develop` to `master`. - Run `bash ./scripts/test-transaction-builder-tests-audit.sh && bash ./scripts/audit-transaction-builder-tests.sh` and confirm Bitcoin, Solana, Iroha, and TON fail-closed transfer coverage remains in place. +- Run + `bash ./scripts/test-testflight-publication-readiness-audit.sh && bash ./scripts/audit-testflight-publication-readiness.sh` + and review the exact tracked publication snapshot. Do not mark the TestFlight + build release-enabled until an in-place TestFlight update preserves the + existing app container, five cold launches pass, store integrity is unchanged, + and the remaining third-party symbolication follow-up is closed or explicitly + accepted by release review. - Run `bash ./scripts/check-iroha-mobile-sdk-release-assets.sh --self-test`. If `IROHA_MOBILE_SDK_RELEASE_TAG` is configured for the release, also run `bash ./scripts/check-iroha-mobile-sdk-release-assets.sh --download --tag "$IROHA_MOBILE_SDK_RELEASE_TAG"`. diff --git a/docs/testflight-publication-readiness.md b/docs/testflight-publication-readiness.md new file mode 100644 index 0000000000..6fd14afaa5 --- /dev/null +++ b/docs/testflight-publication-readiness.md @@ -0,0 +1,106 @@ +# TestFlight Publication Readiness + +Status: **BLOCKED only on exact Apple-delivered install/rehearsal and symbolication follow-up** + +This document records the sanitized, reviewable publication snapshot for the +migration-fixed Fearless Wallet iOS build. It does not contain App Store +credentials, signing secrets, wallet data, device data, or a private tester +handoff. + +## Exact Published Build + +- Artifact source commit: + `f56b7b896344cfded39456217097747ef9efeacf`. +- Bundle and version: + `jp.co.soramitsu.fearlesswallet`, `4.2.0 (2026.7.26)`. +- Pre-upload archive tree SHA-256: + `301f19a4f1232fb05719d85b825ac081196fa5fb6988b58011b7569a4bd9e6fa`. +- Executable SHA-256: + `cf0318792fc361bbd8704b21b6e1a08c4d81897f23492e4a807eab7f22403568`. +- Signed-archive audit receipt SHA-256: + `1dbf38740b38403dde9cc7d4b1710cd28fdd5dc6f6f25990a7102020f11d1abc`. +- Preserved-data archive rehearsal result SHA-256: + `418d22cdd9e673ddfa1f47a49c666df11a740aac6737f6ef2b0328fa1b6a8641`. + +Xcode uploaded the exact archive successfully at `2026-07-26T13:16:00Z`. +Its only archive mutation was the normal `Distributions` receipt in +`Info.plist`. Removing that receipt from a copy reconstructed the pre-upload +tree hash, while the embedded app signature and executable hash remained +unchanged. + +## External TestFlight State + +The authenticated App Store Connect observation at +`2026-07-26T13:26:11Z` records: + +- `4.2.0 (2026.7.26)` is `Testing`; +- external group `Public Beta Test` has stable identifier + `9410949d-b468-40e5-b2f4-24055e65d270`; +- the group contains the exact build and showed `122` testers, `2` builds, and + `120/500` public-link places used; +- automatic tester notification was enabled; and +- the anyone-with-the-link URL is + `https://testflight.apple.com/join/012KzFyD`. + +An unauthenticated Safari request resolved that URL to Apple's +`Fearless Wallet: DeFi Wallet` page and exposed the TestFlight deep link. +Tester and build counts are a dated snapshot and can change; current App Store +Connect state must be revalidated for a later production release decision. + +## Evidence Boundary + +The raw post-upload, publication, and physical rehearsal attestations are in +ignored `build/` output. Their exact SHA-256 values are copied into the tracked +manifest, but those ignored files must not be treated as canonical release source. The tracked +`config/testflight-publication-readiness.json` is the sanitized public contract +reviewed by the offline audit. + +The publication snapshot proves successful upload, external testing, exact +group assignment, public-link enablement, Apple landing-page resolution, and +the pre-publication preserved-data archive rehearsal. It does not prove that +the Apple-delivered TestFlight package has replaced the locally installed +Developer App on the affected phone. + +## Symbolication Follow-up + +The main application dSYM is present. Xcode nevertheless warned about +`MPQRCoreSDK.framework`, `blake2lib.framework`, `libed25519.framework`, and +`sr25519lib.framework`. + +The dSYM warnings cannot alter install, launch, or Core Data migration runtime +behavior. The three crypto framework warnings correspond to static-stub +packaging while their useful symbols are linked into the main app image. +`MPQRCoreSDK.framework` is the remaining runtime framework without a matching +vendor dSYM, so third-party QR crash frames can have degraded symbolication. +Obtain the matching vendor dSYM or record an explicit reviewed production +acceptance before marking symbolication follow-up complete. + +## Remaining Device Gate + +Update the existing installation through the TestFlight app on the preserved- +data physical iPhone. Do not uninstall the app or clear its container. Then: + +1. verify the installed identity is Apple/TestFlight-distributed build + `4.2.0 (2026.7.26)`; +2. preserve the database UUIDs, protected row counts, and semantic digest; +3. run five terminate-and-cold-launch cycles with the full observation window; +4. rerun SQLite `quick_check` and compare every protected fingerprint; and +5. confirm there is no new Fearless crash report. + +Until that succeeds, +`exactAppleDeliveredInstallVerified=false`, +`preservedDataPostInstallRehearsalVerified=false`, and +`releaseEnabled=false` remain mandatory. + +## Offline Verification + +Run: + +```bash +bash ./scripts/test-testflight-publication-readiness-audit.sh +bash ./scripts/audit-testflight-publication-readiness.sh +``` + +The audit is offline. It validates a dated, content-addressed publication +snapshot and deliberately does not contact Apple or infer current tester +capacity from an old observation. diff --git a/fearless.xcodeproj/project.pbxproj b/fearless.xcodeproj/project.pbxproj index ba9a2d4864..0b2b2c72eb 100644 --- a/fearless.xcodeproj/project.pbxproj +++ b/fearless.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 04F9CF04588676D79EFB8570 /* ClaimCrowdloanRewardsAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBAA28C551344F1457D76DD5 /* ClaimCrowdloanRewardsAssembly.swift */; }; 054C4BCDEC29ED5F74A36E8B /* ExportMnemonicPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61EBE466BDCF77E65FDCDF81 /* ExportMnemonicPresenter.swift */; }; 05A6BB4F8F0912404A4D8413 /* WalletTransactionDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82FD4E0BB1ABA364AFD2E891 /* WalletTransactionDetailsPresenter.swift */; }; + 060167927467FDFE3B939051 /* SubstrateStorageClassResolutionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB5A97E2CECA69B16DCE8E3 /* SubstrateStorageClassResolutionTests.swift */; }; 06197BBE4299DC971C42DB92 /* WalletSendConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A687FBDA0912F8727CE0D81 /* WalletSendConfirmPresenter.swift */; }; 0678271BE1BA5BBC084F478A /* RecommendedValidatorListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57C624E71FCE0FFF8EAD5BA9 /* RecommendedValidatorListWireframe.swift */; }; 06826AA6DBAEA5BBF45BB5CA /* LiquidityPoolSupplyConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4594686D10DBB7627B8C9A12 /* LiquidityPoolSupplyConfirmInteractor.swift */; }; @@ -230,6 +231,7 @@ 152AC909C26E809ACCA55B35 /* CreateContactInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D482753E0D75C5F5E0617998 /* CreateContactInteractor.swift */; }; 1550A6E8789263C0D734091A /* StakingUnbondSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC5083A5751A1A3CC95F4F6F /* StakingUnbondSetupWireframe.swift */; }; 159A8702C30A21988AD76805 /* StakingPoolCreateConfirmAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 408D33DEE675B00ED511517A /* StakingPoolCreateConfirmAssembly.swift */; }; + 16BD370B2E1EBEB7FF26A839 /* ManagedObjectRuntimeClassRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD40C25879A8EC87DA2178B8 /* ManagedObjectRuntimeClassRegistry.swift */; }; 175D58C44C007FFA22679B5F /* NftDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC012CF1C792B34BD5FF45A2 /* NftDetailsProtocols.swift */; }; 179591AAC5B3B7115BB21E53 /* ChainAccountBalanceListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80DE21374A7FA5AE4D26CEB2 /* ChainAccountBalanceListTests.swift */; }; 1795E946F1E386442E96E2BC /* StakingPayoutConfirmationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C0AC11A4A195BB697578CE /* StakingPayoutConfirmationPresenter.swift */; }; @@ -253,6 +255,7 @@ 20F28EF4AD17FC56A5A6697B /* NftSendPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62522E202A1C5EE60D25122 /* NftSendPresenter.swift */; }; 225493AF467A54A56F74FFF5 /* LiquidityPoolsOverviewProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = A692D227372B24F922EFA058 /* LiquidityPoolsOverviewProtocols.swift */; }; 23398AEC756086FEEEE91E65 /* WalletsManagmentRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B55A4C7E8BD87A7C8634ADD /* WalletsManagmentRouter.swift */; }; + 23418E85C0C9C5A35F115B95 /* UserStorageCompatibilityMigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36C64B63B4C227F2467C5C20 /* UserStorageCompatibilityMigrationTests.swift */; }; 237AD34CD1C2778834D7B330 /* AnalyticsValidatorsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6F8BBBA9EABA266B288333F /* AnalyticsValidatorsViewFactory.swift */; }; 23E30A21620831C600CBC1D6 /* LiquidityPoolDetailsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28E3B4BA1160B87C435C2AAF /* LiquidityPoolDetailsRouter.swift */; }; 24E6794278FEC01DFFE7C69C /* LiquidityPoolSupplyConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D430E8B808864B281A62AB43 /* LiquidityPoolSupplyConfirmViewController.swift */; }; @@ -269,6 +272,7 @@ 27CD06DA03B268E2C6A90B15 /* PolkaswapAdjustmentRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D2C2FC3E31C03D08BDEC7A1 /* PolkaswapAdjustmentRouter.swift */; }; 27FA1D57A06AA3A030D226B6 /* StakingUnbondConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = A84638893DC99974E098719E /* StakingUnbondConfirmWireframe.swift */; }; 281D17EF8C45A1FC49FD1523 /* StakingPoolInfoViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97E2A7A3731FAC0C965A898A /* StakingPoolInfoViewLayout.swift */; }; + 2825B0FA4C33C5645A0DD2A7 /* SubstrateV3toV4.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = F191AB8E98289B7B14F71208 /* SubstrateV3toV4.xcmappingmodel */; }; 28FC2FE3E3BE82BF1965B9C1 /* ClaimCrowdloanRewardsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 523339F3ED67EDEB8C5D2110 /* ClaimCrowdloanRewardsPresenter.swift */; }; 2918DCAEB91F8276446873C8 /* StakingRewardPayoutsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = E57E3EA5C070C64000ABCDC0 /* StakingRewardPayoutsWireframe.swift */; }; 2A66CF4F25D109780006E4C1 /* CDPhishingItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A66CF4E25D109770006E4C1 /* CDPhishingItem+CoreDataDecodable.swift */; }; @@ -317,6 +321,7 @@ 3B9314DE6AFC01CA7EF0DAAA /* SelectValidatorsConfirmFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 364C90F7AD36FD6F6E690D7D /* SelectValidatorsConfirmFlow.swift */; }; 3CA86739CB09801714B194BD /* PurchaseWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C52C6CD7112BF0E1E3A98CE /* PurchaseWireframe.swift */; }; 3D1FB0EF87D42F08D9250552 /* PurchasePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56FF8DBE5C32EE4C68ECD623 /* PurchasePresenter.swift */; }; + 3D764B6213C7A3B3F42C9170 /* SubstrateStorageMigrationSafetyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61421DD86EF588DEC4B9ED42 /* SubstrateStorageMigrationSafetyTests.swift */; }; 3DCDF9784283313336CC0505 /* NftSendConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE826F356F6D72EACFB0AE31 /* NftSendConfirmPresenter.swift */; }; 3DF50E6F78F1B1052625BA7D /* ChainSelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2222D628B9EA092D1C6B1CAE /* ChainSelectionPresenter.swift */; }; 3E053332BA9D170FB1569ABB /* WalletTransactionDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = B264116DA8F64446D46E12DE /* WalletTransactionDetailsProtocols.swift */; }; @@ -353,11 +358,13 @@ 4A957B3BAC231B70CBC00EC3 /* LiquidityPoolsOverviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD8B69E9E18C11EAEC9284B3 /* LiquidityPoolsOverviewViewController.swift */; }; 4C7AC4E214171478AC98A898 /* StakingRewardDestConfirmTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9403C5F9C88A4690C62A204B /* StakingRewardDestConfirmTests.swift */; }; 4D44ACFB841F7CE18CE98559 /* MultichainAssetSelectionAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9596692C164228636164C830 /* MultichainAssetSelectionAssembly.swift */; }; + 4D56353FBB1160698C542499 /* CrashConsistentStoreReplacerResourceLimitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EEC2067F2D6F4E9D194E239 /* CrashConsistentStoreReplacerResourceLimitTests.swift */; }; 4D822D169784790EBF173EEE /* WalletMainContainerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D738FE711DD760B47C0BA65 /* WalletMainContainerPresenter.swift */; }; 4E5CD7B8821FA5298EA1598E /* CrowdloanContributionSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3574BADE9CF77599048C7010 /* CrowdloanContributionSetupWireframe.swift */; }; 4F12420C17B321F52D694E92 /* AddCustomNodeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 900E67A76C0702F8123EBB47 /* AddCustomNodeInteractor.swift */; }; 4F66A13E327CBDD04A2411FA /* WalletTransactionHistoryViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFB1161D25AF1FC90AA23B7A /* WalletTransactionHistoryViewLayout.swift */; }; 4FBD73DD27CAA339727616B5 /* StakingUnbondSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FCECA20E6DCA5D228F44477 /* StakingUnbondSetupPresenter.swift */; }; + 4FD1A1541952770AA5A153CB /* FearlessObjectiveCExceptionCatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B1494192371496FAB4895B8 /* FearlessObjectiveCExceptionCatcher.m */; }; 501347BEA67CD30FE484358E /* AccountImportViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E60EF37AC0A7646ED8FE64 /* AccountImportViewFactory.swift */; }; 502DF063219C7211C2225BD4 /* AddCustomNodeViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4952E0B8F8DCD92FE4A37892 /* AddCustomNodeViewLayout.swift */; }; 503DFF0EFCAD0A8B526FEC3A /* SelectMarketViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 320E2207FB549F7C31A80441 /* SelectMarketViewController.swift */; }; @@ -385,6 +392,7 @@ 5C796EF8ED29F564B5D1126B /* CrowdloanContributionConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F75722D2F921FD1C2D4105D /* CrowdloanContributionConfirmViewController.swift */; }; 5D0665A581B9F8DFDBD0CF7B /* WalletChainAccountDashboardWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 885A9E2D3619FEFC5ED0C093 /* WalletChainAccountDashboardWireframe.swift */; }; 5DDD2206DF795CF205610455 /* AccountExportPasswordPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31226053044986BC828AA912 /* AccountExportPasswordPresenter.swift */; }; + 5E1DDD7E1A2F74184B3C0CE4 /* TransformableArchiveSafetyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0F954ADDD5A4E480392B0 /* TransformableArchiveSafetyTests.swift */; }; 5E8504507116E0177D70314B /* LiquidityPoolSupplyViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 438E01C5C877428168E9F3F8 /* LiquidityPoolSupplyViewLayout.swift */; }; 5E9402965D385607E04156DC /* NftDetailsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DEDC1A0ED429DD43EC621E /* NftDetailsPresenter.swift */; }; 5E974C26655D3E64AD6A923D /* AccountStatisticsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0542BF70B1BADBF1459D57FB /* AccountStatisticsInteractor.swift */; }; @@ -440,6 +448,7 @@ 76214649137E7061F701FE38 /* WalletMainContainerAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E096A576B747C09B14FD38D /* WalletMainContainerAssembly.swift */; }; 762BB1AC2F45142B6319B59F /* NftSendProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F55184167D22A33EF7FF77AE /* NftSendProtocols.swift */; }; 76C5FD0685615E602696B23D /* SelectValidatorsConfirmTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28EF0F9F97C89137F642016E /* SelectValidatorsConfirmTests.swift */; }; + 76CD2DF3F59652CC0B3DB5BA /* ChainModelMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3675C75F2FBA7D24EBD5750A /* ChainModelMapperTests.swift */; }; 76F74188F16A370D79033A12 /* AnalyticsRewardDetailsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB5E8FAB4C12D7BFEEF576AD /* AnalyticsRewardDetailsWireframe.swift */; }; 775C4C720600DAE242C67192 /* WalletSendConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A4416B96A9DD5FB5EEA086E /* WalletSendConfirmViewLayout.swift */; }; 78314B269F1CF1A499DE5CCB /* StakingBondMoreFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 784D20E16EEE55C2CF7B319B /* StakingBondMoreFlow.swift */; }; @@ -767,7 +776,6 @@ 8467FD4C24EEA081005D486C /* ProfileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8467FD4B24EEA081005D486C /* ProfileTests.swift */; }; 8467FD5324EFD210005D486C /* UserDataStorageFacade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8467FD5224EFD210005D486C /* UserDataStorageFacade.swift */; }; 8467FD5524EFD254005D486C /* StorageFacadeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8467FD5424EFD254005D486C /* StorageFacadeProtocol.swift */; }; - 8467FD5824EFD5C2005D486C /* CDAccountItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8467FD5724EFD5C2005D486C /* CDAccountItem+CoreDataDecodable.swift */; }; 8467FD5C24EFDCC9005D486C /* UserDataStorageTestFacade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8467FD5B24EFDCC9005D486C /* UserDataStorageTestFacade.swift */; }; 846802A3265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846802A2265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift */; }; 8468B86524F59D1D00B76BC6 /* IconTitleHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468B86424F59D1D00B76BC6 /* IconTitleHeaderView.swift */; }; @@ -1304,6 +1312,7 @@ 9F4A48B1BE3A1110A0CF9F36 /* ReferralCrowdloanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DDDB2B35CD3299F50613141 /* ReferralCrowdloanViewController.swift */; }; 9F664DA212363F5F2C2B530B /* SelectMarketRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C05A688EA7379572BBCE545 /* SelectMarketRouter.swift */; }; A090FF206B56A0E465C62072 /* CrowdloanListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86F7A369E31DCB9ABD556EE9 /* CrowdloanListPresenter.swift */; }; + A1161E67E9F24527E15AC229 /* SafeTransformableValueReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FDEB6F26DCFB53EA1547948 /* SafeTransformableValueReader.swift */; }; A14F444FA808457C16EF826C /* WalletOptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193908913A5B241C82672D8A /* WalletOptionViewController.swift */; }; A1B2C3D4E5F60718293A4B5E /* TonChainSelectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D4E5F60718293A4B5D /* TonChainSelectionTests.swift */; }; A1C05D0028CD04C16AB6082F /* LiquidityPoolDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67BDE520860A67C800E7F4AB /* LiquidityPoolDetailsViewController.swift */; }; @@ -1315,6 +1324,7 @@ A565F118B7ED356099662F03 /* ExportMnemonicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E32C2DC4CC106A3509BE651D /* ExportMnemonicTests.swift */; }; A5AB7027E1E73E39E4026C5C /* Pods_fearlessTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 59FDAE57EE0A97872E76E6CE /* Pods_fearlessTests.framework */; }; A5C7F51539B8D93D9186DA2C /* LiquidityPoolRemoveLiquidityViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419D75A346CE10236161522 /* LiquidityPoolRemoveLiquidityViewLayout.swift */; }; + A5EF098C5D53D306A7E84844 /* LegacyEcosystemUserDataModel_v12.mom in Resources */ = {isa = PBXBuildFile; fileRef = CDB0BA173951B82DCA58B603 /* LegacyEcosystemUserDataModel_v12.mom */; }; A64E3CA61C6CEE74F2FD9825 /* PolkaswapTransaktionSettingsAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7931155840DACB340284ABBB /* PolkaswapTransaktionSettingsAssembly.swift */; }; A6855830B76B0782A696583A /* AssetNetworksInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C554924081754A981EB4243E /* AssetNetworksInteractor.swift */; }; A69D3B3F6BF76FA9C3070BBD /* AssetNetworksViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFBFF377F35B254AB3141100 /* AssetNetworksViewLayout.swift */; }; @@ -1463,6 +1473,7 @@ AEFC6D672600A808000BD310 /* StoriesPreviewCollectionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEFC6D662600A808000BD310 /* StoriesPreviewCollectionItem.swift */; }; AEFC6D6F2600D7CD000BD310 /* NetworkInfoViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEFC6D6E2600D7CD000BD310 /* NetworkInfoViewModelFactory.swift */; }; AF1FD8891DC8B68A9C17C5B2 /* CreateContactViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 198C6349BED4E521C6D7B3AB /* CreateContactViewLayout.swift */; }; + AF76DAB9F6DF8789FCF083E9 /* ChainSyncServiceCompatibilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189CE1DE8D520FEB61152078 /* ChainSyncServiceCompatibilityTests.swift */; }; AF8193D9F818638254854232 /* StakingMainProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470B64C45E547C25FCCCFC33 /* StakingMainProtocols.swift */; }; B02EAF42C91E069FE6872EE0 /* SelectValidatorsConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D0E02AA5D3EBA9B94950241 /* SelectValidatorsConfirmWireframe.swift */; }; B071927DF8DD5C3CA84494BA /* RecommendedValidatorListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F61D8973ADEB461DE2AD3E13 /* RecommendedValidatorListViewController.swift */; }; @@ -1494,6 +1505,7 @@ C20ED4531583D0C8E38715E0 /* PurchaseProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 782CC21A2F9EEF5DBA3AB1AA /* PurchaseProtocols.swift */; }; C3C7D60B36C778DA0A307BCC /* AddCustomNodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58CD8A37F219A0BCC0C6063E /* AddCustomNodeViewController.swift */; }; C3D915637D26E807B85957CF /* NodeSelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABDA8952766DE724CD078D6 /* NodeSelectionPresenter.swift */; }; + C3E367BDACDDDB4358823EE9 /* CompatibleUserDataModel_v13.mom in Resources */ = {isa = PBXBuildFile; fileRef = 550065CFAAF0723F31DDE3B5 /* CompatibleUserDataModel_v13.mom */; }; C46EEF6A9A9A601694E72DB1 /* StakingMainWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F09665083031502F9693F8 /* StakingMainWireframe.swift */; }; C481665C170F4D9523DC73AF /* WarningAlertViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55EEBFA4A54B3AAF9F52855 /* WarningAlertViewLayout.swift */; }; C4F8BEB6DFA03A374135BD6B /* FiltersInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E692235C8CF576F69971D118 /* FiltersInteractor.swift */; }; @@ -1690,6 +1702,7 @@ E2F9D7BDDE961B162EF100AB /* StakingMainViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A825B6368073B06F32D7C8F /* StakingMainViewFactory.swift */; }; E320ACDB8E3B3CBDAC28691D /* PolkaswapSwapConfirmationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F0FEFEAEC5CDCD7C9BF77D5 /* PolkaswapSwapConfirmationPresenter.swift */; }; E40F3F3C0FE753970B8745DD /* SelectMarketAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7525C3C310DC88A7FA598B9 /* SelectMarketAssembly.swift */; }; + E49A768AD7230A1844DD6C8D /* SubstrateV2toV4.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 3F646753DCEB6599248D9A31 /* SubstrateV2toV4.xcmappingmodel */; }; E58F94758A6B8BCF3BE0EAEA /* MainNftContainerViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BCBF6D6D48704B27B2DBB79 /* MainNftContainerViewLayout.swift */; }; E5A07BDF3D37C761F453696A /* AddCustomNodeViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D81DBDDD34EA20C3270EDB4 /* AddCustomNodeViewFactory.swift */; }; E5B4512B99ED86EF398B648E /* WarningAlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E587507F8CDA7F84A1A4EA95 /* WarningAlertTests.swift */; }; @@ -2964,15 +2977,6 @@ FAE601882ECA700100000001 /* BitcoinTransactionHistorySyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601892ECA700100000001 /* BitcoinTransactionHistorySyncTests.swift */; }; FAE6018A2ECA700100000001 /* BitcoinSendService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE6018B2ECA700100000001 /* BitcoinSendService.swift */; }; FAE6018C2ECA700100000001 /* BitcoinSendServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE6018D2ECA700100000001 /* BitcoinSendServiceTests.swift */; }; - FAE601A22ECA700100000001 /* BitcoinHistoryOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601A32ECA700100000001 /* BitcoinHistoryOperationFactory.swift */; }; - FAE601A42ECA700100000001 /* BitcoinHistoryOperationFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601A52ECA700100000001 /* BitcoinHistoryOperationFactoryTests.swift */; }; - FAE601A62ECA700100000001 /* UniversalWalletAccountAddressResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601A72ECA700100000001 /* UniversalWalletAccountAddressResolver.swift */; }; - FAE601A82ECA700100000001 /* UniversalWalletAccountAddressResolverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601A92ECA700100000001 /* UniversalWalletAccountAddressResolverTests.swift */; }; - FAE601AA2ECA700100000001 /* SolanaHistoryOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601AB2ECA700100000001 /* SolanaHistoryOperationFactory.swift */; }; - FAE601AC2ECA700100000001 /* SolanaHistoryOperationFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601AD2ECA700100000001 /* SolanaHistoryOperationFactoryTests.swift */; }; - FAE601AE2ECA700100000001 /* IrohaHistoryOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601AF2ECA700100000001 /* IrohaHistoryOperationFactory.swift */; }; - FAE601B02ECA700100000001 /* IrohaHistoryOperationFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601B12ECA700100000001 /* IrohaHistoryOperationFactoryTests.swift */; }; - FAE601B22ECA700100000001 /* PasskeyBackupContract.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601B32ECA700100000001 /* PasskeyBackupContract.swift */; }; FAE6018E2ECA700100000001 /* SolanaBalanceSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE6018F2ECA700100000001 /* SolanaBalanceSync.swift */; }; FAE601902ECA700100000001 /* SolanaBalanceSyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601912ECA700100000001 /* SolanaBalanceSyncTests.swift */; }; FAE601922ECA700100000001 /* SolanaTransactionHistorySync.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601932ECA700100000001 /* SolanaTransactionHistorySync.swift */; }; @@ -2983,6 +2987,15 @@ FAE6019C2ECA700100000001 /* SolanaSendService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE6019D2ECA700100000001 /* SolanaSendService.swift */; }; FAE6019E2ECA700100000001 /* SolanaTransferTransactionBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE6019F2ECA700100000001 /* SolanaTransferTransactionBuilderTests.swift */; }; FAE601A02ECA700100000001 /* SolanaSendServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601A12ECA700100000001 /* SolanaSendServiceTests.swift */; }; + FAE601A22ECA700100000001 /* BitcoinHistoryOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601A32ECA700100000001 /* BitcoinHistoryOperationFactory.swift */; }; + FAE601A42ECA700100000001 /* BitcoinHistoryOperationFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601A52ECA700100000001 /* BitcoinHistoryOperationFactoryTests.swift */; }; + FAE601A62ECA700100000001 /* UniversalWalletAccountAddressResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601A72ECA700100000001 /* UniversalWalletAccountAddressResolver.swift */; }; + FAE601A82ECA700100000001 /* UniversalWalletAccountAddressResolverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601A92ECA700100000001 /* UniversalWalletAccountAddressResolverTests.swift */; }; + FAE601AA2ECA700100000001 /* SolanaHistoryOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601AB2ECA700100000001 /* SolanaHistoryOperationFactory.swift */; }; + FAE601AC2ECA700100000001 /* SolanaHistoryOperationFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601AD2ECA700100000001 /* SolanaHistoryOperationFactoryTests.swift */; }; + FAE601AE2ECA700100000001 /* IrohaHistoryOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601AF2ECA700100000001 /* IrohaHistoryOperationFactory.swift */; }; + FAE601B02ECA700100000001 /* IrohaHistoryOperationFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601B12ECA700100000001 /* IrohaHistoryOperationFactoryTests.swift */; }; + FAE601B22ECA700100000001 /* PasskeyBackupContract.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE601B32ECA700100000001 /* PasskeyBackupContract.swift */; }; FAE9EB9D288AB74D009390B6 /* AnalyticsRewardsFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE9EB9C288AB74D009390B6 /* AnalyticsRewardsFlow.swift */; }; FAE9EB9F288ABBBE009390B6 /* AnalyticRewardsParachainViewModelState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE9EB9E288ABBBE009390B6 /* AnalyticRewardsParachainViewModelState.swift */; }; FAE9EBA1288ABBC7009390B6 /* AnalyticRewardsParachainStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE9EBA0288ABBC7009390B6 /* AnalyticRewardsParachainStrategy.swift */; }; @@ -3334,11 +3347,13 @@ 14611E105279789A149B3755 /* AssetNetworksProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetNetworksProtocols.swift; sourceTree = ""; }; 14E3337CDD7C831AEAA4582F /* CustomValidatorListPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CustomValidatorListPresenter.swift; sourceTree = ""; }; 15E7F3E6BBE50797A9EB9145 /* WalletTransactionHistoryViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletTransactionHistoryViewController.swift; sourceTree = ""; }; + 15F0F954ADDD5A4E480392B0 /* TransformableArchiveSafetyTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TransformableArchiveSafetyTests.swift; sourceTree = ""; }; 169ADB0FB6C83C9CEED2F780 /* NetworkIssuesNotificationViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NetworkIssuesNotificationViewLayout.swift; sourceTree = ""; }; 172B3E9BE51A339D7A09BDA3 /* UsernameSetupPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UsernameSetupPresenter.swift; sourceTree = ""; }; 17717EAA891DDB5A0223718F /* AccountCreateTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountCreateTests.swift; sourceTree = ""; }; 17C0AC11A4A195BB697578CE /* StakingPayoutConfirmationPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPayoutConfirmationPresenter.swift; sourceTree = ""; }; 18228EC4A56493660DC7DBB1 /* AccountImportTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountImportTests.swift; sourceTree = ""; }; + 189CE1DE8D520FEB61152078 /* ChainSyncServiceCompatibilityTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainSyncServiceCompatibilityTests.swift; sourceTree = ""; }; 193908913A5B241C82672D8A /* WalletOptionViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletOptionViewController.swift; sourceTree = ""; }; 194C9BFEE9BA8C9E448D79AA /* AccountExportPasswordInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountExportPasswordInteractor.swift; sourceTree = ""; }; 194E6EDD65CA3FB0B1F6727C /* NftDetailsAssembly.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftDetailsAssembly.swift; sourceTree = ""; }; @@ -3415,7 +3430,9 @@ 3574BADE9CF77599048C7010 /* CrowdloanContributionSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupWireframe.swift; sourceTree = ""; }; 35EAD41DB1444DA38D8C65E2 /* NetworkIssuesNotificationPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NetworkIssuesNotificationPresenter.swift; sourceTree = ""; }; 364C90F7AD36FD6F6E690D7D /* SelectValidatorsConfirmFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmFlow.swift; sourceTree = ""; }; + 3675C75F2FBA7D24EBD5750A /* ChainModelMapperTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainModelMapperTests.swift; sourceTree = ""; }; 36A3D64FF58C40E5CC6A6E89 /* AssetNetworksRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetNetworksRouter.swift; sourceTree = ""; }; + 36C64B63B4C227F2467C5C20 /* UserStorageCompatibilityMigrationTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UserStorageCompatibilityMigrationTests.swift; sourceTree = ""; }; 375E9A7A1206E366E862D81D /* WalletTransactionHistoryInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletTransactionHistoryInteractor.swift; sourceTree = ""; }; 3837CE5CB2D48D8A694A7EE0 /* StakingPoolCreateConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPoolCreateConfirmPresenter.swift; sourceTree = ""; }; 385FE8691EA37DE9F562B34E /* CrowdloanContributionConfirmTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmTests.swift; sourceTree = ""; }; @@ -3434,6 +3451,7 @@ 3F25F3A88B4BEB4DE498220C /* LiquidityPoolsOverviewRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LiquidityPoolsOverviewRouter.swift; sourceTree = ""; }; 3F47E5832513985B89D06155 /* AccountExportPasswordWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountExportPasswordWireframe.swift; sourceTree = ""; }; 3F5C47F8D6CB97D16DFF06B7 /* WalletsManagmentInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletsManagmentInteractor.swift; sourceTree = ""; }; + 3F646753DCEB6599248D9A31 /* SubstrateV2toV4.xcmappingmodel */ = {isa = PBXFileReference; includeInIndex = 1; path = SubstrateV2toV4.xcmappingmodel; sourceTree = ""; }; 3F7068913923A6DEEE9D8EA0 /* CrowdloanContributionSetupPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupPresenter.swift; sourceTree = ""; }; 3F75722D2F921FD1C2D4105D /* CrowdloanContributionConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmViewController.swift; sourceTree = ""; }; 40728E7BBC553AFA8FF4142B /* NetworkIssuesNotificationViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NetworkIssuesNotificationViewController.swift; sourceTree = ""; }; @@ -3480,6 +3498,7 @@ 5408FF305E4A49A683BC43E0 /* WalletChainAccountDashboardViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletChainAccountDashboardViewLayout.swift; sourceTree = ""; }; 54776237A20227DFE025E3AC /* AllDoneViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AllDoneViewLayout.swift; sourceTree = ""; }; 54FB887490A8B33890B4E0E4 /* ControllerAccountConfirmationPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ControllerAccountConfirmationPresenter.swift; sourceTree = ""; }; + 550065CFAAF0723F31DDE3B5 /* CompatibleUserDataModel_v13.mom */ = {isa = PBXFileReference; includeInIndex = 1; path = CompatibleUserDataModel_v13.mom; sourceTree = ""; }; 55499F69824A67FA32C02C77 /* StakingPoolInfoRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPoolInfoRouter.swift; sourceTree = ""; }; 5555FA26DF1BD5483F7544B5 /* StakingPoolCreateConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPoolCreateConfirmViewLayout.swift; sourceTree = ""; }; 55CC5A63AC07644409E997C1 /* StakingMainViewController.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; path = StakingMainViewController.xib; sourceTree = ""; }; @@ -3514,6 +3533,7 @@ 5FFEB823BE0057CFB78CC033 /* NetworkManagementTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NetworkManagementTests.swift; sourceTree = ""; }; 605CA30BCCB5F23C64E6D6EC /* NodeSelectionViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NodeSelectionViewController.swift; sourceTree = ""; }; 610A7425DF3F20BE0AB05ECD /* NftCollectionViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftCollectionViewLayout.swift; sourceTree = ""; }; + 61421DD86EF588DEC4B9ED42 /* SubstrateStorageMigrationSafetyTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SubstrateStorageMigrationSafetyTests.swift; sourceTree = ""; }; 61A5A7C701EF966BF48D6B9E /* AllDoneViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AllDoneViewController.swift; sourceTree = ""; }; 61BE50276590067C81F4761F /* ChainAccountBalanceTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainAccountBalanceTests.swift; sourceTree = ""; }; 61E1CD099F7C30ABE0E8A001 /* StakingUnbondSetupTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondSetupTests.swift; sourceTree = ""; }; @@ -3537,6 +3557,7 @@ 67B1037AEC97DBEAF9FD50C1 /* AssetNetworksPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetNetworksPresenter.swift; sourceTree = ""; }; 67B3E1906EEBE32E71E82BB6 /* NodeSelectionViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NodeSelectionViewLayout.swift; sourceTree = ""; }; 67BDE520860A67C800E7F4AB /* LiquidityPoolDetailsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LiquidityPoolDetailsViewController.swift; sourceTree = ""; }; + 67DC38DE23BBEF83BC331009 /* fearless-Bridging-Header.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "fearless-Bridging-Header.h"; sourceTree = ""; }; 6887529305794E17D9434D44 /* LiquidityPoolRemoveLiquidityInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LiquidityPoolRemoveLiquidityInteractor.swift; sourceTree = ""; }; 6897929D244B5C29E3FD0727 /* StakingPoolCreateRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPoolCreateRouter.swift; sourceTree = ""; }; 69B00AC48FB7D11855875EB9 /* SwapTransactionDetailPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SwapTransactionDetailPresenter.swift; sourceTree = ""; }; @@ -3893,7 +3914,6 @@ 8467FD4B24EEA081005D486C /* ProfileTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileTests.swift; sourceTree = ""; }; 8467FD5224EFD210005D486C /* UserDataStorageFacade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDataStorageFacade.swift; sourceTree = ""; }; 8467FD5424EFD254005D486C /* StorageFacadeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageFacadeProtocol.swift; sourceTree = ""; }; - 8467FD5724EFD5C2005D486C /* CDAccountItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDAccountItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8467FD5B24EFDCC9005D486C /* UserDataStorageTestFacade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDataStorageTestFacade.swift; sourceTree = ""; }; 846802A2265DA5530034F9B5 /* CrowdloanContributionSetupViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupViewModel.swift; sourceTree = ""; }; 8468B86424F59D1D00B76BC6 /* IconTitleHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconTitleHeaderView.swift; sourceTree = ""; }; @@ -4396,6 +4416,7 @@ 8D51D60F19284936A6E9F47D /* ReferralCrowdloanWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferralCrowdloanWireframe.swift; sourceTree = ""; }; 8E4DF941DE0EDEF99A843A9D /* ContactsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ContactsInteractor.swift; sourceTree = ""; }; 8E83833EB33E51A12F96F83B /* WalletChainAccountDashboardPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletChainAccountDashboardPresenter.swift; sourceTree = ""; }; + 8EEC2067F2D6F4E9D194E239 /* CrashConsistentStoreReplacerResourceLimitTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrashConsistentStoreReplacerResourceLimitTests.swift; sourceTree = ""; }; 8F04623D6CE10669D914CA2F /* PolkaswapTransaktionSettingsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PolkaswapTransaktionSettingsViewController.swift; sourceTree = ""; }; 8F0FEFEAEC5CDCD7C9BF77D5 /* PolkaswapSwapConfirmationPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PolkaswapSwapConfirmationPresenter.swift; sourceTree = ""; }; 8FB7091F743BBACC09553298 /* LiquidityPoolSupplyProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LiquidityPoolSupplyProtocols.swift; sourceTree = ""; }; @@ -4427,10 +4448,12 @@ 9A22A2EB487E282DCA93C676 /* WalletSendConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletSendConfirmWireframe.swift; sourceTree = ""; }; 9A9EBD3B7AEA5EF594DFEB49 /* PolkaswapAdjustmentProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PolkaswapAdjustmentProtocols.swift; sourceTree = ""; }; 9AEA7ECB8434DF494D2B25B9 /* ChainAccountTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainAccountTests.swift; sourceTree = ""; }; + 9B1494192371496FAB4895B8 /* FearlessObjectiveCExceptionCatcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = FearlessObjectiveCExceptionCatcher.m; sourceTree = ""; }; 9B5626189788682A84D4E9D7 /* SelectValidatorsConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmPresenter.swift; sourceTree = ""; }; 9BA528679A82B9A327853804 /* LiquidityPoolSupplyInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LiquidityPoolSupplyInteractor.swift; sourceTree = ""; }; 9C01DCD4DA014E8FB50B9F11 /* CrowdloanContributionSetupTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupTests.swift; sourceTree = ""; }; 9C05A688EA7379572BBCE545 /* SelectMarketRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectMarketRouter.swift; sourceTree = ""; }; + 9FDEB6F26DCFB53EA1547948 /* SafeTransformableValueReader.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SafeTransformableValueReader.swift; sourceTree = ""; }; 9FED48DE9B681995E6E4A581 /* LiquidityPoolDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LiquidityPoolDetailsProtocols.swift; sourceTree = ""; }; A14CA4551FCC2EBD078E2242 /* AccountConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountConfirmViewFactory.swift; sourceTree = ""; }; A1B2C3D4E5F60718293A4B5D /* TonChainSelectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = fearlessTests/ApplicationLayer/Services/FeatureToggle/TonChainSelectionTests.swift; sourceTree = ""; }; @@ -4461,6 +4484,7 @@ AC404A4071AF571FAC4C1994 /* AccountExportPasswordProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountExportPasswordProtocols.swift; sourceTree = ""; }; ACAEDA02F409FE23749A1551 /* AccountCreateWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountCreateWireframe.swift; sourceTree = ""; }; AD0EAB8749661CB4428685FB /* SelectMarketProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectMarketProtocols.swift; sourceTree = ""; }; + ADB5A97E2CECA69B16DCE8E3 /* SubstrateStorageClassResolutionTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SubstrateStorageClassResolutionTests.swift; sourceTree = ""; }; ADD19595322BF8FEC0F1F746 /* StakingPoolCreatePresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPoolCreatePresenter.swift; sourceTree = ""; }; ADD348E749EC6A7E3BB069DE /* StakingUnbondConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondConfirmProtocols.swift; sourceTree = ""; }; AE20602B2636EA5800357578 /* MoonPayKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoonPayKeys.swift; sourceTree = ""; }; @@ -4611,11 +4635,13 @@ BB837A15BAAED64BC32F3F44 /* SelectMarketInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectMarketInteractor.swift; sourceTree = ""; }; BB86E65E22C0AF7EDD0701A4 /* AccountStatisticsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountStatisticsPresenter.swift; sourceTree = ""; }; BC2C9D26B9F9CC048C67796F /* AnalyticsRewardDetailsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsRewardDetailsViewLayout.swift; sourceTree = ""; }; + BD40C25879A8EC87DA2178B8 /* ManagedObjectRuntimeClassRegistry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ManagedObjectRuntimeClassRegistry.swift; sourceTree = ""; }; BE7D061906CF67230BF5393A /* NftSendConfirmTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftSendConfirmTests.swift; sourceTree = ""; }; C0EE58376751B23A9CEAEE1A /* StakingPoolCreateConfirmRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPoolCreateConfirmRouter.swift; sourceTree = ""; }; C16219B3D0D2A658185C0850 /* MainNftContainerInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MainNftContainerInteractor.swift; sourceTree = ""; }; C191A3875F3255B72E01FA92 /* CrowdloanListWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanListWireframe.swift; sourceTree = ""; }; C23EA8830B337C4F8142A395 /* AddCustomNodeTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddCustomNodeTests.swift; sourceTree = ""; }; + C24D2309D225410A85B67B4A /* FearlessObjectiveCExceptionCatcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = FearlessObjectiveCExceptionCatcher.h; sourceTree = ""; }; C2956D0C69019DDCDAB2EB34 /* CustomValidatorListViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CustomValidatorListViewLayout.swift; sourceTree = ""; }; C316BE4F5A0342D379F783E8 /* StartSelectValidatorsTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StartSelectValidatorsTests.swift; sourceTree = ""; }; C323602A21644DCB1B2EEFF6 /* Pods_fearlessAll_fearlessIntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_fearlessAll_fearlessIntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -4773,6 +4799,7 @@ CD098B40697FD6CC08F9A6AC /* UsernameSetupProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UsernameSetupProtocols.swift; sourceTree = ""; }; CD730FFB75B5D76EA939042D /* PolkaswapTransaktionSettingsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PolkaswapTransaktionSettingsInteractor.swift; sourceTree = ""; }; CD8B6213B00597B3F56F650D /* StakingUnbondSetupFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingUnbondSetupFlow.swift; sourceTree = ""; }; + CDB0BA173951B82DCA58B603 /* LegacyEcosystemUserDataModel_v12.mom */ = {isa = PBXFileReference; includeInIndex = 1; path = LegacyEcosystemUserDataModel_v12.mom; sourceTree = ""; }; CE29083D5CE7EA0D886D069A /* WalletTransactionHistoryViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletTransactionHistoryViewFactory.swift; sourceTree = ""; }; CE294DDEAB7902D7CE1F1BA1 /* AnalyticsRewardDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AnalyticsRewardDetailsProtocols.swift; sourceTree = ""; }; CF4A813A6FB09F9FE5891578 /* WalletSendConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletSendConfirmViewController.swift; sourceTree = ""; }; @@ -4848,6 +4875,7 @@ F0A1B2C3D4E5F60718293A4B /* AssetRepositoryFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRepositoryFactoryTests.swift; sourceTree = ""; }; F12B2D844B474F810C807451 /* AccountManagementTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountManagementTests.swift; sourceTree = ""; }; F15D1C78B2844216802DA000 /* ChainSelectionViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChainSelectionViewFactory.swift; sourceTree = ""; }; + F191AB8E98289B7B14F71208 /* SubstrateV3toV4.xcmappingmodel */ = {isa = PBXFileReference; includeInIndex = 1; path = SubstrateV3toV4.xcmappingmodel; sourceTree = ""; }; F1A2B3C4D5E6F708192A3B4D /* NetworkWorkerCompatibilityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkWorkerCompatibilityTests.swift; sourceTree = ""; }; F1E3F963A56923FD036280BD /* WalletOptionAssembly.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletOptionAssembly.swift; sourceTree = ""; }; F23E38DCBC74C528D7839B76 /* CrowdloanContributionSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupInteractor.swift; sourceTree = ""; }; @@ -6099,15 +6127,6 @@ FAE601892ECA700100000001 /* BitcoinTransactionHistorySyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinTransactionHistorySyncTests.swift; sourceTree = ""; }; FAE6018B2ECA700100000001 /* BitcoinSendService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinSendService.swift; sourceTree = ""; }; FAE6018D2ECA700100000001 /* BitcoinSendServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinSendServiceTests.swift; sourceTree = ""; }; - FAE601A32ECA700100000001 /* BitcoinHistoryOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinHistoryOperationFactory.swift; sourceTree = ""; }; - FAE601A52ECA700100000001 /* BitcoinHistoryOperationFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinHistoryOperationFactoryTests.swift; sourceTree = ""; }; - FAE601A72ECA700100000001 /* UniversalWalletAccountAddressResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalWalletAccountAddressResolver.swift; sourceTree = ""; }; - FAE601A92ECA700100000001 /* UniversalWalletAccountAddressResolverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalWalletAccountAddressResolverTests.swift; sourceTree = ""; }; - FAE601AB2ECA700100000001 /* SolanaHistoryOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaHistoryOperationFactory.swift; sourceTree = ""; }; - FAE601AD2ECA700100000001 /* SolanaHistoryOperationFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaHistoryOperationFactoryTests.swift; sourceTree = ""; }; - FAE601AF2ECA700100000001 /* IrohaHistoryOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IrohaHistoryOperationFactory.swift; sourceTree = ""; }; - FAE601B12ECA700100000001 /* IrohaHistoryOperationFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IrohaHistoryOperationFactoryTests.swift; sourceTree = ""; }; - FAE601B32ECA700100000001 /* PasskeyBackupContract.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasskeyBackupContract.swift; sourceTree = ""; }; FAE6018F2ECA700100000001 /* SolanaBalanceSync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaBalanceSync.swift; sourceTree = ""; }; FAE601912ECA700100000001 /* SolanaBalanceSyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaBalanceSyncTests.swift; sourceTree = ""; }; FAE601932ECA700100000001 /* SolanaTransactionHistorySync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaTransactionHistorySync.swift; sourceTree = ""; }; @@ -6118,6 +6137,15 @@ FAE6019D2ECA700100000001 /* SolanaSendService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaSendService.swift; sourceTree = ""; }; FAE6019F2ECA700100000001 /* SolanaTransferTransactionBuilderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaTransferTransactionBuilderTests.swift; sourceTree = ""; }; FAE601A12ECA700100000001 /* SolanaSendServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaSendServiceTests.swift; sourceTree = ""; }; + FAE601A32ECA700100000001 /* BitcoinHistoryOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinHistoryOperationFactory.swift; sourceTree = ""; }; + FAE601A52ECA700100000001 /* BitcoinHistoryOperationFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinHistoryOperationFactoryTests.swift; sourceTree = ""; }; + FAE601A72ECA700100000001 /* UniversalWalletAccountAddressResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalWalletAccountAddressResolver.swift; sourceTree = ""; }; + FAE601A92ECA700100000001 /* UniversalWalletAccountAddressResolverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalWalletAccountAddressResolverTests.swift; sourceTree = ""; }; + FAE601AB2ECA700100000001 /* SolanaHistoryOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaHistoryOperationFactory.swift; sourceTree = ""; }; + FAE601AD2ECA700100000001 /* SolanaHistoryOperationFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolanaHistoryOperationFactoryTests.swift; sourceTree = ""; }; + FAE601AF2ECA700100000001 /* IrohaHistoryOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IrohaHistoryOperationFactory.swift; sourceTree = ""; }; + FAE601B12ECA700100000001 /* IrohaHistoryOperationFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IrohaHistoryOperationFactoryTests.swift; sourceTree = ""; }; + FAE601B32ECA700100000001 /* PasskeyBackupContract.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasskeyBackupContract.swift; sourceTree = ""; }; FAE9EB9C288AB74D009390B6 /* AnalyticsRewardsFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsRewardsFlow.swift; sourceTree = ""; }; FAE9EB9E288ABBBE009390B6 /* AnalyticRewardsParachainViewModelState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticRewardsParachainViewModelState.swift; sourceTree = ""; }; FAE9EBA0288ABBC7009390B6 /* AnalyticRewardsParachainStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticRewardsParachainStrategy.swift; sourceTree = ""; }; @@ -7390,6 +7418,16 @@ path = ExportMnemonic; sourceTree = ""; }; + 3FB1F51B726C8907AE195C3D /* Compiled */ = { + isa = PBXGroup; + children = ( + CDB0BA173951B82DCA58B603 /* LegacyEcosystemUserDataModel_v12.mom */, + 550065CFAAF0723F31DDE3B5 /* CompatibleUserDataModel_v13.mom */, + ); + name = Compiled; + path = Compiled; + sourceTree = ""; + }; 41E829DF2B0F955B28BB6367 /* ExportMnemonic */ = { isa = PBXGroup; children = ( @@ -8205,6 +8243,7 @@ 84BEE62F26CBFDBC00757009 /* ChainRegistryTests.swift */, 8469936A26CD1BBE002CC786 /* RuntimePoolTests.swift */, 84D9C41026CD361C004AB2AB /* SpecVersionSubscriptionTests.swift */, + 189CE1DE8D520FEB61152078 /* ChainSyncServiceCompatibilityTests.swift */, ); path = ChainRegistry; sourceTree = ""; @@ -8245,6 +8284,8 @@ 84F13F0D26F1D9B1006725FF /* CrowdloadSettingsTests.swift */, 84F13F1326F20AA2006725FF /* StakingSettingsTests.swift */, 0A90ED622F74447700F741B6 /* StorageRequestTests.swift */, + 3675C75F2FBA7D24EBD5750A /* ChainModelMapperTests.swift */, + 15F0F954ADDD5A4E480392B0 /* TransformableArchiveSafetyTests.swift */, ); path = Storage; sourceTree = ""; @@ -8817,6 +8858,7 @@ 845B822826F0BB6700D25C72 /* CrowdloanChainSettings.swift */, 84F13F0726F13898006725FF /* StakingAssetSettings.swift */, 841AAC2E26F73E0C00F0A25E /* LocalStorageKeyFactory.swift */, + 9DA2374947A8488BE1F1CB17 /* CompatibilityModels */, ); path = Storage; sourceTree = ""; @@ -8825,7 +8867,6 @@ isa = PBXGroup; children = ( FA74359629C0734B0085A47E /* CDAccountInfo+CoreDataCodable.swift */, - 8467FD5724EFD5C2005D486C /* CDAccountItem+CoreDataDecodable.swift */, 84EBC54224F656D100459D15 /* SortDescriptor+Storage.swift */, 843910B1253ED4D100E3C217 /* CDChainStorageItem+CoreDataDecodable.swift */, 843910B5253EE62B00E3C217 /* DataProviderChange+Result.swift */, @@ -9014,6 +9055,10 @@ children = ( F418E87B264D14DA00699085 /* NetworkConnectionsMigratorTests.swift */, 849ECD3426DE70B900F542A3 /* SingleToMultiassetUserMigrationTests.swift */, + 36C64B63B4C227F2467C5C20 /* UserStorageCompatibilityMigrationTests.swift */, + 61421DD86EF588DEC4B9ED42 /* SubstrateStorageMigrationSafetyTests.swift */, + ADB5A97E2CECA69B16DCE8E3 /* SubstrateStorageClassResolutionTests.swift */, + 8EEC2067F2D6F4E9D194E239 /* CrashConsistentStoreReplacerResourceLimitTests.swift */, ); path = Migration; sourceTree = ""; @@ -9095,6 +9140,7 @@ 84C07EDA24AF1924008FC35B /* InfoPlist.strings */, 8490146024A94373008F705E /* Localizable.strings */, AE74EC1725FCF09000C494E7 /* Localizable.stringsdict */, + 67DC38DE23BBEF83BC331009 /* fearless-Bridging-Header.h */, ); path = fearless; sourceTree = ""; @@ -10268,6 +10314,8 @@ FA9278A727C382C600FF7B5B /* MultiassetV2.xcmappingmodel */, FA69A94627CE3476000352A6 /* SubstrateV2Mapping.xcmappingmodel */, FA28A9B129D2E451005AA42E /* MultiassetV9.xcmappingmodel */, + F191AB8E98289B7B14F71208 /* SubstrateV3toV4.xcmappingmodel */, + 3F646753DCEB6599248D9A31 /* SubstrateV2toV4.xcmappingmodel */, ); path = MigrationMappings; sourceTree = ""; @@ -10870,6 +10918,15 @@ path = CreateContact; sourceTree = ""; }; + 9DA2374947A8488BE1F1CB17 /* CompatibilityModels */ = { + isa = PBXGroup; + children = ( + 3FB1F51B726C8907AE195C3D /* Compiled */, + ); + name = CompatibilityModels; + path = CompatibilityModels; + sourceTree = ""; + }; A17E1D8ADC21C651CE346F73 /* CrowdloanContributionConfirm */ = { isa = PBXGroup; children = ( @@ -11969,6 +12026,10 @@ isa = PBXGroup; children = ( 46F82B507C2844DA90822C42 /* CoreDataAliases.swift */, + 9B1494192371496FAB4895B8 /* FearlessObjectiveCExceptionCatcher.m */, + C24D2309D225410A85B67B4A /* FearlessObjectiveCExceptionCatcher.h */, + 9FDEB6F26DCFB53EA1547948 /* SafeTransformableValueReader.swift */, + BD40C25879A8EC87DA2178B8 /* ManagedObjectRuntimeClassRegistry.swift */, ); path = CoreData; sourceTree = ""; @@ -15822,6 +15883,8 @@ FA93754A2AE928BE002CA482 /* types.json in Resources */, 742374EE778D76ABC965E107 /* StakingAmountViewController.xib in Resources */, EA8ECCD37FE5D6478018D3FC /* RecommendedValidatorListViewController.xib in Resources */, + A5EF098C5D53D306A7E84844 /* LegacyEcosystemUserDataModel_v12.mom in Resources */, + C3E367BDACDDDB4358823EE9 /* CompatibleUserDataModel_v13.mom in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -16610,7 +16673,6 @@ FAA0139D28DA131B000A5230 /* StakingBondMorePoolViewModelState.swift in Sources */, FA286B0F2A3043DB008BD527 /* CrossChainConfirmationData.swift in Sources */, 8467FD0224E5D2D9005D486C /* OnboardingMainInteractor.swift in Sources */, - 8467FD5824EFD5C2005D486C /* CDAccountItem+CoreDataDecodable.swift in Sources */, 84939B1826E1690D000111DA /* TreasuryDepositEvent.swift in Sources */, 844CB56426F945E200396E13 /* SubstrateLocalSubscriptionFactory.swift in Sources */, FA34EE9C2B9871420042E73E /* StakingLocks.swift in Sources */, @@ -18938,6 +19000,11 @@ 68477096FFF2FE210D9C94B3 /* MultichainAssetSelectionViewController.swift in Sources */, 49F6A6C2A56A3DE9D456FE7D /* MultichainAssetSelectionViewLayout.swift in Sources */, 4D44ACFB841F7CE18CE98559 /* MultichainAssetSelectionAssembly.swift in Sources */, + 4FD1A1541952770AA5A153CB /* FearlessObjectiveCExceptionCatcher.m in Sources */, + A1161E67E9F24527E15AC229 /* SafeTransformableValueReader.swift in Sources */, + 16BD370B2E1EBEB7FF26A839 /* ManagedObjectRuntimeClassRegistry.swift in Sources */, + 2825B0FA4C33C5645A0DD2A7 /* SubstrateV3toV4.xcmappingmodel in Sources */, + E49A768AD7230A1844DD6C8D /* SubstrateV2toV4.xcmappingmodel in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -19153,6 +19220,13 @@ B40863AA7377BFE5F8A30259 /* LiquidityPoolSupplyConfirmTests.swift in Sources */, 6BF307ADE63FA92389340779 /* LiquidityPoolRemoveLiquidityTests.swift in Sources */, ECA54AB8148BBA63084353FD /* LiquidityPoolRemoveLiquidityConfirmTests.swift in Sources */, + 23418E85C0C9C5A35F115B95 /* UserStorageCompatibilityMigrationTests.swift in Sources */, + 3D764B6213C7A3B3F42C9170 /* SubstrateStorageMigrationSafetyTests.swift in Sources */, + 060167927467FDFE3B939051 /* SubstrateStorageClassResolutionTests.swift in Sources */, + 4D56353FBB1160698C542499 /* CrashConsistentStoreReplacerResourceLimitTests.swift in Sources */, + 76CD2DF3F59652CC0B3DB5BA /* ChainModelMapperTests.swift in Sources */, + 5E1DDD7E1A2F74184B3C0CE4 /* TransformableArchiveSafetyTests.swift in Sources */, + AF76DAB9F6DF8789FCF083E9 /* ChainSyncServiceCompatibilityTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -19436,7 +19510,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon$(ICON_SUFFIX)"; CLONED_SOURCE_PACKAGES_DIR_PATH = "$(SRCROOT)/SourcePackages"; - CODE_SIGN_ENTITLEMENTS = fearless/WalletConnect.entitlements; + CODE_SIGN_ENTITLEMENTS = fearless/WalletConnect.dev.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_TEAM = YLWWUD25VZ; @@ -19451,9 +19525,10 @@ ); MARKETING_VERSION = 2.2.3; OTHER_SWIFT_FLAGS = "$(inherited)"; - PRODUCT_BUNDLE_IDENTIFIER = jp.co.soramitsu.fearless; + PRODUCT_BUNDLE_IDENTIFIER = jp.co.soramitsu.fearlesswallet.dev; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ENABLE_EXPLICIT_MODULES = NO; + SWIFT_OBJC_BRIDGING_HEADER = "fearless/fearless-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; }; @@ -19466,9 +19541,9 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon$(ICON_SUFFIX)"; CLONED_SOURCE_PACKAGES_DIR_PATH = "$(SRCROOT)/SourcePackages"; CODE_SIGN_ENTITLEMENTS = fearless/WalletConnect.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CODE_SIGN_IDENTITY = "Apple Distribution: Soramitsu Co., Ltd. (YLWWUD25VZ)"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 2026.7.28; DEVELOPMENT_TEAM = YLWWUD25VZ; ENABLE_BITCODE = NO; INFOPLIST_FILE = fearless/Info.plist; @@ -19479,11 +19554,12 @@ "$(CONFIGURATION_BUILD_DIR)", "$(FRAMEWORK_SEARCH_PATHS)", ); - MARKETING_VERSION = 2.2.3; - PRODUCT_BUNDLE_IDENTIFIER = jp.co.soramitsu.fearless; + MARKETING_VERSION = 4.2.0; + PRODUCT_BUNDLE_IDENTIFIER = jp.co.soramitsu.fearlesswallet; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; + PROVISIONING_PROFILE_SPECIFIER = "Fearless App Store 2026.7.26"; SWIFT_ENABLE_EXPLICIT_MODULES = NO; + SWIFT_OBJC_BRIDGING_HEADER = "fearless/fearless-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; }; @@ -19606,7 +19682,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon$(ICON_SUFFIX)"; CLONED_SOURCE_PACKAGES_DIR_PATH = "$(SRCROOT)/SourcePackages"; - CODE_SIGN_ENTITLEMENTS = fearless/WalletConnect.entitlements; + CODE_SIGN_ENTITLEMENTS = fearless/WalletConnect.dev.entitlements; CODE_SIGN_IDENTITY = "Apple Distribution"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 7; @@ -19626,6 +19702,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "fearlesswallet-dev-adhoc"; SWIFT_ENABLE_EXPLICIT_MODULES = NO; + SWIFT_OBJC_BRIDGING_HEADER = "fearless/fearless-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 1; }; diff --git a/fearless.xcodeproj/xcshareddata/xcschemes/fearless.tests.xcscheme b/fearless.xcodeproj/xcshareddata/xcschemes/fearless.tests.xcscheme index 83640ec2b0..da6f1dfedc 100644 --- a/fearless.xcodeproj/xcshareddata/xcschemes/fearless.tests.xcscheme +++ b/fearless.xcodeproj/xcshareddata/xcschemes/fearless.tests.xcscheme @@ -48,9 +48,12 @@ - + + + + + - diff --git a/fearless.xcodeproj/xcshareddata/xcschemes/fearless.xcscheme b/fearless.xcodeproj/xcshareddata/xcschemes/fearless.xcscheme index b4999e827b..732d2d2027 100644 --- a/fearless.xcodeproj/xcshareddata/xcschemes/fearless.xcscheme +++ b/fearless.xcodeproj/xcshareddata/xcschemes/fearless.xcscheme @@ -82,8 +82,7 @@ bash \"${PROJECT_DIR}/scripts/spm-shared-features-fixes.sh\" \"${ buildConfiguration = "Debug"> - diff --git a/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift b/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift index 8876501dc3..a7ed1b659b 100644 --- a/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift +++ b/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift @@ -29,9 +29,27 @@ extension WalletConnectServiceDelegate { func didChange(sessions _: [Session]) {} } +enum WalletConnectGroupIdentifierResolver { + static let productionBundleIdentifier = "jp.co.soramitsu.fearlesswallet" + static let developmentBundleIdentifier = "jp.co.soramitsu.fearlesswallet.dev" + static let productionGroupIdentifier = "group.jp.co.soramitsu.fearlesswallet" + static let developmentGroupIdentifier = "group.jp.co.soramitsu.fearlesswallet.walletconnect" + + static func resolve(bundleIdentifier: String?) -> String? { + if bundleIdentifier == productionBundleIdentifier { + return productionGroupIdentifier + } + + if bundleIdentifier == developmentBundleIdentifier { + return developmentGroupIdentifier + } + + return nil + } +} + final class WalletConnectServiceImpl: WalletConnectService { static let shared = WalletConnectServiceImpl() - private static let walletConnectGroupIdentifier = "group.com.walletconnect.sdk" private var listeners: [WeakWrapper] = [] private var cancellablesBag = Set() @@ -41,6 +59,17 @@ final class WalletConnectServiceImpl: WalletConnectService { // MARK: - ApplicationServiceProtocol func setup() { + guard + let groupIdentifier = WalletConnectGroupIdentifierResolver.resolve( + bundleIdentifier: Bundle.main.bundleIdentifier + ) + else { + Logger.shared.error( + "WalletConnect setup skipped for an unsupported application identity" + ) + return + } + #if canImport(FearlessKeys) #if F_DEV let projectId = WalletConnectDebug.projectId @@ -51,7 +80,7 @@ final class WalletConnectServiceImpl: WalletConnectService { let projectId = WalletConnect.projectId #endif Networking.configure( - groupIdentifier: Self.walletConnectGroupIdentifier, + groupIdentifier: groupIdentifier, projectId: projectId, socketFactory: WalletConnectSocketFactory() ) diff --git a/fearless/Common/CoreData/CoreDataAliases.swift b/fearless/Common/CoreData/CoreDataAliases.swift index a9885ac577..4e9b6fa723 100644 --- a/fearless/Common/CoreData/CoreDataAliases.swift +++ b/fearless/Common/CoreData/CoreDataAliases.swift @@ -5,23 +5,39 @@ import Foundation import CoreData import RobinHood - // Lightweight stand-in for the private SSFAssetManagmentStorage pod. - // These classes only need to exist so the rest of the app can compile when - // the private pod is not available (e.g. in OSS builds or PRs). + // Runtime-compatible fallback for the unavailable SSFAssetManagmentStorage + // product. Objective-C names and managed properties must stay aligned with + // SubstrateDataModel_v8 so existing stores materialize the expected types. public enum SSFAssetManagmentStorageStub { + public enum CodingError: LocalizedError { + case unsupportedEntity(String) + + public var errorDescription: String? { + switch self { + case let .unsupportedEntity(entityName): + return "Core Data coding is unavailable for \(entityName)" + } + } + } + open class CoreDataStubObject: NSManagedObject, CoreDataCodable { - open func populate(from _: Decoder, using _: NSManagedObjectContext) throws {} + open func populate(from _: Decoder, using _: NSManagedObjectContext) throws { + throw CodingError.unsupportedEntity(entity.name ?? String(describing: type(of: self))) + } - open func encode(to _: Encoder) throws {} + open func encode(to _: Encoder) throws { + throw CodingError.unsupportedEntity(entity.name ?? String(describing: type(of: self))) + } } + @objc(CDChain) public class CDChain: CoreDataStubObject { @NSManaged public var rank: String? @NSManaged public var disabled: Bool @NSManaged public var chainId: String? @NSManaged public var parentId: String? @NSManaged public var name: String? - @NSManaged public var types: String? + @NSManaged public var types: URL? @NSManaged public var typesOverrideCommon: NSNumber? @NSManaged public var addressPrefix: Int16 @NSManaged public var icon: URL? @@ -41,10 +57,16 @@ import Foundation @NSManaged public var historyApiUrl: URL? @NSManaged public var crowdloansApiType: String? @NSManaged public var crowdloansApiUrl: URL? + @NSManaged public var pricingApiType: String? + @NSManaged public var pricingApiUrl: URL? + @NSManaged public var identityChain: String? + @NSManaged public var paraId: String? + @NSManaged public var isOrml: Bool @NSManaged public var xcmConfig: CDChainXcmConfig? @NSManaged public var explorers: NSSet? } + @objc(CDAsset) public class CDAsset: CoreDataStubObject { @NSManaged public var id: String? @NSManaged public var icon: URL? @@ -62,28 +84,101 @@ import Foundation @NSManaged public var ethereumType: String? @NSManaged public var priceProvider: CDPriceProvider? @NSManaged public var purchaseProviders: [String]? + @NSManaged public var chain: CDChain? + @NSManaged public var priceData: NSSet? } public class CDChainAsset: CoreDataStubObject {} + @objc(CDChainNode) public class CDChainNode: CoreDataStubObject { @NSManaged public var url: URL? @NSManaged public var name: String? @NSManaged public var apiKeyName: String? @NSManaged public var apiQueryName: String? + @NSManaged public var chain: CDChain? } + @objc(CDChainStorageItem) public class CDChainStorageItem: CoreDataStubObject { @NSManaged public var identifier: String? + @NSManaged public var data: Data? + + override public func populate(from decoder: Decoder, using _: NSManagedObjectContext) throws { + let container = try decoder.container(keyedBy: ChainStorageItem.CodingKeys.self) + + identifier = try container.decode(String.self, forKey: .identifier) + data = try container.decode(Data.self, forKey: .data) + } + + override public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: ChainStorageItem.CodingKeys.self) + + try container.encodeIfPresent(identifier, forKey: .identifier) + try container.encodeIfPresent(data, forKey: .data) + } + } + + @objc(CDRuntimeMetadataItem) + public class CDRuntimeMetadataItem: CoreDataStubObject { + private enum CodingKeys: String, CodingKey { + case chain + case version + case txVersion + case metadata + } + + @NSManaged public var identifier: String? + @NSManaged public var metadata: Data? + @NSManaged public var resolver: Data? + @NSManaged public var txVersion: Int32 + @NSManaged public var version: Int32 + + override public func populate(from decoder: Decoder, using _: NSManagedObjectContext) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + identifier = try container.decode(String.self, forKey: .chain) + metadata = try container.decode(Data.self, forKey: .metadata) + version = Int32(bitPattern: try container.decode(UInt32.self, forKey: .version)) + txVersion = Int32(bitPattern: try container.decode(UInt32.self, forKey: .txVersion)) + } + + override public func encode(to encoder: Encoder) throws { + guard let identifier, let metadata else { + return + } + + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(identifier, forKey: .chain) + try container.encode(UInt32(bitPattern: version), forKey: .version) + try container.encode(UInt32(bitPattern: txVersion), forKey: .txVersion) + try container.encode(metadata, forKey: .metadata) + } } - public class CDRuntimeMetadataItem: CoreDataStubObject {} public class CDAccountInfo: CoreDataStubObject { @NSManaged public var identifier: String? } + @objc(CDStashItem) public class CDStashItem: CoreDataStubObject { @NSManaged public var stash: String? @NSManaged public var controller: String? + + override public func populate(from decoder: Decoder, using _: NSManagedObjectContext) throws { + let stashItem = try StashItem(from: decoder) + + stash = stashItem.stash + controller = stashItem.controller + } + + override public func encode(to encoder: Encoder) throws { + guard let stash, let controller else { + return + } + + try StashItem(stash: stash, controller: controller).encode(to: encoder) + } } public class CDSingleValue: CoreDataStubObject {} @@ -140,6 +235,7 @@ import Foundation } public class CDAccountItem: CoreDataStubObject {} + @objc(CDPolkaswapRemoteSettings) public class CDPolkaswapRemoteSettings: CoreDataStubObject { @NSManaged public var version: String? @NSManaged public var availableSources: [String]? @@ -148,23 +244,130 @@ import Foundation @NSManaged public var xstusdId: String? } + @objc(CDPolkaswapDex) public class CDPolkaswapDex: CoreDataStubObject { @NSManaged public var name: String? @NSManaged public var code: Int32 @NSManaged public var assetId: String? } - public class CDPhishingItem: CoreDataStubObject {} - public class CDScamInfo: CoreDataStubObject {} - public class CDPriceData: CoreDataStubObject {} + @objc(CDPhishingItem) + public class CDPhishingItem: CoreDataStubObject { + @NSManaged public var identifier: String? + @NSManaged public var publicKey: String? + @NSManaged public var source: String? + + override public func populate(from decoder: Decoder, using _: NSManagedObjectContext) throws { + let phishingItem = try PhishingItem(from: decoder) + + identifier = phishingItem.identifier + source = phishingItem.source + publicKey = phishingItem.publicKey + } + + override public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: PhishingItem.CodingKeys.self) + + try container.encode(source, forKey: .source) + try container.encode(publicKey, forKey: .publicKey) + } + } + + @objc(CDScamInfo) + public class CDScamInfo: CoreDataStubObject { + @NSManaged public var address: String? + @NSManaged public var name: String? + @NSManaged public var subtype: String? + @NSManaged public var type: String? + + override public func populate(from decoder: Decoder, using _: NSManagedObjectContext) throws { + let container = try decoder.container(keyedBy: ScamInfo.CodingKeys.self) + + name = try container.decode(String.self, forKey: .name) + address = try container.decode(String.self, forKey: .address) + type = try container.decode(String.self, forKey: .type) + subtype = try container.decode(String.self, forKey: .subtype) + } + + override public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: ScamInfo.CodingKeys.self) + + try container.encode(name, forKey: .name) + try container.encode(address, forKey: .address) + try container.encode(type, forKey: .type) + try container.encode(subtype, forKey: .subtype) + } + } + + @objc(CDPriceData) + public class CDPriceData: CoreDataStubObject { + @NSManaged public var coingeckoPriceId: String? + @NSManaged public var currencyId: String? + @NSManaged public var fiatDayByChange: String? + @NSManaged public var price: String? + @NSManaged public var priceId: String? + @NSManaged public var asset: CDAsset? + } + + @objc(CDPriceProvider) public class CDPriceProvider: CoreDataStubObject { @NSManaged public var type: String? @NSManaged public var id: String? @NSManaged public var precision: String? + @NSManaged public var asset: CDAsset? + } + + @objc(CDContactItem) + public class CDContactItem: CoreDataStubObject { + @NSManaged public var identifier: String? + @NSManaged public var peerAddress: String? + @NSManaged public var peerName: String? + @NSManaged public var targetAddress: String? + @NSManaged public var updatedAt: Int64 + + override public func populate(from decoder: Decoder, using _: NSManagedObjectContext) throws { + let contact = try ContactItem(from: decoder) + + identifier = contact.identifier + peerAddress = contact.peerAddress + peerName = contact.peerName + targetAddress = contact.targetAddress + updatedAt = contact.updatedAt + } + + override public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: ContactItem.CodingKeys.self) + + try container.encodeIfPresent(peerAddress, forKey: .peerAddress) + try container.encodeIfPresent(peerName, forKey: .peerName) + try container.encodeIfPresent(targetAddress, forKey: .targetAddress) + try container.encode(updatedAt, forKey: .updatedAt) + } + } + + @objc(CDContact) + public class CDContact: CoreDataStubObject { + @NSManaged public var address: String? + @NSManaged public var chainId: String? + @NSManaged public var name: String? + + override public func populate(from decoder: Decoder, using _: NSManagedObjectContext) throws { + let container = try decoder.container(keyedBy: Contact.CodingKeys.self) + + name = try container.decode(String.self, forKey: .name) + address = try container.decode(String.self, forKey: .address) + chainId = try container.decode(String.self, forKey: .chainId) + } + + override public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: Contact.CodingKeys.self) + + try container.encode(name, forKey: .name) + try container.encode(address, forKey: .address) + try container.encode(chainId, forKey: .chainId) + } } - public class CDContactItem: CoreDataStubObject {} - public class CDContact: CoreDataStubObject {} public class CDCurrency: CoreDataStubObject { @NSManaged public var id: String? @NSManaged public var symbol: String? @@ -173,28 +376,36 @@ import Foundation @NSManaged public var isSelected: Bool } + @objc(CDExternalApi) public class CDExternalApi: CoreDataStubObject { @NSManaged public var type: String? @NSManaged public var types: NSArray? - @NSManaged public var url: URL? + @NSManaged public var url: String? + @NSManaged public var chain: CDChain? } + @objc(CDXcmAvailableDestination) public class CDXcmAvailableDestination: CoreDataStubObject { @NSManaged public var chainId: String? @NSManaged public var bridgeParachainId: String? @NSManaged public var assets: NSSet? + @NSManaged public var config: CDChainXcmConfig? } + @objc(CDXcmAvailableAsset) public class CDXcmAvailableAsset: CoreDataStubObject { @NSManaged public var id: String? + @NSManaged public var minAmount: String? @NSManaged public var symbol: String? } + @objc(CDChainXcmConfig) public class CDChainXcmConfig: CoreDataStubObject { @NSManaged public var xcmVersion: String? @NSManaged public var destWeightIsPrimitive: Bool @NSManaged public var availableAssets: NSSet? @NSManaged public var availableDestinations: NSSet? + @NSManaged public var chain: CDChain? } } @@ -216,23 +427,33 @@ public typealias CDChainAsset = SSFAssetManagmentStorage.CDChainAsset public typealias CDChainNode = SSFAssetManagmentStorage.CDChainNode public typealias CDChainStorageItem = SSFAssetManagmentStorage.CDChainStorageItem public typealias CDRuntimeMetadataItem = SSFAssetManagmentStorage.CDRuntimeMetadataItem -public typealias CDAccountInfo = SSFAssetManagmentStorage.CDAccountInfo public typealias CDStashItem = SSFAssetManagmentStorage.CDStashItem #if canImport(SSFSingleValueCache) public typealias CDSingleValue = SSFSingleValueCache.CDSingleValue #else public typealias CDSingleValue = SSFAssetManagmentStorage.CDSingleValue #endif -public typealias CDChainSettings = SSFAssetManagmentStorage.CDChainSettings -public typealias CDAssetVisibility = SSFAssetManagmentStorage.CDAssetVisibility -public typealias CDMetaAccount = SSFAssetManagmentStorage.CDMetaAccount -public typealias CDChainAccount = SSFAssetManagmentStorage.CDChainAccount -public typealias CDCustomChainNode = SSFAssetManagmentStorage.CDCustomChainNode +#if canImport(SSFAccountManagmentStorage) + public typealias CDAccountInfo = SSFAccountManagmentStorage.CDAccountInfo + public typealias CDChainSettings = SSFAccountManagmentStorage.CDChainSettings + public typealias CDAssetVisibility = SSFAccountManagmentStorage.CDAssetVisibility + public typealias CDMetaAccount = SSFAccountManagmentStorage.CDMetaAccount + public typealias CDChainAccount = SSFAccountManagmentStorage.CDChainAccount + public typealias CDCustomChainNode = SSFAccountManagmentStorage.CDCustomChainNode + public typealias CDCurrency = SSFAccountManagmentStorage.CDCurrency +#else + public typealias CDAccountInfo = SSFAssetManagmentStorage.CDAccountInfo + public typealias CDChainSettings = SSFAssetManagmentStorage.CDChainSettings + public typealias CDAssetVisibility = SSFAssetManagmentStorage.CDAssetVisibility + public typealias CDMetaAccount = SSFAssetManagmentStorage.CDMetaAccount + public typealias CDChainAccount = SSFAssetManagmentStorage.CDChainAccount + public typealias CDCustomChainNode = SSFAssetManagmentStorage.CDCustomChainNode + public typealias CDCurrency = SSFAssetManagmentStorage.CDCurrency +#endif public typealias CDPolkaswapRemoteSettings = SSFAssetManagmentStorage.CDPolkaswapRemoteSettings public typealias CDPhishingItem = SSFAssetManagmentStorage.CDPhishingItem public typealias CDPriceData = SSFAssetManagmentStorage.CDPriceData public typealias CDPriceProvider = SSFAssetManagmentStorage.CDPriceProvider -public typealias CDCurrency = SSFAssetManagmentStorage.CDCurrency public typealias CDContactItem = SSFAssetManagmentStorage.CDContactItem public typealias CDContact = SSFAssetManagmentStorage.CDContact public typealias CDAccountItem = SSFAssetManagmentStorage.CDAccountItem diff --git a/fearless/Common/CoreData/FearlessObjectiveCExceptionCatcher.h b/fearless/Common/CoreData/FearlessObjectiveCExceptionCatcher.h new file mode 100644 index 0000000000..ddb2b0c89d --- /dev/null +++ b/fearless/Common/CoreData/FearlessObjectiveCExceptionCatcher.h @@ -0,0 +1,27 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSErrorDomain const FearlessObjectiveCExceptionErrorDomain; + +typedef NS_ERROR_ENUM( + FearlessObjectiveCExceptionErrorDomain, + FearlessObjectiveCExceptionErrorCode +) { + FearlessObjectiveCExceptionErrorCodeRaised = 1 +}; + +typedef id _Nullable (^FearlessObjectiveCObjectReadBlock)(void); + +/// Executes an Objective-C object read behind an exception boundary. +/// +/// The returned error is intentionally generic. Exception names, reasons, +/// userInfo, call stacks, and the object payload must never cross this boundary. +@interface FearlessObjectiveCExceptionCatcher : NSObject + ++ (nullable id)performObjectRead:(FearlessObjectiveCObjectReadBlock)block + caughtError:(NSError * _Nullable * _Nullable)caughtError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/fearless/Common/CoreData/FearlessObjectiveCExceptionCatcher.m b/fearless/Common/CoreData/FearlessObjectiveCExceptionCatcher.m new file mode 100644 index 0000000000..672f7a17f4 --- /dev/null +++ b/fearless/Common/CoreData/FearlessObjectiveCExceptionCatcher.m @@ -0,0 +1,39 @@ +#import "FearlessObjectiveCExceptionCatcher.h" + +NSErrorDomain const FearlessObjectiveCExceptionErrorDomain = + @"jp.co.soramitsu.fearlesswallet.objective-c-exception"; + +@implementation FearlessObjectiveCExceptionCatcher + ++ (nullable id)performObjectRead:(FearlessObjectiveCObjectReadBlock)block + caughtError:(NSError * _Nullable * _Nullable)caughtError { + if (caughtError != NULL) { + *caughtError = nil; + } + + @try { + id value = block(); + + // A nil Objective-C result is conventionally interpreted by Swift as + // failure for NSError-imported methods. Use a private sentinel so a + // legitimate nil stored value remains distinguishable from an + // exception without manufacturing an error. + return value ?: [NSNull null]; + } @catch (NSException *exception) { + (void)exception; + + if (caughtError != NULL) { + *caughtError = [NSError + errorWithDomain:FearlessObjectiveCExceptionErrorDomain + code:FearlessObjectiveCExceptionErrorCodeRaised + userInfo:@{ + NSLocalizedDescriptionKey: + @"A stored value could not be decoded safely." + }]; + } + + return nil; + } +} + +@end diff --git a/fearless/Common/CoreData/ManagedObjectRuntimeClassRegistry.swift b/fearless/Common/CoreData/ManagedObjectRuntimeClassRegistry.swift new file mode 100644 index 0000000000..b358cd867c --- /dev/null +++ b/fearless/Common/CoreData/ManagedObjectRuntimeClassRegistry.swift @@ -0,0 +1,74 @@ +import CoreData +import Foundation + +#if canImport(SSFAssetManagmentStorage) + import SSFAssetManagmentStorage + private typealias RuntimeCDPolkaswapDex = + SSFAssetManagmentStorage.CDPolkaswapDex + private typealias RuntimeCDScamInfo = + SSFAssetManagmentStorage.CDScamInfo +#else + private typealias RuntimeCDPolkaswapDex = + SSFAssetManagmentStorageStub.CDPolkaswapDex + private typealias RuntimeCDScamInfo = + SSFAssetManagmentStorageStub.CDScamInfo +#endif + +/// Strong, production-used references to every managed-object class named by +/// the current bundled stores. This prevents normal Release dead stripping +/// from making a model class disappear only outside ENABLE_TESTABILITY builds. +enum ManagedObjectRuntimeClassRegistry { + static let substrateV8Classes: [NSManagedObject.Type] = [ + CDAsset.self, + CDChain.self, + CDChainNode.self, + CDChainStorageItem.self, + CDChainXcmConfig.self, + CDContact.self, + CDContactItem.self, + CDExternalApi.self, + CDPhishingItem.self, + RuntimeCDPolkaswapDex.self, + CDPolkaswapRemoteSettings.self, + CDPriceData.self, + CDPriceProvider.self, + CDRuntimeMetadataItem.self, + RuntimeCDScamInfo.self, + CDStashItem.self, + CDTransactionHistoryItem.self, + CDXcmAvailableAsset.self, + CDXcmAvailableDestination.self + ] + + static let userV11Classes: [NSManagedObject.Type] = [ + CDAccountInfo.self, + CDAssetVisibility.self, + CDChainAccount.self, + CDChainSettings.self, + CDCurrency.self, + CDCustomChainNode.self, + CDMetaAccount.self + ] + + static let classesByRuntimeName: [String: NSManagedObject.Type] = { + Dictionary( + uniqueKeysWithValues: (substrateV8Classes + userV11Classes).map { + (NSStringFromClass($0), $0) + } + ) + }() + + static func resolve(className: String) -> NSManagedObject.Type? { + if let registeredClass = classesByRuntimeName[className] { + return registeredClass + } + + if let registeredClass = classesByRuntimeName.first(where: { + $0.key.split(separator: ".").last.map(String.init) == className + })?.value { + return registeredClass + } + + return NSClassFromString(className) as? NSManagedObject.Type + } +} diff --git a/fearless/Common/CoreData/SafeTransformableValueReader.swift b/fearless/Common/CoreData/SafeTransformableValueReader.swift new file mode 100644 index 0000000000..670ef74972 --- /dev/null +++ b/fearless/Common/CoreData/SafeTransformableValueReader.swift @@ -0,0 +1,487 @@ +import CoreData +import Foundation +import SQLite3 + +enum SafeTransformableValueReaderError: LocalizedError, Equatable { + case objectiveCException + case unexpectedStoredType + + var errorDescription: String? { + switch self { + case .objectiveCException: + return "A stored value could not be decoded safely" + case .unexpectedStoredType: + return "A stored value has an unexpected type" + } + } +} + +enum SafeObjectiveCExceptionBoundary { + /// Preserves ordinary Swift errors while converting an Objective-C + /// exception into the single generic, payload-free storage error. + static func perform( + _ operation: @escaping () throws -> Void + ) throws { + var operationError: Error? + + do { + _ = try FearlessObjectiveCExceptionCatcher.performObjectRead { + do { + try operation() + } catch { + operationError = error + } + + return nil + } + } catch { + throw SafeTransformableValueReaderError.objectiveCException + } + + if let operationError { + throw operationError + } + } +} + +enum SafeTransformableValueReader { + static func readObject( + from object: NSManagedObject, + key: String + ) throws -> Any? { + do { + let value = try FearlessObjectiveCExceptionCatcher.performObjectRead { + object.value(forKey: key) + } + + return value is NSNull ? nil : value + } catch { + throw SafeTransformableValueReaderError.objectiveCException + } + } + + static func read( + from object: NSManagedObject, + key: String, + as _: Value.Type = Value.self + ) throws -> Value? { + let rawValue = try readObject(from: object, key: key) + + guard let rawValue else { + return nil + } + + guard let value = rawValue as? Value else { + throw SafeTransformableValueReaderError.unexpectedStoredType + } + + return value + } +} + +struct SQLiteTransformableArchiveColumn: Equatable { + let entityName: String + let attributeName: String + let isOptional: Bool + let valueTransformerName: String? +} + +enum SQLiteTransformableArchiveRepairError: LocalizedError, Equatable { + case invalidLimit + case unsafeIdentifier + case databaseUnavailable + case schemaMismatch(String, String) + case transformerUnavailable(String, String) + case sqliteOperationFailed(Int32) + case repairedValueCountOverflow + + var errorDescription: String? { + switch self { + case .invalidLimit: + return "The transformable archive byte limit is invalid" + case .unsafeIdentifier: + return "A transformable archive has an unsafe storage identifier" + case .databaseUnavailable: + return "The private Core Data store could not be opened safely" + case let .schemaMismatch(entityName, attributeName): + return """ + The private Core Data store is missing the expected \ + \(entityName).\(attributeName) archive column + """ + case let .transformerUnavailable(entityName, attributeName): + return """ + The private Core Data store cannot encode an empty \ + \(entityName).\(attributeName) archive + """ + case .sqliteOperationFailed: + return "The private Core Data archive repair failed safely" + case .repairedValueCountOverflow: + return "The private Core Data archive repair count overflowed" + } + } +} + +/// Bounds raw transformable BLOBs before Core Data can invoke a value +/// transformer. The caller must pass only model-verified, allowlisted columns +/// from a disposable SQLite store copy. +enum SQLiteTransformableArchivePreflight { + private static let sqliteTransient = unsafeBitCast( + -1, + to: sqlite3_destructor_type.self + ) + + @discardableResult + static func repairOversizedArchives( + at storeURL: URL, + columns: [SQLiteTransformableArchiveColumn], + maximumArchiveByteCount: Int + ) throws -> Int { + guard + maximumArchiveByteCount >= 0, + UInt64(maximumArchiveByteCount) <= UInt64(Int64.max) + else { + throw SQLiteTransformableArchiveRepairError.invalidLimit + } + + guard !columns.isEmpty else { + return 0 + } + + var database: OpaquePointer? + let openResult = sqlite3_open_v2( + storeURL.path, + &database, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX, + nil + ) + guard openResult == SQLITE_OK, let database else { + if let database { + sqlite3_close_v2(database) + } + throw SQLiteTransformableArchiveRepairError + .databaseUnavailable + } + defer { + sqlite3_close_v2(database) + } + + sqlite3_extended_result_codes(database, 1) + try execute("BEGIN IMMEDIATE TRANSACTION", in: database) + + do { + var repairedValueCount = 0 + for column in columns { + try validateSchema( + for: column, + in: database + ) + let repairedCount = try repairOversizedArchives( + in: column, + maximumArchiveByteCount: + maximumArchiveByteCount, + database: database + ) + let addition = repairedValueCount + .addingReportingOverflow(repairedCount) + guard !addition.overflow else { + throw SQLiteTransformableArchiveRepairError + .repairedValueCountOverflow + } + repairedValueCount = addition.partialValue + } + + try execute("COMMIT TRANSACTION", in: database) + return repairedValueCount + } catch { + _ = try? execute("ROLLBACK TRANSACTION", in: database) + throw error + } + } + + private static func validateSchema( + for column: SQLiteTransformableArchiveColumn, + in database: OpaquePointer + ) throws { + let tableName = try physicalIdentifier( + for: column.entityName + ) + let columnName = try physicalIdentifier( + for: column.attributeName + ) + + var tableStatement: OpaquePointer? + let tableSQL = """ + SELECT COUNT(*) FROM sqlite_master + WHERE type = 'table' AND name = ?1 COLLATE BINARY + """ + try prepare( + tableSQL, + statement: &tableStatement, + in: database + ) + guard let tableStatement else { + throw SQLiteTransformableArchiveRepairError + .sqliteOperationFailed(SQLITE_INTERNAL) + } + defer { + sqlite3_finalize(tableStatement) + } + + guard + sqlite3_bind_text( + tableStatement, + 1, + tableName, + -1, + sqliteTransient + ) == SQLITE_OK, + sqlite3_step(tableStatement) == SQLITE_ROW, + sqlite3_column_int64(tableStatement, 0) == 1, + sqlite3_step(tableStatement) == SQLITE_DONE + else { + throw SQLiteTransformableArchiveRepairError + .schemaMismatch( + column.entityName, + column.attributeName + ) + } + + let quotedTableName = try quotedIdentifier(tableName) + var columnStatement: OpaquePointer? + try prepare( + "PRAGMA table_info(\(quotedTableName))", + statement: &columnStatement, + in: database + ) + guard let columnStatement else { + throw SQLiteTransformableArchiveRepairError + .sqliteOperationFailed(SQLITE_INTERNAL) + } + defer { + sqlite3_finalize(columnStatement) + } + + var matchingColumns = 0 + while true { + let stepResult = sqlite3_step(columnStatement) + if stepResult == SQLITE_DONE { + break + } + guard stepResult == SQLITE_ROW else { + throw SQLiteTransformableArchiveRepairError + .sqliteOperationFailed(stepResult) + } + + guard + let rawName = sqlite3_column_text( + columnStatement, + 1 + ) + else { + throw SQLiteTransformableArchiveRepairError + .sqliteOperationFailed(SQLITE_CORRUPT) + } + let name = String(cString: rawName) + if name == columnName { + guard + let rawType = sqlite3_column_text( + columnStatement, + 2 + ), + String(cString: rawType).uppercased() == "BLOB" + else { + throw SQLiteTransformableArchiveRepairError + .schemaMismatch( + column.entityName, + column.attributeName + ) + } + matchingColumns += 1 + } + } + + guard matchingColumns == 1 else { + throw SQLiteTransformableArchiveRepairError + .schemaMismatch( + column.entityName, + column.attributeName + ) + } + } + + private static func repairOversizedArchives( + in column: SQLiteTransformableArchiveColumn, + maximumArchiveByteCount: Int, + database: OpaquePointer + ) throws -> Int { + let tableName = try quotedIdentifier( + physicalIdentifier(for: column.entityName) + ) + let columnName = try quotedIdentifier( + physicalIdentifier(for: column.attributeName) + ) + let sql = """ + UPDATE \(tableName) + SET \(columnName) = ?1 + WHERE \(columnName) IS NOT NULL + AND ( + typeof(\(columnName)) != 'blob' + OR length(\(columnName)) > ?2 + ) + """ + + var statement: OpaquePointer? + try prepare(sql, statement: &statement, in: database) + guard let statement else { + throw SQLiteTransformableArchiveRepairError + .sqliteOperationFailed(SQLITE_INTERNAL) + } + defer { + sqlite3_finalize(statement) + } + + let replacementResult: Int32 + if column.isOptional { + replacementResult = sqlite3_bind_null(statement, 1) + } else if column.valueTransformerName != nil { + let replacement = try emptyArchiveData(for: column) + guard + replacement.count <= maximumArchiveByteCount + else { + throw SQLiteTransformableArchiveRepairError + .invalidLimit + } + replacementResult = replacement.withUnsafeBytes { + rawBuffer in + + sqlite3_bind_blob( + statement, + 1, + rawBuffer.baseAddress, + Int32(rawBuffer.count), + sqliteTransient + ) + } + } else { + throw SQLiteTransformableArchiveRepairError + .transformerUnavailable( + column.entityName, + column.attributeName + ) + } + + guard + replacementResult == SQLITE_OK, + sqlite3_bind_int64( + statement, + 2, + Int64(maximumArchiveByteCount) + ) == SQLITE_OK + else { + throw SQLiteTransformableArchiveRepairError + .sqliteOperationFailed(sqlite3_errcode(database)) + } + + let stepResult = sqlite3_step(statement) + guard stepResult == SQLITE_DONE else { + throw SQLiteTransformableArchiveRepairError + .sqliteOperationFailed(stepResult) + } + + return Int(sqlite3_changes(database)) + } + + private static func emptyArchiveData( + for column: SQLiteTransformableArchiveColumn + ) throws -> Data { + guard + let transformerName = column.valueTransformerName, + let transformer = ValueTransformer( + forName: NSValueTransformerName( + rawValue: transformerName + ) + ), + let data = transformer.reverseTransformedValue( + NSArray() + ) as? Data + else { + throw SQLiteTransformableArchiveRepairError + .transformerUnavailable( + column.entityName, + column.attributeName + ) + } + + return data + } + + private static func execute( + _ sql: String, + in database: OpaquePointer + ) throws { + let result = sqlite3_exec( + database, + sql, + nil, + nil, + nil + ) + guard result == SQLITE_OK else { + throw SQLiteTransformableArchiveRepairError + .sqliteOperationFailed(result) + } + } + + private static func prepare( + _ sql: String, + statement: inout OpaquePointer?, + in database: OpaquePointer + ) throws { + let result = sqlite3_prepare_v2( + database, + sql, + -1, + &statement, + nil + ) + guard result == SQLITE_OK else { + throw SQLiteTransformableArchiveRepairError + .sqliteOperationFailed(result) + } + } + + private static func physicalIdentifier( + for modelIdentifier: String + ) throws -> String { + let identifier = "Z\(modelIdentifier.uppercased())" + guard isSafeIdentifier(identifier) else { + throw SQLiteTransformableArchiveRepairError + .unsafeIdentifier + } + return identifier + } + + private static func quotedIdentifier( + _ identifier: String + ) throws -> String { + guard isSafeIdentifier(identifier) else { + throw SQLiteTransformableArchiveRepairError + .unsafeIdentifier + } + return "\"\(identifier)\"" + } + + private static func isSafeIdentifier( + _ identifier: String + ) -> Bool { + !identifier.isEmpty && + identifier.unicodeScalars.allSatisfy { + scalar in + + let value = scalar.value + return value == 95 || + (48 ... 57).contains(value) || + (65 ... 90).contains(value) + } + } +} diff --git a/fearless/Common/Extension/Storage/CDAccountInfo+CoreDataCodable.swift b/fearless/Common/Extension/Storage/CDAccountInfo+CoreDataCodable.swift index bac0585997..99939d8b15 100644 --- a/fearless/Common/Extension/Storage/CDAccountInfo+CoreDataCodable.swift +++ b/fearless/Common/Extension/Storage/CDAccountInfo+CoreDataCodable.swift @@ -1,11 +1,11 @@ -#if canImport(SSFAssetManagmentStorage) +#if canImport(SSFAccountManagmentStorage) import Foundation import CoreData import RobinHood import IrohaCrypto - import SSFAssetManagmentStorage + import SSFAccountManagmentStorage - extension CDAccountInfo: CoreDataCodable { + extension CDAccountInfo: @retroactive CoreDataCodable { public func populate(from decoder: Decoder, using _: NSManagedObjectContext) throws { let container = try decoder.container(keyedBy: ChainStorageItem.CodingKeys.self) diff --git a/fearless/Common/Extension/Storage/CDAccountItem+CoreDataDecodable.swift b/fearless/Common/Extension/Storage/CDAccountItem+CoreDataDecodable.swift deleted file mode 100644 index ade33a1b40..0000000000 --- a/fearless/Common/Extension/Storage/CDAccountItem+CoreDataDecodable.swift +++ /dev/null @@ -1,14 +0,0 @@ -#if canImport(SSFAssetManagmentStorage) - import Foundation - import CoreData - import RobinHood - import IrohaCrypto - import SSFAssetManagmentStorage - - // TODO: Fix logic - extension CDMetaAccount: CoreDataCodable { - public func populate(from _: Decoder, using _: NSManagedObjectContext) throws {} - - public func encode(to _: Encoder) throws {} - } -#endif diff --git a/fearless/Common/Helpers/AccountProviderFactory.swift b/fearless/Common/Helpers/AccountProviderFactory.swift index 1064a6ba3b..ff805ea56c 100644 --- a/fearless/Common/Helpers/AccountProviderFactory.swift +++ b/fearless/Common/Helpers/AccountProviderFactory.swift @@ -1,3 +1,4 @@ +import CoreData import Foundation import IrohaCrypto import RobinHood @@ -34,15 +35,11 @@ final class AccountProviderFactory: AccountProviderFactoryProtocol { let mapper = MetaAccountMapper() let filter = NSPredicate.filterAccountItemByAccountId(accountId) - let repository: CoreDataRepository = storageFacade - .createRepository( - filter: filter, - sortDescriptors: [], - mapper: AnyCoreDataMapper(mapper) - ) + let repository = AccountRepositoryFactory(storageFacade: storageFacade) + .createMetaAccountRepository(for: filter, sortDescriptors: []) let hexAccountId = accountId.toHex() - let observable = CoreDataContextObservable( + let observable = TolerantMetaAccountContextObservable( service: storageFacade.databaseService, mapper: AnyCoreDataMapper(mapper), predicate: { [hexAccountId] metaAccount in @@ -58,7 +55,42 @@ final class AccountProviderFactory: AccountProviderFactoryProtocol { return StreamableProvider( source: AnyStreamableSource(EmptyStreamableSource()), - repository: AnyDataProviderRepository(repository), + repository: repository, + observable: AnyDataProviderRepositoryObservable(observable), + operationManager: operationManager + ) + } + + /// Builds the same observable managed-wallet stream as `StorageFacade.createStreamableProvider`, + /// while using the tolerant repository for its initial fetch and paging. + /// + /// The observable deliberately watches every wallet change. Consumers such as banners use an + /// `isSelected` repository filter but still need to observe a wallet becoming unselected. + func createManagedMetaAccountProvider( + for filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor] + ) -> StreamableProvider { + let mapper = ManagedMetaAccountMapper() + let repository = AccountRepositoryFactory(storageFacade: storageFacade) + .createManagedMetaAccountRepository( + for: filter, + sortDescriptors: sortDescriptors + ) + let observable = TolerantMetaAccountContextObservable( + service: storageFacade.databaseService, + mapper: AnyCoreDataMapper(mapper), + predicate: { _ in true } + ) + + observable.start { [weak self] error in + if let error { + self?.logger?.error("Did receive error: \(error)") + } + } + + return StreamableProvider( + source: AnyStreamableSource(EmptyStreamableSource()), + repository: repository, observable: AnyDataProviderRepositoryObservable(observable), operationManager: operationManager ) @@ -82,3 +114,422 @@ final class AccountProviderFactory: AccountProviderFactoryProtocol { } } } + +/// A Core Data observable that quarantines malformed wallet rows for their full lifecycle. +/// +/// RobinHood's generic observable drops mapper failures for inserts and updates, but emits deletes +/// directly from the raw identifier. A corrupt row that duplicates a healthy wallet identifier can +/// therefore remove the healthy item from a stream when that corrupt row is deleted. Tracking +/// successfully mapped rows by object ID makes deletes unambiguous. Aggregating every notification +/// by persistent identifier also makes same-identifier object handoffs independent of Core Data's +/// unordered notification sets. +final class TolerantMetaAccountContextObservable: + DataProviderRepositoryObservable { + private struct MappedObject { + let objectId: NSManagedObjectID + let model: Model? + } + + private enum ObjectMutation { + case replace(Model?) + case delete + } + + private struct InFlightDelivery { + let observerIdentifier: ObjectIdentifier + let identifiers: Set + } + + private let service: CoreDataServiceProtocol + private let mapper: AnyCoreDataMapper + private let predicate: (CDMetaAccount) -> Bool + private let processingQueue: DispatchQueue + + private var observers: [RepositoryObserver] = [] + private var trackedModels: [NSManagedObjectID: Model] = [:] + private var pendingReconciliationIdentifiers = Set() + // StreamableProvider can queue source callbacks behind its user-observer teardown. + // Reconcile identifiers whose serial source deliveries were not acknowledged first. + private var inFlightDeliveries: [UUID: InFlightDelivery] = [:] + private var notificationToken: NSObjectProtocol? + + init( + service: CoreDataServiceProtocol, + mapper: AnyCoreDataMapper, + predicate: @escaping (CDMetaAccount) -> Bool, + processingQueue: DispatchQueue? = nil + ) { + self.service = service + self.mapper = mapper + self.predicate = predicate + self.processingQueue = processingQueue ?? DispatchQueue( + label: "jp.co.fearless.wallet-observable.\(UUID().uuidString)", + qos: .utility + ) + } + + func start(completionBlock: @escaping (Error?) -> Void) { + service.performAsync { [weak self] optionalContext, optionalError in + guard let self else { + completionBlock(optionalError) + return + } + guard optionalError == nil, let context = optionalContext else { + completionBlock(optionalError) + return + } + + let token = NotificationCenter.default.addObserver( + forName: .NSManagedObjectContextDidSave, + object: context, + queue: nil + ) { [weak self] notification in + self?.didReceive(notification: notification) + } + self.notificationToken = token + + do { + let request = NSFetchRequest( + entityName: String(describing: CDMetaAccount.self) + ) + request.includesSubentities = false + let initialModels = try context.fetch(request).compactMap { + self.mappedObject(for: $0) + } + + self.processingQueue.async { + self.trackedModels = Dictionary( + uniqueKeysWithValues: initialModels.compactMap { + guard let model = $0.model else { + return nil + } + + return ($0.objectId, model) + } + ) + self.pendingReconciliationIdentifiers.removeAll() + self.inFlightDeliveries.removeAll() + completionBlock(nil) + } + } catch { + NotificationCenter.default.removeObserver(token) + self.notificationToken = nil + completionBlock(error) + } + } + } + + func stop(completionBlock: @escaping (Error?) -> Void) { + service.performAsync { [weak self] _, optionalError in + guard let self else { + completionBlock(optionalError) + return + } + + if let notificationToken = self.notificationToken { + NotificationCenter.default.removeObserver(notificationToken) + self.notificationToken = nil + } + + self.processingQueue.async { + self.trackedModels.removeAll() + self.pendingReconciliationIdentifiers.removeAll() + self.inFlightDeliveries.removeAll() + completionBlock(optionalError) + } + } + } + + func addObserver( + _ observer: AnyObject, + deliverOn queue: DispatchQueue, + executing updateBlock: @escaping ([DataProviderChange]) -> Void + ) { + processingQueue.async { + self.observers = self.observers.filter { $0.observer != nil } + + guard !self.observers.contains(where: { $0.observer === observer }) else { + return + } + + self.observers.append( + RepositoryObserver( + observer: observer, + queue: queue, + updateBlock: updateBlock + ) + ) + + let reconciliationChanges = self.reconciliationChanges( + for: self.pendingReconciliationIdentifiers + ) + self.pendingReconciliationIdentifiers.removeAll() + self.deliver(reconciliationChanges) + } + } + + func removeObserver(_ observer: AnyObject) { + processingQueue.async { + let observerIdentifier = ObjectIdentifier(observer) + let wasRegistered = self.observers.contains { + $0.observer === observer + } + self.observers = self.observers.filter { + $0.observer != nil && $0.observer !== observer + } + + if wasRegistered, self.observers.isEmpty { + let deliveryTokens = self.inFlightDeliveries.compactMap { + token, delivery in + delivery.observerIdentifier == observerIdentifier + ? token + : nil + } + for token in deliveryTokens { + guard let delivery = self.inFlightDeliveries.removeValue( + forKey: token + ) else { + continue + } + + self.pendingReconciliationIdentifiers.formUnion( + delivery.identifiers + ) + } + } + } + } + + private func didReceive(notification: Notification) { + let updatedObjects = metaAccounts( + in: notification, + userInfoKey: NSUpdatedObjectsKey + ).map(mappedObject) + let deletedObjectIds = metaAccounts( + in: notification, + userInfoKey: NSDeletedObjectsKey + ).map(\.objectID) + let insertedObjects = metaAccounts( + in: notification, + userInfoKey: NSInsertedObjectsKey + ).map(mappedObject) + + guard + !updatedObjects.isEmpty || + !deletedObjectIds.isEmpty || + !insertedObjects.isEmpty + else { + return + } + + processingQueue.async { + self.apply( + updatedObjects: updatedObjects, + deletedObjectIds: deletedObjectIds, + insertedObjects: insertedObjects + ) + } + } + + private func mappedObject(for entity: CDMetaAccount) -> MappedObject { + let model: Model? + if predicate(entity) { + model = try? mapper.transform(entity: entity) + } else { + model = nil + } + + return MappedObject( + objectId: entity.objectID, + model: model + ) + } + + private func metaAccounts( + in notification: Notification, + userInfoKey: String + ) -> [CDMetaAccount] { + guard let objects = notification.userInfo?[userInfoKey] as? NSSet else { + return [] + } + + return objects.allObjects.compactMap { $0 as? CDMetaAccount } + } + + private func apply( + updatedObjects: [MappedObject], + deletedObjectIds: [NSManagedObjectID], + insertedObjects: [MappedObject] + ) { + var mutations: [NSManagedObjectID: ObjectMutation] = [:] + for object in updatedObjects { + mutations[object.objectId] = .replace(object.model) + } + for object in insertedObjects { + mutations[object.objectId] = .replace(object.model) + } + for objectId in deletedObjectIds { + mutations[objectId] = .delete + } + + var affectedIdentifiers = Set() + for (objectId, mutation) in mutations { + if let previousModel = trackedModels[objectId] { + affectedIdentifiers.insert(previousModel.identifier) + } + + if case let .replace(model) = mutation, let model { + affectedIdentifiers.insert(model.identifier) + } + } + + let modelsBefore = aggregateModels(for: affectedIdentifiers) + + for (objectId, mutation) in mutations { + switch mutation { + case let .replace(model): + trackedModels[objectId] = model + case .delete: + trackedModels.removeValue(forKey: objectId) + } + } + + let modelsAfter = aggregateModels(for: affectedIdentifiers) + let changes = affectedIdentifiers.sorted().compactMap { identifier in + aggregateChange( + identifier: identifier, + before: modelsBefore[identifier], + after: modelsAfter[identifier] + ) + } + deliver(changes) + } + + private func aggregateModels( + for identifiers: Set + ) -> [String: Model] { + guard !identifiers.isEmpty else { + return [:] + } + + var models: [String: Model] = [:] + for (_, model) in trackedModels.sorted(by: objectIdOrder) { + guard + identifiers.contains(model.identifier), + models[model.identifier] == nil + else { + continue + } + + models[model.identifier] = model + } + + return models + } + + private func aggregateChange( + identifier: String, + before: Model?, + after: Model? + ) -> DataProviderChange? { + switch (before, after) { + case (nil, nil): + return nil + case (nil, let model?): + return .insert(newItem: model) + case (.some, nil): + return .delete(deletedIdentifier: identifier) + case let (.some, model?): + return .update(newItem: model) + } + } + + private func reconciliationChanges( + for identifiers: Set + ) -> [DataProviderChange] { + let currentModels = aggregateModels(for: identifiers) + + return identifiers.sorted().flatMap { identifier in + var changes: [DataProviderChange] = [ + .delete(deletedIdentifier: identifier) + ] + if let model = currentModels[identifier] { + changes.append(.insert(newItem: model)) + } + + return changes + } + } + + private func deliver(_ changes: [DataProviderChange]) { + guard !changes.isEmpty else { + return + } + + observers = observers.filter { $0.observer != nil } + guard !observers.isEmpty else { + pendingReconciliationIdentifiers.formUnion( + changes.map(changeIdentifier) + ) + return + } + + for observer in observers { + if processingQueue == observer.queue { + observer.updateBlock(changes) + } else { + guard let observerObject = observer.observer else { + continue + } + + let observerIdentifier = ObjectIdentifier(observerObject) + let identifiers = Set(changes.map(changeIdentifier)) + let deliveryToken = beginDelivery( + identifiers: identifiers, + to: observerIdentifier + ) + observer.queue.async { [weak self] in + observer.updateBlock(changes) + self?.finishDelivery(deliveryToken) + } + } + } + } + + private func beginDelivery( + identifiers: Set, + to observerIdentifier: ObjectIdentifier + ) -> UUID { + let token = UUID() + inFlightDeliveries[token] = InFlightDelivery( + observerIdentifier: observerIdentifier, + identifiers: identifiers + ) + return token + } + + private func finishDelivery(_ token: UUID) { + processingQueue.async { + self.inFlightDeliveries.removeValue(forKey: token) + } + } + + private func changeIdentifier( + _ change: DataProviderChange + ) -> String { + switch change { + case let .insert(model), let .update(model): + return model.identifier + case let .delete(identifier): + return identifier + } + } + + private func objectIdOrder( + _ lhs: (key: NSManagedObjectID, value: Model), + _ rhs: (key: NSManagedObjectID, value: Model) + ) -> Bool { + lhs.key.uriRepresentation().absoluteString < + rhs.key.uriRepresentation().absoluteString + } +} diff --git a/fearless/Common/Helpers/AccountRepositoryFactory.swift b/fearless/Common/Helpers/AccountRepositoryFactory.swift index 07dc5671ce..1c58085f93 100644 --- a/fearless/Common/Helpers/AccountRepositoryFactory.swift +++ b/fearless/Common/Helpers/AccountRepositoryFactory.swift @@ -29,43 +29,106 @@ final class AccountRepositoryFactory: AccountRepositoryFactoryProtocol { for filter: NSPredicate?, sortDescriptors: [NSSortDescriptor] ) -> AnyDataProviderRepository { - let mapper = MetaAccountMapper() - - let repository = storageFacade.createRepository( - filter: filter, - sortDescriptors: sortDescriptors, - mapper: AnyCoreDataMapper(mapper) + AnyDataProviderRepository( + createTolerantRepository( + filter: filter, + sortDescriptors: sortDescriptors, + project: \.wallet, + makeUpdate: { + MetaAccountSelectionModel( + identifier: $0.identifier, + wallet: $0, + isSelected: false, + order: ManagedMetaAccountModel.noOrder, + updatesWalletPayload: true, + updatesSelection: false + ) + } + ) ) - - return AnyDataProviderRepository(repository) } func createManagedMetaAccountRepository( for filter: NSPredicate?, sortDescriptors: [NSSortDescriptor] ) -> AnyDataProviderRepository { - let mapper = ManagedMetaAccountMapper() - - let repository = storageFacade.createRepository( - filter: filter, - sortDescriptors: sortDescriptors, - mapper: AnyCoreDataMapper(mapper) + AnyDataProviderRepository( + createTolerantRepository( + filter: filter, + sortDescriptors: sortDescriptors, + project: { projection in + projection.wallet.map { + ManagedMetaAccountModel( + info: $0, + isSelected: projection.isSelected, + order: projection.order + ) + } + }, + makeUpdate: { + MetaAccountSelectionModel( + identifier: $0.identifier, + wallet: $0.info, + isSelected: $0.isSelected, + order: $0.order, + updatesWalletPayload: true + ) + } + ) ) - - return AnyDataProviderRepository(repository) } func createAsyncMetaAccountRepository( for filter: NSPredicate?, sortDescriptors: [NSSortDescriptor] ) -> AsyncAnyRepository { - let mapper = MetaAccountMapper() - let repository = storageFacade.createAsyncRepository( - filter: filter, + let repository = createMetaAccountRepository( + for: filter, + sortDescriptors: sortDescriptors + ) + + return AsyncAnyRepository( + AsyncOperationBackedRepository(repository: repository) + ) + } + + private func createTolerantRepository( + filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor], + project: @escaping (MetaAccountSelectionModel) -> Model?, + makeUpdate: @escaping (Model) -> MetaAccountSelectionModel + ) -> TolerantMetaAccountRepository { + let supportedWalletFilter = NSPredicate( + format: "%K != nil AND %K != nil", + #keyPath(CDMetaAccount.substrateAccountId), + #keyPath(CDMetaAccount.substratePublicKey) + ) + let readFilter = filter.map { + NSCompoundPredicate( + andPredicateWithSubpredicates: [$0, supportedWalletFilter] + ) + } ?? supportedWalletFilter + let readRepository = storageFacade.createRepository( + filter: readFilter, sortDescriptors: sortDescriptors, - mapper: AnyCoreDataMapper(mapper) + mapper: AnyCoreDataMapper(MetaAccountSelectionMapper()) + ) + let writeRepository = storageFacade.createRepository( + mapper: AnyCoreDataMapper(MetaAccountSelectionMapper()) + ) + let deleteRepository = storageFacade.createRepository( + filter: filter, + sortDescriptors: [], + mapper: AnyCoreDataMapper(MetaAccountSelectionMapper()) + ) + + return TolerantMetaAccountRepository( + readRepository: readRepository, + writeRepository: writeRepository, + deleteRepository: deleteRepository, + project: project, + makeUpdate: makeUpdate ) - return AsyncAnyRepository(repository) } } @@ -73,9 +136,444 @@ extension AccountRepositoryFactory { static func createRepository( for storageFacade: StorageFacadeProtocol = UserDataStorageFacade.shared ) -> AnyDataProviderRepository { - let mapper = MetaAccountMapper() - let repository = storageFacade.createRepository(mapper: AnyCoreDataMapper(mapper)) + AccountRepositoryFactory(storageFacade: storageFacade) + .createMetaAccountRepository(for: nil, sortDescriptors: []) + } +} + +enum TolerantMetaAccountRepositoryError: LocalizedError, Equatable { + case invalidSliceRequest + + var errorDescription: String? { + switch self { + case .invalidSliceRequest: + return "The repository slice request has an unsupported shape or range" + } + } +} + +/// RobinHood keeps `RepositorySliceRequest` fields internal. Decode its reflected value through +/// one validated boundary so paging can happen after damaged rows have been projected out. +/// Any dependency shape change fails closed instead of silently returning the wrong page. +struct ValidatedRepositorySlice { + typealias ReflectedField = (label: String?, value: Any) + + let offset: Int + let count: Int + let reversed: Bool + + var isEmpty: Bool { + count == 0 + } + + init(request: RepositorySliceRequest) throws { + let mirror = Mirror(reflecting: request) + guard mirror.displayStyle == .struct else { + throw TolerantMetaAccountRepositoryError.invalidSliceRequest + } + + try self.init(reflectedFields: Array(mirror.children)) + } + + init(reflectedFields: [ReflectedField]) throws { + guard reflectedFields.count == 3 else { + throw TolerantMetaAccountRepositoryError.invalidSliceRequest + } + + var values: [String: Any] = [:] + let expectedLabels = Set(["offset", "count", "reversed"]) + + for field in reflectedFields { + guard + let label = field.label, + expectedLabels.contains(label), + values.updateValue(field.value, forKey: label) == nil + else { + throw TolerantMetaAccountRepositoryError.invalidSliceRequest + } + } + + guard + Set(values.keys) == expectedLabels, + let offset = values["offset"] as? Int, + let count = values["count"] as? Int, + let reversed = values["reversed"] as? Bool, + offset >= 0, + count >= 0 + else { + throw TolerantMetaAccountRepositoryError.invalidSliceRequest + } + + self.offset = offset + self.count = count + self.reversed = reversed + } +} + +private final class TolerantMetaAccountRepository: DataProviderRepositoryProtocol { + fileprivate typealias ProjectionRepository = CoreDataRepository< + MetaAccountSelectionModel, + CDMetaAccount + > + + private let readRepository: ProjectionRepository + private let writeRepository: ProjectionRepository + private let deleteRepository: ProjectionRepository + private let project: (MetaAccountSelectionModel) -> Model? + private let makeUpdate: (Model) -> MetaAccountSelectionModel + private let operationQueue = OperationQueue() + + fileprivate init( + readRepository: ProjectionRepository, + writeRepository: ProjectionRepository, + deleteRepository: ProjectionRepository, + project: @escaping (MetaAccountSelectionModel) -> Model?, + makeUpdate: @escaping (Model) -> MetaAccountSelectionModel + ) { + self.readRepository = readRepository + self.writeRepository = writeRepository + self.deleteRepository = deleteRepository + self.project = project + self.makeUpdate = makeUpdate + } + + func fetchOperation( + by modelIdsClosure: @escaping () throws -> [String], + options: RepositoryFetchOptions + ) -> BaseOperation<[Model]> { + ClosureOperation { + let identifiers = Set(try modelIdsClosure()) + let projections = try self.fetchAllVisibleProjections(options: options) + + return try self.projectModels( + projections.filter { identifiers.contains($0.identifier) } + ) + } + } + + func fetchOperation( + by modelIdClosure: @escaping () throws -> String, + options: RepositoryFetchOptions + ) -> BaseOperation { + ClosureOperation { + let identifier = try modelIdClosure() + let projections = try self.fetchAllVisibleProjections(options: options) + + return try self.projectModels( + projections.filter { $0.identifier == identifier } + ).first + } + } + + func fetchAllOperation( + with options: RepositoryFetchOptions + ) -> BaseOperation<[Model]> { + ClosureOperation { + try self.projectModels( + self.fetchAllVisibleProjections(options: options) + ) + } + } + + func fetchOperation( + by request: RepositorySliceRequest, + options: RepositoryFetchOptions + ) -> BaseOperation<[Model]> { + ClosureOperation { + let slice = try ValidatedRepositorySlice(request: request) + let visibleModels = try self.projectModels( + self.fetchAllVisibleProjections(options: options) + ) + let orderedModels = slice.reversed + ? Array(visibleModels.reversed()) + : visibleModels + + guard + !slice.isEmpty, + slice.offset < orderedModels.count + else { + return [] + } + + return Array( + orderedModels + .dropFirst(slice.offset) + .prefix(slice.count) + ) + } + } + + func saveOperation( + _ updateModelsBlock: @escaping () throws -> [Model], + _ deleteIdsBlock: @escaping () throws -> [String] + ) -> BaseOperation { + ClosureOperation { + let models = try updateModelsBlock() + let requestedDeleteIds = try deleteIdsBlock() + try self.save(models: models, requestedDeleteIds: requestedDeleteIds) + } + } + + func saveBatchOperation( + _ updateModelsBlock: @escaping () throws -> [Model], + _ deleteIdsBlock: @escaping () throws -> [String] + ) -> BaseOperation { + saveOperation(updateModelsBlock, deleteIdsBlock) + } + + func replaceOperation( + _ newModelsBlock: @escaping () throws -> [Model] + ) -> BaseOperation { + ClosureOperation { + let models = try newModelsBlock() + try self.validateUniqueIdentifiers(models.map(\.identifier)) + try self.validateNoUnsupportedCollisions(for: models.map(\.identifier)) + + let existingOperation = self.readRepository.fetchAllOperation( + with: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ) + let existing = try self.execute(existingOperation) + let replacementIds = Set(models.map(\.identifier)) + let supportedIdsToDelete: [String] = existing.compactMap { projection -> String? in + guard + projection.wallet != nil, + !replacementIds.contains(projection.identifier) + else { + return nil + } + + return projection.identifier + } + try self.validateUnambiguousStoredIdentifiers( + supportedIdsToDelete + ) + + try self.persist( + models: models, + deleteIds: supportedIdsToDelete + ) + } + } + + func fetchCountOperation() -> BaseOperation { + ClosureOperation { + let operation = self.readRepository.fetchAllOperation( + with: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ) + + return try self.projectModels(self.execute(operation)).count + } + } + + func deleteAllOperation() -> BaseOperation { + ClosureOperation { + let operation = self.deleteRepository.deleteAllOperation() + _ = try self.execute(operation) + } + } + + private func save( + models: [Model], + requestedDeleteIds: [String] + ) throws { + try validateUniqueIdentifiers(models.map(\.identifier)) + try validateNoUnsupportedCollisions(for: models.map(\.identifier)) + try validateUnambiguousStoredIdentifiers(requestedDeleteIds) + + let requestedDeleteIdSet = Set(requestedDeleteIds) + let visibleProjections = requestedDeleteIdSet.isEmpty + ? [] + : try fetchAllVisibleProjections( + options: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ) + let safeDeleteIds: [String] = visibleProjections.compactMap { projection -> String? in + guard + projection.wallet != nil, + requestedDeleteIdSet.contains(projection.identifier) + else { + return nil + } + + return projection.identifier + } + + try persist(models: models, deleteIds: safeDeleteIds) + } + + private func validateUniqueIdentifiers(_ identifiers: [String]) throws { + guard Set(identifiers).count == identifiers.count else { + throw SelectedWalletSettingsError.duplicateWalletIdentifier + } + } + + private func projectModels( + _ projections: [MetaAccountSelectionModel] + ) throws -> [Model] { + let models = projections.compactMap(project) + try validateUniqueIdentifiers(models.map(\.identifier)) + return models + } + + private func validateNoUnsupportedCollisions( + for identifiers: [String] + ) throws { + guard !identifiers.isEmpty else { + return + } + + let identifierSet = Set(identifiers) + let operation = writeRepository.fetchAllOperation( + with: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ) + let existing = try execute(operation).filter { + identifierSet.contains($0.identifier) + } + + guard Set(existing.map(\.identifier)).count == existing.count else { + throw SelectedWalletSettingsError.duplicateWalletIdentifier + } + + guard !existing.contains(where: { $0.wallet == nil }) else { + throw SelectedWalletSettingsError.unsupportedWalletIdentifierConflict + } + } + + private func validateUnambiguousStoredIdentifiers( + _ identifiers: [String] + ) throws { + let identifierSet = Set(identifiers) + guard !identifierSet.isEmpty else { + return + } + + let operation = writeRepository.fetchAllOperation( + with: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ) + let matchingProjections = try execute(operation).filter { + identifierSet.contains($0.identifier) + } + let projectionsByIdentifier = Dictionary( + grouping: matchingProjections, + by: \.identifier + ) + + guard projectionsByIdentifier.values.allSatisfy({ $0.count <= 1 }) else { + // CoreDataRepository deletes the first matching entity. Duplicate identifiers + // would therefore make deletion depend on persistent-store fetch order and could + // destroy a quarantined or unsupported wallet instead of its healthy sibling. + throw SelectedWalletSettingsError.duplicateWalletIdentifier + } + } + + private func fetchAllVisibleProjections( + options: RepositoryFetchOptions + ) throws -> [MetaAccountSelectionModel] { + let operation = readRepository.fetchAllOperation(with: options) + return try execute(operation) + } + + private func persist( + models: [Model], + deleteIds: [String] + ) throws { + let updates = models.map(makeUpdate) + let operation = writeRepository.saveOperation( + { updates }, + { deleteIds } + ) + + _ = try execute(operation) + } + + private func execute( + _ operation: BaseOperation + ) throws -> Result { + operationQueue.addOperations([operation], waitUntilFinished: true) + return try operation.extractNoCancellableResultData() + } +} + +private final class AsyncOperationBackedRepository: AsyncCoreDataRepository { + private let repository: AnyDataProviderRepository + private let operationQueue = OperationQueue() + + init(repository: AnyDataProviderRepository) { + self.repository = repository + } + + func fetch( + by modelIds: [String], + options: RepositoryFetchOptions + ) async throws -> [Model] { + try await execute( + repository.fetchOperation( + by: { modelIds }, + options: options + ) + ) + } + + func fetch( + by modelId: String, + options: RepositoryFetchOptions + ) async throws -> Model? { + try await execute( + repository.fetchOperation( + by: { modelId }, + options: options + ) + ) + } + + func fetchAll( + with options: RepositoryFetchOptions + ) async throws -> [Model] { + try await execute(repository.fetchAllOperation(with: options)) + } + + func save(models: [Model], deleteIds: [String]) async { + let operation = repository.saveOperation( + { models }, + { deleteIds } + ) + + await withCheckedContinuation { continuation in + operation.completionBlock = { + continuation.resume() + } + operationQueue.addOperation(operation) + } + } - return AnyDataProviderRepository(repository) + private func execute( + _ operation: BaseOperation + ) async throws -> Result { + try await withCheckedThrowingContinuation { continuation in + operation.completionBlock = { + do { + continuation.resume( + returning: try operation.extractNoCancellableResultData() + ) + } catch { + continuation.resume(throwing: error) + } + } + operationQueue.addOperation(operation) + } } } diff --git a/fearless/Common/Helpers/AssetModelMapper.swift b/fearless/Common/Helpers/AssetModelMapper.swift index a1517cc134..980bfb5ed0 100644 --- a/fearless/Common/Helpers/AssetModelMapper.swift +++ b/fearless/Common/Helpers/AssetModelMapper.swift @@ -51,7 +51,11 @@ extension AssetModelMapper: CoreDataMapperProtocol { } else { staking = nil } - let purchaseProviders: [SSFModels.PurchaseProvider]? = entity.purchaseProviders?.compactMap { + let storedPurchaseProviders: [String]? = try? SafeTransformableValueReader.read( + from: entity, + key: "purchaseProviders" + ) + let purchaseProviders: [SSFModels.PurchaseProvider]? = storedPurchaseProviders?.compactMap { SSFModels.PurchaseProvider(rawValue: $0) } diff --git a/fearless/Common/Helpers/ChainRepositoryFactory.swift b/fearless/Common/Helpers/ChainRepositoryFactory.swift index 0f35a5ff67..462af4b93c 100644 --- a/fearless/Common/Helpers/ChainRepositoryFactory.swift +++ b/fearless/Common/Helpers/ChainRepositoryFactory.swift @@ -1,3 +1,4 @@ +import CoreData import Foundation import RobinHood #if canImport(SSFAssetManagmentStorage) @@ -36,3 +37,629 @@ final class ChainRepositoryFactory { ) } } + +extension ChainRepositoryFactory { + func createMalformedChainCleanupOperation() -> BaseOperation { + ClosureOperation { [storageFacade] in + let semaphore = DispatchSemaphore(value: 0) + let result = ChainCleanupResultBox() + + storageFacade.databaseService.performAsync { context, error in + defer { semaphore.signal() } + + do { + if let error { + throw error + } + + guard let context else { + throw CoreDataRepositoryError.undefined + } + + // Cleanup traverses every persisted CDChain scalar and + // relationship. Treat that entire graph, including save, + // as one exception-safe transaction so a damaged generated + // getter cannot terminate cold boot or leave a partial + // quarantine/merge in the context. + try SafeObjectiveCExceptionBoundary.perform { + let request = NSFetchRequest( + entityName: String(describing: CDChain.self) + ) + let chains = try context.fetch(request) + self.cleanupMalformedChains( + chains, + in: context + ) + + if context.hasChanges { + try context.save() + } + } + + result.set(.success(())) + } catch { + // A damaged generated accessor can also be touched while + // Core Data unwinds a failed transaction. Keep rollback + // inside the same exception-safe contract so the recovery + // path cannot terminate the process. + try? SafeObjectiveCExceptionBoundary.perform { + context?.rollback() + } + result.set(.failure(error)) + } + } + + semaphore.wait() + return try result.get().get() + } + } + + private func cleanupMalformedChains( + _ chains: [CDChain], + in context: NSManagedObjectContext + ) { + var chainsByCanonicalIdentifier: [String: [CDChain]] = [:] + var chainsWithoutIdentifier: [CDChain] = [] + + for chain in chains { + guard let rawIdentifier = chain.chainId else { + chainsWithoutIdentifier.append(chain) + continue + } + + let canonicalIdentifier = rawIdentifier.trimmingCharacters( + in: .whitespacesAndNewlines + ) + + guard canonicalIdentifier.isNotEmpty else { + chainsWithoutIdentifier.append(chain) + continue + } + + chainsByCanonicalIdentifier[ + canonicalIdentifier, + default: [] + ].append(chain) + } + + var occupiedIdentifiers = Set( + chainsByCanonicalIdentifier.keys + ) + for chain in chainsWithoutIdentifier.sorted(by: { + $0.objectID.uriRepresentation().absoluteString + < $1.objectID.uriRepresentation().absoluteString + }) { + quarantineChain( + chain, + occupiedIdentifiers: &occupiedIdentifiers + ) + } + + for (canonicalIdentifier, collidingChains) in + chainsByCanonicalIdentifier { + let orderedChains = collidingChains.sorted { + $0.objectID.uriRepresentation().absoluteString + < $1.objectID.uriRepresentation().absoluteString + } + guard + let target = orderedChains.first(where: { + $0.chainId == canonicalIdentifier + }) ?? orderedChains.first + else { + continue + } + + for source in orderedChains where source !== target { + if let mergePlan = makeLosslessMergePlan( + from: source, + into: target + ) { + applyLosslessMerge( + mergePlan, + from: source, + into: target + ) + context.delete(source) + } else { + quarantineChain( + source, + occupiedIdentifiers: &occupiedIdentifiers + ) + } + } + + target.chainId = canonicalIdentifier + } + } + + private func makeLosslessMergePlan( + from source: CDChain, + into target: CDChain + ) -> ChainMergePlan? { + do { + let targetOptions: [String]? = + try SafeTransformableValueReader.read( + from: target, + key: "options" + ) + let sourceOptions: [String]? = + try SafeTransformableValueReader.read( + from: source, + key: "options" + ) + + guard + scalarValuesCanMerge( + from: source, + into: target, + sourceOptions: sourceOptions, + targetOptions: targetOptions + ), + target.xcmConfig == nil || + source.xcmConfig == nil || + target.xcmConfig === source.xcmConfig, + let targetNodeGraph = makeNodeGraph(for: target), + let sourceNodeGraph = makeNodeGraph(for: source), + nodeGraphsCanMerge( + sourceNodeGraph, + into: targetNodeGraph + ), + assetsCanMerge(from: source, into: target) + else { + return nil + } + + return ChainMergePlan( + targetOptions: targetOptions, + sourceOptions: sourceOptions, + targetNodeGraph: targetNodeGraph, + sourceNodeGraph: sourceNodeGraph, + sourceAssets: managedObjects( + in: source.assets, + as: CDAsset.self + ), + sourceExplorers: managedObjects( + in: source.explorers, + as: CDExternalApi.self + ) + ) + } catch { + return nil + } + } + + private func scalarValuesCanMerge( + from source: CDChain, + into target: CDChain, + sourceOptions: [String]?, + targetOptions: [String]? + ) -> Bool { + guard + !valuesConflict(target.rank, source.rank), + target.disabled == source.disabled, + !valuesConflict(target.parentId, source.parentId), + !valuesConflict(target.name, source.name), + !valuesConflict(target.types, source.types), + !valuesConflict( + target.typesOverrideCommon?.boolValue, + source.typesOverrideCommon?.boolValue + ), + target.addressPrefix == source.addressPrefix, + !valuesConflict(target.icon, source.icon), + target.isEthereumBased == source.isEthereumBased, + target.isTestnet == source.isTestnet, + target.hasCrowdloans == source.hasCrowdloans, + target.isTipRequired == source.isTipRequired, + !valuesConflict( + target.minimalAppVersion, + source.minimalAppVersion + ), + !valuesConflict(targetOptions, sourceOptions), + !valuesConflict(target.stakingApiType, source.stakingApiType), + !valuesConflict(target.stakingApiUrl, source.stakingApiUrl), + !valuesConflict(target.historyApiType, source.historyApiType), + !valuesConflict(target.historyApiUrl, source.historyApiUrl), + !valuesConflict( + target.crowdloansApiType, + source.crowdloansApiType + ), + !valuesConflict( + target.crowdloansApiUrl, + source.crowdloansApiUrl + ), + !valuesConflict(target.pricingApiType, source.pricingApiType), + !valuesConflict(target.pricingApiUrl, source.pricingApiUrl), + !valuesConflict(target.identityChain, source.identityChain), + !valuesConflict(target.paraId, source.paraId), + target.isOrml == source.isOrml + else { + return false + } + + return true + } + + private func valuesConflict( + _ target: Value?, + _ source: Value? + ) -> Bool { + guard let target, let source else { + return false + } + + return target != source + } +} + +private extension ChainRepositoryFactory { + private func makeNodeGraph(for chain: CDChain) -> ChainNodeGraph? { + let defaultNodes = managedObjects( + in: chain.nodes, + as: CDChainNode.self + ) + let customNodes = managedObjects( + in: chain.customNodes, + as: CDChainNode.self + ) + let rawSelectedNode = chain.selectedNode + let selectedNode = rawSelectedNode.flatMap { + isValidNode($0) ? $0 : nil + } + let orderedValidNodes = ( + defaultNodes.filter(isValidNode) + + customNodes.filter(isValidNode) + + [selectedNode].compactMap { $0 } + ).sorted { + $0.objectID.uriRepresentation().absoluteString + < $1.objectID.uriRepresentation().absoluteString + } + + var nodesByURL: [URL: CDChainNode] = [:] + var fingerprintsByURL: [URL: ChainNodeFingerprint] = [:] + + for node in orderedValidNodes { + guard + let url = node.url, + let fingerprint = nodeFingerprint(for: node) + else { + continue + } + + if let existing = fingerprintsByURL[url], + existing != fingerprint { + return nil + } + + if nodesByURL[url] == nil { + nodesByURL[url] = node + fingerprintsByURL[url] = fingerprint + } + } + + return ChainNodeGraph( + allDefaultNodes: defaultNodes, + allCustomNodes: customNodes, + rawSelectedNode: rawSelectedNode, + nodesByURL: nodesByURL, + fingerprintsByURL: fingerprintsByURL + ) + } + + private func nodeGraphsCanMerge( + _ source: ChainNodeGraph, + into target: ChainNodeGraph + ) -> Bool { + for (url, sourceFingerprint) in source.fingerprintsByURL { + if let targetFingerprint = target.fingerprintsByURL[url], + targetFingerprint != sourceFingerprint { + return false + } + } + + if let targetSelection = target.rawSelectedNode, + let sourceSelection = source.rawSelectedNode { + guard + targetSelection === sourceSelection || + ( + nodeFingerprint(for: targetSelection) != nil && + nodeFingerprint(for: targetSelection) == + nodeFingerprint(for: sourceSelection) + ) + else { + return false + } + } + + return true + } + + private func nodeFingerprint( + for node: CDChainNode + ) -> ChainNodeFingerprint? { + guard + let url = node.url, + let name = node.name, + ChainModelMapper.isUsableNodeURL(url), + name.trimmingCharacters( + in: .whitespacesAndNewlines + ).isNotEmpty + else { + return nil + } + + return ChainNodeFingerprint( + url: url, + name: name, + apiQueryName: node.apiQueryName, + apiKeyName: node.apiKeyName + ) + } + + private func assetsCanMerge( + from source: CDChain, + into target: CDChain + ) -> Bool { + let targetIdentifiers = validAssetIdentifiers(in: target.assets) + let sourceIdentifiers = validAssetIdentifiers(in: source.assets) + + guard + targetIdentifiers.count == + Set(targetIdentifiers).count, + sourceIdentifiers.count == + Set(sourceIdentifiers).count + else { + return false + } + + return Set(targetIdentifiers) + .isDisjoint(with: sourceIdentifiers) + } + + private func validAssetIdentifiers(in relationship: NSSet?) -> [String] { + managedObjects(in: relationship, as: CDAsset.self).compactMap { + guard + let identifier = $0.id, + identifier.trimmingCharacters( + in: .whitespacesAndNewlines + ).isNotEmpty + else { + return nil + } + + return identifier + } + } +} + +private extension ChainRepositoryFactory { + private func applyLosslessMerge( + _ plan: ChainMergePlan, + from source: CDChain, + into target: CDChain + ) { + mergeScalarValues(plan, from: source, into: target) + + var preferredNodesByURL = plan.targetNodeGraph.nodesByURL + let resolveNode: (CDChainNode) -> CDChainNode = { node in + guard + let url = node.url, + plan.sourceNodeGraph.fingerprintsByURL[url] != nil + else { + return node + } + + if let existingNode = preferredNodesByURL[url] { + return existingNode + } + + preferredNodesByURL[url] = node + return node + } + + var targetDefaultNodes = Set( + managedObjects(in: target.nodes, as: CDChainNode.self) + ) + for node in plan.sourceNodeGraph.allDefaultNodes { + targetDefaultNodes.insert(resolveNode(node)) + } + + var targetCustomNodes = Set( + managedObjects( + in: target.customNodes, + as: CDChainNode.self + ) + ) + for node in plan.sourceNodeGraph.allCustomNodes { + targetCustomNodes.insert(resolveNode(node)) + } + + if plan.targetNodeGraph.rawSelectedNode == nil, + let sourceSelectedNode = + plan.sourceNodeGraph.rawSelectedNode { + target.selectedNode = resolveNode(sourceSelectedNode) + } + + target.nodes = NSSet(set: targetDefaultNodes) + target.customNodes = NSSet(set: targetCustomNodes) + + var targetAssets = Set( + managedObjects(in: target.assets, as: CDAsset.self) + ) + targetAssets.formUnion(plan.sourceAssets) + target.assets = NSSet(set: targetAssets) + + var targetExplorers = Set( + managedObjects( + in: target.explorers, + as: CDExternalApi.self + ) + ) + targetExplorers.formUnion(plan.sourceExplorers) + target.explorers = NSSet(set: targetExplorers) + + if target.xcmConfig == nil { + target.xcmConfig = source.xcmConfig + } + + source.nodes = NSSet() + source.customNodes = NSSet() + source.selectedNode = nil + source.assets = NSSet() + source.explorers = NSSet() + source.xcmConfig = nil + } + + private func mergeScalarValues( + _ plan: ChainMergePlan, + from source: CDChain, + into target: CDChain + ) { + if target.rank == nil { + target.rank = source.rank + } + if target.parentId == nil { + target.parentId = source.parentId + } + if target.name == nil { + target.name = source.name + } + if target.types == nil { + target.types = source.types + } + if target.typesOverrideCommon == nil { + target.typesOverrideCommon = source.typesOverrideCommon + } + if target.icon == nil { + target.icon = source.icon + } + if target.minimalAppVersion == nil { + target.minimalAppVersion = source.minimalAppVersion + } + if plan.targetOptions == nil, let sourceOptions = plan.sourceOptions { + target.setValue( + NSArray(array: sourceOptions), + forKey: "options" + ) + } + if target.stakingApiType == nil { + target.stakingApiType = source.stakingApiType + } + if target.stakingApiUrl == nil { + target.stakingApiUrl = source.stakingApiUrl + } + if target.historyApiType == nil { + target.historyApiType = source.historyApiType + } + if target.historyApiUrl == nil { + target.historyApiUrl = source.historyApiUrl + } + if target.crowdloansApiType == nil { + target.crowdloansApiType = source.crowdloansApiType + } + if target.crowdloansApiUrl == nil { + target.crowdloansApiUrl = source.crowdloansApiUrl + } + if target.pricingApiType == nil { + target.pricingApiType = source.pricingApiType + } + if target.pricingApiUrl == nil { + target.pricingApiUrl = source.pricingApiUrl + } + if target.identityChain == nil { + target.identityChain = source.identityChain + } + if target.paraId == nil { + target.paraId = source.paraId + } + } + + private func quarantineChain( + _ chain: CDChain, + occupiedIdentifiers: inout Set + ) { + let baseIdentifier = + ChainModelMapper.quarantinedChainIdentifierPrefix + + chain.objectID.uriRepresentation().absoluteString + var identifier = baseIdentifier + var collisionIndex = 0 + + while occupiedIdentifiers.contains(identifier) { + collisionIndex += 1 + identifier = "\(baseIdentifier)#\(collisionIndex)" + } + + chain.chainId = identifier + occupiedIdentifiers.insert(identifier) + chain.disabled = true + + if chain.name? + .trimmingCharacters(in: .whitespacesAndNewlines) + .isEmpty != false { + chain.name = ChainModelMapper.quarantinedChainName + } + } + + private func managedObjects( + in relationship: NSSet?, + as _: Object.Type + ) -> [Object] { + relationship?.compactMap { $0 as? Object } ?? [] + } + + private func isValidNode(_ node: CDChainNode) -> Bool { + guard + let url = node.url, + ChainModelMapper.isUsableNodeURL(url), + let name = node.name, + name.trimmingCharacters( + in: .whitespacesAndNewlines + ).isNotEmpty + else { + return false + } + + return true + } +} + +private struct ChainMergePlan { + let targetOptions: [String]? + let sourceOptions: [String]? + let targetNodeGraph: ChainNodeGraph + let sourceNodeGraph: ChainNodeGraph + let sourceAssets: [CDAsset] + let sourceExplorers: [CDExternalApi] +} + +private struct ChainNodeGraph { + let allDefaultNodes: [CDChainNode] + let allCustomNodes: [CDChainNode] + let rawSelectedNode: CDChainNode? + let nodesByURL: [URL: CDChainNode] + let fingerprintsByURL: [URL: ChainNodeFingerprint] +} + +private struct ChainNodeFingerprint: Equatable { + let url: URL + let name: String + let apiQueryName: String? + let apiKeyName: String? +} + +private final class ChainCleanupResultBox: @unchecked Sendable { + private let lock = NSLock() + private var result: Result? + + func set(_ result: Result) { + lock.lock() + self.result = result + lock.unlock() + } + + func get() -> Result { + lock.lock() + defer { lock.unlock() } + + return result ?? .failure(CoreDataRepositoryError.undefined) + } +} diff --git a/fearless/Common/Helpers/EthereumNodeFetching.swift b/fearless/Common/Helpers/EthereumNodeFetching.swift index 51749b2b89..ba08a2d797 100644 --- a/fearless/Common/Helpers/EthereumNodeFetching.swift +++ b/fearless/Common/Helpers/EthereumNodeFetching.swift @@ -95,14 +95,21 @@ enum EthereumChain: String { } } -final class EthereumNodeFetching { +protocol EthereumNodeFetchingProtocol { + func getNode(for chain: ChainModel) throws -> Web3.Eth +} + +final class EthereumNodeFetching: EthereumNodeFetchingProtocol { func getNode(for chain: ChainModel) throws -> Web3.Eth { if let https = try? getHttps(for: chain) { return https } - let randomWssNode = chain.nodes.filter { $0.url.absoluteString.contains("wss") }.randomElement() - let hasSelectedWssNode = chain.selectedNode?.url.absoluteString.contains("wss") == true + let randomWssNode = chain.nodes.filter { + $0.url.scheme?.lowercased() == "wss" + }.randomElement() + let hasSelectedWssNode = + chain.selectedNode?.url.scheme?.lowercased() == "wss" let node = hasSelectedWssNode ? chain.selectedNode : randomWssNode guard var wssURL = node?.url else { @@ -119,9 +126,14 @@ final class EthereumNodeFetching { } func getHttps(for chain: ChainModel) throws -> Web3.Eth { - let randomWssNode = chain.nodes.filter { $0.url.absoluteString.contains("https") }.randomElement() - let hasSelectedWssNode = chain.selectedNode?.url.absoluteString.contains("https") == true - let node = hasSelectedWssNode ? chain.selectedNode : randomWssNode + let randomHttpsNode = chain.nodes.filter { + $0.url.scheme?.lowercased() == "https" + }.randomElement() + let hasSelectedHttpsNode = + chain.selectedNode?.url.scheme?.lowercased() == "https" + let node = hasSelectedHttpsNode + ? chain.selectedNode + : randomHttpsNode guard let httpsURL = node?.url else { throw ConvenienceError(error: "cannot obtain eth https url for chain: \(chain.name)") diff --git a/fearless/Common/Model/ChainRegistry/ChainModel.swift b/fearless/Common/Model/ChainRegistry/ChainModel.swift index 57c1bd0cdc..a83dfd0e5d 100644 --- a/fearless/Common/Model/ChainRegistry/ChainModel.swift +++ b/fearless/Common/Model/ChainRegistry/ChainModel.swift @@ -3,6 +3,79 @@ import SSFModels import RobinHood extension ChainModel { + func replacingNodeConfiguration( + nodes: Set, + selectedNode: ChainNodeModel?, + customNodes: Set? + ) -> ChainModel { + ChainModel( + rank: rank, + disabled: disabled, + chainId: chainId, + parentId: parentId, + paraId: paraId, + name: name, + assets: assets, + xcm: xcm, + nodes: nodes, + addressPrefix: addressPrefix, + types: types, + icon: icon, + options: options, + externalApi: externalApi, + selectedNode: selectedNode, + customNodes: customNodes, + iosMinAppVersion: iosMinAppVersion, + identityChain: identityChain + ) + } + + func replacingNodes(_ nodes: Set) -> ChainModel { + ChainModel( + rank: rank, + disabled: disabled, + chainId: chainId, + parentId: parentId, + paraId: paraId, + name: name, + assets: assets, + xcm: xcm, + nodes: nodes, + addressPrefix: addressPrefix, + types: types, + icon: icon, + options: options, + externalApi: externalApi, + selectedNode: selectedNode, + customNodes: customNodes, + iosMinAppVersion: iosMinAppVersion, + identityChain: identityChain + ) + } + + func replacingDisabled(_ disabled: Bool) -> ChainModel { + ChainModel( + rank: rank, + disabled: disabled, + chainId: chainId, + parentId: parentId, + paraId: paraId, + name: name, + assets: assets, + xcm: xcm, + nodes: nodes, + addressPrefix: addressPrefix, + types: types, + icon: icon, + options: options, + externalApi: externalApi, + selectedNode: selectedNode, + customNodes: customNodes, + iosMinAppVersion: iosMinAppVersion, + identityChain: identityChain + ) + } + var isSupported: Bool { AppVersion.stringValue?.versionLowerThan(iosMinAppVersion) == false } diff --git a/fearless/Common/Model/RuntimeMetadataItem.swift b/fearless/Common/Model/RuntimeMetadataItem.swift index 2e48b2c5ff..cab8dff367 100644 --- a/fearless/Common/Model/RuntimeMetadataItem.swift +++ b/fearless/Common/Model/RuntimeMetadataItem.swift @@ -1,3 +1,4 @@ +import CoreData import Foundation import RobinHood import SSFUtils @@ -52,3 +53,58 @@ extension RuntimeMetadataItem: Identifiable { } extension RuntimeMetadataItem: RuntimeMetadataItemProtocol {} + +/// Keeps the generic Codable mapper's valid serialization behavior while +/// converting damaged Core Data getter exceptions into a catchable, +/// payload-free Swift error during runtime hot boot. +final class RuntimeMetadataMapper: CoreDataMapperProtocol { + typealias DataProviderModel = RuntimeMetadataItem + typealias CoreDataEntity = CDRuntimeMetadataItem + + private let mapper = + CodableCoreDataMapper< + RuntimeMetadataItem, + CDRuntimeMetadataItem + >() + + var entityIdentifierFieldName: String { + mapper.entityIdentifierFieldName + } + + func transform( + entity: CDRuntimeMetadataItem + ) throws -> RuntimeMetadataItem { + var item: RuntimeMetadataItem? + + try SafeObjectiveCExceptionBoundary.perform { + item = try self.mapper.transform(entity: entity) + } + + guard let item else { + throw SafeTransformableValueReaderError + .objectiveCException + } + + return item + } + + func populate( + entity: CDRuntimeMetadataItem, + from model: RuntimeMetadataItem, + using context: NSManagedObjectContext + ) throws { + try SafeObjectiveCExceptionBoundary.perform { + try self.mapper.populate( + entity: entity, + from: model, + using: context + ) + } + } + + func dict( + for model: RuntimeMetadataItem + ) throws -> [String: Any] { + try mapper.dict(for: model) + } +} diff --git a/fearless/Common/Model/UniversalWalletAccountAddressResolver.swift b/fearless/Common/Model/UniversalWalletAccountAddressResolver.swift index 897aa09f9a..20675225fd 100644 --- a/fearless/Common/Model/UniversalWalletAccountAddressResolver.swift +++ b/fearless/Common/Model/UniversalWalletAccountAddressResolver.swift @@ -25,6 +25,40 @@ enum UniversalWalletChainAccountSupport { equivalentChainIds(for: chainId) != nil } + /// Returns the stable storage identity for a universal-wallet chain alias. + /// + /// Non-universal chain identifiers are intentionally returned unchanged: + /// their alias semantics belong to the remote registry and must not be + /// guessed during migration or stored-wallet validation. + static func canonicalChainId(for chainId: String) -> String { + switch chainId.lowercased() { + case UniversalWalletRegistry.bitcoinMainnet.chainId, + UniversalWalletRegistry.bitcoinMainnet.id: + return UniversalWalletRegistry.bitcoinMainnet.chainId + case UniversalWalletRegistry.bitcoinTestnet.chainId, + UniversalWalletRegistry.bitcoinTestnet.id: + return UniversalWalletRegistry.bitcoinTestnet.chainId + case UniversalWalletRegistry.solanaMainnet.chainId, + UniversalWalletRegistry.solanaMainnet.id: + return UniversalWalletRegistry.solanaMainnet.chainId + case UniversalWalletRegistry.solanaDevnet.chainId, + UniversalWalletRegistry.solanaDevnet.id: + return UniversalWalletRegistry.solanaDevnet.chainId + case TonChainSelection.mainnetChainId, + UniversalWalletRegistry.tonMainnetRegistryEntry.chainId, + UniversalWalletRegistry.tonMainnetRegistryEntry.id: + return UniversalWalletRegistry.tonMainnetRegistryEntry.chainId + case UniversalWalletRegistry.taira.chainId, + UniversalWalletRegistry.taira.id: + return UniversalWalletRegistry.taira.chainId + case UniversalWalletRegistry.nexus.chainId, + UniversalWalletRegistry.nexus.id: + return UniversalWalletRegistry.nexus.chainId + default: + return chainId + } + } + static func chainId(_ storedChainId: String, matches requestedChainId: String) -> Bool { guard let equivalentIds = equivalentChainIds(for: requestedChainId) else { return storedChainId == requestedChainId diff --git a/fearless/Common/Services/ChainRegistry/ChainRegistry.swift b/fearless/Common/Services/ChainRegistry/ChainRegistry.swift index bedd59f67c..5fd143d037 100644 --- a/fearless/Common/Services/ChainRegistry/ChainRegistry.swift +++ b/fearless/Common/Services/ChainRegistry/ChainRegistry.swift @@ -16,15 +16,212 @@ import HTTPTypes enum TonAPITransportError: Error { case invalidRequestURL(path: String, method: HTTPRequest.Method, baseURL: URL) case notHTTPResponse(URLResponse) + case missingResponse + case responseTooLarge(actualBytes: Int, maximumBytes: Int) } -private final class TonAPIURLSessionTransport: ClientTransport, @unchecked Sendable { - private let session: URLSession +enum TonAPITransportPolicy { + static let requestTimeout: TimeInterval = 15 + static let resourceTimeout: TimeInterval = 30 + static let maximumResponseBytes = 2 * 1024 * 1024 + static let maximumRequestBodyBytes = 1 * 1024 * 1024 + static let followsRedirects = false +} + +/// Authentication-bearing API calls must never follow a redirect because Foundation otherwise +/// decides header forwarding after the server has already selected the next origin. +final class TonAPINoRedirectDelegate: NSObject, URLSessionTaskDelegate, @unchecked Sendable { + static func redirectedRequest(_: URLRequest) -> URLRequest? { + nil + } + + func urlSession( + _: URLSession, + task _: URLSessionTask, + willPerformHTTPRedirection _: HTTPURLResponse, + newRequest request: URLRequest, + completionHandler: @escaping (URLRequest?) -> Void + ) { + completionHandler(Self.redirectedRequest(request)) + } +} + +final class TonAPIBoundedSessionDelegate: NSObject, URLSessionDataDelegate, @unchecked Sendable { + private final class RequestCancellationState: @unchecked Sendable { + let lock = NSLock() + var isCancelled = false + } + + private struct RequestState { + var data = Data() + var response: URLResponse? + let continuation: CheckedContinuation<(Data, URLResponse), Error> + } + + private let maximumResponseBytes: Int + private let lock = NSLock() + private var states: [Int: RequestState] = [:] + + init(maximumResponseBytes: Int) { + self.maximumResponseBytes = maximumResponseBytes + } + + var inFlightRequestCount: Int { + lock.lock() + defer { lock.unlock() } + return states.count + } + + func data(for request: URLRequest, session: URLSession) async throws -> (Data, URLResponse) { + let task = session.dataTask(with: request) + let cancellationState = RequestCancellationState() + + return try await withTaskCancellationHandler { + try await withCheckedThrowingContinuation { continuation in + cancellationState.lock.lock() + let wasCancelled = cancellationState.isCancelled + if !wasCancelled { + lock.lock() + states[task.taskIdentifier] = RequestState(continuation: continuation) + lock.unlock() + } + cancellationState.lock.unlock() + + if wasCancelled { + task.cancel() + continuation.resume(throwing: CancellationError()) + } else { + task.resume() + } + } + } onCancel: { + self.cancel(task: task, cancellationState: cancellationState) + } + } + + func urlSession( + _: URLSession, + task _: URLSessionTask, + willPerformHTTPRedirection _: HTTPURLResponse, + newRequest _: URLRequest, + completionHandler: @escaping (URLRequest?) -> Void + ) { + completionHandler(nil) + } + + func urlSession( + _: URLSession, + dataTask: URLSessionDataTask, + didReceive response: URLResponse, + completionHandler: @escaping (URLSession.ResponseDisposition) -> Void + ) { + if response.expectedContentLength > Int64(maximumResponseBytes) { + resolveOversized(task: dataTask, actualBytes: Int(response.expectedContentLength)) + completionHandler(.cancel) + return + } + + lock.lock() + if var state = states[dataTask.taskIdentifier] { + state.response = response + states[dataTask.taskIdentifier] = state + } + lock.unlock() + completionHandler(.allow) + } + + func urlSession(_: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { + var oversizedActual: Int? + lock.lock() + if var state = states[dataTask.taskIdentifier] { + let (nextCount, overflowed) = state.data.count.addingReportingOverflow(data.count) + if overflowed || nextCount > maximumResponseBytes { + oversizedActual = overflowed ? Int.max : nextCount + } else { + state.data.append(data) + states[dataTask.taskIdentifier] = state + } + } + lock.unlock() + + if let oversizedActual { + resolveOversized(task: dataTask, actualBytes: oversizedActual) + dataTask.cancel() + } + } + + func urlSession( + _: URLSession, + task: URLSessionTask, + didCompleteWithError error: Error? + ) { + lock.lock() + let state = states.removeValue(forKey: task.taskIdentifier) + lock.unlock() + guard let state else { + return + } + + if let error { + state.continuation.resume(throwing: error) + } else if let response = state.response { + state.continuation.resume(returning: (state.data, response)) + } else { + state.continuation.resume(throwing: TonAPITransportError.missingResponse) + } + } + + private func resolveOversized(task: URLSessionTask, actualBytes: Int) { + lock.lock() + let state = states.removeValue(forKey: task.taskIdentifier) + lock.unlock() + state?.continuation.resume( + throwing: TonAPITransportError.responseTooLarge( + actualBytes: actualBytes, + maximumBytes: maximumResponseBytes + ) + ) + } + + private func cancel( + task: URLSessionTask, + cancellationState: RequestCancellationState + ) { + cancellationState.lock.lock() + cancellationState.isCancelled = true + lock.lock() + let state = states.removeValue(forKey: task.taskIdentifier) + lock.unlock() + cancellationState.lock.unlock() + + task.cancel() + state?.continuation.resume(throwing: CancellationError()) + } +} - init(configuration: URLSessionConfiguration = .default) { - session = URLSession(configuration: configuration) +final class TonAPIURLSessionTransport: ClientTransport, @unchecked Sendable { + private let session: URLSession + private let delegate: TonAPIBoundedSessionDelegate + + init(configuration: URLSessionConfiguration? = nil) { + let configuration = configuration ?? .ephemeral + configuration.timeoutIntervalForRequest = TonAPITransportPolicy.requestTimeout + configuration.timeoutIntervalForResource = TonAPITransportPolicy.resourceTimeout + configuration.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData + configuration.urlCache = nil + configuration.httpCookieStorage = nil + delegate = TonAPIBoundedSessionDelegate( + maximumResponseBytes: TonAPITransportPolicy.maximumResponseBytes + ) + session = URLSession( + configuration: configuration, + delegate: delegate, + delegateQueue: nil + ) } + var inFlightRequestCount: Int { delegate.inFlightRequestCount } + func send( _ request: HTTPRequest, body: HTTPBody?, @@ -34,7 +231,7 @@ private final class TonAPIURLSessionTransport: ClientTransport, @unchecked Senda var urlRequest = try await URLRequest(request, body: body, baseURL: baseURL) urlRequest.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData - let (data, response) = try await session.data(for: urlRequest) + let (data, response) = try await delegate.data(for: urlRequest, session: session) let httpResponse = try HTTPResponse.from(urlResponse: response) let responseBody: HTTPBody? = data.isEmpty ? nil : HTTPBody(data) return (httpResponse, responseBody) @@ -51,7 +248,9 @@ private struct TonAPIAuthorizationMiddleware: ClientMiddleware { operationID _: String, next: @Sendable(HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?) ) async throws -> (HTTPResponse, HTTPBody?) { - guard !token.isEmpty else { + guard TonAPIClientFactory.isValidAuthorizationToken(token), + TonAPIClientFactory.canAttachAuthorization(to: baseURL) + else { return try await next(request, body, baseURL) } @@ -62,16 +261,73 @@ private struct TonAPIAuthorizationMiddleware: ClientMiddleware { } final class TonAPIClientFactory { + static let canonicalAuthenticatedOrigin = URL(string: "https://tonapi.io")! + /// Binary-owned allowlist for operations that expose a signed bearer BOC. + /// Read-only balance clients may still use other valid registry nodes, but native + /// submission must remain pinned to an independently reviewed exact origin. + static let reviewedProductionSendOrigins = [canonicalAuthenticatedOrigin] + private let tonAPIURL: URL private let token: String + var serverURL: URL { tonAPIURL } + var usesAuthorization: Bool { Self.isValidAuthorizationToken(token) } + var hasReviewedProductionSendCredential: Bool { + usesAuthorization && Self.isReviewedProductionSendServerURL(tonAPIURL) + } + init(tonAPIURL: URL, token: String) { self.tonAPIURL = tonAPIURL - self.token = token + self.token = Self.canAttachAuthorization(to: tonAPIURL) && Self.isValidAuthorizationToken(token) ? token : "" + } + + static func isValidServerURL(_ url: URL) -> Bool { + guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false), + components.scheme?.lowercased() == "https", + components.host?.isEmpty == false, + components.user == nil, + components.password == nil, + components.query == nil, + components.fragment == nil, + components.percentEncodedPath.isEmpty || components.percentEncodedPath == "/" + else { + return false + } + return true + } + + static func canAttachAuthorization(to url: URL) -> Bool { + hasExactOrigin(url, canonical: canonicalAuthenticatedOrigin) + } + + static func isValidAuthorizationToken(_ token: String) -> Bool { + let bytes = Array(token.utf8) + return !bytes.isEmpty && bytes.count <= 4096 && bytes.allSatisfy { byte in + (0x21 ... 0x7E).contains(byte) + } } - func tonAPIClient() -> Client { - let transport = TonAPIURLSessionTransport() + static func isReviewedProductionSendServerURL(_ url: URL) -> Bool { + reviewedProductionSendOrigins.contains { canonical in + hasExactOrigin(url, canonical: canonical) + } + } + + private static func hasExactOrigin(_ url: URL, canonical: URL) -> Bool { + guard isValidServerURL(url), + let components = URLComponents(url: url, resolvingAgainstBaseURL: false), + let canonical = URLComponents(url: canonical, resolvingAgainstBaseURL: false) + else { + return false + } + + return components.scheme?.lowercased() == canonical.scheme?.lowercased() && + components.host?.lowercased() == canonical.host?.lowercased() && + components.port == canonical.port + } + + func tonAPIClient(configuration: URLSessionConfiguration? = nil) -> Client { + let transport = TonAPIURLSessionTransport(configuration: configuration) let middlewares: [any ClientMiddleware] = token.isEmpty ? [] : [TonAPIAuthorizationMiddleware(token: token)] return Client( @@ -88,9 +344,24 @@ private extension URLRequest { body: HTTPBody?, baseURL: URL ) async throws { + let requestPath = request.path ?? "" guard + TonAPIClientFactory.isValidServerURL(baseURL), var baseURLComponents = URLComponents(string: baseURL.absoluteString), - let requestURLComponents = URLComponents(string: request.path ?? "") + let requestURLComponents = URLComponents(string: requestPath), + requestURLComponents.scheme == nil, + requestURLComponents.host == nil, + requestURLComponents.user == nil, + requestURLComponents.password == nil, + requestURLComponents.fragment == nil, + requestURLComponents.percentEncodedPath.hasPrefix("/"), + !requestURLComponents.percentEncodedPath.hasPrefix("//"), + let decodedPath = requestURLComponents.percentEncodedPath.removingPercentEncoding, + decodedPath.hasPrefix("/"), + !decodedPath.hasPrefix("//"), + !decodedPath.contains("\\"), + !decodedPath.split(separator: "/", omittingEmptySubsequences: false).contains("."), + !decodedPath.split(separator: "/", omittingEmptySubsequences: false).contains("..") else { throw TonAPITransportError.invalidRequestURL( path: request.path ?? "", @@ -99,7 +370,10 @@ private extension URLRequest { ) } - baseURLComponents.percentEncodedPath += requestURLComponents.percentEncodedPath + // Valid server URLs may use either an empty path or a single trailing slash. + // The generated operation path is already absolute, so replacement avoids a + // double slash such as https://tonapi.io//v2/... without permitting base paths. + baseURLComponents.percentEncodedPath = requestURLComponents.percentEncodedPath baseURLComponents.percentEncodedQuery = requestURLComponents.percentEncodedQuery guard let resolvedURL = baseURLComponents.url else { @@ -118,7 +392,10 @@ private extension URLRequest { } if let body { - httpBody = try await Data(collecting: body, upTo: .max) + httpBody = try await Data( + collecting: body, + upTo: TonAPITransportPolicy.maximumRequestBodyBytes + ) } } } @@ -248,12 +525,22 @@ final class ChainRegistry { do { switch change { case let .insert(newChain): - try self.handleInsert(newChain) + if !newChain.disabled { + try self.handleInsert(newChain) + } case let .update(updatedChain): let currentChain = self.chains.first { $0.chainId == updatedChain.chainId } - if let chain = currentChain, - chain.nodes != updatedChain.nodes || chain.selectedNode != updatedChain.selectedNode { - try self.handleUpdate(updatedChain) + if updatedChain.disabled { + if currentChain != nil { + self.handleDelete(updatedChain.chainId) + } + } else if let chain = currentChain { + if chain.nodes != updatedChain.nodes || + chain.selectedNode != updatedChain.selectedNode { + try self.handleUpdate(updatedChain) + } + } else { + try self.handleInsert(updatedChain) } case let .delete(chainId): self.handleDelete(chainId) @@ -349,14 +636,18 @@ final class ChainRegistry { } clearRuntimeSubscription(for: updatedChain.chainId) + runtimeProviderPool.destroyRuntimeProvider(for: updatedChain.chainId) + runtimeSyncService.unregister(chainId: updatedChain.chainId) + substrateConnectionPool.resetConnection(for: updatedChain.chainId) + chains = chains.filter { $0.chainId != updatedChain.chainId } let connection = try substrateConnectionPool.setupConnection(for: updatedChain) let chainTypes = chainsTypesMap[updatedChain.chainId] runtimeProviderPool.setupRuntimeProvider(for: updatedChain, chainTypes: chainTypes) + runtimeSyncService.register(chain: updatedChain, with: connection) setupRuntimeVersionSubscription(for: updatedChain, connection: connection) - chains = chains.filter { $0.chainId != updatedChain.chainId } chains.append(updatedChain) } @@ -364,6 +655,7 @@ final class ChainRegistry { runtimeProviderPool.destroyRuntimeProvider(for: chainId) clearRuntimeSubscription(for: chainId) runtimeSyncService.unregister(chainId: chainId) + resetSubstrateConnection(for: chainId) chains = chains.filter { $0.chainId != chainId } } @@ -395,13 +687,15 @@ final class ChainRegistry { return } + ethereumConnectionPool.resetConnection(for: updatedChain.chainId) + chains = chains.filter { $0.chainId != updatedChain.chainId } + do { _ = try ethereumConnectionPool.setupConnection(for: updatedChain) } catch { logger?.customError(error) } - chains = chains.filter { $0.chainId != updatedChain.chainId } chains.append(updatedChain) } @@ -422,8 +716,7 @@ final class ChainRegistry { chains = chains.filter { $0.chainId != chain.chainId } chains.append(chain) - let token = currentTonApiKey - guard let node = Self.resolveTonNode(for: chain) else { + guard let baseURL = try? Self.tonAPIBaseURL(for: chain) else { logger?.error("Missing TON node URL") if tonApiChainId == chain.chainId { tonApiClientFactory = nil @@ -440,7 +733,8 @@ final class ChainRegistry { return } - tonApiClientFactory = TonAPIClientFactory(tonAPIURL: node.url, token: token) + let token = TonAPIClientFactory.canAttachAuthorization(to: baseURL) ? currentTonApiKey : "" + tonApiClientFactory = TonAPIClientFactory(tonAPIURL: baseURL, token: token) tonApiChainId = chain.chainId } @@ -569,12 +863,13 @@ extension ChainRegistry: ChainRegistryProtocol { return cachedTonApiClientFactory } - guard let node = Self.resolveTonNode(for: selectedTonChain) else { + guard let baseURL = try? Self.tonAPIBaseURL(for: selectedTonChain) else { logger?.error("Missing TON node URL") return nil } - return TonAPIClientFactory(tonAPIURL: node.url, token: currentTonApiKey) + let token = TonAPIClientFactory.canAttachAuthorization(to: baseURL) ? currentTonApiKey : "" + return TonAPIClientFactory(tonAPIURL: baseURL, token: token) } guard let resolvedTonApiClientFactory else { @@ -584,6 +879,26 @@ extension ChainRegistry: ChainRegistryProtocol { return resolvedTonApiClientFactory } + /// Creates a client for the exact chain being sent from. This deliberately does not use + /// the environment-toggle/global TON selection used by balance subscriptions. + func getTonApiClientFactory(for chain: ChainModel) throws -> TonAPIClientFactory { + let baseURL = try Self.tonAPIBaseURL(for: chain) + guard TonAPIClientFactory.isReviewedProductionSendServerURL(baseURL) else { + throw ChainRegistryError.connectionUnavailable + } + let token = TonAPIClientFactory.canAttachAuthorization(to: baseURL) ? currentTonApiKey : "" + return TonAPIClientFactory(tonAPIURL: baseURL, token: token) + } + + static func tonAPIBaseURL(for chain: ChainModel) throws -> URL { + guard let node = resolveTonNode(for: chain), + TonAPIClientFactory.isValidServerURL(node.url) + else { + throw ChainRegistryError.connectionUnavailable + } + return node.url + } + func chainsSubscribe( _ target: AnyObject, runningInQueue: DispatchQueue, diff --git a/fearless/Common/Services/ChainRegistry/ChainRegistryFactory.swift b/fearless/Common/Services/ChainRegistry/ChainRegistryFactory.swift index ec2af91c86..0832749602 100644 --- a/fearless/Common/Services/ChainRegistry/ChainRegistryFactory.swift +++ b/fearless/Common/Services/ChainRegistry/ChainRegistryFactory.swift @@ -80,7 +80,11 @@ enum ChainRegistryFactory { dependencies: ChainRegistryFactoryDependencies = .live ) -> ChainRegistryProtocol & SSFChainRegistry.ChainRegistryProtocol { let runtimeMetadataRepository: CoreDataRepository = - repositoryFacade.createRepository() + repositoryFacade.createRepository( + mapper: AnyCoreDataMapper( + RuntimeMetadataMapper() + ) + ) let dataFetchOperationFactory = dependencies.dataOperationFactory @@ -119,7 +123,10 @@ enum ChainRegistryFactory { eventCenter: dependencies.eventCenter, operationQueue: dependencies.syncQueue, logger: dependencies.logger, - applicationHandler: dependencies.applicationHandler + applicationHandler: dependencies.applicationHandler, + malformedChainCleanupOperationFactory: { + chainRepositoryFactory.createMalformedChainCleanupOperation() + } ) let specVersionSubscriptionFactory = SpecVersionSubscriptionFactory( diff --git a/fearless/Common/Services/ChainRegistry/ChainSyncService.swift b/fearless/Common/Services/ChainRegistry/ChainSyncService.swift index 34dd92fa18..434425f2ad 100644 --- a/fearless/Common/Services/ChainRegistry/ChainSyncService.swift +++ b/fearless/Common/Services/ChainRegistry/ChainSyncService.swift @@ -12,6 +12,9 @@ protocol ChainSyncServiceProtocol { enum ChainSyncServiceError: Error { case missingLocalFile + case emptyRemotePayload + case invalidRemoteChain(String) + case duplicateRemoteChainIdentifier(String) } final class ChainSyncService { @@ -34,11 +37,16 @@ final class ChainSyncService { private let applicationHandler: ApplicationHandlerProtocol private let operationQueue: OperationQueue private let logger: LoggerProtocol? + private let malformedChainCleanupOperationFactory: (() -> BaseOperation)? private var retryAttempt: Int = 0 - private var isSyncing: Bool = false + private var isSyncInFlight = false + private var isCooldownActive = false + private var reservationIdentifier: UInt = 0 + private var timerReservationIdentifier: UInt? private let mutex = NSLock() - private var timer = CountdownTimer(notificationInterval: 300) + private let timer: CountdownTimerProtocol + private let cooldownTimerQueue: DispatchQueue private lazy var scheduler = Scheduler(with: self, callbackQueue: DispatchQueue.global()) @@ -50,7 +58,12 @@ final class ChainSyncService { operationQueue: OperationQueue, retryStrategy: ReconnectionStrategyProtocol = ExponentialReconnection(), logger: LoggerProtocol? = nil, - applicationHandler: ApplicationHandlerProtocol + applicationHandler: ApplicationHandlerProtocol, + malformedChainCleanupOperationFactory: (() -> BaseOperation)? = nil, + cooldownTimer: CountdownTimerProtocol = CountdownTimer( + notificationInterval: 300 + ), + cooldownTimerQueue: DispatchQueue = .main ) { self.chainsUrl = chainsUrl self.dataFetchFactory = dataFetchFactory @@ -60,21 +73,75 @@ final class ChainSyncService { self.retryStrategy = retryStrategy self.logger = logger self.applicationHandler = applicationHandler + self.malformedChainCleanupOperationFactory = malformedChainCleanupOperationFactory + timer = cooldownTimer + self.cooldownTimerQueue = cooldownTimerQueue timer.delegate = self } - private func performSyncUpIfNeeded() { - guard !isSyncing else { + private func performSyncUpIfNeeded( + cancelScheduledRetry: Bool = false, + installApplicationDelegate: Bool = false + ) { + mutex.lock() + + if cancelScheduledRetry, retryAttempt > 0 { + scheduler.cancel() + } + + if installApplicationDelegate, + applicationHandler.delegate == nil { + applicationHandler.delegate = self + } + + guard !isSyncInFlight, !isCooldownActive else { + mutex.unlock() logger?.debug("Tried to sync up chains but already syncing") return } - DispatchQueue.main.async { - self.timer.start(with: 300) - } + isSyncInFlight = true + isCooldownActive = true + reservationIdentifier &+= 1 + let currentReservationIdentifier = reservationIdentifier retryAttempt += 1 + let currentRetryAttempt = retryAttempt + mutex.unlock() + + cooldownTimerQueue.async { + self.mutex.lock() + let shouldStartTimer = + self.isCooldownActive && + self.reservationIdentifier == currentReservationIdentifier + self.mutex.unlock() + + guard shouldStartTimer else { + return + } - logger?.debug("Will start chain sync with attempt \(retryAttempt)") + // CountdownTimer.start() synchronously stops its previous run. + // Keep every timer mutation on this serial queue, and stop the old + // run before publishing the new reservation. + self.timer.stop() + + self.mutex.lock() + let timerIsCurrent = + self.isCooldownActive && + self.reservationIdentifier == currentReservationIdentifier + if timerIsCurrent { + self.timerReservationIdentifier = + currentReservationIdentifier + } + self.mutex.unlock() + + if timerIsCurrent { + self.timer.start(with: 300) + } + } + + logger?.debug( + "Will start chain sync with attempt \(currentRetryAttempt)" + ) let event = ChainSyncDidStart() eventCenter.notify(with: event) @@ -82,14 +149,29 @@ final class ChainSyncService { executeSync() } - private func setApplicationDelegateIfNeeded() { - guard applicationHandler.delegate == nil else { + private func executeSync() { + guard let malformedChainCleanupOperationFactory else { + executeRemoteSync() return } - applicationHandler.delegate = self + + let cleanupOperation = malformedChainCleanupOperationFactory() + cleanupOperation.completionBlock = { [weak self, weak cleanupOperation] in + do { + guard let cleanupOperation else { + throw BaseOperationError.parentOperationCancelled + } + + _ = try cleanupOperation.extractNoCancellableResultData() + self?.executeRemoteSync() + } catch { + self?.complete(result: .failure(error)) + } + } + operationQueue.addOperation(cleanupOperation) } - private func executeSync() { + private func executeRemoteSync() { if Self.fetchLocalData { do { let localData = try fetchLocalData() @@ -220,7 +302,21 @@ final class ChainSyncService { } private func handle(remoteChains: [ChainModel]) { - let normalizedRemoteChains = remoteChains.map { normalizeSoraNexusChainAssets($0) } + let normalizedRemoteChains: [ChainModel] + do { + normalizedRemoteChains = try Self.sanitizingRemoteChains( + remoteChains.map { normalizeSoraNexusChainAssets($0) } + ) + } catch { + complete(result: .failure(error)) + return + } + + guard normalizedRemoteChains.isNotEmpty else { + complete(result: .failure(ChainSyncServiceError.emptyRemotePayload)) + return + } + let localFetchOperation = repository.fetchAllOperation(with: RepositoryFetchOptions()) let processingOperation: BaseOperation<( @@ -262,6 +358,84 @@ final class ChainSyncService { ) } + static func sanitizingRemoteChains( + _ remoteChains: [ChainModel] + ) throws -> [ChainModel] { + var seenIdentifiers = Set() + + return try remoteChains.map { chain in + let canonicalIdentifier = chain.chainId.trimmingCharacters( + in: .whitespacesAndNewlines + ) + guard + canonicalIdentifier.isNotEmpty, + canonicalIdentifier == chain.chainId, + !canonicalIdentifier.hasPrefix( + ChainModelMapper.quarantinedChainIdentifierPrefix + ), + chain.name.trimmingCharacters( + in: .whitespacesAndNewlines + ).isNotEmpty + else { + throw ChainSyncServiceError.invalidRemoteChain( + chain.chainId + ) + } + + guard seenIdentifiers.insert(chain.chainId).inserted else { + throw ChainSyncServiceError + .duplicateRemoteChainIdentifier(chain.chainId) + } + + let usableNodesByURL = chain.nodes + .filter { node in + ChainModelMapper.isUsableNodeURL(node.url) + && node.name.trimmingCharacters( + in: .whitespacesAndNewlines + ).isNotEmpty + && ChainModelMapper.isNodeCompatibleWithRuntime( + node, + for: chain + ) + } + .sorted { lhs, rhs in + if lhs.url.absoluteString != rhs.url.absoluteString { + return lhs.url.absoluteString + < rhs.url.absoluteString + } + + if lhs.name != rhs.name { + return lhs.name < rhs.name + } + + let lhsQueryName = lhs.apikey?.queryName ?? "" + let rhsQueryName = rhs.apikey?.queryName ?? "" + if lhsQueryName != rhsQueryName { + return lhsQueryName < rhsQueryName + } + + return (lhs.apikey?.keyName ?? "") + < (rhs.apikey?.keyName ?? "") + } + .reduce(into: [URL: ChainNodeModel]()) { result, node in + if result[node.url] == nil { + result[node.url] = node + } + } + + guard chain.disabled || usableNodesByURL.isNotEmpty else { + throw ChainSyncServiceError.invalidRemoteChain( + chain.chainId + ) + } + + return chain + .replacingNodes(Set(usableNodesByURL.values)) + .replacingCustomNodes([]) + .replacingSelectedNode(nil) + } + } + private func normalizeSoraNexusChainAssets(_ chain: ChainModel) -> ChainModel { guard isSoraNexus(chain) else { return chain @@ -275,7 +449,7 @@ final class ChainSyncService { return chain } - var updatedChain = chain + let updatedChain = chain let xorAsset = AssetModel( id: "b5a44630-920e-43ee-809f-61890d0888b0", name: "sora", @@ -311,11 +485,12 @@ final class ChainSyncService { remoteChains: [ChainModel], localChains: [ChainModel] ) { - remoteChains.forEach { chain in - chain.selectedNode = localChains.first(where: { $0.chainId == chain.chainId })?.selectedNode - } + let mergedRemoteChains = Self.preservingLocalNodePreferences( + remoteChains: remoteChains, + localChains: localChains + ) - let remoteMapping = remoteChains.reduce(into: [ChainModel.Id: ChainModel]()) { mapping, item in + let remoteMapping = mergedRemoteChains.reduce(into: [ChainModel.Id: ChainModel]()) { mapping, item in mapping[item.chainId] = item } @@ -323,7 +498,7 @@ final class ChainSyncService { mapping[item.chainId] = item } - let newOrUpdated: [ChainModel] = remoteChains.compactMap { remoteItem in + var newOrUpdated: [ChainModel] = mergedRemoteChains.compactMap { remoteItem in if let localItem = localMapping[remoteItem.chainId] { return localItem != remoteItem ? remoteItem : nil } else { @@ -331,15 +506,78 @@ final class ChainSyncService { } } - let removed = localChains.compactMap { localItem in - let isRemoved = remoteMapping[localItem.chainId] == nil - return isRemoved ? localItem : nil + let disabledOmittedChains: [ChainModel] = localChains.compactMap { + localItem -> ChainModel? in + guard + !localItem.chainId.hasPrefix( + ChainModelMapper.quarantinedChainIdentifierPrefix + ), + remoteMapping[localItem.chainId] == nil, + !localItem.disabled + else { + return nil + } + + return localItem.replacingDisabled(true) } - let syncChanges = SyncChanges(newOrUpdatedItems: newOrUpdated, removedItems: removed) + newOrUpdated.append(contentsOf: disabledOmittedChains) + + let syncChanges = SyncChanges( + newOrUpdatedItems: newOrUpdated, + removedItems: [] + ) handle(syncChanges: syncChanges) } + static func preservingLocalNodePreferences( + remoteChains: [ChainModel], + localChains: [ChainModel] + ) -> [ChainModel] { + let localMapping = localChains.reduce(into: [ChainModel.Id: ChainModel]()) { mapping, chain in + mapping[chain.chainId] = chain + } + + return remoteChains.map { remoteChain in + guard let localChain = localMapping[remoteChain.chainId] else { + return remoteChain + } + + let localCustomNodes = Set( + (localChain.customNodes ?? []).filter { + ChainModelMapper.isUsableNodeURL($0.url) + && $0.name.trimmingCharacters( + in: .whitespacesAndNewlines + ).isNotEmpty + && ChainModelMapper + .isNodeCompatibleWithRuntime( + $0, + for: remoteChain + ) + } + ) + let selectedNode: ChainNodeModel? + + if let localSelectedNode = localChain.selectedNode, + ChainModelMapper.isNodeCompatibleWithRuntime( + localSelectedNode, + for: remoteChain + ) { + selectedNode = remoteChain.nodes.first { + $0.url == localSelectedNode.url + } ?? localCustomNodes.first { + $0.url == localSelectedNode.url + } + } else { + selectedNode = nil + } + + return remoteChain + .replacingCustomNodes(Array(localCustomNodes)) + .replacingSelectedNode(selectedNode) + } + } + private func handle(syncChanges: SyncChanges) { let localSaveOperation = repository.saveOperation({ syncChanges.newOrUpdatedItems @@ -347,9 +585,22 @@ final class ChainSyncService { syncChanges.removedItems.map { $0.identifier } }) - localSaveOperation.completionBlock = { + localSaveOperation.completionBlock = { [weak self, weak localSaveOperation] in + let result: Result + + do { + guard let localSaveOperation else { + throw BaseOperationError.parentOperationCancelled + } + + _ = try localSaveOperation.extractNoCancellableResultData() + result = .success(syncChanges) + } catch { + result = .failure(error) + } + DispatchQueue.global(qos: .userInitiated).async { [weak self] in - self?.complete(result: .success(syncChanges)) + self?.complete(result: result) } } @@ -388,7 +639,10 @@ final class ChainSyncService { ) } + mutex.lock() + isSyncInFlight = false retryAttempt = 0 + mutex.unlock() let event = ChainSyncDidComplete( newOrUpdatedChains: changes.newOrUpdatedItems, @@ -398,7 +652,15 @@ final class ChainSyncService { eventCenter.notify(with: event) case let .failure(error): logger?.error("Sync failed with error: \(error)") - timer.stop() + mutex.lock() + let failedReservationIdentifier = reservationIdentifier + isSyncInFlight = false + isCooldownActive = false + reservationIdentifier &+= 1 + mutex.unlock() + stopCooldownTimer( + forFailedReservation: failedReservationIdentifier + ) let event = ChainSyncDidFail(error: error) eventCenter.notify(with: event) @@ -406,8 +668,33 @@ final class ChainSyncService { } } + private func stopCooldownTimer( + forFailedReservation failedReservationIdentifier: UInt + ) { + cooldownTimerQueue.async { + self.mutex.lock() + let shouldStopTimer = + self.timerReservationIdentifier == + failedReservationIdentifier + if shouldStopTimer { + self.timerReservationIdentifier = nil + } + self.mutex.unlock() + + if shouldStopTimer { + self.timer.stop() + } + } + } + private func retry() { - if let nextDelay = retryStrategy.reconnectAfter(attempt: retryAttempt) { + mutex.lock() + let currentRetryAttempt = retryAttempt + mutex.unlock() + + if let nextDelay = retryStrategy.reconnectAfter( + attempt: currentRetryAttempt + ) { logger?.debug("Scheduling chain sync retry after \(nextDelay)") scheduler.notifyAfter(nextDelay) @@ -417,42 +704,38 @@ final class ChainSyncService { extension ChainSyncService: ChainSyncServiceProtocol { func syncUp() { - mutex.lock() - - defer { - mutex.unlock() - } - - if retryAttempt > 0 { - scheduler.cancel() - } - - setApplicationDelegateIfNeeded() - performSyncUpIfNeeded() + performSyncUpIfNeeded( + cancelScheduledRetry: true, + installApplicationDelegate: true + ) } } extension ChainSyncService: SchedulerDelegate { func didTrigger(scheduler _: SchedulerProtocol) { - mutex.lock() - - defer { - mutex.unlock() - } - performSyncUpIfNeeded() } } extension ChainSyncService: CountdownTimerDelegate { - func didStart(with _: TimeInterval) { - isSyncing = true - } + func didStart(with _: TimeInterval) {} func didCountdown(remainedInterval _: TimeInterval) {} func didStop(with _: TimeInterval) { - isSyncing = false + mutex.lock() + defer { mutex.unlock() } + + guard case .stopped = timer.state else { + return + } + + guard timerReservationIdentifier == reservationIdentifier else { + return + } + + isCooldownActive = false + timerReservationIdentifier = nil } } diff --git a/fearless/Common/Services/ChainRegistry/ConnectionPool/EthereumConnectionPool.swift b/fearless/Common/Services/ChainRegistry/ConnectionPool/EthereumConnectionPool.swift index 768d67444c..8def7f1ac3 100644 --- a/fearless/Common/Services/ChainRegistry/ConnectionPool/EthereumConnectionPool.swift +++ b/fearless/Common/Services/ChainRegistry/ConnectionPool/EthereumConnectionPool.swift @@ -8,21 +8,29 @@ final class EthereumConnectionPool: ConnectionPoolProtocol { private(set) var connectionsByChainIds: [ChainModel.Id: Web3.Eth] = [:] private weak var delegate: ConnectionPoolDelegate? + private let nodeFetching: EthereumNodeFetchingProtocol private lazy var lock = NSLock() - func setupConnection(for chain: SSFModels.ChainModel) throws -> Web3.Eth { - if let connection = connectionsByChainIds[chain.chainId] { - return connection - } - - let ws = try EthereumNodeFetching().getNode(for: chain) + init( + nodeFetching: EthereumNodeFetchingProtocol = + EthereumNodeFetching() + ) { + self.nodeFetching = nodeFetching + } + func setupConnection(for chain: SSFModels.ChainModel) throws -> Web3.Eth { lock.lock() defer { lock.unlock() } + if let connection = connectionsByChainIds[chain.chainId] { + return connection + } + + let ws = try nodeFetching.getNode(for: chain) + connectionsByChainIds[chain.chainId] = ws return ws @@ -42,6 +50,11 @@ final class EthereumConnectionPool: ConnectionPoolProtocol { } func resetConnection(for chainId: ChainModel.Id) { + lock.lock() + defer { + lock.unlock() + } + connectionsByChainIds = connectionsByChainIds.filter { $0.key != chainId } } } diff --git a/fearless/Common/Storage/CompatibilityModels/Compiled/CompatibleUserDataModel_v13.mom b/fearless/Common/Storage/CompatibilityModels/Compiled/CompatibleUserDataModel_v13.mom new file mode 100644 index 0000000000..bb4949a3c4 Binary files /dev/null and b/fearless/Common/Storage/CompatibilityModels/Compiled/CompatibleUserDataModel_v13.mom differ diff --git a/fearless/Common/Storage/CompatibilityModels/Compiled/LegacyEcosystemUserDataModel_v12.mom b/fearless/Common/Storage/CompatibilityModels/Compiled/LegacyEcosystemUserDataModel_v12.mom new file mode 100644 index 0000000000..f091bb186b Binary files /dev/null and b/fearless/Common/Storage/CompatibilityModels/Compiled/LegacyEcosystemUserDataModel_v12.mom differ diff --git a/fearless/Common/Storage/CompatibilityModels/README.md b/fearless/Common/Storage/CompatibilityModels/README.md new file mode 100644 index 0000000000..29cd70c8d3 --- /dev/null +++ b/fearless/Common/Storage/CompatibilityModels/README.md @@ -0,0 +1,34 @@ +# User storage compatibility models + +These models repair the launch migration path for installations whose existing +database was created by the ecosystem/TON storage schema. + +- `LegacyEcosystemUserDataModel_v12` is an immutable compatibility source. Its + Core Data model checksum must remain + `+oGDYB1AZIk54P/liFbJ3aXArqvhW7YLFAy04AChJ+s=`. +- `CompatibleUserDataModel_v13` is the active superset model. It retains the + legacy ecosystem and TON fields and the public app's `ethereumBased` field. + Its checksum is + `dX3y/Aa+rMRI3ZxRibOGIkyCHwrc0zgNO9OoBnS5G/Y=`. + +The compiled `.mom` files in `Compiled/` are generated with `momc`, copied into +the app bundle, and verified by migration tests. Never edit the legacy source +model in place; add a new destination model and migration edge instead. + +From the iOS repository root, regenerate and audit the checked-in resources: + +```sh +scripts/storage/compile-user-storage-compatibility-models.sh +scripts/storage/audit-user-storage-compatibility-models.sh +``` + +Run the destructive-fixture test suite for the audit itself: + +```sh +scripts/storage/test-user-storage-compatibility-model-audit.sh +``` + +The audit compiles fresh resources, compares Core Data's semantic model +checksums, validates that both schemas retain the ecosystem and TON fields, +validates that the destination also retains `ethereumBased`, and rejects empty, +corrupt, stale, malformed, missing, or duplicated compatibility data. diff --git a/fearless/Common/Storage/CompatibilityModels/Source/CompatibleUserDataModel_v13.xcdatamodel/contents b/fearless/Common/Storage/CompatibilityModels/Source/CompatibleUserDataModel_v13.xcdatamodel/contents new file mode 100644 index 0000000000..b2aa27c19a --- /dev/null +++ b/fearless/Common/Storage/CompatibilityModels/Source/CompatibleUserDataModel_v13.xcdatamodel/contents @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fearless/Common/Storage/CompatibilityModels/Source/LegacyEcosystemUserDataModel_v12.xcdatamodel/contents b/fearless/Common/Storage/CompatibilityModels/Source/LegacyEcosystemUserDataModel_v12.xcdatamodel/contents new file mode 100644 index 0000000000..a95b22480c --- /dev/null +++ b/fearless/Common/Storage/CompatibilityModels/Source/LegacyEcosystemUserDataModel_v12.xcdatamodel/contents @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fearless/Common/Storage/EntityToModel/ChainModelMapper.swift b/fearless/Common/Storage/EntityToModel/ChainModelMapper.swift index cba753abb2..48702596b1 100644 --- a/fearless/Common/Storage/EntityToModel/ChainModelMapper.swift +++ b/fearless/Common/Storage/EntityToModel/ChainModelMapper.swift @@ -7,7 +7,28 @@ import RobinHood import SSFModels import SSFUtils +enum ChainModelMapperError: LocalizedError, Equatable { + case missingNodeURL + case missingNodeName + case invalidNodeURL + + var errorDescription: String? { + switch self { + case .missingNodeURL: + return "Stored chain node is missing its URL" + case .missingNodeName: + return "Stored chain node is missing its name" + case .invalidNodeURL: + return "Stored chain node has an unusable URL" + } + } +} + final class ChainModelMapper { + static let quarantinedChainIdentifierPrefix = "__invalid_local_chain__:" + static let quarantinedChainName = "Unavailable local chain" + private static let supportedNodeSchemes = Set(["http", "https", "ws", "wss"]) + private let assetModelMapper = AssetModelMapper() var entityIdentifierFieldName: String { #keyPath(CDChain.chainId) } @@ -15,7 +36,36 @@ final class ChainModelMapper { typealias DataProviderModel = ChainModel typealias CoreDataEntity = CDChain - private func createPriceData(from object: NSManagedObject) -> PriceData? { + func createPriceData(from object: NSManagedObject) -> PriceData? { + var priceData: PriceData? + + do { + try SafeObjectiveCExceptionBoundary.perform { + let attributes = object.entity.attributesByName + guard + attributes["currencyId"] != nil, + attributes["priceId"] != nil, + attributes["price"] != nil + else { + return + } + + priceData = self.createPriceDataWithoutExceptionBoundary( + from: object, + attributes: attributes + ) + } + } catch { + return nil + } + + return priceData + } + + private func createPriceDataWithoutExceptionBoundary( + from object: NSManagedObject, + attributes: [String: NSAttributeDescription] + ) -> PriceData? { guard let currencyId = object.value(forKey: "currencyId") as? String, let priceId = object.value(forKey: "priceId") as? String @@ -27,10 +77,19 @@ final class ChainModelMapper { if let s = object.value(forKey: "price") as? String { return s } return nil }() - guard let price = priceString else { return nil } + guard + let price = priceString, + Self.isValidCachedPrice(price) + else { + return nil + } - let fiatDayStr = object.value(forKey: "fiatDayByChange") as? String - let coingeckoPriceId = object.value(forKey: "coingeckoPriceId") as? String + let fiatDayStr = attributes["fiatDayByChange"].flatMap { _ in + object.value(forKey: "fiatDayByChange") as? String + } + let coingeckoPriceId = attributes["coingeckoPriceId"].flatMap { _ in + object.value(forKey: "coingeckoPriceId") as? String + } return PriceData( currencyId: currencyId, @@ -41,7 +100,67 @@ final class ChainModelMapper { ) } - private func createChainNode(from entity: CDChainNode) -> ChainNodeModel { + private func cachedPriceObjects( + from assetEntity: CDAsset + ) -> [NSManagedObject] { + guard + assetEntity.entity.relationshipsByName["priceData"] != nil + else { + return [] + } + + do { + let rawValue = try SafeTransformableValueReader.readObject( + from: assetEntity, + key: "priceData" + ) + + return (rawValue as? NSSet)? + .compactMap { $0 as? NSManagedObject } ?? [] + } catch { + return [] + } + } + + private static func isValidCachedPrice(_ price: String) -> Bool { + let normalizedPrice = price.trimmingCharacters( + in: .whitespacesAndNewlines + ) + guard normalizedPrice.isNotEmpty else { + return false + } + + let scanner = Scanner(string: normalizedPrice) + scanner.locale = Locale(identifier: "en_US_POSIX") + scanner.charactersToBeSkipped = nil + + guard + let decimalPrice = scanner.scanDecimal(), + scanner.isAtEnd, + !decimalPrice.isNaN + else { + return false + } + + return decimalPrice >= 0 + } + + private func createChainNode(from entity: CDChainNode) throws -> ChainNodeModel { + guard let url = entity.url else { + throw ChainModelMapperError.missingNodeURL + } + + guard Self.isUsableNodeURL(url) else { + throw ChainModelMapperError.invalidNodeURL + } + + guard + let name = entity.name, + !name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty + else { + throw ChainModelMapperError.missingNodeName + } + let apiKey: ChainNodeModel.ApiKey? if let queryName = entity.apiQueryName, let keyName = entity.apiKeyName { @@ -51,12 +170,68 @@ final class ChainModelMapper { } return ChainNodeModel( - url: entity.url!, - name: entity.name!, + url: url, + name: name, apikey: apiKey ) } + static func isUsableNodeURL(_ url: URL) -> Bool { + guard + let components = URLComponents( + url: url, + resolvingAgainstBaseURL: false + ), + let scheme = components.scheme?.lowercased(), + supportedNodeSchemes.contains(scheme), + components.host?.isEmpty == false + else { + return false + } + + return true + } + + static func isNodeCompatibleWithRuntime( + _ node: ChainNodeModel, + for chain: ChainModel + ) -> Bool { + if chain.isTonCompatibilityChain { + return TonAPIClientFactory.isValidServerURL(node.url) + } + + let scheme = node.url.scheme?.lowercased() + if chain.chainBaseType == .ethereum { + return scheme == "https" || scheme == "wss" + } + + return scheme == "ws" || scheme == "wss" + } + + private func createQuarantinedChain(from entity: CDChain) -> ChainModel { + let objectIdentifier = entity.objectID.uriRepresentation().absoluteString + + return ChainModel( + rank: nil, + disabled: true, + chainId: Self.quarantinedChainIdentifierPrefix + objectIdentifier, + parentId: nil, + paraId: nil, + name: Self.quarantinedChainName, + xcm: nil, + nodes: [], + addressPrefix: UInt16(bitPattern: entity.addressPrefix), + types: nil, + icon: nil, + options: nil, + externalApi: nil, + selectedNode: nil, + customNodes: nil, + iosMinAppVersion: nil, + identityChain: nil + ) + } + private func updateEntityAsset( for entity: CDChain, from model: ChainModel, @@ -101,7 +276,10 @@ final class ChainModelMapper { let maybeExistingEntity = entity.nodes? .first { ($0 as? CDChainNode)?.url == node.url } as? CDChainNode - if let existingEntity = maybeExistingEntity { + let existingCustomEntity = entity.customNodes? + .first { ($0 as? CDChainNode)?.url == node.url } as? CDChainNode + + if let existingEntity = maybeExistingEntity ?? existingCustomEntity { nodeEntity = existingEntity } else { nodeEntity = CDChainNode(context: context) @@ -115,11 +293,26 @@ final class ChainModelMapper { return nodeEntity } - let existingNodeIds = Set(model.nodes.map(\.url)) + let retainedNodeEntities = Set(nodeEntities) if let oldNodes = entity.nodes as? Set { for oldNode in oldNodes { - if !existingNodeIds.contains(oldNode.url!) { + let oldNodeURL = oldNode.url + let remainsDefault = retainedNodeEntities.contains(oldNode) + let remainsSharedCustom = oldNodeURL.map { url in + model.customNodes?.contains { + $0.url == url + } == true && + (entity.customNodes as? Set)? + .contains(oldNode) == true + } ?? false + let remainsSharedSelection = + oldNodeURL == model.selectedNode?.url && + entity.selectedNode === oldNode + + if !remainsDefault, + !remainsSharedCustom, + !remainsSharedSelection { context.delete(oldNode) } } @@ -143,7 +336,10 @@ final class ChainModelMapper { let maybeExistingEntity = entity.customNodes? .first { ($0 as? CDChainNode)?.url == node.url } as? CDChainNode - if let existingEntity = maybeExistingEntity { + let existingDefaultEntity = entity.nodes? + .first { ($0 as? CDChainNode)?.url == node.url } as? CDChainNode + + if let existingEntity = maybeExistingEntity ?? existingDefaultEntity { nodeEntity = existingEntity } else { nodeEntity = CDChainNode(context: context) @@ -157,11 +353,26 @@ final class ChainModelMapper { return nodeEntity } - let existingNodeIds = Set(customNodes.map(\.url)) + let retainedNodeEntities = Set(nodeEntities) if let oldNodes = entity.customNodes as? Set { for oldNode in oldNodes { - if !existingNodeIds.contains(oldNode.url!) { + let oldNodeURL = oldNode.url + let remainsCustom = retainedNodeEntities.contains(oldNode) + let remainsSharedDefault = oldNodeURL.map { url in + model.nodes.contains { + $0.url == url + } && + (entity.nodes as? Set)? + .contains(oldNode) == true + } ?? false + let remainsSharedSelection = + oldNodeURL == model.selectedNode?.url && + entity.selectedNode === oldNode + + if !remainsCustom, + !remainsSharedDefault, + !remainsSharedSelection { context.delete(oldNode) } } @@ -295,9 +506,13 @@ final class ChainModelMapper { let explorerEntities = entityExplorers.allObjects as? [CDExternalApi] ?? [] let explorers: [ChainModel.ExternalApiExplorer] = explorerEntities.reduce(into: []) { result, explorer in + let storedTypes: [String]? = try? SafeTransformableValueReader.read( + from: explorer, + key: "types" + ) guard let type = explorer.type, - let types = explorer.types as? [String], + let types = storedTypes, let url = explorer.url else { return @@ -308,7 +523,7 @@ final class ChainModelMapper { result.append(ChainModel.ExternalApiExplorer( type: ChainModel.ExternalApiExplorerType(rawValue: type) ?? .unknown, types: externapApiTypes, - url: url.absoluteString + url: url )) } return explorers @@ -326,7 +541,7 @@ final class ChainModelMapper { let explorer = CDExternalApi(context: context) explorer.type = api.type.rawValue explorer.types = api.types.compactMap { $0.rawValue } as? NSArray - explorer.url = URL(string: api.url) + explorer.url = api.url return explorer } entity.explorers = Set(explorers) as NSSet @@ -391,12 +606,60 @@ final class ChainModelMapper { extension ChainModelMapper: CoreDataMapperProtocol { func transform(entity: CDChain) throws -> ChainModel { + var mappedChain: ChainModel? + + // Mapping a chain traverses several generated Core Data relationships. + // Any one of those getters can raise NSException for a damaged legacy + // row, so the complete startup read is an atomic exception boundary. + try SafeObjectiveCExceptionBoundary.perform { + mappedChain = try self.transformWithoutExceptionBoundary( + entity: entity + ) + } + + guard let mappedChain else { + throw SafeTransformableValueReaderError.objectiveCException + } + + return mappedChain + } + + private func transformWithoutExceptionBoundary( + entity: CDChain + ) throws -> ChainModel { + guard + let rawChainId = entity.chainId, + rawChainId.isNotEmpty + else { + return createQuarantinedChain(from: entity) + } + + let storedChainId = rawChainId.trimmingCharacters( + in: .whitespacesAndNewlines + ) + guard + storedChainId.isNotEmpty, + storedChainId == rawChainId + else { + return createQuarantinedChain(from: entity) + } + + let storedName = entity.name? + .trimmingCharacters(in: .whitespacesAndNewlines) + let hasValidName = storedName?.isNotEmpty == true + let name: String + if let storedName, storedName.isNotEmpty { + name = storedName + } else { + name = Self.quarantinedChainName + } + let nodes: [ChainNodeModel] = entity.nodes?.compactMap { anyNode in guard let node = anyNode as? CDChainNode else { return nil } - return createChainNode(from: node) + return try? createChainNode(from: node) } ?? [] var customNodesSet: Set? @@ -406,7 +669,7 @@ extension ChainModelMapper: CoreDataMapperProtocol { return nil } - return createChainNode(from: node) + return try? createChainNode(from: node) } if let nodes = customNodes { @@ -417,18 +680,21 @@ extension ChainModelMapper: CoreDataMapperProtocol { var selectedNode: ChainNodeModel? if let selectedNodeEntity = entity.selectedNode { - selectedNode = createChainNode(from: selectedNodeEntity) + selectedNode = try? createChainNode(from: selectedNodeEntity) } let types: ChainModel.TypesSettings? - if let url = entity.types.flatMap(URL.init(string:)), let overridesCommon = entity.typesOverrideCommon { + if let url = entity.types, let overridesCommon = entity.typesOverrideCommon { types = .init(url: url, overridesCommon: overridesCommon.boolValue) } else { types = nil } - let options = entity.options as? [String] + let options: [String]? = try? SafeTransformableValueReader.read( + from: entity, + key: "options" + ) let externalApiSet = createExternalApi(from: entity) let xcm = createXcmConfig(from: entity) let paraId: String? = { @@ -449,17 +715,19 @@ extension ChainModelMapper: CoreDataMapperProtocol { rank = UInt16(rankString) } - let assetsArray: [AssetModel] = try (entity.assets?.compactMap { anyAsset in + let assetsArray: [AssetModel] = (entity.assets?.compactMap { anyAsset in guard let assetEntity = anyAsset as? CDAsset else { return nil } - let asset = try assetModelMapper.transform(entity: assetEntity) - let priceDataEntities = (assetEntity.value(forKey: "priceData") as? NSSet)? - .compactMap { $0 as? NSManagedObject } ?? [] - let cachedPrices = priceDataEntities.compactMap(createPriceData(from:)) + guard let asset = try? assetModelMapper.transform(entity: assetEntity) else { + return nil + } + let cachedPrices = cachedPriceObjects(from: assetEntity) + .compactMap(createPriceData(from:)) + .sorted(by: Self.cachedPricePrecedes) - guard !cachedPrices.isEmpty else { + guard let firstCachedPrice = cachedPrices.first else { return asset } @@ -472,16 +740,16 @@ extension ChainModelMapper: CoreDataMapperProtocol { return asset.replacingPrice(matchingCurrency) } - return asset.replacingPrice(cachedPrices[0]) + return asset.replacingPrice(firstCachedPrice) }) ?? [] let chainModel = ChainModel( rank: rank, - disabled: entity.disabled, - chainId: entity.chainId!, + disabled: entity.disabled || !hasValidName, + chainId: storedChainId, parentId: entity.parentId, paraId: paraId, - name: entity.name!, + name: name, xcm: xcm, nodes: Set(nodes), addressPrefix: UInt16(bitPattern: entity.addressPrefix), @@ -497,7 +765,68 @@ extension ChainModelMapper: CoreDataMapperProtocol { chainModel.assets = Set(assetsArray) + let compatibleNodes = Set( + chainModel.nodes.filter { + Self.isNodeCompatibleWithRuntime($0, for: chainModel) + } + ) + let compatibleCustomNodes = chainModel.customNodes.map { + Set( + $0.filter { + Self.isNodeCompatibleWithRuntime( + $0, + for: chainModel + ) + } + ) + } + let compatibleSelectedNode = chainModel.selectedNode.flatMap { + Self.isNodeCompatibleWithRuntime($0, for: chainModel) + ? $0 + : nil + } + let hasRuntimeEndpoint = + compatibleNodes.isNotEmpty || + compatibleSelectedNode != nil || + compatibleCustomNodes?.isNotEmpty == true + return chainModel + .replacingNodeConfiguration( + nodes: compatibleNodes, + selectedNode: compatibleSelectedNode, + customNodes: compatibleCustomNodes + ) + .replacingDisabled( + chainModel.disabled || !hasRuntimeEndpoint + ) + } + + private static func cachedPricePrecedes( + _ lhs: PriceData, + _ rhs: PriceData + ) -> Bool { + let lhsDayChange = lhs.fiatDayChange.map { + NSDecimalNumber(decimal: $0).stringValue + } ?? "" + let rhsDayChange = rhs.fiatDayChange.map { + NSDecimalNumber(decimal: $0).stringValue + } ?? "" + let lhsKey = [ + lhs.priceId, + lhs.currencyId, + lhs.coingeckoPriceId ?? "", + lhs.price, + lhsDayChange + ] + let rhsKey = [ + rhs.priceId, + rhs.currencyId, + rhs.coingeckoPriceId ?? "", + rhs.price, + rhsDayChange + ] + + return lhsKey.lexicographicallyPrecedes(rhsKey) } func populate( @@ -515,7 +844,7 @@ extension ChainModelMapper: CoreDataMapperProtocol { } entity.parentId = model.parentId entity.name = model.name - entity.types = model.types?.url.absoluteString + entity.types = model.types?.url entity.typesOverrideCommon = model.types.map { NSNumber(value: $0.overridesCommon) } entity.addressPrefix = Int16(bitPattern: model.addressPrefix) diff --git a/fearless/Common/Storage/EntityToModel/ManagedMetaAccountMapper.swift b/fearless/Common/Storage/EntityToModel/ManagedMetaAccountMapper.swift index e2b5442840..360ff50b76 100644 --- a/fearless/Common/Storage/EntityToModel/ManagedMetaAccountMapper.swift +++ b/fearless/Common/Storage/EntityToModel/ManagedMetaAccountMapper.swift @@ -51,6 +51,10 @@ extension ManagedMetaAccountMapper: CoreDataMapperProtocol { order = maybeLastItem?.order ?? 0 + guard order < Int32.max else { + throw MetaAccountMapperError.walletOrderOverflow + } + entity.order = order + 1 } else { entity.order = Int32(bitPattern: model.order) diff --git a/fearless/Common/Storage/EntityToModel/MetaAccountMapper.swift b/fearless/Common/Storage/EntityToModel/MetaAccountMapper.swift index dc34ffc805..31c4fa04da 100644 --- a/fearless/Common/Storage/EntityToModel/MetaAccountMapper.swift +++ b/fearless/Common/Storage/EntityToModel/MetaAccountMapper.swift @@ -6,6 +6,23 @@ import SSFModels import SSFAccountManagmentStorage #endif +enum MetaAccountMapperError: LocalizedError { + case unsupportedWalletRecord + case invalidWalletRecord + case walletOrderOverflow + + var errorDescription: String? { + switch self { + case .unsupportedWalletRecord: + return "The stored wallet does not contain the account fields supported by this app version" + case .invalidWalletRecord: + return "The stored wallet record is invalid" + case .walletOrderOverflow: + return "The wallet order cannot be incremented safely" + } + } +} + final class MetaAccountMapper { var entityIdentifierFieldName: String { #keyPath(CDMetaAccount.metaId) } @@ -15,26 +32,116 @@ final class MetaAccountMapper { extension MetaAccountMapper: CoreDataMapperProtocol { func transform(entity: CoreDataEntity) throws -> DataProviderModel { + var mappedAccount: DataProviderModel? + + // A generated Core Data getter may raise NSException when an old or + // damaged row cannot materialize. Keep the complete read graph, + // including every child relationship traversal, inside one Objective-C + // exception boundary so startup receives a catchable Swift error. + try SafeObjectiveCExceptionBoundary.perform { + mappedAccount = try self.transformWithoutExceptionBoundary( + entity: entity + ) + } + + guard let mappedAccount else { + throw MetaAccountMapperError.invalidWalletRecord + } + + return mappedAccount + } + + private func transformWithoutExceptionBoundary( + entity: CoreDataEntity + ) throws -> DataProviderModel { + guard + let metaId = entity.metaId, + !metaId.isEmpty, + metaId == metaId.trimmingCharacters(in: .whitespacesAndNewlines), + let name = entity.name, + !name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty + else { + throw MetaAccountMapperError.invalidWalletRecord + } + + guard + let substrateAccountIdHex = entity.substrateAccountId, + let substratePublicKey = entity.substratePublicKey + else { + throw MetaAccountMapperError.unsupportedWalletRecord + } + + guard + !substrateAccountIdHex.isEmpty, + let substrateCryptoType = CryptoType( + rawValue: UInt8(truncatingIfNeeded: entity.substrateCryptoType) + ), + Int16(substrateCryptoType.rawValue) == entity.substrateCryptoType + else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let expectedSubstratePublicKeyLength = substrateCryptoType == .ecdsa ? 33 : 32 + guard substratePublicKey.count == expectedSubstratePublicKeyLength else { + throw MetaAccountMapperError.invalidWalletRecord + } + let chainAccountEntities = entity.chainAccounts?.allObjects as? [CDChainAccount] ?? [] var chainAccounts: [ChainAccountModel] = [] + var canonicalChainIds = Set() for chainAccountEntity in chainAccountEntities { guard let accountIdHex = chainAccountEntity.accountId, let chainId = chainAccountEntity.chainId, - let publicKey = chainAccountEntity.publicKey + !chainId.isEmpty, + chainId == chainId.trimmingCharacters(in: .whitespacesAndNewlines), + let publicKey = chainAccountEntity.publicKey, + let cryptoType = CryptoType( + rawValue: UInt8(truncatingIfNeeded: chainAccountEntity.cryptoType) + ), + Int16(cryptoType.rawValue) == chainAccountEntity.cryptoType else { - continue + throw MetaAccountMapperError.invalidWalletRecord } let accountId = try Data(hexStringSSF: accountIdHex) + guard !accountId.isEmpty else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let expectedPublicKeyLength = cryptoType == .ecdsa ? 33 : 32 + guard publicKey.count == expectedPublicKeyLength else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let canonicalChainId = + UniversalWalletChainAccountSupport.canonicalChainId(for: chainId) + guard canonicalChainIds.insert(canonicalChainId).inserted else { + // `chainAccounts` is stored as an unordered Core Data relationship. Allowing + // two rows for one chain would make the selected account depend on fetch order. + throw MetaAccountMapperError.invalidWalletRecord + } + + let storedEcosystem: String? + if chainAccountEntity.entity.propertiesByName["ecosystem"] != nil { + storedEcosystem = chainAccountEntity.value(forKey: "ecosystem") as? String + } else { + storedEcosystem = nil + } + + let isEthereumBased = + storedEcosystem == UniversalWalletEcosystem.evm.rawValue || + storedEcosystem == "ethereum" || + storedEcosystem == "ethereumBased" || + chainAccountEntity.ethereumBased chainAccounts.append( ChainAccountModel( chainId: chainId, accountId: accountId, publicKey: publicKey, - cryptoType: UInt8(truncatingIfNeeded: chainAccountEntity.cryptoType), - ethereumBased: chainAccountEntity.ethereumBased + cryptoType: cryptoType.rawValue, + ethereumBased: isEthereumBased ) ) } @@ -54,8 +161,25 @@ extension MetaAccountMapper: CoreDataMapperProtocol { ) } - let substrateAccountId = try Data(hexStringSSF: entity.substrateAccountId!) - let ethereumAddress = try entity.ethereumAddress.map { try Data(hexStringSSF: $0) } + let substrateAccountId = try Data(hexStringSSF: substrateAccountIdHex) + guard substrateAccountId.count == 32 else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let ethereumAddress = try entity.ethereumAddress.map { + let address = try Data(hexStringSSF: $0) + guard address.count == 20 else { + throw MetaAccountMapperError.invalidWalletRecord + } + + return address + } + + if let ethereumPublicKey = entity.ethereumPublicKey, + ethereumPublicKey.isEmpty { + throw MetaAccountMapperError.invalidWalletRecord + } + // Read assetsVisibility relationship via KVC, but only if the property exists in the loaded model var assetsVisibility: [AssetVisibility] = [] if entity.entity.propertiesByName["assetsVisibility"] != nil, @@ -66,23 +190,35 @@ extension MetaAccountMapper: CoreDataMapperProtocol { return AssetVisibility(assetId: assetId, hidden: hidden) } } - var favouriteChainIds: [String] = [] - if let entityFavouriteChainIds = entity.favouriteChainIds { - favouriteChainIds = (entityFavouriteChainIds as? [String]) ?? [] - } + // These are user preferences, not wallet identity. Decode each behind + // its own exception boundary so one damaged archive cannot hide an + // otherwise usable wallet or discard the other valid preferences. + let assetKeysOrder: [String]? = try? SafeTransformableValueReader.read( + from: entity, + key: "assetKeysOrder" + ) + let unusedChainIds: [String]? = try? SafeTransformableValueReader.read( + from: entity, + key: "unusedChainIds" + ) + let favouriteChainIds: [String] = + (try? SafeTransformableValueReader.read( + from: entity, + key: "favouriteChainIds" + )) ?? [] return DataProviderModel( - metaId: entity.metaId!, - name: entity.name!, + metaId: metaId, + name: name, substrateAccountId: substrateAccountId, - substrateCryptoType: UInt8(truncatingIfNeeded: entity.substrateCryptoType), - substratePublicKey: entity.substratePublicKey!, + substrateCryptoType: substrateCryptoType.rawValue, + substratePublicKey: substratePublicKey, ethereumAddress: ethereumAddress, ethereumPublicKey: entity.ethereumPublicKey, chainAccounts: Set(chainAccounts), - assetKeysOrder: entity.assetKeysOrder as? [String], + assetKeysOrder: assetKeysOrder, canExportEthereumMnemonic: entity.canExportEthereumMnemonic, - unusedChainIds: entity.unusedChainIds as? [String], + unusedChainIds: unusedChainIds, selectedCurrency: selectedCurrency ?? Currency.defaultCurrency(), networkManagmentFilter: entity.networkManagmentFilter, assetsVisibility: assetsVisibility, @@ -96,6 +232,13 @@ extension MetaAccountMapper: CoreDataMapperProtocol { from model: DataProviderModel, using context: NSManagedObjectContext ) throws { + // Validate unordered child identities before changing the managed object. A model can + // contain distinct `ChainAccountModel` values whose chain IDs are aliases of one chain. + // Persisting both would make subsequent account selection depend on NSSet iteration order. + try validateChainAccountsBeforeMutation(model.chainAccounts) + let storedChainAccounts = entity.chainAccounts?.allObjects as? [CDChainAccount] ?? [] + try validateStoredChainAccountsBeforeMutation(storedChainAccounts) + entity.metaId = model.metaId entity.name = model.name entity.substrateAccountId = model.substrateAccountId.toHex() @@ -132,9 +275,13 @@ extension MetaAccountMapper: CoreDataMapperProtocol { } for chainAccount in model.chainAccounts { + let canonicalChainId = + UniversalWalletChainAccountSupport.canonicalChainId(for: chainAccount.chainId) var chainAccountEntity = entity.chainAccounts?.first { if let entity = $0 as? CDChainAccount, - entity.chainId == chainAccount.chainId { + let storedChainId = entity.chainId, + UniversalWalletChainAccountSupport.canonicalChainId(for: storedChainId) == + canonicalChainId { return true } else { return false @@ -152,11 +299,90 @@ extension MetaAccountMapper: CoreDataMapperProtocol { chainAccountEntity?.cryptoType = Int16(bitPattern: UInt16(chainAccount.cryptoType)) chainAccountEntity?.publicKey = chainAccount.publicKey chainAccountEntity?.ethereumBased = chainAccount.ethereumBased + + if + let chainAccountEntity, + chainAccountEntity.entity.propertiesByName["ecosystem"] != nil, + chainAccountEntity.value(forKey: "ecosystem") == nil { + chainAccountEntity.setValue( + chainAccount.ethereumBased + ? UniversalWalletEcosystem.evm.rawValue + : UniversalWalletEcosystem.substrate.rawValue, + forKey: "ecosystem" + ) + } } updatedEntityCurrency(for: entity, from: model, context: context) } + private func validateChainAccountsBeforeMutation( + _ chainAccounts: Set + ) throws { + var canonicalChainIds = Set() + + for chainAccount in chainAccounts { + let chainId = chainAccount.chainId + let cryptoType = CryptoType(rawValue: chainAccount.cryptoType) + guard + !chainId.isEmpty, + chainId == chainId.trimmingCharacters(in: .whitespacesAndNewlines), + !chainAccount.accountId.isEmpty, + let cryptoType + else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let expectedPublicKeyLength = cryptoType == .ecdsa ? 33 : 32 + guard chainAccount.publicKey.count == expectedPublicKeyLength else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let canonicalChainId = + UniversalWalletChainAccountSupport.canonicalChainId(for: chainId) + guard canonicalChainIds.insert(canonicalChainId).inserted else { + throw MetaAccountMapperError.invalidWalletRecord + } + } + } + + private func validateStoredChainAccountsBeforeMutation( + _ chainAccounts: [CDChainAccount] + ) throws { + var canonicalChainIds = Set() + + for chainAccount in chainAccounts { + guard + let accountIdHex = chainAccount.accountId, + let chainId = chainAccount.chainId, + !chainId.isEmpty, + chainId == chainId.trimmingCharacters(in: .whitespacesAndNewlines), + let publicKey = chainAccount.publicKey, + let cryptoType = CryptoType( + rawValue: UInt8(truncatingIfNeeded: chainAccount.cryptoType) + ), + Int16(cryptoType.rawValue) == chainAccount.cryptoType + else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let accountId = try Data(hexStringSSF: accountIdHex) + let expectedPublicKeyLength = cryptoType == .ecdsa ? 33 : 32 + guard + !accountId.isEmpty, + publicKey.count == expectedPublicKeyLength + else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let canonicalChainId = + UniversalWalletChainAccountSupport.canonicalChainId(for: chainId) + guard canonicalChainIds.insert(canonicalChainId).inserted else { + throw MetaAccountMapperError.invalidWalletRecord + } + } + } + private func updatedEntityCurrency( for entity: CoreDataEntity, from model: DataProviderModel, @@ -172,3 +398,243 @@ extension MetaAccountMapper: CoreDataMapperProtocol { entity.selectedCurrency = currencyEntity } } + +/// A selection-safe projection of a stored wallet. Unsupported or corrupt rows are represented +/// without manufacturing a `MetaAccountModel`; corrupt projections are strictly read-only. +enum MetaAccountSelectionRecordState: Equatable { + case supported + case unsupported + case corrupt + + var allowsStoredRecordUpdates: Bool { + self != .corrupt + } +} + +struct MetaAccountSelectionModel: Identifiable { + let identifier: String + let wallet: MetaAccountModel? + let isSelected: Bool + let order: UInt32 + let recordState: MetaAccountSelectionRecordState + let updatesWalletPayload: Bool + let updatesSelection: Bool + + init( + identifier: String, + wallet: MetaAccountModel?, + isSelected: Bool, + order: UInt32, + recordState: MetaAccountSelectionRecordState = .supported, + updatesWalletPayload: Bool = false, + updatesSelection: Bool = true + ) { + self.identifier = identifier + self.wallet = wallet + self.isSelected = isSelected + self.order = order + self.recordState = recordState + self.updatesWalletPayload = updatesWalletPayload + self.updatesSelection = updatesSelection + } + + func replacingSelection(_ isSelected: Bool) -> MetaAccountSelectionModel { + MetaAccountSelectionModel( + identifier: identifier, + wallet: wallet, + isSelected: isSelected, + order: order, + recordState: recordState, + updatesSelection: recordState.allowsStoredRecordUpdates + ) + } +} + +final class MetaAccountSelectionMapper { + var entityIdentifierFieldName: String { #keyPath(CDMetaAccount.metaId) } + + typealias DataProviderModel = MetaAccountSelectionModel + typealias CoreDataEntity = CDMetaAccount + + private lazy var metaAccountMapper = MetaAccountMapper() + + private func quarantineIdentifier(for entity: CDMetaAccount) -> String { + "fearless.quarantined-wallet:\(entity.objectID.uriRepresentation().absoluteString)" + } +} + +extension MetaAccountSelectionMapper: CoreDataMapperProtocol { + func transform(entity: CDMetaAccount) throws -> MetaAccountSelectionModel { + var mappedSelection: MetaAccountSelectionModel? + + // Selection is the first wallet read on startup. It must be protected + // independently of MetaAccountMapper because corrupt rows may throw + // while reading the identifier, selection flag, or ordering fields + // before the nested wallet mapper is reached. + try SafeObjectiveCExceptionBoundary.perform { + mappedSelection = try self.transformWithoutExceptionBoundary( + entity: entity + ) + } + + guard let mappedSelection else { + throw MetaAccountMapperError.invalidWalletRecord + } + + return mappedSelection + } + + private func transformWithoutExceptionBoundary( + entity: CDMetaAccount + ) throws -> MetaAccountSelectionModel { + let storedIdentifier: String? + let storedIsSelected: Bool + let storedOrder: UInt32 + + do { + storedIdentifier = try SafeTransformableValueReader.read( + from: entity, + key: "metaId" + ) + let selectedNumber: NSNumber? = + try SafeTransformableValueReader.read( + from: entity, + key: "isSelected" + ) + let orderNumber: NSNumber? = + try SafeTransformableValueReader.read( + from: entity, + key: "order" + ) + storedIsSelected = selectedNumber?.boolValue ?? false + storedOrder = UInt32( + bitPattern: orderNumber?.int32Value ?? 0 + ) + } catch { + // The selection repository must keep mapping healthy siblings even + // if this row cannot materialize its own projection fields. + return MetaAccountSelectionModel( + identifier: quarantineIdentifier(for: entity), + wallet: nil, + isSelected: false, + order: 0, + recordState: .corrupt + ) + } + + let identifier = storedIdentifier.flatMap { + let trimmedIdentifier = $0.trimmingCharacters(in: .whitespacesAndNewlines) + return !$0.isEmpty && $0 == trimmedIdentifier ? $0 : nil + } ?? quarantineIdentifier(for: entity) + let wallet: MetaAccountModel? + let recordState: MetaAccountSelectionRecordState + + guard storedIdentifier.map({ + !$0.isEmpty && + $0 == $0.trimmingCharacters(in: .whitespacesAndNewlines) + }) == true + else { + wallet = nil + recordState = .corrupt + + return MetaAccountSelectionModel( + identifier: identifier, + wallet: wallet, + isSelected: storedIsSelected, + order: storedOrder, + recordState: recordState + ) + } + + do { + wallet = try metaAccountMapper.transform(entity: entity) + recordState = .supported + } catch MetaAccountMapperError.unsupportedWalletRecord { + wallet = nil + recordState = .unsupported + } catch { + // A damaged app-local row must not abort mapping of its healthy siblings. + // Keep it as an immutable projection so no read or selection repair rewrites it. + wallet = nil + recordState = .corrupt + } + + return MetaAccountSelectionModel( + identifier: identifier, + wallet: wallet, + isSelected: storedIsSelected, + order: storedOrder, + recordState: recordState + ) + } + + func populate( + entity: CDMetaAccount, + from model: MetaAccountSelectionModel, + using context: NSManagedObjectContext + ) throws { + if model.updatesWalletPayload { + guard + let wallet = model.wallet, + wallet.metaId == model.identifier, + entity.metaId == nil || entity.metaId == model.identifier + else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let isNew = entity.metaId == nil + + if !isNew { + do { + _ = try metaAccountMapper.transform(entity: entity) + } catch { + throw SelectedWalletSettingsError.unsupportedWalletIdentifierConflict + } + } + + try metaAccountMapper.populate(entity: entity, from: wallet, using: context) + + if isNew { + entity.order = try nextOrder(in: context) + } else if model.order != ManagedMetaAccountModel.noOrder { + entity.order = Int32(bitPattern: model.order) + } + } else { + guard entity.metaId == model.identifier else { + // A selection repair must never manufacture a partial wallet row. + throw MetaAccountMapperError.invalidWalletRecord + } + + guard + !model.updatesSelection || + model.recordState.allowsStoredRecordUpdates + else { + // Corrupt projections are read-only, including their selection metadata. + throw MetaAccountMapperError.invalidWalletRecord + } + } + + if model.updatesSelection { + entity.isSelected = model.isSelected + } + } + + private func nextOrder(in context: NSManagedObjectContext) throws -> Int32 { + let fetchRequest = NSFetchRequest(entityName: "CDMetaAccount") + fetchRequest.includesPendingChanges = true + fetchRequest.includesSubentities = false + fetchRequest.sortDescriptors = [ + NSSortDescriptor(key: #keyPath(CDMetaAccount.order), ascending: false) + ] + fetchRequest.predicate = NSPredicate(format: "%K > 0", #keyPath(CDMetaAccount.order)) + fetchRequest.fetchLimit = 1 + + let lastOrder = try context.fetch(fetchRequest).first?.order ?? 0 + + guard lastOrder < Int32.max else { + throw MetaAccountMapperError.walletOrderOverflow + } + + return lastOrder + 1 + } +} diff --git a/fearless/Common/Storage/EntityToModel/PolkaswapSettingMapper.swift b/fearless/Common/Storage/EntityToModel/PolkaswapSettingMapper.swift index 584f12ea05..96692cce37 100644 --- a/fearless/Common/Storage/EntityToModel/PolkaswapSettingMapper.swift +++ b/fearless/Common/Storage/EntityToModel/PolkaswapSettingMapper.swift @@ -19,11 +19,26 @@ final class PolkaswapSettingMapper { extension PolkaswapSettingMapper: CoreDataMapperProtocol { func transform(entity: SSFAssetManagmentStorage.CDPolkaswapRemoteSettings) throws -> PolkaswapRemoteSettings { + let storedAvailableSources: [String]? + let forceSmartIds: [String]? + do { + storedAvailableSources = try SafeTransformableValueReader.read( + from: entity, + key: "availableSources" + ) + forceSmartIds = try SafeTransformableValueReader.read( + from: entity, + key: "forceSmartIds" + ) + } catch { + throw PolkaswapSettingMapperError.requiredFieldsMissing + } + guard let version = entity.version, - let availableSources = entity.availableSources?.compactMap({ + let availableSources = storedAvailableSources?.compactMap({ LiquiditySourceType(rawValue: $0) }), - let forceSmartIds = entity.forceSmartIds, + let forceSmartIds, let availableDexIdsSet = entity.availableDexIds, let xstusdId = entity.xstusdId else { diff --git a/fearless/Common/Storage/Migration/KeystoreMigrator.swift b/fearless/Common/Storage/Migration/KeystoreMigrator.swift index d9fa22cda1..a95e28de1c 100644 --- a/fearless/Common/Storage/Migration/KeystoreMigrator.swift +++ b/fearless/Common/Storage/Migration/KeystoreMigrator.swift @@ -1,43 +1,208 @@ import Foundation +import CryptoKit +import IrohaCrypto import SoraKeystore protocol KeystoreMigrating: AnyObject { func switchVersion() throws - func fetchKey(for identifier: String) -> Data? + func registerLegacyAccountRow() throws + func throwIfResourceLimitExceeded() throws + func fetchKey(for identifier: String) throws -> Data? func deleteKey(for identifier: String) func save(key: Data, for identifier: String) + func prepare() throws func finalize() throws } -enum KeystoreMigratingError: Error { +extension KeystoreMigrating { + func registerLegacyAccountRow() throws {} + func throwIfResourceLimitExceeded() throws {} +} + +enum KeystoreMigrationResource: String { + case legacyAccountRows + case stagedKeyCount + case identifierUTF8Bytes + case stagedKeyBytes + case deletionCount + case cleanupJournalBytes +} + +struct KeystoreMigrationResourceLimits { + // A v1 row can produce at most seven v2 keys and four legacy deletions. + // The byte ceilings remain intentionally independent so a small number of + // adversarially large keychain values or identifiers still fail closed. + static let production = KeystoreMigrationResourceLimits( + maximumLegacyAccountRows: 1024, + maximumStagedKeyCount: 7168, + maximumIdentifierUTF8Bytes: 2 * 1024 * 1024, + maximumStagedKeyBytes: 8 * 1024 * 1024, + maximumDeletionCount: 4096, + maximumCleanupJournalBytes: 2 * 1024 * 1024 + ) + + let maximumLegacyAccountRows: Int + let maximumStagedKeyCount: Int + let maximumIdentifierUTF8Bytes: Int + let maximumStagedKeyBytes: Int + let maximumDeletionCount: Int + let maximumCleanupJournalBytes: Int + + init( + maximumLegacyAccountRows: Int, + maximumStagedKeyCount: Int, + maximumIdentifierUTF8Bytes: Int, + maximumStagedKeyBytes: Int, + maximumDeletionCount: Int, + maximumCleanupJournalBytes: Int + ) { + precondition(maximumLegacyAccountRows >= 0) + precondition(maximumStagedKeyCount >= 0) + precondition(maximumIdentifierUTF8Bytes >= 0) + precondition(maximumStagedKeyBytes >= 0) + precondition(maximumDeletionCount >= 0) + precondition(maximumCleanupJournalBytes >= 0) + + self.maximumLegacyAccountRows = maximumLegacyAccountRows + self.maximumStagedKeyCount = maximumStagedKeyCount + self.maximumIdentifierUTF8Bytes = maximumIdentifierUTF8Bytes + self.maximumStagedKeyBytes = maximumStagedKeyBytes + self.maximumDeletionCount = maximumDeletionCount + self.maximumCleanupJournalBytes = maximumCleanupJournalBytes + } +} + +enum KeystoreMigratingError: LocalizedError { case nextVersionMissing case destinationNotReached + case notPrepared + case resourceLimitExceeded( + resource: KeystoreMigrationResource, + maximum: Int + ) + case stagedKeyConflict(String) + case stagedKeyVerificationFailed(String) + case cleanupJournalVerificationFailed + case invalidCleanupJournalVersion(String) + case invalidCleanupJournal(String) + case cleanupDestinationKeyMissing(String) + case cleanupDestinationKeyVerificationFailed(String) + + var errorDescription: String? { + switch self { + case .nextVersionMissing: + return "The next user-storage version is unavailable" + case .destinationNotReached: + return "The user-storage migration did not reach its destination version" + case .notPrepared: + return "Replacement keys were not staged before user-storage cleanup" + case let .resourceLimitExceeded(resource, maximum): + return """ + The user-storage key migration exceeded the \(resource.rawValue) \ + safety limit of \(maximum) + """ + case let .stagedKeyConflict(identifier): + return "Refusing to overwrite an unrelated keychain item at \(identifier)" + case let .stagedKeyVerificationFailed(identifier): + return "Unable to verify staged keychain item at \(identifier)" + case .cleanupJournalVerificationFailed: + return "Unable to verify the user-storage key cleanup journal" + case let .invalidCleanupJournalVersion(version): + return "The user-storage key cleanup journal contains an invalid version: \(version)" + case let .invalidCleanupJournal(reason): + return "The user-storage key cleanup journal is invalid: \(reason)" + case let .cleanupDestinationKeyMissing(identifier): + return "The migrated keychain item required for cleanup is missing: \(identifier)" + case let .cleanupDestinationKeyVerificationFailed(identifier): + return "The migrated keychain item required for cleanup failed verification: \(identifier)" + } + } } class KeystoreMigrator { + static let pendingCleanupIdentifier = "io.fearless.user-storage-migration.pending-key-cleanup" + private static let cleanupJournalSchemaVersion = 1 + private static let legacyDeletionSuffixes = [ + "-secretKey", + "-entropy", + "-deriv", + "-seed" + ] + private static let destinationKeySuffixes = [ + "-substrateSecretKey", + "-ethereumSecretKey", + "-substrateSeed", + "-ethereumSeed", + "-substrateDeriv", + "-ethereumDeriv", + "-entropy" + ] + + private struct CleanupJournal: Codable { + let schemaVersion: Int + let sourceVersion: String + let destinationVersion: String + let identifiersToRemove: [String] + let stagedIdentifiers: [String] + let destinationKeyProofs: [DestinationKeyProof] + } + + private struct DestinationKeyProof: Codable { + let identifier: String + let sha256: Data + } + + private struct CleanupJournalEnvelope: Decodable { + let schemaVersion: Int? + let destinationKeyProofs: [DestinationKeyProof]? + } + + private struct LegacyCleanupJournal: Decodable { + let sourceVersion: String + let destinationVersion: String + let identifiersToRemove: [String] + let stagedIdentifiers: [String] + } + let sourceVersion: UserStorageVersion let destinationVersion: UserStorageVersion let keystore: KeystoreProtocol + let resourceLimits: KeystoreMigrationResourceLimits private(set) var currentVersion: UserStorageVersion private(set) var identifiersToRemoveOnFinalize: Set = [] private(set) var tempKeystore: [String: Data] = [:] + private(set) var isPrepared = false + private var identifiersStagedDuringPrepare = Set() + private var stagedKeyConflicts = Set() + private var migratedLegacyAccountRowCount = 0 + private var retainedIdentifierUTF8ByteCount = 0 + private var stagedKeyByteCount = 0 + // save/delete cannot throw. The first violation is retained and freezes + // every later mutation until the throwing migration boundary observes it. + private var resourceLimitError: KeystoreMigratingError? init( sourceVersion: UserStorageVersion, destinationVersion: UserStorageVersion, - keystore: KeystoreProtocol + keystore: KeystoreProtocol, + resourceLimits: KeystoreMigrationResourceLimits = .production ) { self.sourceVersion = sourceVersion self.destinationVersion = destinationVersion currentVersion = sourceVersion self.keystore = keystore + self.resourceLimits = resourceLimits } } extension KeystoreMigrator: KeystoreMigrating { func switchVersion() throws { + if let resourceLimitError { + throw resourceLimitError + } + guard let nextVersion = currentVersion.nextVersion() else { throw KeystoreMigratingError.nextVersionMissing } @@ -45,35 +210,871 @@ extension KeystoreMigrator: KeystoreMigrating { currentVersion = nextVersion } - func fetchKey(for identifier: String) -> Data? { + func registerLegacyAccountRow() throws { + if let resourceLimitError { + throw resourceLimitError + } + + guard + let nextCount = checkedAdding( + 1, + to: migratedLegacyAccountRowCount, + resource: .legacyAccountRows, + maximum: resourceLimits.maximumLegacyAccountRows + ) + else { + throw resourceLimitError ?? KeystoreMigratingError + .resourceLimitExceeded( + resource: .legacyAccountRows, + maximum: resourceLimits.maximumLegacyAccountRows + ) + } + + migratedLegacyAccountRowCount = nextCount + } + + func throwIfResourceLimitExceeded() throws { + if let resourceLimitError { + throw resourceLimitError + } + } + + func fetchKey(for identifier: String) throws -> Data? { + if let resourceLimitError { + throw resourceLimitError + } + if sourceVersion.nextVersion() == currentVersion { - return try? keystore.fetchKey(for: identifier) + do { + return try keystore.fetchKey(for: identifier) + } catch KeystoreError.noKeyFound { + return nil + } } else { return tempKeystore[identifier] } } func deleteKey(for identifier: String) { - tempKeystore[identifier] = nil + guard resourceLimitError == nil else { + return + } + let stagedKey = tempKeystore[identifier] + let isAlreadyScheduledForDeletion = + identifiersToRemoveOnFinalize.contains(identifier) + + guard !isAlreadyScheduledForDeletion else { + return + } + + guard + checkedAdding( + 1, + to: identifiersToRemoveOnFinalize.count, + resource: .deletionCount, + maximum: resourceLimits.maximumDeletionCount + ) != nil + else { + return + } + + if stagedKey == nil { + guard + checkedAdding( + identifier.utf8.count, + to: retainedIdentifierUTF8ByteCount, + resource: .identifierUTF8Bytes, + maximum: resourceLimits.maximumIdentifierUTF8Bytes + ) != nil + else { + return + } + } + + tempKeystore[identifier] = nil identifiersToRemoveOnFinalize.insert(identifier) + + if let stagedKey { + stagedKeyByteCount -= stagedKey.count + } else { + retainedIdentifierUTF8ByteCount += identifier.utf8.count + } } func save(key: Data, for identifier: String) { + guard resourceLimitError == nil else { + return + } + + if let stagedKey = tempKeystore[identifier], stagedKey != key { + stagedKeyConflicts.insert(identifier) + return + } + + if tempKeystore[identifier] != nil { + return + } + + guard + checkedAdding( + 1, + to: tempKeystore.count, + resource: .stagedKeyCount, + maximum: resourceLimits.maximumStagedKeyCount + ) != nil + else { + return + } + + let isMovingFromDeletion = + identifiersToRemoveOnFinalize.contains(identifier) + + if !isMovingFromDeletion { + guard + checkedAdding( + identifier.utf8.count, + to: retainedIdentifierUTF8ByteCount, + resource: .identifierUTF8Bytes, + maximum: resourceLimits.maximumIdentifierUTF8Bytes + ) != nil + else { + return + } + } + + guard + checkedAdding( + key.count, + to: stagedKeyByteCount, + resource: .stagedKeyBytes, + maximum: resourceLimits.maximumStagedKeyBytes + ) != nil + else { + return + } + tempKeystore[identifier] = key + identifiersToRemoveOnFinalize.remove(identifier) + stagedKeyByteCount += key.count + + if !isMovingFromDeletion { + retainedIdentifierUTF8ByteCount += identifier.utf8.count + } + } + + func prepare() throws { + if let resourceLimitError { + throw resourceLimitError + } + + guard currentVersion == destinationVersion else { + throw KeystoreMigratingError.destinationNotReached + } + + if let identifier = stagedKeyConflicts.sorted().first { + throw KeystoreMigratingError.stagedKeyConflict(identifier) + } + + guard !tempKeystore.isEmpty || !identifiersToRemoveOnFinalize.isEmpty else { + isPrepared = true + return + } + + var identifiersNeedingWrite = Set() + + for identifier in tempKeystore.keys.sorted() { + guard let key = tempKeystore[identifier] else { + continue + } + + if try keystore.checkKey(for: identifier) { + guard try keystore.fetchKey(for: identifier) == key else { + throw KeystoreMigratingError.stagedKeyConflict(identifier) + } + } else { + identifiersNeedingWrite.insert(identifier) + } + } + + identifiersStagedDuringPrepare.formUnion(identifiersNeedingWrite) + + let journal = CleanupJournal( + schemaVersion: Self.cleanupJournalSchemaVersion, + sourceVersion: sourceVersion.rawValue, + destinationVersion: destinationVersion.rawValue, + identifiersToRemove: identifiersToRemoveOnFinalize.sorted(), + stagedIdentifiers: identifiersStagedDuringPrepare.sorted(), + destinationKeyProofs: tempKeystore + .map { identifier, key in + DestinationKeyProof( + identifier: identifier, + sha256: Self.digest(for: key) + ) + } + .sorted { $0.identifier < $1.identifier } + ) + try Self.validate( + journal, + resourceLimits: resourceLimits + ) + + let journalData = try Self.encode(journal) + guard + journalData.count <= + resourceLimits.maximumCleanupJournalBytes + else { + let error = recordResourceLimitError( + resource: .cleanupJournalBytes, + maximum: resourceLimits.maximumCleanupJournalBytes + ) + throw error + } + + try keystore.saveKey(journalData, with: Self.pendingCleanupIdentifier) + + guard + try keystore.fetchKey(for: Self.pendingCleanupIdentifier) == journalData + else { + throw KeystoreMigratingError.cleanupJournalVerificationFailed + } + + for identifier in identifiersNeedingWrite.sorted() { + guard let key = tempKeystore[identifier] else { + continue + } + + try keystore.addKey(key, with: identifier) + } + + for identifier in tempKeystore.keys.sorted() { + guard + let expectedKey = tempKeystore[identifier], + try keystore.fetchKey(for: identifier) == expectedKey + else { + throw KeystoreMigratingError.stagedKeyVerificationFailed(identifier) + } + } + + isPrepared = true } func finalize() throws { + if let resourceLimitError { + throw resourceLimitError + } + guard currentVersion == destinationVersion else { throw KeystoreMigratingError.destinationNotReached } - try identifiersToRemoveOnFinalize.forEach { identifier in - try keystore.deleteKeyIfExists(for: identifier) + guard isPrepared else { + throw KeystoreMigratingError.notPrepared + } + + guard !tempKeystore.isEmpty || !identifiersToRemoveOnFinalize.isEmpty else { + return + } + + try Self.verifyDestinationKeys( + CleanupJournal( + schemaVersion: Self.cleanupJournalSchemaVersion, + sourceVersion: sourceVersion.rawValue, + destinationVersion: destinationVersion.rawValue, + identifiersToRemove: identifiersToRemoveOnFinalize.sorted(), + stagedIdentifiers: identifiersStagedDuringPrepare.sorted(), + destinationKeyProofs: tempKeystore + .map { identifier, key in + DestinationKeyProof( + identifier: identifier, + sha256: Self.digest(for: key) + ) + } + .sorted { $0.identifier < $1.identifier } + ).destinationKeyProofs, + in: keystore, + resourceLimits: resourceLimits + ) + + try Self.removeKeys( + identifiersToRemoveOnFinalize.sorted(), + from: keystore + ) + try Self.deleteKeyIfPresent( + Self.pendingCleanupIdentifier, + from: keystore + ) + } +} + +private extension KeystoreMigrator { + func checkedAdding( + _ increment: Int, + to current: Int, + resource: KeystoreMigrationResource, + maximum: Int + ) -> Int? { + let (result, overflow) = current.addingReportingOverflow(increment) + + guard !overflow, result <= maximum else { + _ = recordResourceLimitError( + resource: resource, + maximum: maximum + ) + + return nil + } + + return result + } + + func recordResourceLimitError( + resource: KeystoreMigrationResource, + maximum: Int + ) -> KeystoreMigratingError { + if let resourceLimitError { + return resourceLimitError + } + + let error = KeystoreMigratingError.resourceLimitExceeded( + resource: resource, + maximum: maximum + ) + resourceLimitError = error + + return error + } +} + +extension KeystoreMigrator { + static func recoverPendingCleanup( + keystore: KeystoreProtocol, + currentVersion: UserStorageVersion + ) throws { + let journalData: Data + + do { + journalData = try keystore.fetchKey(for: pendingCleanupIdentifier) + } catch KeystoreError.noKeyFound { + return + } + + guard + journalData.count <= + KeystoreMigrationResourceLimits.production + .maximumCleanupJournalBytes + else { + throw KeystoreMigratingError.resourceLimitExceeded( + resource: .cleanupJournalBytes, + maximum: KeystoreMigrationResourceLimits.production + .maximumCleanupJournalBytes + ) + } + + let decoder = JSONDecoder() + let envelope = try decoder.decode( + CleanupJournalEnvelope.self, + from: journalData + ) + + if envelope.schemaVersion == nil { + guard envelope.destinationKeyProofs == nil else { + throw KeystoreMigratingError.invalidCleanupJournal( + "a destination proof list has no schema version" + ) + } + + let legacyJournal = try decoder.decode( + LegacyCleanupJournal.self, + from: journalData + ) + try recoverLegacyCleanupJournal( + legacyJournal, + keystore: keystore, + currentVersion: currentVersion + ) + return + } + + let journal = try decoder.decode(CleanupJournal.self, from: journalData) + try validate( + journal, + resourceLimits: .production + ) + + guard let sourceVersion = UserStorageVersion(rawValue: journal.sourceVersion) else { + throw KeystoreMigratingError.invalidCleanupJournalVersion(journal.sourceVersion) + } + + guard let destinationVersion = UserStorageVersion(rawValue: journal.destinationVersion) else { + throw KeystoreMigratingError.invalidCleanupJournalVersion(journal.destinationVersion) + } + + if currentVersion.isSameOrNewer(than: destinationVersion) { + try verifyDestinationKeys( + journal.destinationKeyProofs, + in: keystore, + resourceLimits: .production + ) + try removeKeys(journal.identifiersToRemove, from: keystore) + try deleteKeyIfPresent(pendingCleanupIdentifier, from: keystore) + } else if currentVersion == sourceVersion { + try verifyAndRemoveRollbackKeys( + journal.stagedIdentifiers, + destinationKeyProofs: journal.destinationKeyProofs, + from: keystore, + resourceLimits: .production + ) + try deleteKeyIfPresent(pendingCleanupIdentifier, from: keystore) + } else { + throw KeystoreMigratingError.invalidCleanupJournal( + "the database version does not match the journal boundary" + ) + } + } + + private static func recoverLegacyCleanupJournal( + _ journal: LegacyCleanupJournal, + keystore: KeystoreProtocol, + currentVersion: UserStorageVersion + ) throws { + try validateResourceLimits( + identifiersToRemove: journal.identifiersToRemove, + stagedIdentifiers: journal.stagedIdentifiers, + destinationProofIdentifiers: journal.stagedIdentifiers, + resourceLimits: .production + ) + + let versions = try validateVersions( + sourceVersion: journal.sourceVersion, + destinationVersion: journal.destinationVersion + ) + let identifiersToRemove = Set(journal.identifiersToRemove) + let stagedIdentifiers = Set(journal.stagedIdentifiers) + + guard identifiersToRemove.count == journal.identifiersToRemove.count else { + throw KeystoreMigratingError.invalidCleanupJournal( + "duplicate legacy identifiers" + ) + } + + guard stagedIdentifiers.count == journal.stagedIdentifiers.count else { + throw KeystoreMigratingError.invalidCleanupJournal( + "duplicate staged identifiers" + ) + } + + let allIdentifiers = identifiersToRemove.union(stagedIdentifiers) + + guard !allIdentifiers.contains(where: \.isEmpty) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "empty keychain identifier" + ) + } + + guard !allIdentifiers.contains(pendingCleanupIdentifier) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "the cleanup journal identifier is reserved" + ) + } + + guard identifiersToRemove.isDisjoint(with: stagedIdentifiers) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "a staged identifier appears in the legacy deletion list" + ) + } + + try validateLegacyDeletionIdentifiers(identifiersToRemove) + try validateDestinationIdentifiers(stagedIdentifiers) + + guard + currentVersion == versions.source || + currentVersion.isSameOrNewer(than: versions.destination) + else { + throw KeystoreMigratingError.invalidCleanupJournal( + "the database version does not match the journal boundary" + ) + } + + // Legacy journals contain no integrity proof. Clearing only the journal + // preserves every user and staged key while allowing a source store to + // rerun migration with the current verified two-phase protocol. + try deleteKeyIfPresent(pendingCleanupIdentifier, from: keystore) + } + + private static func validate( + _ journal: CleanupJournal, + resourceLimits: KeystoreMigrationResourceLimits + ) throws { + try validateResourceLimits( + identifiersToRemove: journal.identifiersToRemove, + stagedIdentifiers: journal.stagedIdentifiers, + destinationProofIdentifiers: + journal.destinationKeyProofs.map(\.identifier), + resourceLimits: resourceLimits + ) + + guard journal.schemaVersion == cleanupJournalSchemaVersion else { + throw KeystoreMigratingError.invalidCleanupJournal( + "unsupported schema version \(journal.schemaVersion)" + ) + } + + _ = try validateVersions( + sourceVersion: journal.sourceVersion, + destinationVersion: journal.destinationVersion + ) + + let identifiersToRemove = Set(journal.identifiersToRemove) + let stagedIdentifiers = Set(journal.stagedIdentifiers) + let destinationIdentifiers = Set(journal.destinationKeyProofs.map(\.identifier)) + + guard identifiersToRemove.count == journal.identifiersToRemove.count else { + throw KeystoreMigratingError.invalidCleanupJournal( + "duplicate legacy identifiers" + ) + } + + guard stagedIdentifiers.count == journal.stagedIdentifiers.count else { + throw KeystoreMigratingError.invalidCleanupJournal( + "duplicate staged identifiers" + ) + } + + guard destinationIdentifiers.count == journal.destinationKeyProofs.count else { + throw KeystoreMigratingError.invalidCleanupJournal( + "duplicate destination key proofs" + ) + } + + let allIdentifiers = identifiersToRemove + .union(stagedIdentifiers) + .union(destinationIdentifiers) + + guard !allIdentifiers.contains(where: \.isEmpty) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "empty keychain identifier" + ) + } + + guard !allIdentifiers.contains(pendingCleanupIdentifier) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "the cleanup journal identifier is reserved" + ) + } + + guard identifiersToRemove.isDisjoint(with: destinationIdentifiers) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "a destination identifier appears in the legacy deletion list" + ) + } + + try validateLegacyDeletionIdentifiers(identifiersToRemove) + try validateDestinationIdentifiers(destinationIdentifiers) + + guard stagedIdentifiers.isSubset(of: destinationIdentifiers) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "a staged identifier has no destination integrity proof" + ) } - for (identifier, key) in tempKeystore { - try keystore.saveKey(key, with: identifier) + guard identifiersToRemove.isEmpty || !destinationIdentifiers.isEmpty else { + throw KeystoreMigratingError.invalidCleanupJournal( + "legacy deletion has no destination integrity proof" + ) } + + guard journal.destinationKeyProofs.allSatisfy({ $0.sha256.count == SHA256.byteCount }) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "a destination integrity proof has an invalid digest" + ) + } + } + + private static func validateVersions( + sourceVersion: String, + destinationVersion: String + ) throws -> ( + source: UserStorageVersion, + destination: UserStorageVersion + ) { + guard + let source = UserStorageVersion(rawValue: sourceVersion), + let destination = UserStorageVersion(rawValue: destinationVersion), + source != destination, + destination.isSameOrNewer(than: source) + else { + throw KeystoreMigratingError.invalidCleanupJournal( + "source and destination versions do not form a valid forward migration" + ) + } + + return (source, destination) + } + + private static func validateResourceLimits( + identifiersToRemove: [String], + stagedIdentifiers: [String], + destinationProofIdentifiers: [String], + resourceLimits: KeystoreMigrationResourceLimits + ) throws { + guard + identifiersToRemove.count <= + resourceLimits.maximumDeletionCount + else { + throw KeystoreMigratingError.resourceLimitExceeded( + resource: .deletionCount, + maximum: resourceLimits.maximumDeletionCount + ) + } + + guard + stagedIdentifiers.count <= + resourceLimits.maximumStagedKeyCount, + destinationProofIdentifiers.count <= + resourceLimits.maximumStagedKeyCount + else { + throw KeystoreMigratingError.resourceLimitExceeded( + resource: .stagedKeyCount, + maximum: resourceLimits.maximumStagedKeyCount + ) + } + + let uniqueIdentifiers = Set( + identifiersToRemove + + stagedIdentifiers + + destinationProofIdentifiers + ) + var aggregateIdentifierBytes = 0 + + for identifier in uniqueIdentifiers { + let (nextCount, overflow) = + aggregateIdentifierBytes.addingReportingOverflow( + identifier.utf8.count + ) + + guard + !overflow, + nextCount <= + resourceLimits.maximumIdentifierUTF8Bytes + else { + throw KeystoreMigratingError.resourceLimitExceeded( + resource: .identifierUTF8Bytes, + maximum: resourceLimits + .maximumIdentifierUTF8Bytes + ) + } + + aggregateIdentifierBytes = nextCount + } + } + + private static func encode(_ journal: CleanupJournal) throws -> Data { + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys] + + return try encoder.encode(journal) + } + + private static func validateLegacyDeletionIdentifiers( + _ identifiers: Set + ) throws { + guard identifiers.allSatisfy(isLegacyDeletionIdentifier) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "the legacy deletion list contains a non-migration keychain identifier" + ) + } + } + + private static func validateDestinationIdentifiers( + _ identifiers: Set + ) throws { + guard identifiers.allSatisfy(isDestinationMigrationIdentifier) else { + throw KeystoreMigratingError.invalidCleanupJournal( + "the destination list contains a non-migration keychain identifier" + ) + } + } + + private static func isLegacyDeletionIdentifier( + _ identifier: String + ) -> Bool { + guard + let suffix = legacyDeletionSuffixes.first( + where: identifier.hasSuffix + ), + identifier.count > suffix.count + else { + return false + } + + let address = String(identifier.dropLast(suffix.count)) + + do { + _ = try SS58AddressFactory().accountId(from: address) + return true + } catch { + return false + } + } + + private static func isDestinationMigrationIdentifier( + _ identifier: String + ) -> Bool { + guard + let suffix = destinationKeySuffixes.first( + where: identifier.hasSuffix + ), + identifier.count > suffix.count + else { + return false + } + + let metaId = String(identifier.dropLast(suffix.count)) + + return UUID(uuidString: metaId) != nil + } + + private static func verifyDestinationKeys( + _ proofs: [DestinationKeyProof], + in keystore: KeystoreProtocol, + resourceLimits: KeystoreMigrationResourceLimits + ) throws { + var aggregateKeyBytes = 0 + + for proof in proofs { + let key: Data + + do { + key = try keystore.fetchKey(for: proof.identifier) + } catch KeystoreError.noKeyFound { + throw KeystoreMigratingError.cleanupDestinationKeyMissing( + proof.identifier + ) + } + + aggregateKeyBytes = try checkedResourceTotal( + aggregateKeyBytes, + adding: key.count, + resource: .stagedKeyBytes, + maximum: resourceLimits.maximumStagedKeyBytes + ) + + guard digest(for: key) == proof.sha256 else { + throw KeystoreMigratingError.cleanupDestinationKeyVerificationFailed( + proof.identifier + ) + } + } + } + + private static func verifyAndRemoveRollbackKeys( + _ identifiers: [String], + destinationKeyProofs: [DestinationKeyProof], + from keystore: KeystoreProtocol, + resourceLimits: KeystoreMigrationResourceLimits + ) throws { + let proofsByIdentifier = Dictionary( + uniqueKeysWithValues: destinationKeyProofs.map { + ($0.identifier, $0) + } + ) + var identifiersPresent = [String]() + var aggregateKeyBytes = 0 + + for identifier in identifiers { + guard let proof = proofsByIdentifier[identifier] else { + throw KeystoreMigratingError.invalidCleanupJournal( + "a staged identifier has no destination integrity proof" + ) + } + + let key: Data + + do { + key = try keystore.fetchKey(for: identifier) + } catch KeystoreError.noKeyFound { + continue + } + + aggregateKeyBytes = try checkedResourceTotal( + aggregateKeyBytes, + adding: key.count, + resource: .stagedKeyBytes, + maximum: resourceLimits.maximumStagedKeyBytes + ) + + guard digest(for: key) == proof.sha256 else { + throw KeystoreMigratingError.cleanupDestinationKeyVerificationFailed( + identifier + ) + } + + identifiersPresent.append(identifier) + } + + try removeKeys(identifiersPresent, from: keystore) + } + + private static func checkedResourceTotal( + _ current: Int, + adding increment: Int, + resource: KeystoreMigrationResource, + maximum: Int + ) throws -> Int { + let (result, overflow) = current.addingReportingOverflow(increment) + + guard !overflow, result <= maximum else { + throw KeystoreMigratingError.resourceLimitExceeded( + resource: resource, + maximum: maximum + ) + } + + return result + } + + private static func digest(for key: Data) -> Data { + Data(SHA256.hash(data: key)) + } + + private static func removeKeys( + _ identifiers: [String], + from keystore: KeystoreProtocol + ) throws { + for identifier in identifiers { + try deleteKeyIfPresent(identifier, from: keystore) + } + } + + private static func deleteKeyIfPresent( + _ identifier: String, + from keystore: KeystoreProtocol + ) throws { + guard try keystore.checkKey(for: identifier) else { + return + } + + do { + try keystore.deleteKey(for: identifier) + } catch KeystoreError.noKeyFound { + // Another cleanup attempt already removed it. + } + } +} + +private extension UserStorageVersion { + func isSameOrNewer(than version: UserStorageVersion) -> Bool { + var candidate: UserStorageVersion? = version + + while let unwrappedCandidate = candidate { + if unwrappedCandidate == self { + return true + } + + candidate = unwrappedCandidate.nextVersion() + } + + return false } } diff --git a/fearless/Common/Storage/Migration/SettingsMigrator.swift b/fearless/Common/Storage/Migration/SettingsMigrator.swift index 5646ed4d6c..24e6b00c7f 100644 --- a/fearless/Common/Storage/Migration/SettingsMigrator.swift +++ b/fearless/Common/Storage/Migration/SettingsMigrator.swift @@ -6,10 +6,56 @@ protocol SettingsMigrating: AnyObject { func value(for key: String) -> Any? func remove(key: String) func set(value: Any, for key: String) + func prepare() throws func finalize() throws } +enum SettingsMigratingError: LocalizedError { + case destinationNotReached + case notPrepared + case unsupportedPendingValues + case cleanupJournalVerificationFailed + case invalidCleanupJournal + + var errorDescription: String? { + switch self { + case .destinationNotReached: + return "The settings migration did not reach its destination version" + case .notPrepared: + return "The settings cleanup was not prepared before database replacement" + case .unsupportedPendingValues: + return "The settings migration contains unsupported pending values" + case .cleanupJournalVerificationFailed: + return "Unable to verify the pending settings cleanup" + case .invalidCleanupJournal: + return "The pending settings cleanup is invalid" + } + } +} + class SettingsMigrator { + static let pendingCleanupKey = + "io.fearless.user-storage-migration.pending-settings-cleanup" + private static let cleanupJournalSchemaVersion = 1 + private static let maximumCleanupJournalBytes = 4096 + private static let cleanupJournalFields: Set = [ + "schemaVersion", + "sourceVersion", + "destinationVersion", + "keysToRemove" + ] + private static let allowedCleanupKeys: Set = [ + SettingsKey.selectedAccount.rawValue, + SettingsKey.selectedConnection.rawValue + ] + + private struct CleanupJournal: Codable { + let schemaVersion: Int + let sourceVersion: String + let destinationVersion: String + let keysToRemove: [String] + } + let sourceVersion: UserStorageVersion let destinationVersion: UserStorageVersion private(set) var settings: SettingsManagerProtocol @@ -18,6 +64,7 @@ class SettingsMigrator { private(set) var keysToRemoveOnFinalize: Set = [] private(set) var tempKeystore: [String: Any] = [:] + private(set) var isPrepared = false init( sourceVersion: UserStorageVersion, @@ -58,17 +105,221 @@ extension SettingsMigrator: SettingsMigrating { tempKeystore[key] = value } + func prepare() throws { + guard currentVersion == destinationVersion else { + throw SettingsMigratingError.destinationNotReached + } + + // No current user-storage mapping stages settings values. Refuse to + // cross the database replacement boundary if a future mapping starts + // doing so without extending the durable journal format first. + guard tempKeystore.isEmpty else { + throw SettingsMigratingError.unsupportedPendingValues + } + + guard !keysToRemoveOnFinalize.isEmpty else { + isPrepared = true + return + } + + let journal = CleanupJournal( + schemaVersion: Self.cleanupJournalSchemaVersion, + sourceVersion: sourceVersion.rawValue, + destinationVersion: destinationVersion.rawValue, + keysToRemove: keysToRemoveOnFinalize.sorted() + ) + try Self.validate(journal) + + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys] + let data = try encoder.encode(journal) + settings.set(value: data, for: Self.pendingCleanupKey) + + guard settings.data(for: Self.pendingCleanupKey) == data else { + throw SettingsMigratingError + .cleanupJournalVerificationFailed + } + + isPrepared = true + } + func finalize() throws { guard currentVersion == destinationVersion else { - throw KeystoreMigratingError.destinationNotReached + throw SettingsMigratingError.destinationNotReached + } + + guard isPrepared else { + throw SettingsMigratingError.notPrepared + } + + guard !keysToRemoveOnFinalize.isEmpty else { + return + } + + guard settings.data(for: Self.pendingCleanupKey) != nil else { + throw SettingsMigratingError + .cleanupJournalVerificationFailed + } + + try Self.recoverPendingCleanup( + settings: settings, + currentVersion: destinationVersion + ) + } +} + +extension SettingsMigrator { + static func recoverPendingCleanup( + settings: SettingsManagerProtocol, + currentVersion: UserStorageVersion + ) throws { + guard let storedValue = settings.anyValue( + for: pendingCleanupKey + ) else { + return + } + + guard let data = storedValue as? Data else { + throw SettingsMigratingError.invalidCleanupJournal + } + try validateEncodedJournalShape(data) + + let journal: CleanupJournal + do { + journal = try JSONDecoder().decode( + CleanupJournal.self, + from: data + ) + } catch { + throw SettingsMigratingError.invalidCleanupJournal + } + + try validate(journal) + + guard + let sourceVersion = + UserStorageVersion(rawValue: journal.sourceVersion), + let destinationVersion = + UserStorageVersion(rawValue: journal.destinationVersion) + else { + throw SettingsMigratingError.invalidCleanupJournal } - keysToRemoveOnFinalize.forEach { key in - settings.removeValue(for: key) + if isVersion( + currentVersion, + sameOrNewerThan: destinationVersion + ) { + for key in journal.keysToRemove { + settings.removeValue(for: key) + } + + guard journal.keysToRemove.allSatisfy({ + settings.anyValue(for: $0) == nil + }) else { + throw SettingsMigratingError + .cleanupJournalVerificationFailed + } + + settings.removeValue(for: pendingCleanupKey) + } else if currentVersion == sourceVersion { + // Database replacement did not occur. Discard the cleanup intent; + // the next migration attempt will reconstruct it. + settings.removeValue(for: pendingCleanupKey) + } else { + throw SettingsMigratingError.invalidCleanupJournal + } + } + + private static func validate( + _ journal: CleanupJournal + ) throws { + guard + journal.schemaVersion == cleanupJournalSchemaVersion, + let sourceVersion = + UserStorageVersion(rawValue: journal.sourceVersion), + let destinationVersion = + UserStorageVersion(rawValue: journal.destinationVersion), + isVersion( + destinationVersion, + sameOrNewerThan: sourceVersion + ), + sourceVersion != destinationVersion, + Set(journal.keysToRemove).count == + journal.keysToRemove.count, + Set(journal.keysToRemove) == allowedCleanupKeys + else { + throw SettingsMigratingError.invalidCleanupJournal } + } - for (key, value) in tempKeystore { - settings.set(anyValue: value, for: key) + private static func validateEncodedJournalShape( + _ data: Data + ) throws { + guard + !data.isEmpty, + data.count <= maximumCleanupJournalBytes, + let object = try? JSONSerialization.jsonObject( + with: data, + options: [] + ) as? [String: Any], + Set(object.keys) == cleanupJournalFields, + object["schemaVersion"] is Int, + object["sourceVersion"] is String, + object["destinationVersion"] is String, + object["keysToRemove"] is [String] + else { + throw SettingsMigratingError.invalidCleanupJournal } + + // JSONSerialization accepts duplicate members and keeps one value. + // Require every exact ASCII field token once so a duplicate or escaped + // spelling can never smuggle an alternate cleanup request. + for field in cleanupJournalFields { + let token = Data("\"\(field)\"".utf8) + guard data.nonOverlappingOccurrenceCount(of: token) == 1 else { + throw SettingsMigratingError.invalidCleanupJournal + } + } + } + + private static func isVersion( + _ candidate: UserStorageVersion, + sameOrNewerThan version: UserStorageVersion + ) -> Bool { + var current: UserStorageVersion? = version + + while let currentVersion = current { + if currentVersion == candidate { + return true + } + + current = currentVersion.nextVersion() + } + + return false + } +} + +private extension Data { + func nonOverlappingOccurrenceCount(of token: Data) -> Int { + guard !token.isEmpty else { + return 0 + } + + var count = 0 + var searchStart = startIndex + + while + searchStart < endIndex, + let range = range( + of: token, + options: [], + in: searchStart ..< endIndex + ) { + count += 1 + searchStart = range.upperBound + } + + return count } } diff --git a/fearless/Common/Storage/Migration/SubstrateStorage/ChainModelV4MigrationPolicy.swift b/fearless/Common/Storage/Migration/SubstrateStorage/ChainModelV4MigrationPolicy.swift index 4e21586134..0ac9ca70bc 100644 --- a/fearless/Common/Storage/Migration/SubstrateStorage/ChainModelV4MigrationPolicy.swift +++ b/fearless/Common/Storage/Migration/SubstrateStorage/ChainModelV4MigrationPolicy.swift @@ -2,6 +2,20 @@ import Foundation import CoreData class ChainModelV4MigrationPolicy: NSEntityMigrationPolicy { + private enum Constants { + static let assetEntityName = "CDAsset" + static let assetsRelationshipName = "assets" + static let disabledAttributeName = "disabled" + static let legacyAssetRelationshipName = "asset" + static let wrapperMetadataKeys = [ + "isNative", + "isUtility", + "purchaseProviders", + "staking", + "type" + ] + } + override func createDestinationInstances( forSource chainModel: NSManagedObject, in mapping: NSEntityMapping, @@ -9,75 +23,106 @@ class ChainModelV4MigrationPolicy: NSEntityMigrationPolicy { ) throws { try super.createDestinationInstances(forSource: chainModel, in: mapping, manager: manager) - guard let updatedChainModel = manager.destinationInstances( + guard let destinationChain = manager.destinationInstances( forEntityMappingName: mapping.name, sourceInstances: [chainModel] ).first else { throw ConvenienceError(error: "Can't create destination instance") } - guard let chainAssetsModels = chainModel.value(forKey: "assets") as? Set else { - throw ConvenienceError(error: "No assets value") + destinationChain.setValue( + false, + forKey: Constants.disabledAttributeName + ) + } + + override func createRelationships( + forDestination destinationChain: NSManagedObject, + in mapping: NSEntityMapping, + manager: NSMigrationManager + ) throws { + try super.createRelationships( + forDestination: destinationChain, + in: mapping, + manager: manager + ) + + guard let sourceChain = manager.sourceInstances( + forEntityMappingName: mapping.name, + destinationInstances: [destinationChain] + ).first else { + return } - let assetModels: [NSManagedObject] = chainAssetsModels.compactMap { - guard - let assetModel = $0.value(forKey: "asset") as? NSManagedObject, - let id = assetModel.value(forKey: "id") as? String, - let symbol = assetModel.value(forKey: "symbol") as? String, - let precision = assetModel.value(forKey: "precision") as? UInt16 - else { - return nil + let legacyWrappers = + sourceChain.value(forKey: Constants.assetsRelationshipName) as? Set + ?? [] + guard !legacyWrappers.isEmpty else { + return + } + + guard + let assetMappingName = manager.mappingModel.entityMappings.first(where: { + $0.sourceEntityName == Constants.assetEntityName && + $0.destinationEntityName == Constants.assetEntityName + })?.name + else { + throw ConvenienceError(error: "Can't find the CDAsset entity mapping") + } + + let destinationAssets = destinationChain.mutableSetValue( + forKey: Constants.assetsRelationshipName + ) + + for wrapper in legacyWrappers { + guard let sourceAsset = wrapper.value( + forKey: Constants.legacyAssetRelationshipName + ) as? NSManagedObject else { + continue } - let icon = assetModel.value(forKey: "icon") as? URL - let priceId = assetModel.value(forKey: "priceId") as? String - let price = assetModel.value(forKey: "price") as? Decimal - let fiatDayChange = assetModel.value(forKey: "fiatDayChange") as? String - let currencyId = assetModel.value(forKey: "currencyId") as? String - let existentialDeposit = assetModel.value(forKey: "existentialDeposit") as? String - let color = assetModel.value(forKey: "color") as? String - - let isNative: Bool = ($0.value(forKey: "isNative") as? Bool) ?? false - let isUtility: Bool = ($0.value(forKey: "isUtility") as? Bool) ?? false - let purchaseProviders: [String]? = $0.value(forKey: "purchaseProviders") as? [String] - let staking: String? = $0.value(forKey: "staking") as? String - let type: String = ($0.value(forKey: "type") as? String) ?? "normal" - - let updatedAssetModel = NSEntityDescription.insertNewObject( - forEntityName: "CDAsset", - into: manager.destinationContext - ) - updatedAssetModel.setValue(id, forKey: "id") - updatedAssetModel.setValue(symbol, forKey: "symbol") - updatedAssetModel.setValue(precision, forKey: "precision") - updatedAssetModel.setValue(icon, forKey: "icon") - updatedAssetModel.setValue(priceId, forKey: "priceId") - updatedAssetModel.setValue(price, forKey: "price") - updatedAssetModel.setValue(fiatDayChange, forKey: "fiatDayChange") - updatedAssetModel.setValue(currencyId, forKey: "currencyId") - updatedAssetModel.setValue(existentialDeposit, forKey: "existentialDeposit") - updatedAssetModel.setValue(color, forKey: "color") - updatedAssetModel.setValue(isNative, forKey: "isNative") - updatedAssetModel.setValue(isUtility, forKey: "isUtility") - updatedAssetModel.setValue(purchaseProviders, forKey: "purchaseProviders") - updatedAssetModel.setValue(staking, forKey: "staking") - updatedAssetModel.setValue(type, forKey: "type") - - return updatedAssetModel + guard let destinationAsset = manager.destinationInstances( + forEntityMappingName: assetMappingName, + sourceInstances: [sourceAsset] + ).first else { + throw ConvenienceError( + error: "Can't find migrated CDAsset destination instance" + ) + } + + copyWrapperMetadata( + from: wrapper, + to: destinationAsset + ) + destinationAssets.add(destinationAsset) } - let assetsSet = Set(assetModels) as NSSet + } - let updatedAssetsSet = updatedChainModel.mutableSetValue(forKey: "assets") - updatedAssetsSet.addObjects(from: assetsSet.allObjects) + private func copyWrapperMetadata( + from wrapper: NSManagedObject, + to destinationAsset: NSManagedObject + ) { + for key in Constants.wrapperMetadataKeys { + let value: Any? + if key == "purchaseProviders" { + value = try? SafeTransformableValueReader.read( + from: wrapper, + key: key, + as: NSArray.self + ) + } else { + value = wrapper.value(forKey: key) + } - updatedChainModel.setValue(updatedAssetsSet, forKey: "assets") - updatedChainModel.setValue(false, forKey: "disabled") + guard let value else { + continue + } - manager.associate( - sourceInstance: chainModel, - withDestinationInstance: updatedChainModel, - for: mapping - ) + destinationAsset.setValue(value, forKey: key) + } + + if destinationAsset.value(forKey: "type") == nil { + destinationAsset.setValue("normal", forKey: "type") + } } } diff --git a/fearless/Common/Storage/Migration/SubstrateStorage/ChainSubstrateV2MigrationPolicy.swift b/fearless/Common/Storage/Migration/SubstrateStorage/ChainSubstrateV2MigrationPolicy.swift index 944b5d320e..ee0977ab00 100644 --- a/fearless/Common/Storage/Migration/SubstrateStorage/ChainSubstrateV2MigrationPolicy.swift +++ b/fearless/Common/Storage/Migration/SubstrateStorage/ChainSubstrateV2MigrationPolicy.swift @@ -10,11 +10,34 @@ class ChainSubstrateV2MigrationPolicy: NSEntityMigrationPolicy { ) throws { try super.createRelationships(forDestination: chainModel, in: mapping, manager: manager) - guard let nodes = chainModel.value(forKey: "nodes") as? Set, - let node = nodes.first else { + guard chainModel.value(forKey: "selectedNode") == nil, + let nodes = chainModel.value(forKey: "nodes") as? Set, + let node = nodes.min(by: isOrderedBefore) else { return } chainModel.setValue(node, forKey: "selectedNode") } + + private func isOrderedBefore( + _ lhs: NSManagedObject, + _ rhs: NSManagedObject + ) -> Bool { + let lhsURL = (lhs.value(forKey: "url") as? URL)?.absoluteString ?? "" + let rhsURL = (rhs.value(forKey: "url") as? URL)?.absoluteString ?? "" + + if lhsURL != rhsURL { + return lhsURL < rhsURL + } + + let lhsName = lhs.value(forKey: "name") as? String ?? "" + let rhsName = rhs.value(forKey: "name") as? String ?? "" + + if lhsName != rhsName { + return lhsName < rhsName + } + + return lhs.objectID.uriRepresentation().absoluteString < + rhs.objectID.uriRepresentation().absoluteString + } } diff --git a/fearless/Common/Storage/Migration/SubstrateStorage/SubstrateStorageMigrator+Sync.swift b/fearless/Common/Storage/Migration/SubstrateStorage/SubstrateStorageMigrator+Sync.swift index 1a7a8e47e6..f86ed03af1 100644 --- a/fearless/Common/Storage/Migration/SubstrateStorage/SubstrateStorageMigrator+Sync.swift +++ b/fearless/Common/Storage/Migration/SubstrateStorage/SubstrateStorageMigrator+Sync.swift @@ -2,12 +2,17 @@ import Foundation extension SubstrateStorageMigrator: Migrating { func migrate() throws { - guard requiresMigration() else { - return - } + let recoveryURL = try performMigrationWithRecovery() - performMigration() + if let recoveryURL { + Logger.shared.warning( + """ + Recovered from a Substrate cache migration error by quarantining a verified \ + cache-only store at \(recoveryURL.path) + """ + ) + } - Logger.shared.info("Db migration completed") + Logger.shared.info("Substrate DB migration check completed") } } diff --git a/fearless/Common/Storage/Migration/SubstrateStorage/SubstrateStorageMigrator.swift b/fearless/Common/Storage/Migration/SubstrateStorage/SubstrateStorageMigrator.swift index 5b2b806c9f..7c30ebe44b 100644 --- a/fearless/Common/Storage/Migration/SubstrateStorage/SubstrateStorageMigrator.swift +++ b/fearless/Common/Storage/Migration/SubstrateStorage/SubstrateStorageMigrator.swift @@ -1,150 +1,5914 @@ -import Foundation import CoreData -import SoraKeystore +import CryptoKit +import Darwin +import Foundation +import SQLite3 + +enum SubstrateStorageMigrationOperation: String { + case sourceMetadata = "source metadata inspection" + case sourceCheckpoint = "private source checkpoint" + case transformableSanitization = "private source transformable repair" + case sourceRowInspection = "private source row inspection" + case protectedDataInspection = "protected local-data inspection" + case stagedMigration = "staged migration" + case stagedValidation = "staged-store validation" +} + +enum SubstrateStorageMigrationError: LocalizedError { + case metadataUnreadable(URL, Error) + case unknownStoreVersion(URL) + case modelUnavailable(SubstrateStorageVersion) + case migrationPathUnavailable(SubstrateStorageVersion, SubstrateStorageVersion) + case mappingUnavailable(SubstrateStorageVersion, SubstrateStorageVersion, Error) + case sourceSnapshotFailed(URL, Error) + case walCheckpointFailed(URL, Error) + case transformableSanitizationFailed(SubstrateStorageVersion, Error) + case unsupportedTransformableAttribute(SubstrateStorageVersion, String, String) + case objectiveCException(SubstrateStorageMigrationOperation) + case temporaryDirectoryCreationFailed(URL, Error) + case temporaryStoreCleanupFailed(URL, Error) + case migrationStepFailed(SubstrateStorageVersion, SubstrateStorageVersion, Error) + case sourceStoreInspectionFailed(URL, Error) + case protectedDataInspectionRejected(URL, Error) + case stagedStoreMetadataUnreadable(URL, Error) + case stagedStoreInvalid(URL, SubstrateStorageVersion) + case stagedStoreInspectionFailed(URL, Error) + case stagedStoreRowCountMismatch(String, Int, Int) + case stagedStoreProtectedDataMismatch + case storeReplacementFailed(URL, Error) + case cacheRecoveryBlockedByProtectedData(URL, Error, [String: Int]) + case pendingCacheRecoveryFailed(URL, Error) + case cacheRecoveryFailed(URL, Error, Error) + + var errorDescription: String? { + switch self { + case let .metadataUnreadable(url, error): + return "Unable to read Substrate store metadata at \(url.path): \(error.localizedDescription)" + case let .unknownStoreVersion(url): + return "Unsupported Substrate store version at \(url.path)" + case let .modelUnavailable(version): + return "Substrate store model is unavailable for \(version.rawValue)" + case let .migrationPathUnavailable(source, destination): + return "No forward Substrate store migration path from \(source.rawValue) to \(destination.rawValue)" + case let .mappingUnavailable(source, destination, error): + return """ + Unable to create the Substrate store mapping from \(source.rawValue) \ + to \(destination.rawValue): \(error.localizedDescription) + """ + case let .sourceSnapshotFailed(url, error): + return """ + Unable to create a private Substrate store snapshot for \(url.path): \ + \(error.localizedDescription) + """ + case let .walCheckpointFailed(url, error): + return "Unable to checkpoint Substrate store at \(url.path): \(error.localizedDescription)" + case let .transformableSanitizationFailed(version, error): + return """ + Unable to safely repair cached values in the private \(version.rawValue) \ + Substrate store copy: \(error.localizedDescription) + """ + case let .unsupportedTransformableAttribute(version, entityName, attributeName): + return """ + The \(version.rawValue) Substrate model contains an unsupported cached value at \ + \(entityName).\(attributeName) + """ + case let .objectiveCException(operation): + return "Substrate storage safely stopped during \(operation.rawValue)" + case let .temporaryDirectoryCreationFailed(url, error): + return "Unable to create Substrate migration directory at \(url.path): \(error.localizedDescription)" + case let .temporaryStoreCleanupFailed(url, error): + return """ + Unable to remove a completed temporary Substrate migration store at \ + \(url.path): \(error.localizedDescription) + """ + case let .migrationStepFailed(source, destination, error): + return """ + Substrate store migration from \(source.rawValue) to \(destination.rawValue) \ + failed: \(error.localizedDescription) + """ + case let .sourceStoreInspectionFailed(url, error): + return "Unable to inspect Substrate store rows at \(url.path): \(error.localizedDescription)" + case let .protectedDataInspectionRejected(url, error): + return """ + Protected-data inspection rejected the store at \(url.path): \ + \(error.localizedDescription) + """ + case let .stagedStoreMetadataUnreadable(url, error): + return "Unable to read staged Substrate store metadata at \(url.path): \(error.localizedDescription)" + case let .stagedStoreInvalid(url, destination): + return "Staged Substrate store at \(url.path) is not compatible with \(destination.rawValue)" + case let .stagedStoreInspectionFailed(url, error): + return "Unable to inspect staged Substrate store rows at \(url.path): \(error.localizedDescription)" + case let .stagedStoreRowCountMismatch(entity, expected, actual): + return """ + Staged Substrate store changed the \(entity) row count from \(expected) to \(actual) + """ + case .stagedStoreProtectedDataMismatch: + return """ + Staged Substrate store changed protected local values or node relationships + """ + case let .storeReplacementFailed(url, error): + return "Unable to replace Substrate store at \(url.path): \(error.localizedDescription)" + case let .cacheRecoveryBlockedByProtectedData(url, migrationError, counts): + let protectedData = counts + .filter { $0.value > 0 } + .sorted { $0.key < $1.key } + .map { "\($0.key)=\($0.value)" } + .joined(separator: ", ") + + return """ + Refusing to rebuild the Substrate store at \(url.path) after \ + \(migrationError.localizedDescription) because it contains protected local data: \ + \(protectedData) + """ + case let .pendingCacheRecoveryFailed(url, error): + return """ + Unable to reconcile an interrupted Substrate cache recovery at \(url.path): \ + \(error.localizedDescription) + """ + case let .cacheRecoveryFailed(url, migrationError, recoveryError): + return """ + Unable to quarantine the rebuildable Substrate cache at \(url.path) after \ + \(migrationError.localizedDescription): \(recoveryError.localizedDescription) + """ + } + } + + var allowsCacheRebuild: Bool { + switch self { + case .modelUnavailable, + .migrationPathUnavailable, + .sourceSnapshotFailed, + .temporaryDirectoryCreationFailed, + .temporaryStoreCleanupFailed, + .metadataUnreadable, + .unknownStoreVersion, + .transformableSanitizationFailed, + .unsupportedTransformableAttribute, + .objectiveCException, + .sourceStoreInspectionFailed, + .protectedDataInspectionRejected, + .stagedStoreProtectedDataMismatch, + .storeReplacementFailed, + .cacheRecoveryBlockedByProtectedData, + .pendingCacheRecoveryFailed, + .cacheRecoveryFailed: + return false + case .mappingUnavailable, + .walCheckpointFailed, + .migrationStepFailed, + .stagedStoreMetadataUnreadable, + .stagedStoreInvalid, + .stagedStoreInspectionFailed, + .stagedStoreRowCountMismatch: + return true + } + } +} + +private enum SubstrateCustomMappingError: LocalizedError { + case resourceUnavailable(String) + case resourceUnreadable(String) + case incompatible(String) + case policyUnavailable(String, String) + + var errorDescription: String? { + switch self { + case let .resourceUnavailable(resourceName): + return "Required Substrate mapping \(resourceName).cdm is not bundled" + case let .resourceUnreadable(resourceName): + return "Required Substrate mapping \(resourceName).cdm cannot be loaded" + case let .incompatible(resourceName): + return "Required Substrate mapping \(resourceName).cdm does not match the bundled models" + case let .policyUnavailable(resourceName, policyClassName): + return """ + Required Substrate mapping \(resourceName).cdm does not use \ + \(policyClassName) for CDChain + """ + } + } +} + +enum SubstrateCacheRecoveryBoundary: Equatable { + case markerPersisted + case familyMemberMoved(String) + case legacyFamilyMemberRestored(String) + case markerRemoved + case retentionMarkerPersisted(String) + case retentionFamilyMemberRemoved(String, String) + case retentionMarkerRemoved(String) + case retentionArchiveRemoved(String) +} + +enum SubstrateCacheRecoveryInterruption: Error { + /// Test-only fault used to emulate process death without Swift unwinding. + case simulatedProcessDeath +} + +enum SubstrateCacheRecoveryTransactionError: LocalizedError { + case sourceStoreMissing + case unsafeFile(URL) + case unsafeDirectory(URL) + case invalidMarker + case markerTooLarge + case familyMismatch + case multiplePendingTransactions + case archiveScanLimitExceeded(Int) + case archiveByteScanLimitExceeded(UInt64) + case backupExclusionFailed(URL, Error) + case fileSynchronizationFailed(URL, Error) + case directorySynchronizationFailed(URL, Error) + + var errorDescription: String? { + switch self { + case .sourceStoreMissing: + return "The rebuildable Substrate cache store is missing" + case .unsafeFile: + return "The Substrate cache recovery transaction contains an unsafe file" + case .unsafeDirectory: + return "The Substrate cache recovery transaction contains an unsafe directory" + case .invalidMarker: + return "The Substrate cache recovery marker is invalid" + case .markerTooLarge: + return "The Substrate cache recovery marker is too large" + case .familyMismatch: + return "The Substrate cache family does not match its durable recovery manifest" + case .multiplePendingTransactions: + return "More than one Substrate cache recovery transaction is pending" + case let .archiveScanLimitExceeded(maximum): + return """ + Substrate cache recovery contains more than \(maximum) archive \ + directories and cannot be scanned safely + """ + case let .archiveByteScanLimitExceeded(maximum): + return """ + Substrate cache recovery exceeds the safe \(maximum)-byte archive \ + inspection budget + """ + case let .backupExclusionFailed(url, error): + return """ + Unable to exclude the Substrate cache recovery archive at \(url.path) \ + from device backup: \(error.localizedDescription) + """ + case let .fileSynchronizationFailed(_, error): + return "Unable to synchronize a Substrate cache recovery file: \(error.localizedDescription)" + case let .directorySynchronizationFailed(_, error): + return "Unable to synchronize a Substrate cache recovery directory: \(error.localizedDescription)" + } + } +} + +/// Moves a verified cache-only SQLite family into quarantine using a durable, +/// bounded transaction. A relaunch deterministically finishes any family move +/// or retention deletion interrupted after its marker became durable. +/// Completed archives are excluded from backup and the newest two are retained +/// subject to a combined 128 MiB byte budget. +final class CrashConsistentSubstrateCacheRecovery { + private enum Operation: String { + case quarantine + case restoreLegacy = "restore-legacy" + case deleteArchive = "delete-archive" + } + + private struct FamilyMember: Equatable { + let suffix: String + let byteCount: UInt64 + let sha256: String + } + + private struct Marker: Equatable { + let operation: Operation + let storePathSHA256: String + let family: [FamilyMember] + let restoreSuffixes: [String] + } + + private enum PathKind { + case missing + case regularFile + case directory + case symbolicLink + case other + } + + private struct FileIdentity: Hashable { + let deviceID: UInt64 + let inode: UInt64 + } + + private struct ArchiveCompletionTime: Equatable { + let seconds: Int64 + let nanoseconds: Int64 + } + + private struct CompletedArchive { + let url: URL + let family: [FamilyMember] + let byteCount: UInt64 + let completionTime: ArchiveCompletionTime + } + + private struct CompletedArchivePreflight { + let url: URL + let byteCount: UInt64 + let completionTime: ArchiveCompletionTime + } + + static let storeFamilySuffixes = ["", "-wal", "-shm", "-journal"] + + private static let markerHeader = "fearless-substrate-cache-recovery-v1" + private static let markerFileName = "recovery-transaction" + private static let markerTemporaryFileName = "recovery-transaction.pending" + private static let maximumMarkerByteCount: UInt64 = 4 * 1024 + private static let digestChunkByteCount = 1024 * 1024 + private static let recoveryRootName = "SubstrateStoreRecovery" + private static let restorationTemporarySuffix = + ".cache-recovery-restore.pending" + private static let maximumArchiveDirectoryScanCount = 64 + private static let maximumArchiveByteScanCount: UInt64 = + 512 * 1024 * 1024 + static let defaultRetainedArchiveCount = 2 + static let defaultRetainedArchiveByteCount: UInt64 = + 128 * 1024 * 1024 + + let storeURL: URL + let recoveryRootURL: URL + + private let fileManager: FileManager + private let boundaryHook: (SubstrateCacheRecoveryBoundary) throws -> Void + private let restorationTemporaryFileSynchronizationHook: + (URL) throws -> Void + private let directorySynchronizationHook: (URL) throws -> Void + private let backupExclusionHook: (URL) throws -> Void + private let retainedArchiveCount: Int + private let retainedArchiveByteCount: UInt64 + + private var databaseDirectoryURL: URL { + storeURL.deletingLastPathComponent() + } + + private var storePathSHA256: String { + Self.digest(data: Data(storeURL.path.utf8)) + } + + var hasPendingTransaction: Bool { + switch pathKind(at: recoveryRootURL) { + case .missing: + return false + case .directory: + break + case .regularFile, .symbolicLink, .other: + return true + } + + guard + let candidateURLs = try? + boundedRecoveryDirectoryURLs() + else { + return true + } + + return candidateURLs.contains { candidateURL in + guard pathKind(at: candidateURL) == .directory else { + return true + } + + if pathKind( + at: markerURL(in: candidateURL) + ) != .missing || + pathKind( + at: markerTemporaryURL(in: candidateURL) + ) != .missing { + return true + } + + guard + let contents = try? boundedImmediateChildURLs( + at: candidateURL, + maximumCount: Self.storeFamilySuffixes.count, + overflowError: + SubstrateCacheRecoveryTransactionError + .unsafeDirectory(candidateURL) + ) + else { + return true + } + return contents.isEmpty + } + } + + init( + storeURL: URL, + fileManager: FileManager, + boundaryHook: @escaping ( + SubstrateCacheRecoveryBoundary + ) throws -> Void = { _ in }, + restorationTemporaryFileSynchronizationHook: + @escaping (URL) throws -> Void = { _ in }, + directorySynchronizationHook: + @escaping (URL) throws -> Void = { _ in }, + backupExclusionHook: ((URL) throws -> Void)? = nil, + retainedArchiveCount: Int = + CrashConsistentSubstrateCacheRecovery + .defaultRetainedArchiveCount, + retainedArchiveByteCount: UInt64 = + CrashConsistentSubstrateCacheRecovery + .defaultRetainedArchiveByteCount + ) { + precondition(retainedArchiveCount >= 0) + + self.storeURL = storeURL.standardizedFileURL + self.fileManager = fileManager + self.boundaryHook = boundaryHook + self.restorationTemporaryFileSynchronizationHook = + restorationTemporaryFileSynchronizationHook + self.directorySynchronizationHook = + directorySynchronizationHook + self.backupExclusionHook = backupExclusionHook ?? { + url in + var resourceURL = url + var values = URLResourceValues() + values.isExcludedFromBackup = true + try resourceURL.setResourceValues(values) + } + self.retainedArchiveCount = retainedArchiveCount + self.retainedArchiveByteCount = retainedArchiveByteCount + recoveryRootURL = self.storeURL + .deletingLastPathComponent() + .appendingPathComponent( + Self.recoveryRootName, + isDirectory: true + ) + } + + func quarantine() throws -> URL? { + try requireSafeDatabaseDirectory() + guard try pendingTransactionDirectories().isEmpty else { + throw SubstrateCacheRecoveryTransactionError + .multiplePendingTransactions + } + try maintainCompletedArchives() + + let sourceFamily = try manifest( + for: storeURL, + requiringMainStore: false + ) + guard !sourceFamily.isEmpty else { + return nil + } + guard sourceFamily.first?.suffix.isEmpty == true else { + throw SubstrateCacheRecoveryTransactionError.sourceStoreMissing + } + + try createRecoveryRootIfNeeded() + + let transactionDirectoryURL = recoveryRootURL + .appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + var markerBecameDurable = false + + do { + try fileManager.createDirectory( + at: transactionDirectoryURL, + withIntermediateDirectories: false + ) + try synchronizeDirectory(recoveryRootURL) + try excludeFromBackup(transactionDirectoryURL) + + let marker = Marker( + operation: .quarantine, + storePathSHA256: storePathSHA256, + family: sourceFamily, + restoreSuffixes: [] + ) + try persist( + marker, + in: transactionDirectoryURL + ) + markerBecameDurable = true + try boundaryHook(.markerPersisted) + + try completeTransaction( + at: transactionDirectoryURL, + marker: marker + ) + try maintainCompletedArchives() + return pathKind(at: transactionDirectoryURL) == .directory + ? transactionDirectoryURL + : nil + } catch is SubstrateCacheRecoveryInterruption { + throw SubstrateCacheRecoveryInterruption + .simulatedProcessDeath + } catch { + if !markerBecameDurable { + try? removeUncommittedPreparation( + at: transactionDirectoryURL + ) + } + throw error + } + } + + @discardableResult + func reconcile() throws -> URL? { + try requireSafeDatabaseDirectory() + + switch pathKind(at: recoveryRootURL) { + case .missing: + return nil + case .directory: + break + case .regularFile, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(recoveryRootURL) + } + try excludeFromBackup(recoveryRootURL) + + let directoryNames = try boundedRecoveryDirectoryURLs() + .map(\.lastPathComponent) + var pendingTransactions: [(URL, Marker)] = [] + var markerlessArchiveURLs: [URL] = [] + + for directoryName in directoryNames { + guard UUID(uuidString: directoryName) != nil else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory( + recoveryRootURL.appendingPathComponent( + directoryName + ) + ) + } + + let transactionDirectoryURL = recoveryRootURL + .appendingPathComponent( + directoryName, + isDirectory: true + ) + guard pathKind(at: transactionDirectoryURL) == .directory else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(transactionDirectoryURL) + } + + let markerURL = markerURL( + in: transactionDirectoryURL + ) + let temporaryMarkerURL = markerTemporaryURL( + in: transactionDirectoryURL + ) + + switch pathKind(at: markerURL) { + case .regularFile: + guard pathKind(at: temporaryMarkerURL) == .missing else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(temporaryMarkerURL) + } + pendingTransactions.append( + ( + transactionDirectoryURL, + try readMarker(at: markerURL) + ) + ) + case .missing: + switch pathKind(at: temporaryMarkerURL) { + case .missing: + let contents = try boundedImmediateChildURLs( + at: transactionDirectoryURL, + maximumCount: Self.storeFamilySuffixes.count, + overflowError: + SubstrateCacheRecoveryTransactionError + .unsafeDirectory( + transactionDirectoryURL + ) + ).map(\.lastPathComponent) + if contents.isEmpty { + try fileManager.removeItem( + at: transactionDirectoryURL + ) + try synchronizeDirectory(recoveryRootURL) + } else { + markerlessArchiveURLs.append( + transactionDirectoryURL + ) + } + case .regularFile: + let contents = Set( + try boundedImmediateChildURLs( + at: transactionDirectoryURL, + maximumCount: + Self.storeFamilySuffixes.count + 1, + overflowError: + SubstrateCacheRecoveryTransactionError + .unsafeDirectory( + transactionDirectoryURL + ) + ).map(\.lastPathComponent) + ) + if contents == [Self.markerTemporaryFileName] { + try removeUncommittedPreparation( + at: transactionDirectoryURL + ) + } else { + let allowedLegacyNames = Set( + Self.storeFamilySuffixes.map { + self.storeURL.lastPathComponent + $0 + } + [Self.markerTemporaryFileName] + ) + try requireExactTree( + at: transactionDirectoryURL, + allowedFileNames: allowedLegacyNames + ) + guard contents.contains( + storeURL.lastPathComponent + ) else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + + try fileManager.removeItem( + at: temporaryMarkerURL + ) + try synchronizeDirectory( + transactionDirectoryURL + ) + markerlessArchiveURLs.append( + transactionDirectoryURL + ) + } + case .directory, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(temporaryMarkerURL) + } + case .directory, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(markerURL) + } + } + + guard pendingTransactions.count <= 1 else { + throw SubstrateCacheRecoveryTransactionError + .multiplePendingTransactions + } + + guard let pendingTransaction = pendingTransactions.first else { + let recoveredLegacyURL = + try reconcileLegacyInterruptedTransaction( + archiveURLs: markerlessArchiveURLs + ) + + try maintainCompletedArchives() + return recoveredLegacyURL.flatMap { + pathKind(at: $0) == .directory ? $0 : nil + } + } + + try excludeFromBackup(pendingTransaction.0) + let reconciledArchiveURL: URL? + switch pendingTransaction.1.operation { + case .quarantine: + try completeTransaction( + at: pendingTransaction.0, + marker: pendingTransaction.1 + ) + reconciledArchiveURL = pendingTransaction.0 + case .restoreLegacy: + try restoreLegacyTransaction( + at: pendingTransaction.0, + marker: pendingTransaction.1 + ) + reconciledArchiveURL = pendingTransaction.0 + case .deleteArchive: + try completeArchiveDeletion( + at: pendingTransaction.0, + marker: pendingTransaction.1 + ) + reconciledArchiveURL = nil + } + + try maintainCompletedArchives() + return reconciledArchiveURL.flatMap { + pathKind(at: $0) == .directory ? $0 : nil + } + } + + private func reconcileLegacyInterruptedTransaction( + archiveURLs: [URL] + ) throws -> URL? { + // A live main store means the app either still has its original + // family or already rebuilt the cache. Avoid hashing a potentially + // large healthy cache merely because historical archives remain. + switch pathKind(at: storeURL) { + case .regularFile: + return nil + case .missing: + break + case .directory, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(storeURL) + } + + let liveFamily = try manifest( + for: storeURL, + requiringMainStore: false + ) + + // No live family is the fully completed legacy outcome. + guard !liveFamily.isEmpty else { + return nil + } + + var candidates: [(URL, Marker)] = [] + for archiveURL in archiveURLs { + if let marker = try legacyMarker( + archiveURL: archiveURL, + liveFamily: liveFamily + ) { + candidates.append((archiveURL, marker)) + } + } + + guard candidates.count <= 1 else { + throw SubstrateCacheRecoveryTransactionError + .multiplePendingTransactions + } + guard let candidate = candidates.first else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + + try persist(candidate.1, in: candidate.0) + try boundaryHook(.markerPersisted) + try restoreLegacyTransaction( + at: candidate.0, + marker: candidate.1 + ) + return candidate.0 + } + + private func legacyMarker( + archiveURL: URL, + liveFamily: [FamilyMember] + ) throws -> Marker? { + let archiveStoreURL = quarantineStoreURL(in: archiveURL) + let allowedNames = Set( + Self.storeFamilySuffixes.map { + storeURL.lastPathComponent + $0 + } + ) + let archiveNames = Set( + try boundedImmediateChildURLs( + at: archiveURL, + maximumCount: allowedNames.count, + overflowError: + SubstrateCacheRecoveryTransactionError + .unsafeDirectory(archiveURL) + ).map(\.lastPathComponent) + ) + guard archiveNames.isSubset(of: allowedNames) else { + return nil + } + + let archivedFamily = try manifest( + for: archiveStoreURL, + requiringMainStore: false + ) + guard archivedFamily.first?.suffix.isEmpty == true else { + return nil + } + + let archivedSuffixes = Set(archivedFamily.map(\.suffix)) + let liveSuffixes = Set(liveFamily.map(\.suffix)) + guard archivedSuffixes.isDisjoint(with: liveSuffixes) else { + return nil + } + + let unionFamily = Self.storeFamilySuffixes.compactMap { + suffix in + archivedFamily.first { $0.suffix == suffix } ?? + liveFamily.first { $0.suffix == suffix } + } + guard + Array(unionFamily.prefix(archivedFamily.count)) == + archivedFamily, + Array(unionFamily.dropFirst(archivedFamily.count)) == + liveFamily + else { + return nil + } + + var identities = Set() + for member in archivedFamily { + let values = try lstatValues( + at: familyURL( + storeURL: archiveStoreURL, + suffix: member.suffix + ) + ) + guard identities.insert( + FileIdentity( + deviceID: values.deviceID, + inode: values.inode + ) + ).inserted else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(archiveStoreURL) + } + } + for member in liveFamily { + let liveURL = familyURL( + storeURL: storeURL, + suffix: member.suffix + ) + let values = try lstatValues(at: liveURL) + guard identities.insert( + FileIdentity( + deviceID: values.deviceID, + inode: values.inode + ) + ).inserted else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(liveURL) + } + } + + return Marker( + operation: .restoreLegacy, + storePathSHA256: storePathSHA256, + family: unionFamily, + restoreSuffixes: archivedFamily.map(\.suffix) + ) + } + + private func restoreLegacyTransaction( + at transactionDirectoryURL: URL, + marker: Marker + ) throws { + guard + marker.operation == .restoreLegacy, + marker.storePathSHA256 == storePathSHA256, + !marker.restoreSuffixes.isEmpty, + marker.restoreSuffixes == + Array( + marker.family + .prefix(marker.restoreSuffixes.count) + .map(\.suffix) + ) + else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + try requireExactLegacyRestoreTree( + at: transactionDirectoryURL, + marker: marker + ) + let restoreSuffixes = Set(marker.restoreSuffixes) + let archivedStoreURL = quarantineStoreURL( + in: transactionDirectoryURL + ) + let expectedArchivedFamily = marker.family.filter { + restoreSuffixes.contains($0.suffix) + } + guard + try manifest( + for: archivedStoreURL, + requiringMainStore: true + ) == expectedArchivedFamily + else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + + for member in marker.family { + let liveURL = familyURL( + storeURL: storeURL, + suffix: member.suffix + ) + + if restoreSuffixes.contains(member.suffix) { + let archivedURL = familyURL( + storeURL: archivedStoreURL, + suffix: member.suffix + ) + guard + try familyMember( + at: archivedURL, + suffix: member.suffix + ) == member + else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + + switch pathKind(at: liveURL) { + case .missing: + try installRestoredMember( + member, + from: archivedURL, + to: liveURL, + transactionDirectoryURL: + transactionDirectoryURL + ) + try boundaryHook( + .legacyFamilyMemberRestored(member.suffix) + ) + case .regularFile: + guard + try familyMember( + at: liveURL, + suffix: member.suffix + ) == member + else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + case .directory, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(liveURL) + } + } else { + switch pathKind(at: liveURL) { + case .regularFile: + guard + try familyMember( + at: liveURL, + suffix: member.suffix + ) == member + else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + case .missing: + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + case .directory, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(liveURL) + } + } + } + + guard + try manifest( + for: storeURL, + requiringMainStore: true + ) == marker.family + else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + + // A previous attempt may have completed its final rename and then + // failed while syncing either directory. Re-establish both directory + // durability obligations even when this retry had no rename to do. + try synchronizeDirectory(databaseDirectoryURL) + try synchronizeDirectory(transactionDirectoryURL) + + let markerURL = markerURL(in: transactionDirectoryURL) + guard pathKind(at: markerURL) == .regularFile else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(markerURL) + } + try fileManager.removeItem(at: markerURL) + try synchronizeDirectory(transactionDirectoryURL) + try boundaryHook(.markerRemoved) + } + + private func installRestoredMember( + _ member: FamilyMember, + from archivedURL: URL, + to liveURL: URL, + transactionDirectoryURL: URL + ) throws { + let temporaryURL = try restorationTemporaryURL( + for: member.suffix, + in: transactionDirectoryURL + ) + + switch pathKind(at: temporaryURL) { + case .missing: + try fileManager.copyItem( + at: archivedURL, + to: temporaryURL + ) + guard + try familyMember( + at: temporaryURL, + suffix: member.suffix + ) == member + else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + case .regularFile: + if try familyMember( + at: temporaryURL, + suffix: member.suffix + ) != member { + // The durable archive remains authoritative. A regular + // partial copy can be discarded and recreated after power + // loss; unsafe path types are never removed. + try fileManager.removeItem(at: temporaryURL) + try synchronizeDirectory(transactionDirectoryURL) + try fileManager.copyItem( + at: archivedURL, + to: temporaryURL + ) + guard + try familyMember( + at: temporaryURL, + suffix: member.suffix + ) == member + else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + } + case .directory, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(temporaryURL) + } + + try restorationTemporaryFileSynchronizationHook( + temporaryURL + ) + try synchronizeFile(temporaryURL) + try synchronizeDirectory(transactionDirectoryURL) + + guard pathKind(at: liveURL) == .missing else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + try fileManager.moveItem(at: temporaryURL, to: liveURL) + guard + pathKind(at: temporaryURL) == .missing, + try familyMember( + at: liveURL, + suffix: member.suffix + ) == member + else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + try synchronizeDirectory(databaseDirectoryURL) + try synchronizeDirectory(transactionDirectoryURL) + } + + private func completeTransaction( + at transactionDirectoryURL: URL, + marker: Marker + ) throws { + guard + marker.operation == .quarantine, + marker.restoreSuffixes.isEmpty, + marker.storePathSHA256 == storePathSHA256 + else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + try requireExactActiveTree( + at: transactionDirectoryURL, + marker: marker + ) + + for member in marker.family { + let sourceURL = familyURL( + storeURL: storeURL, + suffix: member.suffix + ) + let destinationURL = transactionDirectoryURL + .appendingPathComponent( + sourceURL.lastPathComponent + ) + + let sourceKind = pathKind(at: sourceURL) + let destinationKind = pathKind(at: destinationURL) + + switch (sourceKind, destinationKind) { + case (.regularFile, .missing): + guard try familyMember( + at: sourceURL, + suffix: member.suffix + ) == member else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + + try fileManager.moveItem( + at: sourceURL, + to: destinationURL + ) + guard + pathKind(at: sourceURL) == .missing, + try familyMember( + at: destinationURL, + suffix: member.suffix + ) == member + else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + + try synchronizeDirectory(transactionDirectoryURL) + try synchronizeDirectory(databaseDirectoryURL) + try boundaryHook( + .familyMemberMoved(member.suffix) + ) + case (.missing, .regularFile): + guard try familyMember( + at: destinationURL, + suffix: member.suffix + ) == member else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + case (.missing, .missing), (.regularFile, .regularFile): + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + case (.directory, _), (.symbolicLink, _), (.other, _): + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(sourceURL) + case (_, .directory), (_, .symbolicLink), (_, .other): + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(destinationURL) + } + } + + guard + try manifest( + for: quarantineStoreURL( + in: transactionDirectoryURL + ), + requiringMainStore: true + ) == marker.family + else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + + for suffix in Self.storeFamilySuffixes { + let sourceURL = familyURL( + storeURL: storeURL, + suffix: suffix + ) + guard pathKind(at: sourceURL) == .missing else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + } + + // A previous attempt may have completed its final rename and then + // failed while syncing either directory. Re-establish both directory + // durability obligations even when this retry had no rename to do. + try synchronizeDirectory(transactionDirectoryURL) + try synchronizeDirectory(databaseDirectoryURL) + + let markerURL = markerURL(in: transactionDirectoryURL) + guard pathKind(at: markerURL) == .regularFile else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(markerURL) + } + try fileManager.removeItem(at: markerURL) + try synchronizeDirectory(transactionDirectoryURL) + try boundaryHook(.markerRemoved) + } + + private func completeArchiveDeletion( + at transactionDirectoryURL: URL, + marker: Marker + ) throws { + guard + marker.operation == .deleteArchive, + marker.restoreSuffixes.isEmpty, + marker.storePathSHA256 == storePathSHA256 + else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + try requireExactActiveTree( + at: transactionDirectoryURL, + marker: marker + ) + + let archiveName = transactionDirectoryURL.lastPathComponent + let archivedStoreURL = quarantineStoreURL( + in: transactionDirectoryURL + ) + + for member in marker.family { + let archivedURL = familyURL( + storeURL: archivedStoreURL, + suffix: member.suffix + ) + + switch pathKind(at: archivedURL) { + case .missing: + continue + case .regularFile: + guard + try familyMember( + at: archivedURL, + suffix: member.suffix + ) == member, + try lstatValues(at: archivedURL).linkCount == 1 + else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + + try fileManager.removeItem(at: archivedURL) + try synchronizeDirectory(transactionDirectoryURL) + try boundaryHook( + .retentionFamilyMemberRemoved( + archiveName, + member.suffix + ) + ) + case .directory, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(archivedURL) + } + } + + let markerURL = markerURL(in: transactionDirectoryURL) + guard + pathKind(at: markerURL) == .regularFile, + try fileManager.contentsOfDirectory( + atPath: transactionDirectoryURL.path + ) == [Self.markerFileName] + else { + throw SubstrateCacheRecoveryTransactionError + .familyMismatch + } + + try fileManager.removeItem(at: markerURL) + try synchronizeDirectory(transactionDirectoryURL) + try boundaryHook(.retentionMarkerRemoved(archiveName)) + + guard try fileManager.contentsOfDirectory( + atPath: transactionDirectoryURL.path + ).isEmpty else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(transactionDirectoryURL) + } + try fileManager.removeItem(at: transactionDirectoryURL) + try synchronizeDirectory(recoveryRootURL) + try boundaryHook(.retentionArchiveRemoved(archiveName)) + } + + private func maintainCompletedArchives() throws { + switch pathKind(at: recoveryRootURL) { + case .missing: + return + case .directory: + break + case .regularFile, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(recoveryRootURL) + } + + guard try pendingTransactionDirectories().isEmpty else { + throw SubstrateCacheRecoveryTransactionError + .multiplePendingTransactions + } + + let directoryNames = try boundedRecoveryDirectoryURLs() + .map(\.lastPathComponent) + var preflights: [CompletedArchivePreflight] = [] + var preflightByteCount: UInt64 = 0 + + for directoryName in directoryNames { + guard UUID(uuidString: directoryName) != nil else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory( + recoveryRootURL.appendingPathComponent( + directoryName + ) + ) + } + + let archiveURL = recoveryRootURL.appendingPathComponent( + directoryName, + isDirectory: true + ) + guard pathKind(at: archiveURL) == .directory else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(archiveURL) + } + + let children = try boundedImmediateChildURLs( + at: archiveURL, + maximumCount: Self.storeFamilySuffixes.count, + overflowError: + SubstrateCacheRecoveryTransactionError + .unsafeDirectory(archiveURL) + ) + if children.isEmpty { + try fileManager.removeItem(at: archiveURL) + try synchronizeDirectory(recoveryRootURL) + continue + } + + let preflight = try completedArchivePreflight( + at: archiveURL + ) + let addition = preflightByteCount + .addingReportingOverflow(preflight.byteCount) + guard + !addition.overflow, + addition.partialValue <= + Self.maximumArchiveByteScanCount + else { + throw SubstrateCacheRecoveryTransactionError + .archiveByteScanLimitExceeded( + Self.maximumArchiveByteScanCount + ) + } + preflightByteCount = addition.partialValue + preflights.append(preflight) + } + + try excludeFromBackup(recoveryRootURL) + for preflight in preflights { + try excludeFromBackup(preflight.url) + } + + // Every candidate tree and its aggregate byte footprint is bounded + // before the first SHA-256 read or deletion authorization is written. + let archives = try preflights.map { + try completedArchive(after: $0) + } + + var retainedArchives = archives.sorted { + if $0.completionTime.seconds != + $1.completionTime.seconds { + return $0.completionTime.seconds < + $1.completionTime.seconds + } + if $0.completionTime.nanoseconds != + $1.completionTime.nanoseconds { + return $0.completionTime.nanoseconds < + $1.completionTime.nanoseconds + } + return $0.url.lastPathComponent < + $1.url.lastPathComponent + } + + var retainedByteCount: UInt64 = 0 + for archive in retainedArchives { + let addition = retainedByteCount.addingReportingOverflow( + archive.byteCount + ) + guard !addition.overflow else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + retainedByteCount = addition.partialValue + } + + while + retainedArchives.count > retainedArchiveCount || + retainedByteCount > retainedArchiveByteCount + { + let archive = retainedArchives.removeFirst() + retainedByteCount -= archive.byteCount + try deleteCompletedArchive(archive) + } + + try removeRecoveryRootIfEmpty() + } + + private func completedArchivePreflight( + at archiveURL: URL + ) throws -> CompletedArchivePreflight { + let allowedNames = Set( + Self.storeFamilySuffixes.map { + storeURL.lastPathComponent + $0 + } + ) + try requireExactTree( + at: archiveURL, + allowedFileNames: allowedNames + ) + + let childURLs = try boundedImmediateChildURLs( + at: archiveURL, + maximumCount: allowedNames.count, + overflowError: SubstrateCacheRecoveryTransactionError + .unsafeDirectory(archiveURL) + ) + let names = Set(childURLs.map(\.lastPathComponent)) + guard names.contains(storeURL.lastPathComponent) else { + throw SubstrateCacheRecoveryTransactionError + .sourceStoreMissing + } + + var identities = Set() + var byteCount: UInt64 = 0 + for childURL in childURLs { + let values = try lstatValues(at: childURL) + guard + values.linkCount == 1, + identities.insert( + FileIdentity( + deviceID: values.deviceID, + inode: values.inode + ) + ).inserted + else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(childURL) + } + let addition = byteCount.addingReportingOverflow( + values.byteCount + ) + guard + !addition.overflow, + addition.partialValue <= + Self.maximumArchiveByteScanCount + else { + throw SubstrateCacheRecoveryTransactionError + .archiveByteScanLimitExceeded( + Self.maximumArchiveByteScanCount + ) + } + byteCount = addition.partialValue + } + + return CompletedArchivePreflight( + url: archiveURL, + byteCount: byteCount, + completionTime: try directoryCompletionTime( + at: archiveURL + ) + ) + } + + private func completedArchive( + after preflight: CompletedArchivePreflight + ) throws -> CompletedArchive { + let archiveURL = preflight.url + let family = try manifest( + for: quarantineStoreURL(in: archiveURL), + requiringMainStore: true + ) + let expectedNames = Set( + family.map { + storeURL.lastPathComponent + $0.suffix + } + ) + guard + Set( + try boundedImmediateChildURLs( + at: archiveURL, + maximumCount: Self.storeFamilySuffixes.count, + overflowError: + SubstrateCacheRecoveryTransactionError + .unsafeDirectory(archiveURL) + ).map(\.lastPathComponent) + ) == expectedNames + else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + + var byteCount: UInt64 = 0 + for member in family { + let memberURL = familyURL( + storeURL: quarantineStoreURL(in: archiveURL), + suffix: member.suffix + ) + guard try lstatValues(at: memberURL).linkCount == 1 else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(memberURL) + } + let addition = byteCount.addingReportingOverflow( + member.byteCount + ) + guard !addition.overflow else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + byteCount = addition.partialValue + } + guard byteCount == preflight.byteCount else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + + return CompletedArchive( + url: archiveURL, + family: family, + byteCount: byteCount, + completionTime: preflight.completionTime + ) + } + + private func deleteCompletedArchive( + _ archive: CompletedArchive + ) throws { + let marker = Marker( + operation: .deleteArchive, + storePathSHA256: storePathSHA256, + family: archive.family, + restoreSuffixes: [] + ) + try persist(marker, in: archive.url) + try boundaryHook( + .retentionMarkerPersisted( + archive.url.lastPathComponent + ) + ) + try completeArchiveDeletion( + at: archive.url, + marker: marker + ) + } + + private func persist( + _ marker: Marker, + in transactionDirectoryURL: URL + ) throws { + let markerURL = markerURL(in: transactionDirectoryURL) + let temporaryMarkerURL = markerTemporaryURL( + in: transactionDirectoryURL + ) + guard + pathKind(at: markerURL) == .missing, + pathKind(at: temporaryMarkerURL) == .missing + else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(markerURL) + } + + let data = try encode(marker) + guard data.count <= Self.maximumMarkerByteCount else { + throw SubstrateCacheRecoveryTransactionError.markerTooLarge + } + + try data.write( + to: temporaryMarkerURL, + options: .withoutOverwriting + ) + try synchronizeFile(temporaryMarkerURL) + try fileManager.moveItem( + at: temporaryMarkerURL, + to: markerURL + ) + try synchronizeDirectory(transactionDirectoryURL) + } + + private func readMarker(at markerURL: URL) throws -> Marker { + let values = try lstatValues(at: markerURL) + guard values.byteCount <= Self.maximumMarkerByteCount else { + throw SubstrateCacheRecoveryTransactionError.markerTooLarge + } + + let data = try Data(contentsOf: markerURL) + guard UInt64(data.count) == values.byteCount else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + return try decodeMarker(data) + } + + private func encode(_ marker: Marker) throws -> Data { + let restoreSuffixes = marker.restoreSuffixes.isEmpty + ? "-" + : try marker.restoreSuffixes.map { + try token(for: $0) + }.joined( + separator: "," + ) + var lines = [ + Self.markerHeader, + "operation\t\(marker.operation.rawValue)", + "store-path-sha256\t\(marker.storePathSHA256)", + "restore-suffixes\t\(restoreSuffixes)" + ] + + for member in marker.family { + lines.append( + [ + try token(for: member.suffix), + String(member.byteCount), + member.sha256 + ].joined(separator: "\t") + ) + } + + return Data((lines.joined(separator: "\n") + "\n").utf8) + } + + private func decodeMarker(_ data: Data) throws -> Marker { + guard + let text = String(data: data, encoding: .utf8), + Data(text.utf8) == data + else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + let lines = text.split( + separator: "\n", + omittingEmptySubsequences: false + ) + guard + lines.count >= 6, + lines.count <= 9, + lines.last?.isEmpty == true, + lines[0] == Self.markerHeader + else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + let operationFields = lines[1].split( + separator: "\t", + omittingEmptySubsequences: false + ) + guard + operationFields.count == 2, + operationFields[0] == "operation", + let operation = Operation( + rawValue: String(operationFields[1]) + ) + else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + let pathFields = lines[2].split( + separator: "\t", + omittingEmptySubsequences: false + ) + guard + pathFields.count == 2, + pathFields[0] == "store-path-sha256", + isLowercaseSHA256(String(pathFields[1])) + else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + let restoreFields = lines[3].split( + separator: "\t", + omittingEmptySubsequences: false + ) + guard + restoreFields.count == 2, + restoreFields[0] == "restore-suffixes" + else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + let restoreSuffixes: [String] + if restoreFields[1] == "-" { + restoreSuffixes = [] + } else { + restoreSuffixes = try restoreFields[1] + .split( + separator: ",", + omittingEmptySubsequences: false + ).map { + guard let suffix = suffix(for: String($0)) else { + throw SubstrateCacheRecoveryTransactionError + .invalidMarker + } + return suffix + } + } + + var family: [FamilyMember] = [] + for line in lines.dropFirst(4).dropLast() { + let fields = line.split( + separator: "\t", + omittingEmptySubsequences: false + ) + guard + fields.count == 3, + let suffix = suffix(for: String(fields[0])), + let byteCount = UInt64(fields[1]), + String(byteCount) == fields[1], + isLowercaseSHA256(String(fields[2])) + else { + throw SubstrateCacheRecoveryTransactionError + .invalidMarker + } + + family.append( + FamilyMember( + suffix: suffix, + byteCount: byteCount, + sha256: String(fields[2]) + ) + ) + } + + let canonicalSuffixes = Self.storeFamilySuffixes.filter { + suffix in + family.contains { $0.suffix == suffix } + } + guard + !family.isEmpty, + family.first?.suffix.isEmpty == true, + family.map(\.suffix) == canonicalSuffixes, + Set(family.map(\.suffix)).count == family.count, + ( + operation == .quarantine && + restoreSuffixes.isEmpty + ) || ( + operation == .deleteArchive && + restoreSuffixes.isEmpty + ) || ( + operation == .restoreLegacy && + !restoreSuffixes.isEmpty && + restoreSuffixes == + Array( + family + .prefix(restoreSuffixes.count) + .map(\.suffix) + ) + ) + else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + let marker = Marker( + operation: operation, + storePathSHA256: String(pathFields[1]), + family: family, + restoreSuffixes: restoreSuffixes + ) + guard try encode(marker) == data else { + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + + return marker + } + + private func requireExactActiveTree( + at transactionDirectoryURL: URL, + marker: Marker + ) throws { + let allowedNames = Set( + marker.family.map { + storeURL.lastPathComponent + $0.suffix + } + [Self.markerFileName] + ) + try requireExactTree( + at: transactionDirectoryURL, + allowedFileNames: allowedNames + ) + } + + private func requireExactLegacyRestoreTree( + at transactionDirectoryURL: URL, + marker: Marker + ) throws { + let archivedNames = marker.restoreSuffixes.map { + storeURL.lastPathComponent + $0 + } + let temporaryNames = try marker.restoreSuffixes.map { + try restorationTemporaryURL( + for: $0, + in: transactionDirectoryURL + ).lastPathComponent + } + let allowedNames = Set( + archivedNames + + temporaryNames + + [Self.markerFileName] + ) + try requireExactTree( + at: transactionDirectoryURL, + allowedFileNames: allowedNames + ) + } + + private func requireExactTree( + at directoryURL: URL, + allowedFileNames: Set + ) throws { + guard pathKind(at: directoryURL) == .directory else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(directoryURL) + } + + let childURLs = try boundedImmediateChildURLs( + at: directoryURL, + maximumCount: allowedFileNames.count, + overflowError: SubstrateCacheRecoveryTransactionError + .unsafeDirectory(directoryURL) + ) + let names = Set(childURLs.map(\.lastPathComponent)) + guard names.isSubset(of: allowedFileNames) else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(directoryURL) + } + + for url in childURLs { + guard pathKind(at: url) == .regularFile else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(url) + } + } + } + + private func manifest( + for familyStoreURL: URL, + requiringMainStore: Bool + ) throws -> [FamilyMember] { + var members: [FamilyMember] = [] + var identities = Set() + + for suffix in Self.storeFamilySuffixes { + let url = familyURL( + storeURL: familyStoreURL, + suffix: suffix + ) + + switch pathKind(at: url) { + case .missing: + if suffix.isEmpty, requiringMainStore { + throw SubstrateCacheRecoveryTransactionError + .sourceStoreMissing + } + case .regularFile: + let values = try lstatValues(at: url) + guard identities.insert( + FileIdentity( + deviceID: values.deviceID, + inode: values.inode + ) + ).inserted else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(url) + } + members.append( + try familyMember( + at: url, + suffix: suffix + ) + ) + case .directory, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(url) + } + } + + if requiringMainStore { + guard members.first?.suffix.isEmpty == true else { + throw SubstrateCacheRecoveryTransactionError + .sourceStoreMissing + } + } + + return members + } + + private func familyMember( + at url: URL, + suffix: String + ) throws -> FamilyMember { + guard pathKind(at: url) == .regularFile else { + throw SubstrateCacheRecoveryTransactionError.unsafeFile(url) + } + let valuesBefore = try lstatValues(at: url) + let sha256 = try digest(at: url) + let valuesAfter = try lstatValues(at: url) + guard + valuesBefore.byteCount == valuesAfter.byteCount, + valuesBefore.deviceID == valuesAfter.deviceID, + valuesBefore.inode == valuesAfter.inode + else { + throw SubstrateCacheRecoveryTransactionError.familyMismatch + } + + return FamilyMember( + suffix: suffix, + byteCount: valuesAfter.byteCount, + sha256: sha256 + ) + } + + private func digest(at url: URL) throws -> String { + let handle = try FileHandle(forReadingFrom: url) + defer { + try? handle.close() + } + + var hasher = SHA256() + while true { + let data = try handle.read( + upToCount: Self.digestChunkByteCount + ) ?? Data() + guard !data.isEmpty else { + break + } + hasher.update(data: data) + } + + return hasher.finalize().map { + String(format: "%02x", $0) + }.joined() + } + + private static func digest(data: Data) -> String { + SHA256.hash(data: data).map { + String(format: "%02x", $0) + }.joined() + } + + private func token(for suffix: String) throws -> String { + switch suffix { + case "": + return "main" + case "-wal": + return "wal" + case "-shm": + return "shm" + case "-journal": + return "journal" + default: + throw SubstrateCacheRecoveryTransactionError.invalidMarker + } + } + + private func suffix(for token: String) -> String? { + switch token { + case "main": + return "" + case "wal": + return "-wal" + case "shm": + return "-shm" + case "journal": + return "-journal" + default: + return nil + } + } + + private func isLowercaseSHA256(_ value: String) -> Bool { + value.count == 64 && value.utf8.allSatisfy { + (0x30 ... 0x39).contains($0) || + (0x61 ... 0x66).contains($0) + } + } + + private func createRecoveryRootIfNeeded() throws { + switch pathKind(at: recoveryRootURL) { + case .missing: + try fileManager.createDirectory( + at: recoveryRootURL, + withIntermediateDirectories: false + ) + try synchronizeDirectory(databaseDirectoryURL) + case .directory: + break + case .regularFile, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(recoveryRootURL) + } + + try excludeFromBackup(recoveryRootURL) + } + + private func removeUncommittedPreparation( + at transactionDirectoryURL: URL + ) throws { + guard pathKind(at: transactionDirectoryURL) == .directory else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(transactionDirectoryURL) + } + + let names = try fileManager.contentsOfDirectory( + atPath: transactionDirectoryURL.path + ) + guard Set(names).isSubset( + of: [ + Self.markerFileName, + Self.markerTemporaryFileName + ] + ) else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(transactionDirectoryURL) + } + + for name in names { + let url = transactionDirectoryURL.appendingPathComponent(name) + guard pathKind(at: url) == .regularFile else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(url) + } + try fileManager.removeItem(at: url) + try synchronizeDirectory(transactionDirectoryURL) + } + + try fileManager.removeItem(at: transactionDirectoryURL) + try synchronizeDirectory(recoveryRootURL) + try removeRecoveryRootIfEmpty() + } + + private func removeRecoveryRootIfEmpty() throws { + guard pathKind(at: recoveryRootURL) == .directory else { + return + } + guard try fileManager.contentsOfDirectory( + atPath: recoveryRootURL.path + ).isEmpty else { + return + } + + try fileManager.removeItem(at: recoveryRootURL) + try synchronizeDirectory(databaseDirectoryURL) + } + + private func synchronizeFile(_ url: URL) throws { + do { + guard pathKind(at: url) == .regularFile else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(url) + } + let handle = try FileHandle(forUpdating: url) + defer { + try? handle.close() + } + try handle.synchronize() + } catch { + throw SubstrateCacheRecoveryTransactionError + .fileSynchronizationFailed(url, error) + } + } + + private func synchronizeDirectory(_ url: URL) throws { + do { + guard pathKind(at: url) == .directory else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(url) + } + + try directorySynchronizationHook(url) + + let descriptor = Darwin.open(url.path, O_RDONLY) + guard descriptor >= 0 else { + throw POSIXError( + POSIXErrorCode(rawValue: errno) ?? .EIO + ) + } + defer { + _ = Darwin.close(descriptor) + } + + guard Darwin.fsync(descriptor) == 0 else { + throw POSIXError( + POSIXErrorCode(rawValue: errno) ?? .EIO + ) + } + } catch { + throw SubstrateCacheRecoveryTransactionError + .directorySynchronizationFailed(url, error) + } + } + + private func excludeFromBackup(_ url: URL) throws { + do { + guard pathKind(at: url) == .directory else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(url) + } + try backupExclusionHook(url) + } catch let transactionError + as SubstrateCacheRecoveryTransactionError { + throw transactionError + } catch { + throw SubstrateCacheRecoveryTransactionError + .backupExclusionFailed(url, error) + } + } + + private func directoryCompletionTime( + at url: URL + ) throws -> ArchiveCompletionTime { + var directoryStatus = stat() + guard + Darwin.lstat(url.path, &directoryStatus) == 0, + directoryStatus.st_mode & S_IFMT == S_IFDIR + else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(url) + } + + return ArchiveCompletionTime( + seconds: Int64(directoryStatus.st_mtimespec.tv_sec), + nanoseconds: Int64(directoryStatus.st_mtimespec.tv_nsec) + ) + } + + private func requireSafeDatabaseDirectory() throws { + guard pathKind(at: databaseDirectoryURL) == .directory else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(databaseDirectoryURL) + } + + switch pathKind(at: recoveryRootURL) { + case .missing, .directory: + return + case .regularFile, .symbolicLink, .other: + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(recoveryRootURL) + } + } + + private func familyURL( + storeURL: URL, + suffix: String + ) -> URL { + URL(fileURLWithPath: storeURL.path + suffix) + } + + private func quarantineStoreURL( + in transactionDirectoryURL: URL + ) -> URL { + transactionDirectoryURL.appendingPathComponent( + storeURL.lastPathComponent + ) + } + + private func markerURL( + in transactionDirectoryURL: URL + ) -> URL { + transactionDirectoryURL.appendingPathComponent( + Self.markerFileName + ) + } + + private func markerTemporaryURL( + in transactionDirectoryURL: URL + ) -> URL { + transactionDirectoryURL.appendingPathComponent( + Self.markerTemporaryFileName + ) + } + + private func restorationTemporaryURL( + for suffix: String, + in transactionDirectoryURL: URL + ) throws -> URL { + transactionDirectoryURL.appendingPathComponent( + "\(try token(for: suffix))\(Self.restorationTemporarySuffix)" + ) + } + + private func boundedRecoveryDirectoryURLs() throws -> [URL] { + try boundedImmediateChildURLs( + at: recoveryRootURL, + maximumCount: Self.maximumArchiveDirectoryScanCount, + overflowError: SubstrateCacheRecoveryTransactionError + .archiveScanLimitExceeded( + Self.maximumArchiveDirectoryScanCount + ) + ) + } + + private func boundedImmediateChildURLs( + at directoryURL: URL, + maximumCount: Int, + overflowError: Error + ) throws -> [URL] { + guard pathKind(at: directoryURL) == .directory else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(directoryURL) + } + + var enumerationFailed = false + guard + let enumerator = fileManager.enumerator( + at: directoryURL, + includingPropertiesForKeys: nil, + options: [.skipsSubdirectoryDescendants], + errorHandler: { _, _ in + enumerationFailed = true + return false + } + ) + else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(directoryURL) + } + + var childURLs: [URL] = [] + while let childURL = enumerator.nextObject() as? URL { + childURLs.append(childURL) + guard childURLs.count <= maximumCount else { + throw overflowError + } + } + guard !enumerationFailed else { + throw SubstrateCacheRecoveryTransactionError + .unsafeDirectory(directoryURL) + } + + return childURLs.sorted { + $0.lastPathComponent < $1.lastPathComponent + } + } + + private func pendingTransactionDirectories() throws -> [URL] { + guard pathKind(at: recoveryRootURL) == .directory else { + return [] + } + + return try boundedRecoveryDirectoryURLs().filter { + candidateURL in + pathKind(at: markerURL(in: candidateURL)) != .missing || + pathKind( + at: markerTemporaryURL(in: candidateURL) + ) != .missing + } + } + + private func pathKind(at url: URL) -> PathKind { + var fileStatus = stat() + guard Darwin.lstat(url.path, &fileStatus) == 0 else { + return errno == ENOENT ? .missing : .other + } + + switch fileStatus.st_mode & S_IFMT { + case S_IFREG: + return .regularFile + case S_IFDIR: + return .directory + case S_IFLNK: + return .symbolicLink + default: + return .other + } + } + + private func lstatValues( + at url: URL + ) throws -> ( + byteCount: UInt64, + deviceID: UInt64, + inode: UInt64, + linkCount: UInt64 + ) { + var fileStatus = stat() + guard Darwin.lstat(url.path, &fileStatus) == 0 else { + throw POSIXError( + POSIXErrorCode(rawValue: errno) ?? .EIO + ) + } + guard + fileStatus.st_mode & S_IFMT == S_IFREG, + fileStatus.st_size >= 0 + else { + throw SubstrateCacheRecoveryTransactionError + .unsafeFile(url) + } + + return ( + byteCount: UInt64(fileStatus.st_size), + deviceID: UInt64( + truncatingIfNeeded: fileStatus.st_dev + ), + inode: UInt64( + truncatingIfNeeded: fileStatus.st_ino + ), + linkCount: UInt64( + truncatingIfNeeded: fileStatus.st_nlink + ) + ) + } +} + +struct SubstrateProtectedDataInspectionLimits { + static let production = SubstrateProtectedDataInspectionLimits( + fetchPageSize: 256, + maximumRowsPerEntity: 250_000, + maximumTotalRows: 1_000_000, + maximumStartupRootRowsPerEntity: 4096, + maximumStartupRootPayloadByteCount: 256 * 1024 * 1024, + maximumStartupChildValueByteCount: 256 * 1024, + maximumStartupChildPayloadByteCount: 256 * 1024 * 1024, + maximumRelationshipMembers: 10000, + maximumTotalRelationshipMembers: 1_000_000, + maximumTransformableElements: 4096, + maximumTransformableArchiveByteCount: 256 * 1024, + maximumValueByteCount: 256 * 1024, + maximumRecordByteCount: 1024 * 1024 + ) + + let fetchPageSize: Int + let maximumRowsPerEntity: Int + let maximumTotalRows: Int + let maximumStartupRootRowsPerEntity: Int + let maximumStartupRootPayloadByteCount: UInt64 + let maximumStartupChildValueByteCount: UInt64 + let maximumStartupChildPayloadByteCount: UInt64 + let maximumRelationshipMembers: Int + let maximumTotalRelationshipMembers: Int + let maximumTransformableElements: Int + let maximumTransformableArchiveByteCount: Int + let maximumValueByteCount: Int + let maximumRecordByteCount: Int + + init( + fetchPageSize: Int, + maximumRowsPerEntity: Int, + maximumTotalRows: Int, + maximumStartupRootRowsPerEntity: Int, + maximumStartupRootPayloadByteCount: UInt64, + maximumStartupChildValueByteCount: UInt64, + maximumStartupChildPayloadByteCount: UInt64, + maximumRelationshipMembers: Int, + maximumTotalRelationshipMembers: Int, + maximumTransformableElements: Int, + maximumTransformableArchiveByteCount: Int, + maximumValueByteCount: Int, + maximumRecordByteCount: Int + ) { + precondition(fetchPageSize > 0) + precondition(maximumRowsPerEntity >= 0) + precondition(maximumTotalRows >= 0) + precondition(maximumStartupRootRowsPerEntity >= 0) + precondition(maximumRelationshipMembers >= 0) + precondition(maximumTotalRelationshipMembers >= 0) + precondition(maximumTransformableElements >= 0) + precondition(maximumTransformableArchiveByteCount >= 0) + precondition(maximumValueByteCount >= 0) + precondition(maximumRecordByteCount >= 0) + + self.fetchPageSize = fetchPageSize + self.maximumRowsPerEntity = maximumRowsPerEntity + self.maximumTotalRows = maximumTotalRows + self.maximumStartupRootRowsPerEntity = + maximumStartupRootRowsPerEntity + self.maximumStartupRootPayloadByteCount = + maximumStartupRootPayloadByteCount + self.maximumStartupChildValueByteCount = + maximumStartupChildValueByteCount + self.maximumStartupChildPayloadByteCount = + maximumStartupChildPayloadByteCount + self.maximumRelationshipMembers = + maximumRelationshipMembers + self.maximumTotalRelationshipMembers = + maximumTotalRelationshipMembers + self.maximumTransformableElements = + maximumTransformableElements + self.maximumTransformableArchiveByteCount = + maximumTransformableArchiveByteCount + self.maximumValueByteCount = maximumValueByteCount + self.maximumRecordByteCount = maximumRecordByteCount + } +} + +enum SubstrateProtectedDataInspectionError: LocalizedError { + case entityUnavailable(String) + case relationshipUnavailable(String, String) + case countUnavailable(String) + case entityRowLimitExceeded(String, Int, Int) + case totalRowLimitExceeded(Int, Int) + case relationshipLimitExceeded(String, String, Int, Int) + case relationshipCountUnavailable(String, String) + case totalRelationshipLimitExceeded(Int, Int) + case valueByteLimitExceeded(String, String, Int, Int) + case recordByteLimitExceeded(String, Int, Int) + case relationshipValueInvalid(String, String) + case unsupportedAttributeValue(String, String, String) + case startupRootPayloadByteLimitExceeded(UInt64, UInt64) + case startupChildValueByteLimitExceeded( + String, + String, + UInt64, + UInt64 + ) + case startupChildPayloadByteLimitExceeded(UInt64, UInt64) + + var errorDescription: String? { + switch self { + case let .entityUnavailable(entityName): + return "Protected-data inspection requires the \(entityName) entity" + case let .relationshipUnavailable(entityName, relationshipName): + return """ + Protected-data inspection requires the \(entityName).\(relationshipName) relationship + """ + case let .countUnavailable(entityName): + return "Protected-data inspection could not count \(entityName)" + case let .entityRowLimitExceeded( + entityName, + actual, + maximum + ): + return """ + Protected-data inspection found \(actual) \(entityName) rows; \ + the deterministic safety limit is \(maximum) + """ + case let .totalRowLimitExceeded(actual, maximum): + return """ + Protected-data inspection found \(actual) total protected rows; \ + the deterministic safety limit is \(maximum) + """ + case let .relationshipLimitExceeded( + entityName, + relationshipName, + actual, + maximum + ): + return """ + Protected-data inspection found \(actual) members in \ + \(entityName).\(relationshipName); the deterministic safety limit \ + is \(maximum) + """ + case let .relationshipCountUnavailable( + entityName, + relationshipName + ): + return """ + Protected-data inspection could not count \ + \(entityName).\(relationshipName) without materializing it + """ + case let .totalRelationshipLimitExceeded(actual, maximum): + return """ + Protected-data inspection found \(actual) protected relationship \ + members; the deterministic safety limit is \(maximum) + """ + case let .valueByteLimitExceeded( + entityName, + attributeName, + actual, + maximum + ): + return """ + Protected-data inspection found a \(actual)-byte value at \ + \(entityName).\(attributeName); the deterministic safety limit is \ + \(maximum) bytes + """ + case let .recordByteLimitExceeded( + category, + actual, + maximum + ): + return """ + Protected-data inspection produced a \(actual)-byte \(category) \ + record; the deterministic safety limit is \(maximum) bytes + """ + case let .relationshipValueInvalid( + entityName, + relationshipName + ): + return """ + Protected-data inspection found an invalid relationship value at \ + \(entityName).\(relationshipName) + """ + case let .unsupportedAttributeValue( + entityName, + attributeName, + className + ): + return """ + Protected-data inspection cannot safely compare \(className) at \ + \(entityName).\(attributeName) + """ + case let .startupRootPayloadByteLimitExceeded( + actual, + maximum + ): + return """ + Startup root payloads use \(actual) bytes; the deterministic \ + safety limit is \(maximum) + """ + case let .startupChildValueByteLimitExceeded( + entityName, + attributeName, + actual, + maximum + ): + return """ + Startup child payload \(entityName).\(attributeName) uses \ + \(actual) bytes; the deterministic safety limit is \(maximum) + """ + case let .startupChildPayloadByteLimitExceeded( + actual, + maximum + ): + return """ + Startup child payloads use \(actual) bytes; the deterministic \ + safety limit is \(maximum) + """ + } + } +} + +private enum SubstrateLegacyXcmMappingError: LocalizedError { + case entityMappingUnavailable(String) + case sourceAssociationUnavailable(String) + case destinationRelationshipUnavailable(String, String) + case destinationEntityUnavailable(String) + + var errorDescription: String? { + switch self { + case let .entityMappingUnavailable(entityName): + return "Legacy XCM migration requires the \(entityName) entity mapping" + case let .sourceAssociationUnavailable(entityName): + return "Legacy XCM migration cannot find the source \(entityName) object" + case let .destinationRelationshipUnavailable(entityName, relationshipName): + return "Legacy XCM migration requires \(entityName).\(relationshipName)" + case let .destinationEntityUnavailable(entityName): + return "Legacy XCM migration requires the \(entityName) destination entity" + } + } +} + +private enum SubstrateTransformableRepairError: LocalizedError { + case countUnavailable(String) + case entityRowLimitExceeded(String, Int, Int) + case totalRowLimitExceeded(Int, Int) + case objectIDEnumerationMismatch(String) + case unexpectedBatchUpdateResult(String, String) + case repairedValueCountOverflow + + var errorDescription: String? { + switch self { + case let .countUnavailable(entityName): + return "Unable to count \(entityName) rows for private cache repair" + case let .entityRowLimitExceeded( + entityName, + actual, + maximum + ): + return """ + Private cache repair found \(actual) \(entityName) rows; \ + the deterministic safety limit is \(maximum) + """ + case let .totalRowLimitExceeded(actual, maximum): + return """ + Private cache repair found \(actual) total rows; \ + the deterministic safety limit is \(maximum) + """ + case let .objectIDEnumerationMismatch(entityName): + return "Unable to enumerate every \(entityName) row for private cache repair" + case let .unexpectedBatchUpdateResult(entityName, attributeName): + return """ + Private cache repair did not update exactly one \ + \(entityName).\(attributeName) row + """ + case .repairedValueCountOverflow: + return "Private cache repair count exceeded its bounded counter" + } + } +} + +final class SubstrateStorageMigrator { + private struct StartupToManyRelationshipFamily { + let entityName: String + let relationshipNames: [String] + } + + private static let intentionallyTransformedEntityNames: Set = [ + "CDChainAsset" + ] + + private static let storeFamilySuffixes = ["", "-wal", "-shm", "-journal"] + + // These collections are mapped eagerly during normal v8 startup. Audit + // their SQL counts on the disposable store before application mapping can + // materialize any unbounded relationship value. + private static let version8StartupRootEntityNames = [ + "CDChain", + "CDRuntimeMetadataItem" + ] + // ChainModelMapper traverses every one of these entities from CDChain + // during the first repository fetch. Keep the raw SQLite audit explicit: + // to-one children such as priceProvider and selected/custom nodes are not + // covered by the to-many relationship-count audit below. + private static let version8StartupChildEntityNames = [ + "CDAsset", + "CDChainNode", + "CDChainXcmConfig", + "CDExternalApi", + "CDPriceData", + "CDPriceProvider", + "CDXcmAvailableAsset", + "CDXcmAvailableDestination" + ] + private static let version8StartupToManyRelationshipFamilies = [ + StartupToManyRelationshipFamily( + entityName: "CDAsset", + relationshipNames: ["priceData"] + ), + StartupToManyRelationshipFamily( + entityName: "CDChain", + relationshipNames: [ + "assets", + "customNodes", + "explorers", + "nodes" + ] + ), + StartupToManyRelationshipFamily( + entityName: "CDChainXcmConfig", + relationshipNames: [ + "availableAssets", + "availableDestinations" + ] + ), + StartupToManyRelationshipFamily( + entityName: "CDXcmAvailableDestination", + relationshipNames: ["assets"] + ) + ] + + private static let resilientStringArrayTransformables: Set = [ + "CDAsset.purchaseProviders", + "CDChain.options", + "CDChainAsset.purchaseProviders", + "CDChainXcmConfig.availableAssets", + "CDExternalApi.types", + "CDPolkaswapRemoteSettings.availableSources", + "CDPolkaswapRemoteSettings.forceSmartIds", + "CDXcmAvailableDestination.assets" + ] + + private enum ProtectedDataCategory { + static let contacts = "CDContact" + static let contactItems = "CDContactItem" + static let transactionHistory = "CDTransactionHistoryItem" + static let customNodeRelationships = "CDChain.customNodes" + static let selectedNodeRelationships = "CDChain.selectedNode" + static let orphanNodes = "CDChainNode.orphan" + } + + private struct ProtectedDataFootprint { + let counts: [String: Int] + + var isEmpty: Bool { + counts.values.allSatisfy { $0 == 0 } + } + } + + private struct ProtectedDataDigest: Equatable { + let recordCount: UInt64 + let additiveWords: [UInt64] + } + + private struct ProtectedDataDigestAccumulator { + private(set) var recordCount: UInt64 = 0 + private var additiveWords = Array( + repeating: UInt64(0), + count: 8 + ) + + mutating func append( + _ record: String, + category: String, + maximumByteCount: Int + ) throws { + let recordData = Data(record.utf8) + guard recordData.count <= maximumByteCount else { + throw SubstrateProtectedDataInspectionError + .recordByteLimitExceeded( + category, + recordData.count, + maximumByteCount + ) + } + let domainData = Data(category.utf8) + for discriminator in UInt8(0) ... UInt8(1) { + var framedData = Data([discriminator]) + var domainLength = UInt64(domainData.count).bigEndian + withUnsafeBytes(of: &domainLength) { + framedData.append(contentsOf: $0) + } + framedData.append(domainData) + var recordLength = UInt64(recordData.count).bigEndian + withUnsafeBytes(of: &recordLength) { + framedData.append(contentsOf: $0) + } + framedData.append(recordData) + + let digest = Array(SHA256.hash(data: framedData)) + let wordOffset = Int(discriminator) * 4 + for wordIndex in 0 ..< 4 { + let byteOffset = wordIndex * 8 + var word: UInt64 = 0 + for byte in digest[ + byteOffset ..< byteOffset + 8 + ] { + word = (word << 8) | UInt64(byte) + } + additiveWords[wordOffset + wordIndex] &+= word + } + } + + recordCount += 1 + } + + func finalize() -> ProtectedDataDigest { + ProtectedDataDigest( + recordCount: recordCount, + additiveWords: additiveWords + ) + } + } + + private struct ProtectedDataSnapshot: Equatable { + let contacts: ProtectedDataDigest + let contactItems: ProtectedDataDigest + let transactionHistory: ProtectedDataDigest + let chainNodeTopologies: ProtectedDataDigest + let orphanNodes: ProtectedDataDigest + } + + private struct CompatibleStore { + let version: SubstrateStorageVersion + let model: NSManagedObjectModel + } + + private struct SourceSnapshot { + let rootURL: URL + let workingStoreURL: URL + } + + private struct PreparedSource { + let snapshot: SourceSnapshot + let compatibleStore: CompatibleStore + let repairedTransformableValueCount: Int + } + + private struct MigrationStep { + let sourceVersion: SubstrateStorageVersion + let destinationVersion: SubstrateStorageVersion + let sourceModel: NSManagedObjectModel + let destinationModel: NSManagedObjectModel + let mapping: NSMappingModel + } + + private struct RequiredCustomMapping { + let resourceName: String + let policyClassName: String + } + + let storeURL: URL + let modelDirectory: String + let fileManager: FileManager + let targetVersion: SubstrateStorageVersion + let modelBundle: Bundle + private let crashConsistentStoreReplacer: CrashConsistentStoreReplacer + private let crashConsistentCacheRecovery: + CrashConsistentSubstrateCacheRecovery + private let stagedStoreMutationHook: (URL, NSManagedObjectModel) throws -> Void + private let checkpointStoreHook: ((URL, NSManagedObjectModel) throws -> Void)? + private let privateSourceCopyLimits: + SQLiteStoreFamilyCopyLimits + private let privateSourceAvailableCapacityProvider: + ((URL) throws -> UInt64)? + private let protectedDataInspectionLimits: + SubstrateProtectedDataInspectionLimits + private let transformableObjectIDPageDidFetch: ( + String, + Int, + Int + ) -> Void + private let protectedRelationshipCountDidFetch: ( + NSManagedObject, + String, + Int + ) -> Void + private let protectedRelationshipWillMaterialize: ( + String, + String, + Int + ) -> Void + + init( + targetVersion: SubstrateStorageVersion, + storeURL: URL, + modelDirectory: String, + fileManager: FileManager, + modelBundle: Bundle = .main, + storeReplacer: @escaping (URL, URL) throws -> Void = { targetURL, sourceURL in + try NSPersistentStoreCoordinator.replaceStore( + at: targetURL, + withStoreAt: sourceURL + ) + }, + stagedStoreMutationHook: @escaping ( + URL, + NSManagedObjectModel + ) throws -> Void = { _, _ in }, + checkpointStoreHook: ((URL, NSManagedObjectModel) throws -> Void)? = nil, + privateSourceCopyLimits: + SQLiteStoreFamilyCopyLimits = + .substrateStorageProduction, + privateSourceAvailableCapacityProvider: + ((URL) throws -> UInt64)? = nil, + storeReplacementBoundaryHook: @escaping ( + CrashConsistentStoreReplacementBoundary + ) throws -> Void = { _ in }, + cacheRecoveryBoundaryHook: @escaping ( + SubstrateCacheRecoveryBoundary + ) throws -> Void = { _ in }, + protectedDataInspectionLimits: + SubstrateProtectedDataInspectionLimits = .production, + transformableObjectIDPageDidFetch: @escaping ( + String, + Int, + Int + ) -> Void = { _, _, _ in }, + protectedRelationshipCountDidFetch: @escaping ( + NSManagedObject, + String, + Int + ) -> Void = { _, _, _ in }, + protectedRelationshipWillMaterialize: @escaping ( + String, + String, + Int + ) -> Void = { _, _, _ in } + ) { + self.targetVersion = targetVersion + self.storeURL = storeURL + self.modelDirectory = modelDirectory + self.fileManager = fileManager + self.modelBundle = modelBundle + crashConsistentStoreReplacer = CrashConsistentStoreReplacer( + storeURL: storeURL, + fileManager: fileManager, + storeReplacer: storeReplacer, + boundaryHook: storeReplacementBoundaryHook, + maximumStoreFamilyByteCount: + privateSourceCopyLimits.maximumFamilyByteCount, + minimumFreeStorageReserveByteCount: + privateSourceCopyLimits + .minimumFreeStorageReserveByteCount, + availableCapacityProvider: + privateSourceAvailableCapacityProvider + ) + crashConsistentCacheRecovery = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: fileManager, + boundaryHook: cacheRecoveryBoundaryHook + ) + self.stagedStoreMutationHook = stagedStoreMutationHook + self.checkpointStoreHook = checkpointStoreHook + self.privateSourceCopyLimits = privateSourceCopyLimits + self.privateSourceAvailableCapacityProvider = + privateSourceAvailableCapacityProvider + self.protectedDataInspectionLimits = + protectedDataInspectionLimits + self.transformableObjectIDPageDidFetch = + transformableObjectIDPageDidFetch + self.protectedRelationshipCountDidFetch = + protectedRelationshipCountDidFetch + self.protectedRelationshipWillMaterialize = + protectedRelationshipWillMaterialize + } + + func performMigrationWithRecovery() throws -> URL? { + try reconcilePendingCacheRecovery() + try reconcilePendingStoreReplacement() + + guard try crashConsistentStoreReplacer.liveStoreExistsSafely() else { + return nil + } + + var initialFootprint: ProtectedDataFootprint? + + do { + try withPreparedSource( + afterModelDetection: { source in + guard source.compatibleStore.version != self.targetVersion else { + return + } + + initialFootprint = try self + .inspectProtectedDataUsingSanitizedPrivateCopy( + of: source + ) + } + ) { source in + guard source.compatibleStore.version != targetVersion else { + try repairCurrentStoreIfNeeded(from: source) + return + } + + try performMigration(from: source) + } + + return nil + } catch let migrationError as SubstrateStorageMigrationError { + guard migrationError.allowsCacheRebuild else { + throw migrationError + } + + guard let initialFootprint else { + throw migrationError + } + + guard initialFootprint.isEmpty else { + throw SubstrateStorageMigrationError.cacheRecoveryBlockedByProtectedData( + storeURL, + migrationError, + initialFootprint.counts + ) + } + + let finalFootprint = try inspectProtectedDataInExistingStore() + guard finalFootprint.isEmpty else { + throw SubstrateStorageMigrationError.cacheRecoveryBlockedByProtectedData( + storeURL, + migrationError, + finalFootprint.counts + ) + } + + return try recoverRebuildableCache(after: migrationError) + } + } + + func performMigration() throws { + try reconcilePendingCacheRecovery() + try reconcilePendingStoreReplacement() + + guard try crashConsistentStoreReplacer.liveStoreExistsSafely() else { + return + } + + try withPreparedSource { source in + guard source.compatibleStore.version != targetVersion else { + try repairCurrentStoreIfNeeded(from: source) + return + } + + try performMigration(from: source) + } + } + + private func repairCurrentStoreIfNeeded( + from source: PreparedSource + ) throws { + let model = source.compatibleStore.model + let entityNames = Set( + model.entities.compactMap(\.name) + ) + let expectedRowCounts: [String: Int] + let expectedProtectedData: ProtectedDataSnapshot + + do { + if source.compatibleStore.version == .version8 { + try inspectVersion8StartupGraphBounds( + at: source.snapshot.workingStoreURL, + model: model + ) + } + expectedRowCounts = try inspectStoreRowCounts( + at: source.snapshot.workingStoreURL, + model: model, + entityNames: entityNames, + operation: .sourceRowInspection + ) + expectedProtectedData = try inspectProtectedDataSnapshot( + at: source.snapshot.workingStoreURL, + model: model + ) + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError + .sourceStoreInspectionFailed(storeURL, error) + } + + // A clean current store is still fully inspected above, but remains a + // byte-identical no-op: neither the staged hook nor replacer runs. + guard source.repairedTransformableValueCount > 0 else { + return + } + + do { + try stagedStoreMutationHook( + source.snapshot.workingStoreURL, + model + ) + } catch { + throw SubstrateStorageMigrationError + .stagedStoreInspectionFailed( + source.snapshot.workingStoreURL, + error + ) + } + + try validateStagedStore( + at: source.snapshot.workingStoreURL, + targetModel: model, + expectedRowCounts: expectedRowCounts, + expectedProtectedData: expectedProtectedData + ) + + do { + try crashConsistentStoreReplacer.replaceStore( + with: source.snapshot.workingStoreURL + ) { liveStoreURL in + try self.validateStagedStore( + at: liveStoreURL, + targetModel: model, + expectedRowCounts: expectedRowCounts, + expectedProtectedData: expectedProtectedData + ) + } + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError + .storeReplacementFailed(storeURL, error) + } + } + + private func performMigration(from source: PreparedSource) throws { + let compatibleStore = source.compatibleStore + let migrationPlan = try createMigrationPlan( + from: compatibleStore, + to: targetVersion + ) + + guard let targetModel = migrationPlan.last?.destinationModel else { + throw SubstrateStorageMigrationError.migrationPathUnavailable( + compatibleStore.version, + targetVersion + ) + } + + let preservedEntityNames = Set(compatibleStore.model.entitiesByName.keys) + .intersection(targetModel.entitiesByName.keys) + .subtracting(Self.intentionallyTransformedEntityNames) + let sourceRowCounts: [String: Int] + let sourceProtectedData: ProtectedDataSnapshot + + do { + sourceRowCounts = try inspectStoreRowCounts( + at: source.snapshot.workingStoreURL, + model: compatibleStore.model, + entityNames: preservedEntityNames, + operation: .sourceRowInspection + ) + sourceProtectedData = try inspectProtectedDataSnapshot( + at: source.snapshot.workingStoreURL, + model: compatibleStore.model, + normalizingMissingSelectedNode: + compatibleStore.version == .version1 + ) + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError.sourceStoreInspectionFailed( + storeURL, + error + ) + } + + let tmpMigrationDirURL = source.snapshot.rootURL + .appendingPathComponent("Migration", isDirectory: true) + + do { + try fileManager.createDirectory( + at: tmpMigrationDirURL, + withIntermediateDirectories: true + ) + } catch { + throw SubstrateStorageMigrationError.temporaryDirectoryCreationFailed( + tmpMigrationDirURL, + error + ) + } + + let stagedStore = try createStagedStore( + using: migrationPlan, + sourceStoreURL: source.snapshot.workingStoreURL, + migrationDirectoryURL: tmpMigrationDirURL + ) + + do { + try stagedStoreMutationHook(stagedStore, targetModel) + } catch { + throw SubstrateStorageMigrationError.stagedStoreInspectionFailed( + stagedStore, + error + ) + } + + try validateStagedStore( + at: stagedStore, + targetModel: targetModel, + expectedRowCounts: sourceRowCounts, + expectedProtectedData: sourceProtectedData + ) + + do { + try crashConsistentStoreReplacer.replaceStore( + with: stagedStore + ) { liveStoreURL in + try self.validateStagedStore( + at: liveStoreURL, + targetModel: targetModel, + expectedRowCounts: sourceRowCounts, + expectedProtectedData: sourceProtectedData + ) + } + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError.storeReplacementFailed(storeURL, error) + } + } + + private func reconcilePendingStoreReplacement() throws { + do { + try crashConsistentStoreReplacer.reconcile { + liveStoreURL in + + let compatibleStore = try self.loadCompatibleStore( + at: liveStoreURL + ) + guard compatibleStore.version == self.targetVersion else { + throw SubstrateStorageMigrationError.stagedStoreInvalid( + liveStoreURL, + self.targetVersion + ) + } + } + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError + .storeReplacementFailed(storeURL, error) + } + } + + private func reconcilePendingCacheRecovery() throws { + do { + try crashConsistentCacheRecovery.reconcile() + } catch is SubstrateCacheRecoveryInterruption { + throw SubstrateCacheRecoveryInterruption + .simulatedProcessDeath + } catch { + throw SubstrateStorageMigrationError + .pendingCacheRecoveryFailed(storeURL, error) + } + } + + private func withPreparedSource( + afterModelDetection: ((PreparedSource) throws -> Void)? = nil, + _ operation: (PreparedSource) throws -> Void + ) throws { + let snapshot = try createPrivateSourceSnapshot() + + defer { + do { + if fileManager.fileExists(atPath: snapshot.rootURL.path) { + try fileManager.removeItem(at: snapshot.rootURL) + } + } catch { + Logger.shared.error( + "Unable to clean up a private Substrate store snapshot" + ) + } + } + + let compatibleStore = try loadCompatibleStore( + at: snapshot.workingStoreURL + ) + let detectedSource = PreparedSource( + snapshot: snapshot, + compatibleStore: compatibleStore, + repairedTransformableValueCount: 0 + ) + + // Recovery decisions use a second isolated copy repaired only in + // explicitly rebuildable cache fields. The migration working copy + // remains untouched until this inspection succeeds. + try afterModelDetection?(detectedSource) + + if compatibleStore.version != targetVersion { + try forceWALCheckpointingForStore( + at: snapshot.workingStoreURL, + sourceModel: compatibleStore.model + ) + } + + let repairedTransformableValueCount = + try sanitizeTransformableValues( + at: snapshot.workingStoreURL, + compatibleStore: compatibleStore + ) + let preparedSource = PreparedSource( + snapshot: snapshot, + compatibleStore: compatibleStore, + repairedTransformableValueCount: + repairedTransformableValueCount + ) + + try operation(preparedSource) + } + + private func inspectProtectedDataUsingSanitizedPrivateCopy( + of source: PreparedSource + ) throws -> ProtectedDataFootprint { + let inspectionRootURL = fileManager.temporaryDirectory + .appendingPathComponent( + "SubstrateProtectedInspection-\(UUID().uuidString)", + isDirectory: true + ) + let inspectionStoreURL = inspectionRootURL + .appendingPathComponent(storeURL.lastPathComponent) + defer { + try? fileManager.removeItem(at: inspectionRootURL) + } + + do { + try fileManager.createDirectory( + at: inspectionRootURL, + withIntermediateDirectories: false + ) + try copyStoreFamily( + from: source.snapshot.workingStoreURL, + to: inspectionStoreURL, + includingSharedMemory: false + ) + } catch { + throw SubstrateStorageMigrationError + .sourceStoreInspectionFailed(storeURL, error) + } + + _ = try sanitizeTransformableValues( + at: inspectionStoreURL, + compatibleStore: source.compatibleStore + ) + + return try inspectProtectedData( + at: inspectionStoreURL, + model: source.compatibleStore.model + ) + } + + private func createPrivateSourceSnapshot() throws -> SourceSnapshot { + let rootURL = fileManager.temporaryDirectory.appendingPathComponent( + "SubstrateStorageSource-\(UUID().uuidString)", + isDirectory: true + ) + let workingStoreURL = rootURL.appendingPathComponent( + storeURL.lastPathComponent + ) + + do { + try fileManager.createDirectory( + at: rootURL, + withIntermediateDirectories: true + ) + + // Never open or checkpoint the installed store. The sole private + // copy is disposable and intentionally omits process-local SHM. + try copyStoreFamily( + from: storeURL, + to: workingStoreURL, + includingSharedMemory: false + ) + } catch { + try? fileManager.removeItem(at: rootURL) + throw SubstrateStorageMigrationError.sourceSnapshotFailed( + storeURL, + error + ) + } + + return SourceSnapshot( + rootURL: rootURL, + workingStoreURL: workingStoreURL + ) + } + + private func copyStoreFamily( + from sourceURL: URL, + to destinationURL: URL, + includingSharedMemory: Bool + ) throws { + try SQLiteStoreFamilyCopier.copy( + from: sourceURL, + to: destinationURL, + includingSharedMemory: includingSharedMemory, + fileManager: fileManager, + limits: privateSourceCopyLimits, + availableCapacityProvider: + privateSourceAvailableCapacityProvider + ) + } + + private func sanitizeTransformableValues( + at url: URL, + compatibleStore: CompatibleStore + ) throws -> Int { + let model = compatibleStore.model + let transformables = try transformableAttributes( + in: model, + version: compatibleStore.version + ) + + guard !transformables.isEmpty else { + return 0 + } + + var repairedValueCount = 0 + do { + try performWithObjectiveCExceptionBoundary( + operation: .transformableSanitization + ) { + let archiveColumns = transformables.flatMap { + transformable in + + transformable.1.map { attribute in + SQLiteTransformableArchiveColumn( + entityName: transformable.0, + attributeName: attribute.name, + isOptional: attribute.isOptional, + valueTransformerName: + attribute.valueTransformerName + ) + } + } + + // This runs against the disposable, checkpointed source copy + // before a Core Data coordinator can load or decode any of + // these allowlisted archives. + repairedValueCount = + try SQLiteTransformableArchivePreflight + .repairOversizedArchives( + at: url, + columns: archiveColumns, + maximumArchiveByteCount: + self.protectedDataInspectionLimits + .maximumTransformableArchiveByteCount + ) + + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSSQLitePragmasOption: ["journal_mode": "DELETE"], + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + + var contextError: Error? + context.performAndWait { + do { + let rowCounts = + try self.transformableSanitizationRowCounts( + transformables: transformables, + context: context + ) + for (entityName, attributes) in transformables { + let repairedEntityValueCount = + try self.sanitizeTransformableEntity( + entityName: entityName, + attributes: attributes, + rowCount: rowCounts[entityName] ?? 0, + context: context, + persistentStore: store + ) + try self.addRepairedValueCount( + repairedEntityValueCount, + to: &repairedValueCount + ) + } + } catch { + contextError = error + } + } + + if let contextError { + throw contextError + } + } + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError.transformableSanitizationFailed( + compatibleStore.version, + error + ) + } + + return repairedValueCount + } + + private func addRepairedValueCount( + _ count: Int, + to totalCount: inout Int + ) throws { + let addition = totalCount.addingReportingOverflow(count) + guard !addition.overflow else { + throw SubstrateTransformableRepairError + .repairedValueCountOverflow + } + totalCount = addition.partialValue + } + + private func transformableSanitizationRowCounts( + transformables: [(String, [NSAttributeDescription])], + context: NSManagedObjectContext + ) throws -> [String: Int] { + var rowCounts = [String: Int]() + var totalRowCount = 0 + + // Count and enforce every cap before the first repair write. This + // prevents an adversarial store from forcing an unbounded ID array or + // receiving a partially sanitized private copy before rejection. + for (entityName, _) in transformables { + let request = NSFetchRequest( + entityName: entityName + ) + request.includesPendingChanges = false + request.includesSubentities = false + let rowCount = try context.count(for: request) + guard rowCount != NSNotFound else { + throw SubstrateTransformableRepairError + .countUnavailable(entityName) + } + guard + rowCount <= + protectedDataInspectionLimits.maximumRowsPerEntity + else { + throw SubstrateTransformableRepairError + .entityRowLimitExceeded( + entityName, + rowCount, + protectedDataInspectionLimits + .maximumRowsPerEntity + ) + } + + let addition = + totalRowCount.addingReportingOverflow(rowCount) + guard + !addition.overflow, + addition.partialValue <= + protectedDataInspectionLimits.maximumTotalRows + else { + throw SubstrateTransformableRepairError + .totalRowLimitExceeded( + addition.overflow + ? Int.max + : addition.partialValue, + protectedDataInspectionLimits.maximumTotalRows + ) + } + totalRowCount = addition.partialValue + rowCounts[entityName] = rowCount + } + + return rowCounts + } + + private func sanitizeTransformableEntity( + entityName: String, + attributes: [NSAttributeDescription], + rowCount: Int, + context: NSManagedObjectContext, + persistentStore: NSPersistentStore + ) throws -> Int { + guard rowCount > 0 else { + return 0 + } + + let request = NSFetchRequest( + entityName: entityName + ) + request.resultType = .managedObjectIDResultType + request.includesPendingChanges = false + request.includesSubentities = false + request.affectedStores = [persistentStore] + + guard rowCount < Int.max else { + throw SubstrateTransformableRepairError + .objectIDEnumerationMismatch(entityName) + } + + // Fetch one bounded, exact cohort before the first repair write. + // Slicing this immutable ID list avoids offset pagination over rows + // whose transformable columns are being changed between pages. + request.fetchLimit = rowCount + 1 + request.fetchBatchSize = min( + protectedDataInspectionLimits.fetchPageSize, + rowCount + 1 + ) + let cohortResults = try context.fetch(request) + let cohortObjectIDs = cohortResults.compactMap { + $0 as? NSManagedObjectID + } + guard + cohortObjectIDs.count == cohortResults.count, + cohortObjectIDs.count == rowCount, + Set(cohortObjectIDs).count == rowCount + else { + throw SubstrateTransformableRepairError + .objectIDEnumerationMismatch(entityName) + } + + var pageStart = 0 + var repairedValueCount = 0 + while pageStart < cohortObjectIDs.count { + let pageLength = min( + protectedDataInspectionLimits.fetchPageSize, + cohortObjectIDs.count - pageStart + ) + let pageEnd = pageStart + pageLength + let pageObjectIDs = Array( + cohortObjectIDs[pageStart ..< pageEnd] + ) + let pageRequest = NSFetchRequest( + entityName: entityName + ) + pageRequest.resultType = .managedObjectIDResultType + pageRequest.includesPendingChanges = false + pageRequest.includesSubentities = false + pageRequest.predicate = NSPredicate( + format: "SELF IN %@", + pageObjectIDs + ) + pageRequest.affectedStores = [persistentStore] + pageRequest.fetchLimit = pageObjectIDs.count + pageRequest.fetchBatchSize = pageObjectIDs.count + + let fetchedPageResults = try context.fetch(pageRequest) + let fetchedPageObjectIDs = fetchedPageResults.compactMap { + $0 as? NSManagedObjectID + } + transformableObjectIDPageDidFetch( + entityName, + fetchedPageObjectIDs.count, + pageObjectIDs.count + ) + guard + fetchedPageObjectIDs.count == + fetchedPageResults.count, + fetchedPageObjectIDs.count == + pageObjectIDs.count, + Set(fetchedPageObjectIDs) == Set(pageObjectIDs) + else { + throw SubstrateTransformableRepairError + .objectIDEnumerationMismatch(entityName) + } + + for objectID in pageObjectIDs { + for attribute in attributes { + if try sanitizeStringArray( + objectID: objectID, + entityName: entityName, + attribute: attribute, + context: context, + persistentStore: persistentStore + ) { + try addRepairedValueCount( + 1, + to: &repairedValueCount + ) + } + } + } + pageStart = pageEnd + } + + request.fetchLimit = 0 + request.fetchBatchSize = 0 + guard + pageStart == rowCount, + try context.count(for: request) == rowCount + else { + throw SubstrateTransformableRepairError + .objectIDEnumerationMismatch(entityName) + } + + return repairedValueCount + } + + private func transformableAttributes( + in model: NSManagedObjectModel, + version: SubstrateStorageVersion + ) throws -> [(String, [NSAttributeDescription])] { + try model.entities.compactMap { entity in + guard let entityName = entity.name else { + return nil + } + + let attributes = try entity.attributesByName.values + .filter { $0.attributeType == .transformableAttributeType } + .sorted { $0.name < $1.name } + .map { attribute -> NSAttributeDescription in + let identifier = "\(entityName).\(attribute.name)" + + guard Self.resilientStringArrayTransformables.contains(identifier) else { + throw SubstrateStorageMigrationError + .unsupportedTransformableAttribute( + version, + entityName, + attribute.name + ) + } + + return attribute + } + + return attributes.isEmpty ? nil : (entityName, attributes) + } + .sorted { $0.0 < $1.0 } + } + + private func sanitizeStringArray( + objectID: NSManagedObjectID, + entityName: String, + attribute: NSAttributeDescription, + context: NSManagedObjectContext, + persistentStore: NSPersistentStore + ) throws -> Bool { + let needsRepair: Bool + let request = NSFetchRequest( + entityName: entityName + ) + request.resultType = .dictionaryResultType + request.propertiesToFetch = [attribute.name] + request.predicate = NSPredicate( + format: "SELF == %@", + objectID + ) + request.affectedStores = [persistentStore] + request.fetchLimit = 2 + + do { + var rows: [NSDictionary]? + try SafeObjectiveCExceptionBoundary.perform { + rows = try context.fetch(request) + } + guard + let rows, + rows.count == 1 + else { + throw SubstrateTransformableRepairError + .unexpectedBatchUpdateResult( + entityName, + attribute.name + ) + } + + let value = rows[0][attribute.name] + if let value { + if value is NSNull { + needsRepair = !attribute.isOptional + } else { + needsRepair = !isAcceptableStringArray( + value + ) + } + } else { + needsRepair = !attribute.isOptional + } + } catch is SafeTransformableValueReaderError { + needsRepair = true + } catch let error as NSError + where error.domain == NSCocoaErrorDomain && + error.code == NSCoderReadCorruptError { + needsRepair = true + } + + // A failed transformable decode can leave fetched state unusable. + // Discard it before issuing a direct store-level repair. + context.reset() + + guard needsRepair else { + return false + } + + guard !context.hasChanges else { + throw SubstrateTransformableRepairError + .unexpectedBatchUpdateResult( + entityName, + attribute.name + ) + } + + let update = NSBatchUpdateRequest(entityName: entityName) + update.affectedStores = [persistentStore] + update.predicate = NSPredicate( + format: "SELF == %@", + objectID + ) + update.propertiesToUpdate = [attribute.name: NSArray()] + update.resultType = .updatedObjectIDsResultType + + let result = try context.execute(update) + guard + let batchResult = result as? NSBatchUpdateResult, + let updatedObjectIDs = batchResult.result as? [NSManagedObjectID], + updatedObjectIDs == [objectID] + else { + throw SubstrateTransformableRepairError + .unexpectedBatchUpdateResult( + entityName, + attribute.name + ) + } + + context.reset() + return true + } + + private func isAcceptableStringArray(_ value: Any) -> Bool { + guard + let array = value as? NSArray, + array.count <= + protectedDataInspectionLimits + .maximumTransformableElements + else { + return false + } + + var cumulativeByteCount = 0 + for element in array { + guard let string = element as? String else { + return false + } + + let byteCount = string.utf8.count + guard + byteCount <= + protectedDataInspectionLimits.maximumValueByteCount, + cumulativeByteCount <= + protectedDataInspectionLimits.maximumValueByteCount - + byteCount + else { + return false + } + cumulativeByteCount += byteCount + } + + return true + } + + private func performWithObjectiveCExceptionBoundary( + operation: SubstrateStorageMigrationOperation, + _ block: @escaping () throws -> Void + ) throws { + do { + try SafeObjectiveCExceptionBoundary.perform(block) + } catch SafeTransformableValueReaderError.objectiveCException { + Logger.shared.error( + "Substrate storage safely stopped during \(operation.rawValue)" + ) + throw SubstrateStorageMigrationError.objectiveCException(operation) + } catch { + throw error + } + } + + private func createMigrationPlan( + from source: CompatibleStore, + to destinationVersion: SubstrateStorageVersion + ) throws -> [MigrationStep] { + let versions = SubstrateStorageVersion.allCases + + guard + let sourceIndex = versions.firstIndex(of: source.version), + let destinationIndex = versions.firstIndex(of: destinationVersion), + sourceIndex < destinationIndex + else { + throw SubstrateStorageMigrationError.migrationPathUnavailable( + source.version, + destinationVersion + ) + } + + var currentVersion = source.version + var currentModel = source.model + var visitedVersions = Set() + var migrationPlan: [MigrationStep] = [] + + while currentVersion != destinationVersion { + guard + visitedVersions.insert(currentVersion).inserted, + let nextVersion = currentVersion.nextVersion() + else { + throw SubstrateStorageMigrationError.migrationPathUnavailable( + source.version, + destinationVersion + ) + } + + let nextModel = try createManagedObjectModel(for: nextVersion) + let mapping: NSMappingModel + + do { + mapping = try createMapping( + from: currentModel, + sourceVersion: currentVersion, + nextModel: nextModel, + destinationVersion: nextVersion + ) + } catch { + throw SubstrateStorageMigrationError.mappingUnavailable( + currentVersion, + nextVersion, + error + ) + } + + migrationPlan.append( + MigrationStep( + sourceVersion: currentVersion, + destinationVersion: nextVersion, + sourceModel: currentModel, + destinationModel: nextModel, + mapping: mapping + ) + ) + + currentVersion = nextVersion + currentModel = nextModel + } + + guard !migrationPlan.isEmpty else { + throw SubstrateStorageMigrationError.migrationPathUnavailable( + source.version, + destinationVersion + ) + } + + return migrationPlan + } + + private func createStagedStore( + using migrationPlan: [MigrationStep], + sourceStoreURL: URL, + migrationDirectoryURL: URL + ) throws -> URL { + var currentURL = sourceStoreURL + + for step in migrationPlan { + let nextStepURL = migrationDirectoryURL.appendingPathComponent( + "\(step.destinationVersion.rawValue)-\(UUID().uuidString).sqlite" + ) + let manager = NSMigrationManager( + sourceModel: step.sourceModel, + destinationModel: step.destinationModel + ) + + do { + try performWithObjectiveCExceptionBoundary( + operation: .stagedMigration + ) { + try manager.migrateStore( + from: currentURL, + sourceType: NSSQLiteStoreType, + options: nil, + with: step.mapping, + toDestinationURL: nextStepURL, + destinationType: NSSQLiteStoreType, + destinationOptions: nil + ) + } + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError.migrationStepFailed( + step.sourceVersion, + step.destinationVersion, + error + ) + } + + do { + // At most the current input and its successfully produced + // output coexist. Do not retain a chain of full SQLite stores. + try removeStoreFamily(at: currentURL) + } catch { + // Best effort prevents the new output from adding to the + // footprint while the enclosing source-root cleanup runs. + try? removeStoreFamily(at: nextStepURL) + throw SubstrateStorageMigrationError.temporaryStoreCleanupFailed( + currentURL, + error + ) + } + + currentURL = nextStepURL + } + + return currentURL + } + + private func removeStoreFamily(at url: URL) throws { + for suffix in Self.storeFamilySuffixes { + let familyURL = URL(fileURLWithPath: url.path + suffix) + + guard fileManager.fileExists(atPath: familyURL.path) else { + continue + } + + try fileManager.removeItem(at: familyURL) + } + } + + private func validateStagedStore( + at stagedStoreURL: URL, + targetModel: NSManagedObjectModel, + expectedRowCounts: [String: Int], + expectedProtectedData: ProtectedDataSnapshot + ) throws { + let metadata: [String: Any] + do { + var inspectedMetadata: [String: Any]? + try performWithObjectiveCExceptionBoundary( + operation: .stagedValidation + ) { + inspectedMetadata = try NSPersistentStoreCoordinator + .metadataForPersistentStore( + ofType: NSSQLiteStoreType, + at: stagedStoreURL, + options: nil + ) + } + metadata = inspectedMetadata ?? [:] + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError.stagedStoreMetadataUnreadable( + stagedStoreURL, + error + ) + } + + guard targetModel.isConfiguration( + withName: targetVersion.rawValue, + compatibleWithStoreMetadata: metadata + ) else { + throw SubstrateStorageMigrationError.stagedStoreInvalid( + stagedStoreURL, + targetVersion + ) + } + + if targetVersion == .version8 { + do { + try inspectVersion8StartupGraphBounds( + at: stagedStoreURL, + model: targetModel + ) + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError + .stagedStoreInspectionFailed( + stagedStoreURL, + error + ) + } + } + + let stagedRowCounts: [String: Int] + do { + stagedRowCounts = try inspectStoreRowCounts( + at: stagedStoreURL, + model: targetModel, + entityNames: Set(expectedRowCounts.keys), + operation: .stagedValidation + ) + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError.stagedStoreInspectionFailed( + stagedStoreURL, + error + ) + } + + for (entityName, expectedCount) in expectedRowCounts { + let actualCount = stagedRowCounts[entityName] ?? 0 + + guard actualCount == expectedCount else { + throw SubstrateStorageMigrationError.stagedStoreRowCountMismatch( + entityName, + expectedCount, + actualCount + ) + } + } + + let stagedProtectedData: ProtectedDataSnapshot + do { + stagedProtectedData = try inspectProtectedDataSnapshot( + at: stagedStoreURL, + model: targetModel + ) + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch let inspectionError + as SubstrateProtectedDataInspectionError { + throw SubstrateStorageMigrationError + .protectedDataInspectionRejected( + stagedStoreURL, + inspectionError + ) + } catch { + throw SubstrateStorageMigrationError.stagedStoreInspectionFailed( + stagedStoreURL, + error + ) + } + + guard stagedProtectedData == expectedProtectedData else { + throw SubstrateStorageMigrationError + .stagedStoreProtectedDataMismatch + } + } + + private func inspectProtectedDataInExistingStore() throws -> ProtectedDataFootprint { + guard fileManager.fileExists(atPath: storeURL.path) else { + throw SubstrateStorageMigrationError.sourceStoreInspectionFailed( + storeURL, + CocoaError( + .fileNoSuchFile, + userInfo: [NSFilePathErrorKey: storeURL.path] + ) + ) + } + + let snapshot = try createPrivateSourceSnapshot() + defer { + do { + if fileManager.fileExists(atPath: snapshot.rootURL.path) { + try fileManager.removeItem(at: snapshot.rootURL) + } + } catch { + Logger.shared.error( + "Unable to clean up a private Substrate recovery-inspection copy" + ) + } + } + + // This is the final race-resistant recovery check. Only the private + // copy's explicitly rebuildable transformables may be repaired before + // protected-data inspection; the installed family remains untouched. + let compatibleStore = try loadCompatibleStore( + at: snapshot.workingStoreURL + ) + _ = try sanitizeTransformableValues( + at: snapshot.workingStoreURL, + compatibleStore: compatibleStore + ) + + return try inspectProtectedData( + at: snapshot.workingStoreURL, + model: compatibleStore.model + ) + } + + private func inspectProtectedData( + at url: URL, + model: NSManagedObjectModel + ) throws -> ProtectedDataFootprint { + do { + return try inspectProtectedDataUnchecked( + at: url, + model: model + ) + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError.sourceStoreInspectionFailed( + storeURL, + error + ) + } + } + + private func inspectProtectedDataUnchecked( + at url: URL, + model: NSManagedObjectModel + ) throws -> ProtectedDataFootprint { + var footprint: ProtectedDataFootprint? + try performWithObjectiveCExceptionBoundary( + operation: .protectedDataInspection + ) { + footprint = try self.inspectProtectedDataWithoutExceptionBoundary( + at: url, + model: model + ) + } + + guard let footprint else { + throw SubstrateProtectedDataInspectionError + .countUnavailable("protected-data footprint") + } + return footprint + } + + private func inspectProtectedDataWithoutExceptionBoundary( + at url: URL, + model: NSManagedObjectModel + ) throws -> ProtectedDataFootprint { + guard let chainEntity = model.entitiesByName["CDChain"] else { + throw SubstrateProtectedDataInspectionError.entityUnavailable("CDChain") + } + guard model.entitiesByName["CDChainNode"] != nil else { + throw SubstrateProtectedDataInspectionError.entityUnavailable("CDChainNode") + } + + for relationshipName in ["nodes", "customNodes", "selectedNode"] { + guard chainEntity.relationshipsByName[relationshipName] != nil else { + throw SubstrateProtectedDataInspectionError.relationshipUnavailable( + "CDChain", + relationshipName + ) + } + } + + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSReadOnlyPersistentStoreOption: true, + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + var result: Result? + context.performAndWait { + result = Result { + let rowCounts = try self.protectedEntityRowCounts( + model: model, + context: context + ) + var counts: [String: Int] = [ + ProtectedDataCategory.contacts: + rowCounts[ProtectedDataCategory.contacts] ?? 0, + ProtectedDataCategory.contactItems: + rowCounts[ProtectedDataCategory.contactItems] ?? 0, + ProtectedDataCategory.transactionHistory: + rowCounts[ + ProtectedDataCategory.transactionHistory + ] ?? 0 + ] + + var referencedNodeIDs = Set() + var customNodeRelationshipCount = 0 + var selectedNodeRelationshipCount = 0 + var totalRelationshipCount = 0 + + try self.forEachManagedObjectPage( + entityName: "CDChain", + rowCount: rowCounts["CDChain"] ?? 0, + context: context + ) { chains in + for chain in chains { + let defaultNodeCount = try self + .boundedRelationshipMemberCount( + inRelationship: "nodes", + of: chain + ) + let customNodeCount = try self + .boundedRelationshipMemberCount( + inRelationship: "customNodes", + of: chain + ) + try self.addRelationshipMembers( + defaultNodeCount, + to: &totalRelationshipCount + ) + try self.addRelationshipMembers( + customNodeCount, + to: &totalRelationshipCount + ) + + let defaultNodes = try self + .boundedManagedObjects( + inRelationship: "nodes", + of: chain, + expectedMemberCount: defaultNodeCount + ) + let customNodes = try self + .boundedManagedObjects( + inRelationship: "customNodes", + of: chain, + expectedMemberCount: customNodeCount + ) + referencedNodeIDs.formUnion( + defaultNodes.map(\.objectID) + ) + referencedNodeIDs.formUnion( + customNodes.map(\.objectID) + ) + customNodeRelationshipCount += + customNodes.count + + if let selectedNode = chain.value( + forKey: "selectedNode" + ) as? NSManagedObject { + try self.addRelationshipMembers( + 1, + to: &totalRelationshipCount + ) + referencedNodeIDs.insert( + selectedNode.objectID + ) + selectedNodeRelationshipCount += 1 + } + } + } + + var orphanNodeCount = 0 + try self.forEachManagedObjectPage( + entityName: "CDChainNode", + rowCount: rowCounts["CDChainNode"] ?? 0, + context: context + ) { nodes in + for node in nodes where + !referencedNodeIDs.contains(node.objectID) { + orphanNodeCount += 1 + } + } + + counts[ProtectedDataCategory.customNodeRelationships] = + customNodeRelationshipCount + counts[ProtectedDataCategory.selectedNodeRelationships] = + selectedNodeRelationshipCount + counts[ProtectedDataCategory.orphanNodes] = orphanNodeCount + + return ProtectedDataFootprint(counts: counts) + } + } + + guard let result else { + throw SubstrateProtectedDataInspectionError + .countUnavailable("protected data footprint") + } + return try result.get() + } + + private func protectedEntityRowCounts( + model: NSManagedObjectModel, + context: NSManagedObjectContext + ) throws -> [String: Int] { + let entityNames = [ + ProtectedDataCategory.contacts, + ProtectedDataCategory.contactItems, + ProtectedDataCategory.transactionHistory, + "CDChain", + "CDChainNode" + ] + var counts: [String: Int] = [:] + var totalCount = 0 + + for entityName in entityNames { + let count = try countRowsIfPresent( + entityName: entityName, + model: model, + context: context + ) + guard + count <= protectedDataInspectionLimits + .maximumRowsPerEntity + else { + throw SubstrateProtectedDataInspectionError + .entityRowLimitExceeded( + entityName, + count, + protectedDataInspectionLimits + .maximumRowsPerEntity + ) + } + + let addition = totalCount.addingReportingOverflow(count) + guard + !addition.overflow, + addition.partialValue <= + protectedDataInspectionLimits.maximumTotalRows + else { + throw SubstrateProtectedDataInspectionError + .totalRowLimitExceeded( + addition.overflow + ? Int.max + : addition.partialValue, + protectedDataInspectionLimits.maximumTotalRows + ) + } + totalCount = addition.partialValue + counts[entityName] = count + } + + return counts + } + + private func countRowsIfPresent( + entityName: String, + model: NSManagedObjectModel, + context: NSManagedObjectContext + ) throws -> Int { + guard model.entitiesByName[entityName] != nil else { + return 0 + } + + let request = NSFetchRequest(entityName: entityName) + request.includesPendingChanges = false + request.includesSubentities = false + let count = try context.count(for: request) + + guard count != NSNotFound else { + throw SubstrateProtectedDataInspectionError.countUnavailable(entityName) + } + + return count + } + + private func inspectVersion8StartupGraphBounds( + at url: URL, + model: NSManagedObjectModel + ) throws { + try performWithObjectiveCExceptionBoundary( + operation: .protectedDataInspection + ) { + try self + .inspectVersion8StartupGraphBoundsWithoutExceptionBoundary( + at: url, + model: model + ) + } + } + + private func inspectVersion8StartupGraphBoundsWithoutExceptionBoundary( + at url: URL, + model: NSManagedObjectModel + ) throws { + for entityName in Self.version8StartupRootEntityNames { + guard model.entitiesByName[entityName] != nil else { + throw SubstrateProtectedDataInspectionError + .entityUnavailable(entityName) + } + } + for entityName in Self.version8StartupChildEntityNames { + guard model.entitiesByName[entityName] != nil else { + throw SubstrateProtectedDataInspectionError + .entityUnavailable(entityName) + } + } + for family in Self.version8StartupToManyRelationshipFamilies { + guard let entity = model.entitiesByName[family.entityName] else { + throw SubstrateProtectedDataInspectionError + .entityUnavailable(family.entityName) + } + for relationshipName in family.relationshipNames { + guard + let relationship = + entity.relationshipsByName[relationshipName], + relationship.isToMany + else { + throw SubstrateProtectedDataInspectionError + .relationshipUnavailable( + family.entityName, + relationshipName + ) + } + } + } + + try inspectVersion8StartupRootRawBounds( + at: url, + model: model + ) + try inspectVersion8StartupChildRawBounds( + at: url, + model: model + ) + + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSReadOnlyPersistentStoreOption: true, + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + + var result: Result? + context.performAndWait { + result = Result { + let rowCounts = try self.version8StartupEntityRowCounts( + context: context, + persistentStore: store + ) + var totalRelationshipMemberCount = 0 + + for family in + Self.version8StartupToManyRelationshipFamilies { + let objectIDs = try self + .version8StartupObjectIDs( + entityName: family.entityName, + rowCount: + rowCounts[family.entityName] ?? 0, + context: context, + persistentStore: store + ) + var pageStart = 0 + while pageStart < objectIDs.count { + let pageLength = min( + self.protectedDataInspectionLimits + .fetchPageSize, + objectIDs.count - pageStart + ) + let pageEnd = pageStart + pageLength + + do { + for objectID in + objectIDs[pageStart ..< pageEnd] { + let object = context.object( + with: objectID + ) + for relationshipName in + family.relationshipNames { + let memberCount = try self + .boundedRelationshipMemberCount( + inRelationship: + relationshipName, + of: object + ) + try self.addRelationshipMembers( + memberCount, + to: + &totalRelationshipMemberCount + ) + } + } + } catch { + context.reset() + throw error + } + + pageStart = pageEnd + context.reset() + } + } + + return () + } + } + + guard let result else { + throw SubstrateProtectedDataInspectionError + .countUnavailable("v8 startup graph") + } + try result.get() + } + + private func inspectVersion8StartupRootRawBounds( + at url: URL, + model: NSManagedObjectModel + ) throws { + var database: OpaquePointer? + let openResult = sqlite3_open_v2( + url.path, + &database, + SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX, + nil + ) + guard openResult == SQLITE_OK, let database else { + if let database { + sqlite3_close_v2(database) + } + throw SubstrateProtectedDataInspectionError + .countUnavailable("v8 startup roots") + } + defer { + sqlite3_close_v2(database) + } + + var aggregatePayloadByteCount: UInt64 = 0 + for entityName in Self.version8StartupRootEntityNames.sorted() { + guard let entity = model.entitiesByName[entityName] else { + throw SubstrateProtectedDataInspectionError + .entityUnavailable(entityName) + } + let tableName = try version8PhysicalIdentifier( + entityName + ) + let columnNames = try entity.attributesByName.values + .sorted { $0.name < $1.name } + .map { + try version8PhysicalIdentifier($0.name) + } + guard !columnNames.isEmpty else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + + let payloadExpressions = columnNames.map { + """ + COALESCE(length(CAST("\($0)" AS BLOB)), 0) + """ + }.joined(separator: ", ") + let sql = """ + SELECT \(payloadExpressions) + FROM "\(tableName)" + """ + var statement: OpaquePointer? + guard + sqlite3_prepare_v2( + database, + sql, + -1, + &statement, + nil + ) == SQLITE_OK, + let statement + else { + if let statement { + sqlite3_finalize(statement) + } + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + defer { + sqlite3_finalize(statement) + } + + var rowCount = 0 + while true { + let stepResult = sqlite3_step(statement) + if stepResult == SQLITE_DONE { + break + } + guard stepResult == SQLITE_ROW else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + + let rowAddition = rowCount.addingReportingOverflow(1) + guard + !rowAddition.overflow, + rowAddition.partialValue <= + protectedDataInspectionLimits + .maximumStartupRootRowsPerEntity + else { + throw SubstrateProtectedDataInspectionError + .entityRowLimitExceeded( + entityName, + rowAddition.overflow + ? Int.max + : rowAddition.partialValue, + protectedDataInspectionLimits + .maximumStartupRootRowsPerEntity + ) + } + rowCount = rowAddition.partialValue + + for columnIndex in 0 ..< columnNames.count { + guard + sqlite3_column_type( + statement, + Int32(columnIndex) + ) == SQLITE_INTEGER + else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + let signedByteCount = sqlite3_column_int64( + statement, + Int32(columnIndex) + ) + guard signedByteCount >= 0 else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + + let addition = aggregatePayloadByteCount + .addingReportingOverflow( + UInt64(signedByteCount) + ) + guard + !addition.overflow, + addition.partialValue <= + protectedDataInspectionLimits + .maximumStartupRootPayloadByteCount + else { + throw SubstrateProtectedDataInspectionError + .startupRootPayloadByteLimitExceeded( + addition.overflow + ? UInt64.max + : addition.partialValue, + protectedDataInspectionLimits + .maximumStartupRootPayloadByteCount + ) + } + aggregatePayloadByteCount = + addition.partialValue + } + } + } + } + + private func inspectVersion8StartupChildRawBounds( + at url: URL, + model: NSManagedObjectModel + ) throws { + var database: OpaquePointer? + let openResult = sqlite3_open_v2( + url.path, + &database, + SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX, + nil + ) + guard openResult == SQLITE_OK, let database else { + if let database { + sqlite3_close_v2(database) + } + throw SubstrateProtectedDataInspectionError + .countUnavailable("v8 startup children") + } + defer { + sqlite3_close_v2(database) + } + + var totalRowCount = 0 + var aggregatePayloadByteCount: UInt64 = 0 + + for entityName in Self.version8StartupChildEntityNames.sorted() { + guard let entity = model.entitiesByName[entityName] else { + throw SubstrateProtectedDataInspectionError + .entityUnavailable(entityName) + } + let tableName = try version8PhysicalIdentifier( + entityName + ) + let attributes = try entity.attributesByName.values + .sorted { $0.name < $1.name } + .map { + ( + name: $0.name, + columnName: try version8PhysicalIdentifier( + $0.name + ) + ) + } + guard !attributes.isEmpty else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + + let payloadExpressions = attributes.map { + """ + COALESCE(length(CAST("\($0.columnName)" AS BLOB)), 0) + """ + }.joined(separator: ", ") + let sql = """ + SELECT \(payloadExpressions) + FROM "\(tableName)" + """ + var statement: OpaquePointer? + guard + sqlite3_prepare_v2( + database, + sql, + -1, + &statement, + nil + ) == SQLITE_OK, + let statement + else { + if let statement { + sqlite3_finalize(statement) + } + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + + do { + defer { + sqlite3_finalize(statement) + } + + var entityRowCount = 0 + while true { + let stepResult = sqlite3_step(statement) + if stepResult == SQLITE_DONE { + break + } + guard stepResult == SQLITE_ROW else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + + let entityRowAddition = + entityRowCount.addingReportingOverflow(1) + guard + !entityRowAddition.overflow, + entityRowAddition.partialValue <= + protectedDataInspectionLimits + .maximumRowsPerEntity + else { + throw SubstrateProtectedDataInspectionError + .entityRowLimitExceeded( + entityName, + entityRowAddition.overflow + ? Int.max + : entityRowAddition.partialValue, + protectedDataInspectionLimits + .maximumRowsPerEntity + ) + } + entityRowCount = + entityRowAddition.partialValue + + let totalRowAddition = + totalRowCount.addingReportingOverflow(1) + guard + !totalRowAddition.overflow, + totalRowAddition.partialValue <= + protectedDataInspectionLimits + .maximumTotalRows + else { + throw SubstrateProtectedDataInspectionError + .totalRowLimitExceeded( + totalRowAddition.overflow + ? Int.max + : totalRowAddition.partialValue, + protectedDataInspectionLimits + .maximumTotalRows + ) + } + totalRowCount = totalRowAddition.partialValue + + for ( + columnIndex, + attribute + ) in attributes.enumerated() { + guard + sqlite3_column_type( + statement, + Int32(columnIndex) + ) == SQLITE_INTEGER + else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + let signedByteCount = sqlite3_column_int64( + statement, + Int32(columnIndex) + ) + guard signedByteCount >= 0 else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + let valueByteCount = UInt64( + signedByteCount + ) + + guard + valueByteCount <= + protectedDataInspectionLimits + .maximumStartupChildValueByteCount + else { + throw SubstrateProtectedDataInspectionError + .startupChildValueByteLimitExceeded( + entityName, + attribute.name, + valueByteCount, + protectedDataInspectionLimits + .maximumStartupChildValueByteCount + ) + } + + let aggregateAddition = + aggregatePayloadByteCount + .addingReportingOverflow( + valueByteCount + ) + guard + !aggregateAddition.overflow, + aggregateAddition.partialValue <= + protectedDataInspectionLimits + .maximumStartupChildPayloadByteCount + else { + throw SubstrateProtectedDataInspectionError + .startupChildPayloadByteLimitExceeded( + aggregateAddition.overflow + ? UInt64.max + : aggregateAddition.partialValue, + protectedDataInspectionLimits + .maximumStartupChildPayloadByteCount + ) + } + aggregatePayloadByteCount = + aggregateAddition.partialValue + } + } + } + } + } + + private func version8PhysicalIdentifier( + _ logicalName: String + ) throws -> String { + guard + !logicalName.isEmpty, + logicalName.unicodeScalars.allSatisfy({ + (0x30 ... 0x39).contains($0.value) || + (0x41 ... 0x5A).contains($0.value) || + (0x61 ... 0x7A).contains($0.value) || + $0.value == 0x5F + }) + else { + throw SubstrateProtectedDataInspectionError + .countUnavailable("v8 startup schema") + } + + return "Z\(logicalName.uppercased())" + } + + private func version8StartupEntityRowCounts( + context: NSManagedObjectContext, + persistentStore: NSPersistentStore + ) throws -> [String: Int] { + let entityNames = Set( + Self.version8StartupRootEntityNames + + Self.version8StartupToManyRelationshipFamilies.map( + \.entityName + ) + ) + var rowCounts = [String: Int]() + var totalRowCount = 0 + + for entityName in entityNames.sorted() { + let request = NSFetchRequest( + entityName: entityName + ) + request.includesPendingChanges = false + request.includesSubentities = false + request.affectedStores = [persistentStore] + let rowCount = try context.count(for: request) + guard rowCount != NSNotFound else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + guard + rowCount <= + protectedDataInspectionLimits.maximumRowsPerEntity + else { + throw SubstrateProtectedDataInspectionError + .entityRowLimitExceeded( + entityName, + rowCount, + protectedDataInspectionLimits + .maximumRowsPerEntity + ) + } + + let addition = totalRowCount.addingReportingOverflow( + rowCount + ) + guard + !addition.overflow, + addition.partialValue <= + protectedDataInspectionLimits.maximumTotalRows + else { + throw SubstrateProtectedDataInspectionError + .totalRowLimitExceeded( + addition.overflow + ? Int.max + : addition.partialValue, + protectedDataInspectionLimits.maximumTotalRows + ) + } + totalRowCount = addition.partialValue + rowCounts[entityName] = rowCount + } + + return rowCounts + } + + private func version8StartupObjectIDs( + entityName: String, + rowCount: Int, + context: NSManagedObjectContext, + persistentStore: NSPersistentStore + ) throws -> [NSManagedObjectID] { + guard rowCount > 0 else { + return [] + } + guard rowCount < Int.max else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + + let request = NSFetchRequest( + entityName: entityName + ) + request.resultType = .managedObjectIDResultType + request.includesPendingChanges = false + request.includesSubentities = false + request.affectedStores = [persistentStore] + request.fetchLimit = rowCount + 1 + request.fetchBatchSize = min( + protectedDataInspectionLimits.fetchPageSize, + rowCount + 1 + ) + + let fetchedResults = try context.fetch(request) + let objectIDs = fetchedResults.compactMap { + $0 as? NSManagedObjectID + } + guard + objectIDs.count == fetchedResults.count, + objectIDs.count == rowCount, + Set(objectIDs).count == rowCount, + objectIDs.allSatisfy({ + $0.persistentStore === persistentStore + }) + else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + + return objectIDs + } + + private func forEachManagedObjectPage( + entityName: String, + rowCount: Int, + context: NSManagedObjectContext, + _ operation: ([NSManagedObject]) throws -> Void + ) throws { + guard rowCount > 0 else { + return + } -final class SubstrateStorageMigrator { - let storeURL: URL - let modelDirectory: String - let fileManager: FileManager - let targetVersion: SubstrateStorageVersion + // Materialize the capped ID list once for exact-once enumeration; + // managed objects and their values are hydrated only one page at a + // time below. + let identifierRequest = + NSFetchRequest( + entityName: entityName + ) + identifierRequest.resultType = .managedObjectIDResultType + identifierRequest.includesPendingChanges = false + identifierRequest.includesSubentities = false + let objectIDs = try context.fetch(identifierRequest) + .compactMap { $0 as? NSManagedObjectID } + guard + objectIDs.count == rowCount, + Set(objectIDs).count == rowCount + else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } - init( - targetVersion: SubstrateStorageVersion, - storeURL: URL, - modelDirectory: String, - fileManager: FileManager - ) { - self.targetVersion = targetVersion - self.storeURL = storeURL - self.modelDirectory = modelDirectory - self.fileManager = fileManager + var pageStart = 0 + while pageStart < objectIDs.count { + let pageEnd = min( + pageStart + + protectedDataInspectionLimits.fetchPageSize, + objectIDs.count + ) + let pageObjectIDs = Array( + objectIDs[pageStart ..< pageEnd] + ) + do { + try autoreleasepool { + let request = NSFetchRequest( + entityName: entityName + ) + request.includesPendingChanges = false + request.includesSubentities = false + request.predicate = NSPredicate( + format: "SELF IN %@", + pageObjectIDs + ) + request.fetchLimit = pageObjectIDs.count + request.fetchBatchSize = pageObjectIDs.count + + let page = try context.fetch(request) + guard + page.count == pageObjectIDs.count, + Set(page.map(\.objectID)) == + Set(pageObjectIDs) + else { + throw SubstrateProtectedDataInspectionError + .countUnavailable(entityName) + } + try operation(page) + } + } catch { + context.reset() + throw error + } + pageStart = pageEnd + context.reset() + } } - func performMigration() { - forceWALCheckpointingForStore(at: storeURL) + private func boundedRelationshipMemberCount( + inRelationship relationshipName: String, + of object: NSManagedObject + ) throws -> Int { + let entityName = object.entity.name ?? "unknown" + guard + let relationship = + object.entity.relationshipsByName[relationshipName], + relationship.isToMany, + let context = object.managedObjectContext, + !object.objectID.isTemporaryID, + let persistentStore = object.objectID.persistentStore + else { + throw SubstrateProtectedDataInspectionError + .relationshipCountUnavailable( + entityName, + relationshipName + ) + } - let maybeMetadata = try? NSPersistentStoreCoordinator.metadataForPersistentStore( - ofType: NSSQLiteStoreType, - at: storeURL, - options: nil + let countKey = "__fearlessRelationshipMemberCount" + let countDescription = NSExpressionDescription() + countDescription.name = countKey + countDescription.expression = NSExpression( + forFunction: "count:", + arguments: [ + NSExpression(forKeyPath: relationshipName) + ] ) + countDescription.expressionResultType = + .integer64AttributeType + let request = NSFetchRequest( + entityName: entityName + ) + request.resultType = .dictionaryResultType + request.propertiesToFetch = [countDescription] + request.predicate = NSPredicate( + format: "SELF == %@", + object.objectID + ) + request.includesPendingChanges = false + request.includesSubentities = false + request.affectedStores = [persistentStore] + request.fetchLimit = 2 + + let rows = try context.fetch(request) guard - let metadata = maybeMetadata, - let sourceVersion = compatibleVersionForStoreMetadata(metadata) else { - fatalError("Unknown store version at URL \(storeURL)") + rows.count == 1, + let number = rows[0][countKey] as? NSNumber + else { + throw SubstrateProtectedDataInspectionError + .relationshipCountUnavailable( + entityName, + relationshipName + ) } - do { - let migrationDirName = UUID().uuidString - let tmpMigrationDirURL = URL( - fileURLWithPath: NSTemporaryDirectory(), - isDirectory: true - ).appendingPathComponent(migrationDirName) + let count = number.int64Value + guard + count >= 0, + UInt64(count) <= UInt64(Int.max) + else { + throw SubstrateProtectedDataInspectionError + .relationshipCountUnavailable( + entityName, + relationshipName + ) + } + let memberCount = Int(count) - try fileManager.createDirectory(at: tmpMigrationDirURL, withIntermediateDirectories: true) + protectedRelationshipCountDidFetch( + object, + relationshipName, + memberCount + ) - try performMigration( - from: sourceVersion, - to: targetVersion, - storeURL: storeURL, - tmpMigrationDirURL: tmpMigrationDirURL - ) + guard + memberCount <= protectedDataInspectionLimits + .maximumRelationshipMembers + else { + throw SubstrateProtectedDataInspectionError + .relationshipLimitExceeded( + entityName, + relationshipName, + memberCount, + protectedDataInspectionLimits + .maximumRelationshipMembers + ) + } - try fileManager.removeItem(at: tmpMigrationDirURL) - } catch { - fatalError("Migration failed with error \(error)") + return memberCount + } + + private func boundedManagedObjects( + inRelationship relationshipName: String, + of object: NSManagedObject, + expectedMemberCount: Int + ) throws -> [NSManagedObject] { + let entityName = object.entity.name ?? "unknown" + + // The SQL-backed count and both the per-relationship and aggregate + // caps have succeeded before this is called. KVC may fire the + // relationship only after every allocation is therefore bounded. + protectedRelationshipWillMaterialize( + entityName, + relationshipName, + expectedMemberCount + ) + + guard let value = object.value(forKey: relationshipName) else { + guard expectedMemberCount == 0 else { + throw SubstrateProtectedDataInspectionError + .relationshipValueInvalid( + entityName, + relationshipName + ) + } + return [] + } + guard + let objects = value as? NSSet, + objects.count == expectedMemberCount + else { + throw SubstrateProtectedDataInspectionError + .relationshipValueInvalid( + entityName, + relationshipName + ) + } + + var managedObjects = [NSManagedObject]() + managedObjects.reserveCapacity(expectedMemberCount) + for member in objects { + guard let managedObject = member as? NSManagedObject else { + throw SubstrateProtectedDataInspectionError + .relationshipValueInvalid( + entityName, + relationshipName + ) + } + managedObjects.append(managedObject) } + guard managedObjects.count == expectedMemberCount else { + throw SubstrateProtectedDataInspectionError + .relationshipValueInvalid( + entityName, + relationshipName + ) + } + + return managedObjects } - private func performMigration( - from sourceVersion: SubstrateStorageVersion, - to destinationVersion: SubstrateStorageVersion, - storeURL: URL, - tmpMigrationDirURL: URL + private func addRelationshipMembers( + _ count: Int, + to totalCount: inout Int ) throws { - var currentVersion = sourceVersion - var currentURL = storeURL + let addition = totalCount.addingReportingOverflow(count) + guard + !addition.overflow, + addition.partialValue <= protectedDataInspectionLimits + .maximumTotalRelationshipMembers + else { + throw SubstrateProtectedDataInspectionError + .totalRelationshipLimitExceeded( + addition.overflow ? Int.max : addition.partialValue, + protectedDataInspectionLimits + .maximumTotalRelationshipMembers + ) + } + totalCount = addition.partialValue + } + + private func inspectProtectedDataSnapshot( + at url: URL, + model: NSManagedObjectModel, + normalizingMissingSelectedNode: Bool = false + ) throws -> ProtectedDataSnapshot { + var snapshot: ProtectedDataSnapshot? + try performWithObjectiveCExceptionBoundary( + operation: .protectedDataInspection + ) { + snapshot = try self + .inspectProtectedDataSnapshotWithoutExceptionBoundary( + at: url, + model: model, + normalizingMissingSelectedNode: + normalizingMissingSelectedNode + ) + } + + guard let snapshot else { + throw SubstrateProtectedDataInspectionError + .countUnavailable("protected-data snapshot") + } + return snapshot + } - while currentVersion != destinationVersion, let nextVersion = currentVersion.nextVersion() { - let currentModel = createManagedObjectModel(forResource: currentVersion.rawValue) - let nextModel = createManagedObjectModel(forResource: nextVersion.rawValue) + private func inspectProtectedDataSnapshotWithoutExceptionBoundary( + at url: URL, + model: NSManagedObjectModel, + normalizingMissingSelectedNode: Bool + ) throws -> ProtectedDataSnapshot { + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSReadOnlyPersistentStoreOption: true, + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + + var result: Result? + context.performAndWait { + result = Result { + let rowCounts = try self.protectedEntityRowCounts( + model: model, + context: context + ) + let contacts = try self.semanticDigest( + entityName: "CDContact", + attributeNames: [ + "address", + "chainId", + "name" + ], + model: model, + context: context, + rowCount: rowCounts["CDContact"] ?? 0 + ) + let contactItems = try self.semanticDigest( + entityName: "CDContactItem", + attributeNames: [ + "identifier", + "peerAddress", + "peerName", + "targetAddress", + "updatedAt" + ], + model: model, + context: context, + rowCount: rowCounts["CDContactItem"] ?? 0 + ) + let transactionHistory = try self.semanticDigest( + entityName: "CDTransactionHistoryItem", + attributeNames: [ + "blockNumber", + "call", + "callName", + "fee", + "identifier", + "moduleName", + "receiver", + "sender", + "status", + "timestamp", + "txIndex" + ], + model: model, + context: context, + rowCount: + rowCounts["CDTransactionHistoryItem"] ?? 0 + ) + + guard let chainEntity = + model.entitiesByName["CDChain"] else { + throw SubstrateProtectedDataInspectionError + .entityUnavailable("CDChain") + } + guard model.entitiesByName["CDChainNode"] != nil else { + throw SubstrateProtectedDataInspectionError + .entityUnavailable("CDChainNode") + } + + for relationshipName in [ + "nodes", + "customNodes", + "selectedNode" + ] { + guard + chainEntity.relationshipsByName[ + relationshipName + ] != nil + else { + throw SubstrateProtectedDataInspectionError + .relationshipUnavailable( + "CDChain", + relationshipName + ) + } + } + + let nodeAttributeNames = [ + "apiKeyName", + "apiQueryName", + "name", + "url" + ] + var referencedNodeIDs = Set() + var topologyAccumulator = + ProtectedDataDigestAccumulator() + var totalRelationshipCount = 0 + + try self.forEachManagedObjectPage( + entityName: "CDChain", + rowCount: rowCounts["CDChain"] ?? 0, + context: context + ) { chains in + for chain in chains { + let defaultNodeCount = try self + .boundedRelationshipMemberCount( + inRelationship: "nodes", + of: chain + ) + let customNodeCount = try self + .boundedRelationshipMemberCount( + inRelationship: "customNodes", + of: chain + ) + try self.addRelationshipMembers( + defaultNodeCount, + to: &totalRelationshipCount + ) + try self.addRelationshipMembers( + customNodeCount, + to: &totalRelationshipCount + ) + + let defaultNodes = try self + .boundedManagedObjects( + inRelationship: "nodes", + of: chain, + expectedMemberCount: defaultNodeCount + ) + let customNodes = try self + .boundedManagedObjects( + inRelationship: "customNodes", + of: chain, + expectedMemberCount: customNodeCount + ) + + let defaultNodeDigest = try self + .semanticDigest( + objects: defaultNodes, + attributeNames: nodeAttributeNames, + category: "CDChain.nodes" + ) + let customNodeDigest = try self + .semanticDigest( + objects: customNodes, + attributeNames: nodeAttributeNames, + category: "CDChain.customNodes" + ) + let storedSelectedNode = chain.value( + forKey: "selectedNode" + ) as? NSManagedObject + let selectedNode: NSManagedObject? + if let storedSelectedNode { + selectedNode = storedSelectedNode + } else if normalizingMissingSelectedNode { + selectedNode = try self + .stableSemanticMinimum( + defaultNodes, + attributeNames: + nodeAttributeNames + ) + } else { + selectedNode = nil + } + if selectedNode != nil { + try self.addRelationshipMembers( + 1, + to: &totalRelationshipCount + ) + } + let selectedNodeDigest = try self + .semanticDigest( + objects: selectedNode.map { [$0] } ?? [], + attributeNames: nodeAttributeNames, + category: "CDChain.selectedNode" + ) + + referencedNodeIDs.formUnion( + defaultNodes.map(\.objectID) + ) + referencedNodeIDs.formUnion( + customNodes.map(\.objectID) + ) + if let selectedNode { + referencedNodeIDs.insert( + selectedNode.objectID + ) + } + + let chainIdentifier = try self + .canonicalAttributeValue( + in: chain, + key: "chainId" + ) + let topology = [ + "chain=\(chainIdentifier)", + """ + nodes=\(self.canonicalDigest(defaultNodeDigest)) + """, + """ + custom=\(self.canonicalDigest(customNodeDigest)) + """, + """ + selected=\(self.canonicalDigest(selectedNodeDigest)) + """ + ].joined(separator: ";") + try topologyAccumulator.append( + topology, + category: "CDChain.topology", + maximumByteCount: + self.protectedDataInspectionLimits + .maximumRecordByteCount + ) + } + } + + var orphanNodeAccumulator = + ProtectedDataDigestAccumulator() + try self.forEachManagedObjectPage( + entityName: "CDChainNode", + rowCount: rowCounts["CDChainNode"] ?? 0, + context: context + ) { nodes in + for node in nodes where + !referencedNodeIDs.contains(node.objectID) { + let record = try self.canonicalRecord( + for: node, + attributeNames: nodeAttributeNames + ) + try orphanNodeAccumulator.append( + record, + category: "CDChainNode.orphan", + maximumByteCount: + self.protectedDataInspectionLimits + .maximumRecordByteCount + ) + } + } - let mapping = try createMapping(from: currentModel, nextModel: nextModel) + return ProtectedDataSnapshot( + contacts: contacts, + contactItems: contactItems, + transactionHistory: transactionHistory, + chainNodeTopologies: + topologyAccumulator.finalize(), + orphanNodes: orphanNodeAccumulator.finalize() + ) + } + } - let manager = NSMigrationManager(sourceModel: currentModel, destinationModel: nextModel) + guard let result else { + throw SubstrateProtectedDataInspectionError + .countUnavailable("protected data snapshot") + } + return try result.get() + } - let nextStepURL = tmpMigrationDirURL.appendingPathComponent(UUID().uuidString) + private func stableSemanticMinimum( + _ objects: [NSManagedObject], + attributeNames: [String] + ) throws -> NSManagedObject? { + var selected: ( + record: String, + objectID: String, + object: NSManagedObject + )? - try manager.migrateStore( - from: currentURL, - sourceType: NSSQLiteStoreType, - options: nil, - with: mapping, - toDestinationURL: nextStepURL, - destinationType: NSSQLiteStoreType, - destinationOptions: nil + for object in objects { + let candidate = ( + record: try canonicalRecord( + for: object, + attributeNames: attributeNames + ), + objectID: object.objectID + .uriRepresentation().absoluteString, + object: object ) + guard let currentSelection = selected else { + selected = candidate + continue + } + if + candidate.record < currentSelection.record || + ( + candidate.record == + currentSelection.record && + candidate.objectID < + currentSelection.objectID + ) { + selected = candidate + } + } + + return selected?.object + } + + private func semanticDigest( + entityName: String, + attributeNames: [String], + model: NSManagedObjectModel, + context: NSManagedObjectContext, + rowCount: Int + ) throws -> ProtectedDataDigest { + guard model.entitiesByName[entityName] != nil else { + return ProtectedDataDigestAccumulator().finalize() + } - if currentURL != storeURL { - try NSPersistentStoreCoordinator.destroyStore(at: currentURL) + var accumulator = ProtectedDataDigestAccumulator() + try forEachManagedObjectPage( + entityName: entityName, + rowCount: rowCount, + context: context + ) { objects in + for object in objects { + let record = try self.canonicalRecord( + for: object, + attributeNames: attributeNames + ) + try accumulator.append( + record, + category: entityName, + maximumByteCount: + self.protectedDataInspectionLimits + .maximumRecordByteCount + ) } + } - currentVersion = nextVersion - currentURL = nextStepURL + return accumulator.finalize() + } + + private func semanticDigest( + objects: [NSManagedObject], + attributeNames: [String], + category: String + ) throws -> ProtectedDataDigest { + var accumulator = ProtectedDataDigestAccumulator() + for object in objects { + let record = try canonicalRecord( + for: object, + attributeNames: attributeNames + ) + try accumulator.append( + record, + category: category, + maximumByteCount: protectedDataInspectionLimits + .maximumRecordByteCount + ) + } + + return accumulator.finalize() + } + + private func canonicalRecord( + for object: NSManagedObject, + attributeNames: [String] + ) throws -> String { + try attributeNames.compactMap { key in + guard object.entity.attributesByName[key] != nil else { + return nil + } + + return """ + \(key)=\(try canonicalAttributeValue(in: object, key: key)) + """ + } + .joined(separator: "|") + } + + private func canonicalAttributeValue( + in object: NSManagedObject, + key: String + ) throws -> String { + guard object.entity.attributesByName[key] != nil else { + return "absent" + } + + guard let value = object.value(forKey: key) else { + return "nil" + } + + switch value { + case let string as String: + try requireValueByteLimit( + Data(string.utf8).count, + object: object, + key: key + ) + return "string:\(canonicalString(string))" + case let url as URL: + let absoluteString = url.absoluteString + try requireValueByteLimit( + Data(absoluteString.utf8).count, + object: object, + key: key + ) + return "url:\(canonicalString(absoluteString))" + case let data as Data: + try requireValueByteLimit( + data.count, + object: object, + key: key + ) + return "data:\(data.base64EncodedString())" + case let date as Date: + return "date:\(date.timeIntervalSinceReferenceDate.bitPattern)" + case let decimal as NSDecimalNumber: + let stringValue = decimal.stringValue + try requireValueByteLimit( + Data(stringValue.utf8).count, + object: object, + key: key + ) + return "decimal:\(canonicalString(stringValue))" + case let number as NSNumber: + let stringValue = number.stringValue + try requireValueByteLimit( + Data(stringValue.utf8).count, + object: object, + key: key + ) + return """ + number:\(String(cString: number.objCType)):\(canonicalString(stringValue)) + """ + default: + let className = NSStringFromClass( + type(of: value as AnyObject) + ) + throw SubstrateProtectedDataInspectionError + .unsupportedAttributeValue( + object.entity.name ?? "unknown", + key, + className + ) + } + } + + private func requireValueByteLimit( + _ byteCount: Int, + object: NSManagedObject, + key: String + ) throws { + guard + byteCount <= + protectedDataInspectionLimits.maximumValueByteCount + else { + throw SubstrateProtectedDataInspectionError + .valueByteLimitExceeded( + object.entity.name ?? "unknown", + key, + byteCount, + protectedDataInspectionLimits + .maximumValueByteCount + ) + } + } + + private func canonicalDigest( + _ digest: ProtectedDataDigest + ) -> String { + let words = digest.additiveWords.map { + String(format: "%016llx", $0) + }.joined(separator: ",") + return "\(digest.recordCount):\(words)" + } + + private func canonicalString(_ value: String) -> String { + Data(value.utf8).base64EncodedString() + } + + private func inspectStoreRowCounts( + at url: URL, + model: NSManagedObjectModel, + entityNames: Set, + operation: SubstrateStorageMigrationOperation + ) throws -> [String: Int] { + var counts: [String: Int]? + try performWithObjectiveCExceptionBoundary(operation: operation) { + counts = try self.inspectStoreRowCountsWithoutExceptionBoundary( + at: url, + model: model, + entityNames: entityNames + ) + } + + guard let counts else { + throw SubstrateProtectedDataInspectionError + .countUnavailable("store row counts") + } + return counts + } + + private func inspectStoreRowCountsWithoutExceptionBoundary( + at url: URL, + model: NSManagedObjectModel, + entityNames: Set + ) throws -> [String: Int] { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSReadOnlyPersistentStoreOption: true, + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) } - try NSPersistentStoreCoordinator.replaceStore(at: storeURL, withStoreAt: currentURL) + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + var result: Result<[String: Int], Error>? + context.performAndWait { + result = Result { + var counts: [String: Int] = [:] + + for entityName in entityNames.sorted() { + let request = NSFetchRequest( + entityName: entityName + ) + counts[entityName] = try context.count(for: request) + } + + return counts + } + } - if currentURL != storeURL { - try NSPersistentStoreCoordinator.destroyStore(at: currentURL) + guard let result else { + throw SubstrateProtectedDataInspectionError + .countUnavailable("store row counts") } + return try result.get() } private func checkIfMigrationNeeded(to version: SubstrateStorageVersion) -> Bool { - let storageExists = fileManager.fileExists(atPath: storeURL.path) + if crashConsistentCacheRecovery.hasPendingTransaction { + return true + } - guard storageExists else { - return false + if crashConsistentStoreReplacer.hasPendingTransaction { + return true } - guard let metadata = NSPersistentStoreCoordinator.metadata(at: storeURL) else { - return false + do { + guard try crashConsistentStoreReplacer.liveStoreExistsSafely() else { + return false + } + } catch { + return true } - let compatibleVersion = compatibleVersionForStoreMetadata(metadata) + do { + let snapshot = try createPrivateSourceSnapshot() + defer { + try? fileManager.removeItem(at: snapshot.rootURL) + } + let compatibleStore = try loadCompatibleStore( + at: snapshot.workingStoreURL + ) + + guard compatibleStore.version == version else { + return true + } + + let repairedTransformableValueCount = + try sanitizeTransformableValues( + at: snapshot.workingStoreURL, + compatibleStore: compatibleStore + ) + + if compatibleStore.version == .version8 { + try inspectVersion8StartupGraphBounds( + at: snapshot.workingStoreURL, + model: compatibleStore.model + ) + _ = try inspectProtectedDataSnapshot( + at: snapshot.workingStoreURL, + model: compatibleStore.model + ) + } - return compatibleVersion != version + return repairedTransformableValueCount > 0 + } catch { + return true + } } - private func compatibleVersionForStoreMetadata(_ metadata: [String: Any]) -> SubstrateStorageVersion? { - let compatibleVersion = SubstrateStorageVersion.allCases.first { - let model = createManagedObjectModel(forResource: $0.rawValue) - return model.isConfiguration(withName: $0.rawValue, compatibleWithStoreMetadata: metadata) + private func loadCompatibleStore(at url: URL) throws -> CompatibleStore { + let metadata: [String: Any] + do { + var inspectedMetadata: [String: Any]? + try performWithObjectiveCExceptionBoundary( + operation: .sourceMetadata + ) { + inspectedMetadata = try NSPersistentStoreCoordinator + .metadataForPersistentStore( + ofType: NSSQLiteStoreType, + at: url, + options: nil + ) + } + metadata = inspectedMetadata ?? [:] + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError.metadataUnreadable(storeURL, error) + } + + guard let compatibleStore = try compatibleStore(for: metadata) else { + throw SubstrateStorageMigrationError.unknownStoreVersion(storeURL) } - return compatibleVersion + return compatibleStore } - private func createManagedObjectModel(forResource resource: String) -> NSManagedObjectModel { - let bundle = Bundle.main + private func compatibleStore( + for metadata: [String: Any] + ) throws -> CompatibleStore? { + for version in SubstrateStorageVersion.allCases { + let model = try createManagedObjectModel(for: version) + + if model.isConfiguration( + withName: version.rawValue, + compatibleWithStoreMetadata: metadata + ) { + return CompatibleStore(version: version, model: model) + } + } + + return nil + } - let omoURL = bundle.url( - forResource: resource, + private func createManagedObjectModel( + for version: SubstrateStorageVersion + ) throws -> NSManagedObjectModel { + let omoURL = modelBundle.url( + forResource: version.rawValue, withExtension: "omo", subdirectory: modelDirectory ) - let momURL = bundle.url( - forResource: resource, + let momURL = modelBundle.url( + forResource: version.rawValue, withExtension: "mom", subdirectory: modelDirectory ) guard let modelURL = omoURL ?? momURL, - let model = NSManagedObjectModel(contentsOf: modelURL) else { - fatalError("Unable to load model in bundle for resource \(resource)") + let model = NSManagedObjectModel(contentsOf: modelURL) + else { + throw SubstrateStorageMigrationError.modelUnavailable(version) } return model @@ -152,48 +5916,311 @@ final class SubstrateStorageMigrator { private func createMapping( from sourceModel: NSManagedObjectModel, - nextModel: NSManagedObjectModel + sourceVersion: SubstrateStorageVersion, + nextModel: NSManagedObjectModel, + destinationVersion: SubstrateStorageVersion ) throws -> NSMappingModel { - let maybeCustomMapping = NSMappingModel( - from: [Bundle.main], + if let requiredMapping = requiredCustomMapping( + from: sourceVersion, + to: destinationVersion + ) { + return try loadRequiredCustomMapping( + requiredMapping, + sourceModel: sourceModel, + destinationModel: nextModel + ) + } + + let mapping = try NSMappingModel.inferredMappingModel( forSourceModel: sourceModel, destinationModel: nextModel ) - if let customMapping = maybeCustomMapping { + if sourceVersion == .version4, destinationVersion == .version5 { + try configureLegacyXcmTransforms(in: mapping) + } + + return mapping + } + + private func configureLegacyXcmTransforms( + in mapping: NSMappingModel + ) throws { + let entityNames = [ + "CDChainXcmConfig", + "CDXcmAvailableDestination" + ] + let policyClassName = NSStringFromClass( + SubstrateLegacyXcmMigrationPolicy.self + ) + var transformedEntityNames = Set() + + mapping.entityMappings = mapping.entityMappings.map { + inferredMapping in + guard + let entityName = inferredMapping.sourceEntityName, + entityNames.contains(entityName), + inferredMapping.destinationEntityName == entityName + else { + return inferredMapping + } + + transformedEntityNames.insert(entityName) + + // Merely assigning a policy to an inferred "transform" mapping + // does not make Core Data invoke that policy. Rebuild these two + // mappings as complete custom mappings, retaining every inferred + // property expression and both version hashes. + let customMapping = NSEntityMapping() + customMapping.name = "LegacyXcm_\(entityName)" + customMapping.mappingType = .customEntityMappingType + customMapping.sourceEntityName = inferredMapping.sourceEntityName + customMapping.destinationEntityName = + inferredMapping.destinationEntityName + customMapping.sourceEntityVersionHash = + inferredMapping.sourceEntityVersionHash + customMapping.destinationEntityVersionHash = + inferredMapping.destinationEntityVersionHash + customMapping.sourceExpression = NSExpression( + format: "FETCH(FUNCTION($manager, " + + "'fetchRequestForSourceEntityNamed:predicateString:', " + + "'\(entityName)', 'TRUEPREDICATE'), " + + "$manager.sourceContext, NO)" + ) + customMapping.attributeMappings = + inferredMapping.attributeMappings + customMapping.relationshipMappings = + inferredMapping.relationshipMappings + customMapping.entityMigrationPolicyClassName = policyClassName + return customMapping } - return try NSMappingModel.inferredMappingModel( + for entityName in entityNames + where !transformedEntityNames.contains(entityName) { + throw SubstrateLegacyXcmMappingError + .entityMappingUnavailable(entityName) + } + } + + private func requiredCustomMapping( + from sourceVersion: SubstrateStorageVersion, + to destinationVersion: SubstrateStorageVersion + ) -> RequiredCustomMapping? { + switch (sourceVersion, destinationVersion) { + case (.version1, .version2): + return RequiredCustomMapping( + resourceName: "SubstrateV2Mapping", + policyClassName: NSStringFromClass( + ChainSubstrateV2MigrationPolicy.self + ) + ) + case (.version3, .version4): + return RequiredCustomMapping( + resourceName: "SubstrateV3toV4", + policyClassName: NSStringFromClass( + ChainModelV4MigrationPolicy.self + ) + ) + default: + return nil + } + } + + private func loadRequiredCustomMapping( + _ requiredMapping: RequiredCustomMapping, + sourceModel: NSManagedObjectModel, + destinationModel: NSManagedObjectModel + ) throws -> NSMappingModel { + guard let mappingURL = modelBundle.url( + forResource: requiredMapping.resourceName, + withExtension: "cdm" + ) else { + throw SubstrateCustomMappingError.resourceUnavailable( + requiredMapping.resourceName + ) + } + + guard let mapping = NSMappingModel(contentsOf: mappingURL) else { + throw SubstrateCustomMappingError.resourceUnreadable( + requiredMapping.resourceName + ) + } + + let bundleMapping = NSMappingModel( + from: [modelBundle], forSourceModel: sourceModel, - destinationModel: nextModel + destinationModel: destinationModel ) + let entityHashesMatch = mapping.entityMappings.allSatisfy { entityMapping in + let sourceMatches = entityMapping.sourceEntityName.map { + sourceModel.entitiesByName[$0]?.versionHash == + entityMapping.sourceEntityVersionHash + } ?? true + let destinationMatches = entityMapping.destinationEntityName.map { + destinationModel.entitiesByName[$0]?.versionHash == + entityMapping.destinationEntityVersionHash + } ?? true + + return sourceMatches && destinationMatches + } + + guard bundleMapping != nil, entityHashesMatch else { + throw SubstrateCustomMappingError.incompatible( + requiredMapping.resourceName + ) + } + + let chainMapping = mapping.entityMappings.first { + $0.sourceEntityName == "CDChain" && + $0.destinationEntityName == "CDChain" + } + + guard + chainMapping?.entityMigrationPolicyClassName == + requiredMapping.policyClassName + else { + throw SubstrateCustomMappingError.policyUnavailable( + requiredMapping.resourceName, + requiredMapping.policyClassName + ) + } + + return mapping } - private func forceWALCheckpointingForStore(at storeURL: URL) { - let maybeMetadata = try? NSPersistentStoreCoordinator.metadataForPersistentStore( - ofType: NSSQLiteStoreType, - at: storeURL, - options: nil + private func forceWALCheckpointingForStore( + at storeURL: URL, + sourceModel: NSManagedObjectModel + ) throws { + do { + try performWithObjectiveCExceptionBoundary( + operation: .sourceCheckpoint + ) { + if let checkpointStoreHook = self.checkpointStoreHook { + try checkpointStoreHook(storeURL, sourceModel) + return + } + + let persistentStoreCoordinator = NSPersistentStoreCoordinator( + managedObjectModel: sourceModel + ) + let options = [NSSQLitePragmasOption: ["journal_mode": "DELETE"]] + let store = try persistentStoreCoordinator.addPersistentStore( + at: storeURL, + options: options + ) + try persistentStoreCoordinator.remove(store) + } + } catch let migrationError as SubstrateStorageMigrationError { + throw migrationError + } catch { + throw SubstrateStorageMigrationError.walCheckpointFailed(storeURL, error) + } + } + + private func recoverRebuildableCache( + after migrationError: SubstrateStorageMigrationError + ) throws -> URL? { + guard migrationError.allowsCacheRebuild else { + throw migrationError + } + + do { + return try crashConsistentCacheRecovery.quarantine() + } catch is SubstrateCacheRecoveryInterruption { + throw SubstrateCacheRecoveryInterruption + .simulatedProcessDeath + } catch { + throw SubstrateStorageMigrationError.cacheRecoveryFailed( + storeURL, + migrationError, + error + ) + } + } +} + +@objc(SubstrateLegacyXcmMigrationPolicy) +private final class SubstrateLegacyXcmMigrationPolicy: NSEntityMigrationPolicy { + private static let availableAssetEntityName = "CDXcmAvailableAsset" + + override func createRelationships( + forDestination destination: NSManagedObject, + in mapping: NSEntityMapping, + manager: NSMigrationManager + ) throws { + try super.createRelationships( + forDestination: destination, + in: mapping, + manager: manager ) - guard - let metadata = maybeMetadata, - let currentModel = NSManagedObjectModel.mergedModel( - from: [Bundle.main], - forStoreMetadata: metadata - ) else { + let relationshipName: String + switch mapping.sourceEntityName { + case "CDChainXcmConfig": + relationshipName = "availableAssets" + case "CDXcmAvailableDestination": + relationshipName = "assets" + default: return } - do { - let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: currentModel) + let entityName = mapping.sourceEntityName ?? "legacy XCM" + guard destination.entity.relationshipsByName[relationshipName] != nil else { + throw SubstrateLegacyXcmMappingError + .destinationRelationshipUnavailable( + entityName, + relationshipName + ) + } + + guard let source = manager.sourceInstances( + forEntityMappingName: mapping.name, + destinationInstances: [destination] + ).first else { + throw SubstrateLegacyXcmMappingError + .sourceAssociationUnavailable(entityName) + } - let options = [NSSQLitePragmasOption: ["journal_mode": "DELETE"]] - let store = try persistentStoreCoordinator.addPersistentStore(at: storeURL, options: options) - try persistentStoreCoordinator.remove(store) + let symbols: [String]? + do { + symbols = try SafeTransformableValueReader.read( + from: source, + key: relationshipName + ) } catch { - fatalError("Failed to force WAL checkpointing, error: \(error)") + // The disposable source is sanitized before migration. A residual + // decode failure must fail closed inside the outer ObjC boundary. + throw error + } + + guard let symbols else { + return + } + + guard + manager.destinationModel.entitiesByName[ + Self.availableAssetEntityName + ] != nil + else { + throw SubstrateLegacyXcmMappingError + .destinationEntityUnavailable( + Self.availableAssetEntityName + ) + } + + let destinationAssets = destination.mutableSetValue( + forKey: relationshipName + ) + + for symbol in symbols { + let availableAsset = NSEntityDescription.insertNewObject( + forEntityName: Self.availableAssetEntityName, + into: manager.destinationContext + ) + availableAsset.setValue(symbol, forKey: "symbol") + destinationAssets.add(availableAsset) } } } @@ -205,7 +6232,22 @@ extension SubstrateStorageMigrator: StorageMigrating { func migrate(_ completion: @escaping () -> Void) { DispatchQueue.global(qos: .utility).async { [weak self] in - self?.performMigration() + guard let self else { + return + } + + var completedSafely = false + + do { + try self.migrate() + completedSafely = true + } catch { + Logger.shared.error(error.localizedDescription) + } + + guard completedSafely else { + return + } DispatchQueue.main.async { completion() diff --git a/fearless/Common/Storage/Migration/UserStorage/MultiassetV2MigrationPolicy.swift b/fearless/Common/Storage/Migration/UserStorage/MultiassetV2MigrationPolicy.swift index d5fa4adeba..8fdb6bbfea 100644 --- a/fearless/Common/Storage/Migration/UserStorage/MultiassetV2MigrationPolicy.swift +++ b/fearless/Common/Storage/Migration/UserStorage/MultiassetV2MigrationPolicy.swift @@ -4,10 +4,14 @@ import IrohaCrypto class MultiassetV2MigrationPolicy: NSEntityMigrationPolicy { override func createDestinationInstances( - forSource _: NSManagedObject, - in _: NSEntityMapping, - manager _: NSMigrationManager + forSource source: NSManagedObject, + in mapping: NSEntityMapping, + manager: NSMigrationManager ) throws { - // TODO: tech debt + try super.createDestinationInstances( + forSource: source, + in: mapping, + manager: manager + ) } } diff --git a/fearless/Common/Storage/Migration/UserStorage/MultiassetV9MigrationPolicy.swift b/fearless/Common/Storage/Migration/UserStorage/MultiassetV9MigrationPolicy.swift index bac31a3458..b7ad898130 100644 --- a/fearless/Common/Storage/Migration/UserStorage/MultiassetV9MigrationPolicy.swift +++ b/fearless/Common/Storage/Migration/UserStorage/MultiassetV9MigrationPolicy.swift @@ -10,7 +10,11 @@ class MultiassetV9MigrationPolicy: NSEntityMigrationPolicy { ) throws { try super.createDestinationInstances(forSource: wallet, in: mapping, manager: manager) - guard let assetIdsEnabled = wallet.value(forKey: "assetIdsEnabled") as? [String] else { + let assetIdsEnabled: [String]? = try? SafeTransformableValueReader.read( + from: wallet, + key: "assetIdsEnabled" + ) + guard let assetIdsEnabled else { return } diff --git a/fearless/Common/Storage/Migration/UserStorage/SingleToMultiassetMigrationPolicy.swift b/fearless/Common/Storage/Migration/UserStorage/SingleToMultiassetMigrationPolicy.swift index 674f786791..150f0059b1 100644 --- a/fearless/Common/Storage/Migration/UserStorage/SingleToMultiassetMigrationPolicy.swift +++ b/fearless/Common/Storage/Migration/UserStorage/SingleToMultiassetMigrationPolicy.swift @@ -1,148 +1,334 @@ -import Foundation import CoreData -import SSFUtils -import SoraKeystore +import Foundation import IrohaCrypto +import SoraKeystore +import SSFUtils + +enum SingleToMultiassetMigrationError: LocalizedError { + case keystoreMigratorMissing + case settingsMigratorMissing + case sourceAddressMissing + case destinationAccountMissing + + var errorDescription: String? { + switch self { + case .keystoreMigratorMissing: + return "The v1-to-v2 migration is missing its keystore migrator" + case .settingsMigratorMissing: + return "The v1-to-v2 migration is missing its settings migrator" + case .sourceAddressMissing: + return "The v1-to-v2 migration encountered an account without an address" + case .destinationAccountMissing: + return "The v1-to-v2 migration failed to create a destination account" + } + } +} + +final class SingleToMultiassetMigrationPolicy: NSEntityMigrationPolicy { + private struct LegacySecrets { + let entropy: Data? + let seed: Data? + let secretKey: Data? + let derivationPath: Data? + + var signingRank: Int { + if secretKey != nil { + return 3 + } + + if entropy != nil { + return 2 + } + + if seed != nil { + return 1 + } + + return 0 + } + + var materialCount: Int { + [entropy, seed, secretKey, derivationPath] + .compactMap { $0 } + .count + } + } + + private struct SourceCandidate { + let address: AccountAddress + let name: Any? + let publicKey: Any? + let cryptoType: Any? + let secrets: LegacySecrets + + func isPreferred(over candidate: SourceCandidate) -> Bool { + if secrets.signingRank != candidate.secrets.signingRank { + return secrets.signingRank > candidate.secrets.signingRank + } + + if secrets.materialCount != candidate.secrets.materialCount { + return secrets.materialCount > candidate.secrets.materialCount + } + + return address < candidate.address + } + } + + private struct AccountMigration { + let metaAccount: NSManagedObject + let metaId: String + var preferredCandidate: SourceCandidate + } + + private var isSelected = false + private var order: Int32 = 0 + private var migratedAccounts = [Data: AccountMigration]() + + private lazy var addressFactory = SS58AddressFactory() + + override func createDestinationInstances( + forSource accountItem: NSManagedObject, + in mapping: NSEntityMapping, + manager: NSMigrationManager + ) throws { + guard + let keystoreMigrator = manager + .userInfo?[UserStorageMigratorKeys.keystoreMigrator] as? KeystoreMigrating + else { + throw SingleToMultiassetMigrationError.keystoreMigratorMissing + } + + try keystoreMigrator.registerLegacyAccountRow() + + guard let sourceAddress = accountItem.value(forKey: "identifier") as? AccountAddress else { + throw SingleToMultiassetMigrationError.sourceAddressMissing + } + + let accountId = try addressFactory.accountId(from: sourceAddress) + let secrets = try loadLegacySecrets( + for: sourceAddress, + keystoreMigrator: keystoreMigrator + ) + let candidate = SourceCandidate( + address: sourceAddress, + name: accountItem.value(forKey: "username"), + publicKey: accountItem.value(forKey: "publicKey"), + cryptoType: accountItem.value(forKey: "cryptoType"), + secrets: secrets + ) + + if var accountMigration = migratedAccounts[accountId] { + if candidate.isPreferred(over: accountMigration.preferredCandidate) { + applyMappedValues( + from: candidate, + to: accountMigration.metaAccount + ) + accountMigration.preferredCandidate = candidate + migratedAccounts[accountId] = accountMigration + } + + try migrateKeystore( + secrets, + sourceAddress: sourceAddress, + metaId: accountMigration.metaId, + metaAccount: accountMigration.metaAccount, + keystoreMigrator: keystoreMigrator + ) + return + } + + try super.createDestinationInstances( + forSource: accountItem, + in: mapping, + manager: manager + ) + + guard + let metaAccount = manager.destinationInstances( + forEntityMappingName: mapping.name, + sourceInstances: [accountItem] + ).first + else { + throw SingleToMultiassetMigrationError.destinationAccountMissing + } + + let metaId = UUID().uuidString + metaAccount.setValue(metaId, forKey: "metaId") + metaAccount.setValue(accountId.toHex(), forKey: "substrateAccountId") + metaAccount.setValue(!isSelected, forKey: "isSelected") + metaAccount.setValue(order, forKey: "order") + + migratedAccounts[accountId] = AccountMigration( + metaAccount: metaAccount, + metaId: metaId, + preferredCandidate: candidate + ) + + isSelected = true + order += 1 + + try migrateKeystore( + secrets, + sourceAddress: sourceAddress, + metaId: metaId, + metaAccount: metaAccount, + keystoreMigrator: keystoreMigrator + ) + } + + override func end( + _ mapping: NSEntityMapping, + manager: NSMigrationManager + ) throws { + guard + let settingsMigrator = manager + .userInfo?[UserStorageMigratorKeys.settingsMigrator] as? SettingsMigrating + else { + throw SingleToMultiassetMigrationError.settingsMigratorMissing + } + + settingsMigrator.remove(key: SettingsKey.selectedAccount.rawValue) + settingsMigrator.remove(key: SettingsKey.selectedConnection.rawValue) + + try super.end(mapping, manager: manager) + } + + private func loadLegacySecrets( + for sourceAddress: AccountAddress, + keystoreMigrator: KeystoreMigrating + ) throws -> LegacySecrets { + try LegacySecrets( + entropy: keystoreMigrator.fetchKey( + for: KeystoreTag.entropyTagForAddress(sourceAddress) + ), + seed: keystoreMigrator.fetchKey( + for: KeystoreTag.seedTagForAddress(sourceAddress) + ), + secretKey: keystoreMigrator.fetchKey( + for: KeystoreTag.secretKeyTagForAddress(sourceAddress) + ), + derivationPath: keystoreMigrator.fetchKey( + for: KeystoreTag.deriviationTagForAddress(sourceAddress) + ) + ) + } + + private func applyMappedValues( + from candidate: SourceCandidate, + to metaAccount: NSManagedObject + ) { + metaAccount.setValue(candidate.name, forKey: "name") + metaAccount.setValue(candidate.publicKey, forKey: "substratePublicKey") + metaAccount.setValue(candidate.cryptoType, forKey: "substrateCryptoType") + } + + private func migrateKeystore( + _ secrets: LegacySecrets, + sourceAddress: AccountAddress, + metaId: String, + metaAccount: NSManagedObject, + keystoreMigrator: KeystoreMigrating + ) throws { + let oldEntropyTag = KeystoreTag.entropyTagForAddress(sourceAddress) + if let entropy = secrets.entropy { + let newEntropyTag = KeystoreTagV2.entropyTagForMetaId(metaId) + + try stage( + key: entropy, + for: newEntropyTag, + keystoreMigrator: keystoreMigrator + ) + try scheduleDeletion( + oldEntropyTag, + keystoreMigrator: keystoreMigrator + ) + + let ethereumDerivationPath = DerivationPathConstants.defaultEthereum + let secrets = try EthereumAccountImportWrapper().importEntropy( + entropy, + derivationPath: ethereumDerivationPath + ) + + try stage( + key: secrets.seed, + for: KeystoreTagV2.ethereumSeedTagForMetaId(metaId), + keystoreMigrator: keystoreMigrator + ) + try stage( + key: secrets.keypair.privateKey().rawData(), + for: KeystoreTagV2.ethereumSecretKeyTagForMetaId(metaId), + keystoreMigrator: keystoreMigrator + ) + + if let derivationPathData = ethereumDerivationPath.data(using: .utf8) { + try stage( + key: derivationPathData, + for: KeystoreTagV2.ethereumDerivationTagForMetaId(metaId), + keystoreMigrator: keystoreMigrator + ) + } + + let rawPublicKey = secrets.keypair.publicKey().rawData() + metaAccount.setValue(rawPublicKey, forKey: "ethereumPublicKey") + + let ethereumAddress = try rawPublicKey.ethereumAddressFromPublicKey() + metaAccount.setValue(ethereumAddress.toHex(), forKey: "ethereumAddress") + } + + let oldSeedTag = KeystoreTag.seedTagForAddress(sourceAddress) + if let seed = secrets.seed { + try stage( + key: seed, + for: KeystoreTagV2.substrateSeedTagForMetaId(metaId), + keystoreMigrator: keystoreMigrator + ) + try scheduleDeletion( + oldSeedTag, + keystoreMigrator: keystoreMigrator + ) + } + + let oldSecretKeyTag = KeystoreTag.secretKeyTagForAddress(sourceAddress) + if let secretKey = secrets.secretKey { + try stage( + key: secretKey, + for: KeystoreTagV2.substrateSecretKeyTagForMetaId(metaId), + keystoreMigrator: keystoreMigrator + ) + try scheduleDeletion( + oldSecretKeyTag, + keystoreMigrator: keystoreMigrator + ) + } + + let oldDerivationTag = KeystoreTag.deriviationTagForAddress(sourceAddress) + if let derivationPath = secrets.derivationPath { + try stage( + key: derivationPath, + for: KeystoreTagV2.substrateDerivationTagForMetaId(metaId), + keystoreMigrator: keystoreMigrator + ) + try scheduleDeletion( + oldDerivationTag, + keystoreMigrator: keystoreMigrator + ) + } + } + + private func stage( + key: Data, + for identifier: String, + keystoreMigrator: KeystoreMigrating + ) throws { + keystoreMigrator.save(key: key, for: identifier) + try keystoreMigrator.throwIfResourceLimitExceeded() + } -// class SingleToMultiassetMigrationPolicy: NSEntityMigrationPolicy { -// var isSelected: Bool = false -// var order: Int32 = 0 -// private var privateKeysUsed: [Data] = [] -// -// private lazy var addressFactory = SS58AddressFactory() -// -// override func createDestinationInstances( -// forSource accountItem: NSManagedObject, -// in mapping: NSEntityMapping, -// manager: NSMigrationManager -// ) throws { -// guard let keystoreMigrator = manager -// .userInfo?[UserStorageMigratorKeys.keystoreMigrator] as? KeystoreMigrating else { -// fatalError("No keystore migrator found in context") -// } -// -// guard let sourceAddress = accountItem.value(forKey: "identifier") as? AccountAddress else { -// fatalError("Unexpected empty source address") -// } -// -// let accountId = try addressFactory.accountId(from: sourceAddress) -// -// if privateKeysUsed.contains(accountId) { -// return -// } -// -// try super.createDestinationInstances(forSource: accountItem, in: mapping, manager: manager) -// -// guard let metaAccount = manager.destinationInstances( -// forEntityMappingName: mapping.name, -// sourceInstances: [accountItem] -// ).first else { -// return -// } -// -// privateKeysUsed.append(accountId) -// -// let metaId = UUID().uuidString -// metaAccount.setValue(metaId, forKey: "metaId") -// -// metaAccount.setValue(accountId.toHex(), forKey: "substrateAccountId") -// -// if !isSelected { -// isSelected = true -// -// metaAccount.setValue(true, forKey: "isSelected") -// } else { -// metaAccount.setValue(false, forKey: "isSelected") -// } -// -// metaAccount.setValue(order, forKey: "order") -// order += 1 -// -// if let ethereumPublicKey = try migrateKeystore( -// for: sourceAddress, -// metaId: metaId, -// keystoreMigrator: keystoreMigrator -// ) { -// let rawPublicKey = ethereumPublicKey.rawData() -// metaAccount.setValue(rawPublicKey, forKey: "ethereumPublicKey") -// -// let ethereumAddress = try rawPublicKey.ethereumAddressFromPublicKey() -// metaAccount.setValue(ethereumAddress.toHex(), forKey: "ethereumAddress") -// } -// } -// -// override func end(_ mapping: NSEntityMapping, manager: NSMigrationManager) throws { -// guard let settingsMigrator = manager -// .userInfo?[UserStorageMigratorKeys.settingsMigrator] as? SettingsMigrating else { -// fatalError("No settings migrator found in context") -// } -// -// settingsMigrator.remove(key: SettingsKey.selectedAccount.rawValue) -// settingsMigrator.remove(key: SettingsKey.selectedConnection.rawValue) -// -// try super.end(mapping, manager: manager) -// } -// -// // MARK: Private -// -// private func migrateKeystore( -// for sourceAddress: AccountAddress, -// metaId: String, -// keystoreMigrator: KeystoreMigrating -// ) throws -> IRPublicKeyProtocol? { -// var publicKey: IRPublicKeyProtocol? -// -// let oldEntropyTag = KeystoreTag.entropyTagForAddress(sourceAddress) -// if let entropy = keystoreMigrator.fetchKey(for: oldEntropyTag) { -// let newEntropyTag = KeystoreTagV2.entropyTagForMetaId(metaId) -// -// keystoreMigrator.deleteKey(for: oldEntropyTag) -// keystoreMigrator.save(key: entropy, for: newEntropyTag) -// -// let ethereumDPString = DerivationPathConstants.defaultEthereum -// let secrets = try EthereumAccountImportWrapper().importEntropy( -// entropy, -// derivationPath: ethereumDPString -// ) -// -// let ethSeedTag = KeystoreTagV2.ethereumSeedTagForMetaId(metaId) -// keystoreMigrator.save(key: secrets.seed, for: ethSeedTag) -// -// let ethSecretKeyTag = KeystoreTagV2.ethereumSecretKeyTagForMetaId(metaId) -// keystoreMigrator.save(key: secrets.keypair.privateKey().rawData(), for: ethSecretKeyTag) -// -// if let ethereumDP = ethereumDPString.data(using: .utf8) { -// let ethDPTag = KeystoreTagV2.ethereumDerivationTagForMetaId(metaId) -// keystoreMigrator.save(key: ethereumDP, for: ethDPTag) -// } -// -// publicKey = secrets.keypair.publicKey() -// } -// -// let oldSeedTag = KeystoreTag.seedTagForAddress(sourceAddress) -// if let seed = keystoreMigrator.fetchKey(for: oldSeedTag) { -// let newSeedTag = KeystoreTagV2.substrateSeedTagForMetaId(metaId) -// -// keystoreMigrator.deleteKey(for: oldSeedTag) -// keystoreMigrator.save(key: seed, for: newSeedTag) -// } -// -// let oldSecretKeyTag = KeystoreTag.secretKeyTagForAddress(sourceAddress) -// if let secretKey = keystoreMigrator.fetchKey(for: oldSecretKeyTag) { -// let newSecretKeyTag = KeystoreTagV2.substrateSecretKeyTagForMetaId(metaId) -// -// keystoreMigrator.deleteKey(for: oldSecretKeyTag) -// keystoreMigrator.save(key: secretKey, for: newSecretKeyTag) -// } -// -// let oldDPTag = KeystoreTag.deriviationTagForAddress(sourceAddress) -// if let derivationPath = keystoreMigrator.fetchKey(for: oldDPTag) { -// keystoreMigrator.deleteKey(for: oldDPTag) -// -// let newDPTag = KeystoreTagV2.substrateDerivationTagForMetaId(metaId) -// keystoreMigrator.save(key: derivationPath, for: newDPTag) -// } -// -// return publicKey -// } -// } + private func scheduleDeletion( + _ identifier: String, + keystoreMigrator: KeystoreMigrating + ) throws { + keystoreMigrator.deleteKey(for: identifier) + try keystoreMigrator.throwIfResourceLimitExceeded() + } +} diff --git a/fearless/Common/Storage/Migration/UserStorage/StorageMigrator+Sync.swift b/fearless/Common/Storage/Migration/UserStorage/StorageMigrator+Sync.swift index 9b6c8bad09..5b90e07ccd 100644 --- a/fearless/Common/Storage/Migration/UserStorage/StorageMigrator+Sync.swift +++ b/fearless/Common/Storage/Migration/UserStorage/StorageMigrator+Sync.swift @@ -1,14 +1,13 @@ import Foundation -// TODO: Move this logic to app loading state +// RootInteractor runs this synchronous adapter on its single-worker migration +// queue. Successful return opens the startup barrier for storage preflight. extension UserStorageMigrator: Migrating { func migrate() throws { - guard requiresMigration() else { - return - } - - performMigration() + let migrationPerformed = try performMigration() - Logger.shared.info("Db migration completed") + if migrationPerformed { + Logger.shared.info("Db migration completed") + } } } diff --git a/fearless/Common/Storage/Migration/UserStorage/StorageMigrator.swift b/fearless/Common/Storage/Migration/UserStorage/StorageMigrator.swift index 905543fcdc..46cf9239f6 100644 --- a/fearless/Common/Storage/Migration/UserStorage/StorageMigrator.swift +++ b/fearless/Common/Storage/Migration/UserStorage/StorageMigrator.swift @@ -1,5 +1,7 @@ -import Foundation import CoreData +import CryptoKit +import Foundation +import IrohaCrypto import SoraKeystore protocol StorageMigrating { @@ -12,13 +14,257 @@ enum UserStorageMigratorKeys { static let settingsMigrator = "settingsMigrator" } +enum UserStorageMigrationError: LocalizedError { + case metadataUnreadable(URL, Error) + case unknownStoreVersion(URL) + case modelUnavailable(UserStorageVersion) + case migrationPathUnavailable(UserStorageVersion, UserStorageVersion) + case objectiveCException + case privateSourceRepairFailed + case stagedStoreValidationFailed + + var errorDescription: String? { + switch self { + case .metadataUnreadable: + return "Unable to read user store metadata safely" + case .unknownStoreVersion: + return "Unsupported user store version" + case let .modelUnavailable(version): + return "User store model is unavailable for \(version.rawValue)" + case let .migrationPathUnavailable(source, destination): + return "No user store migration path from \(source.rawValue) to \(destination.rawValue)" + case .objectiveCException: + return "A stored value could not be processed safely" + case .privateSourceRepairFailed: + return "The private user-storage copy could not be repaired safely" + case .stagedStoreValidationFailed: + return "The migrated user store did not pass integrity validation" + } + } +} + +struct UserStorageIntegrityValidationLimits: Equatable { + static let production = UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 250_000, + maximumRowsAcrossStore: 1_000_000, + fetchBatchSize: 256, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10000, + maximumTransformableElements: 4096, + maximumTransformableArchiveBytes: 1 * 1024 * 1024, + maximumRelationshipDestinationsAcrossStore: 4_000_000 + ) + + let maximumRowsPerEntity: Int + let maximumRowsAcrossStore: Int + let fetchBatchSize: Int + let maximumCanonicalRowBytes: Int + let maximumAttributeBytes: Int + let maximumRelationshipDestinations: Int + let maximumTransformableElements: Int + let maximumTransformableArchiveBytes: Int + let maximumRelationshipDestinationsAcrossStore: Int + + init( + maximumRowsPerEntity: Int, + maximumRowsAcrossStore: Int, + fetchBatchSize: Int, + maximumCanonicalRowBytes: Int, + maximumAttributeBytes: Int, + maximumRelationshipDestinations: Int, + maximumTransformableElements: Int, + maximumTransformableArchiveBytes: Int = + 1 * 1024 * 1024, + maximumRelationshipDestinationsAcrossStore: Int = + 4_000_000 + ) { + self.maximumRowsPerEntity = max(1, maximumRowsPerEntity) + self.maximumRowsAcrossStore = max(1, maximumRowsAcrossStore) + self.fetchBatchSize = max(1, fetchBatchSize) + self.maximumCanonicalRowBytes = max(1, maximumCanonicalRowBytes) + self.maximumAttributeBytes = max(1, maximumAttributeBytes) + self.maximumRelationshipDestinations = max( + 1, + maximumRelationshipDestinations + ) + self.maximumTransformableElements = max( + 1, + maximumTransformableElements + ) + self.maximumTransformableArchiveBytes = max( + 1, + maximumTransformableArchiveBytes + ) + self.maximumRelationshipDestinationsAcrossStore = max( + 1, + maximumRelationshipDestinationsAcrossStore + ) + } +} + final class UserStorageMigrator { + private struct IntegrityField: Equatable { + let name: String + let value: String + + var sortKey: String { + "\(Data(name.utf8).base64EncodedString()):\(value)" + } + } + + private struct IntegrityIdentity: Equatable { + let entityName: String + let fields: [IntegrityField] + + var sortKey: String { + [ + Data(entityName.utf8).base64EncodedString(), + fields.map(\.sortKey).joined(separator: "|") + ].joined(separator: ":") + } + } + + private struct IntegrityRelationship: Equatable { + let name: String + let destinations: [IntegrityIdentity] + + var sortKey: String { + [ + Data(name.utf8).base64EncodedString(), + destinations.map(\.sortKey).joined(separator: ",") + ].joined(separator: ":") + } + } + + private struct IntegrityRow: Equatable { + let identity: IntegrityIdentity + let relationships: [IntegrityRelationship] + + var sortKey: String { + [ + identity.sortKey, + relationships.map(\.sortKey).joined(separator: "|") + ].joined(separator: "#") + } + } + + private struct IntegrityDigest: Equatable { + let rowCount: Int + let xor: Data + let sum: Data + } + + private struct IntegrityDigestAccumulator { + private(set) var rowCount = 0 + private var xor = [UInt8]( + repeating: 0, + count: SHA256.byteCount + ) + private var sum = [UInt8]( + repeating: 0, + count: SHA256.byteCount + ) + + mutating func append(canonicalRow: String) { + let digest = Array( + SHA256.hash(data: Data(canonicalRow.utf8)) + ) + var carry = 0 + + for index in digest.indices.reversed() { + xor[index] ^= digest[index] + + let total = + Int(sum[index]) + + Int(digest[index]) + + carry + sum[index] = UInt8(truncatingIfNeeded: total) + carry = total >> 8 + } + + rowCount += 1 + } + + var digest: IntegrityDigest { + IntegrityDigest( + rowCount: rowCount, + xor: Data(xor), + sum: Data(sum) + ) + } + } + + private struct StagedStoreIntegritySnapshot: Equatable { + let rowsByEntity: [String: IntegrityDigest] + } + + private struct StagedStoreIntegrityAllowlist { + static let none = StagedStoreIntegrityAllowlist( + entityNames: [], + attributeNamesByEntity: [:], + relationshipNamesByEntity: [:] + ) + + let entityNames: Set + let attributeNamesByEntity: [String: Set] + let relationshipNamesByEntity: [String: Set] + } + + private enum StagedStoreSemanticSnapshot: Equatable { + case legacyAccountIds([String]) + case assetVisibility( + walletRows: IntegrityDigest, + visibilityRowCount: Int + ) + case networkManagementFilters(IntegrityDigest) + } + + private static let resilientMetaAccountTransformableKeys = [ + "assetFilterOptions", + "assetIdsEnabled", + "assetKeysOrder", + "favouriteChainIds", + "unusedChainIds" + ] + let storeURL: URL let modelDirectory: String let keystore: KeystoreProtocol let settings: SettingsManagerProtocol let fileManager: FileManager let targetVersion: UserStorageVersion + let modelBundle: Bundle + private let metadataReader: (URL) throws -> [String: Any] + private let crashConsistentStoreReplacer: CrashConsistentStoreReplacer + private let keystoreMigratorFactory: ( + UserStorageVersion, + UserStorageVersion, + KeystoreProtocol + ) -> KeystoreMigrating + private let settingsMigratorFactory: ( + UserStorageVersion, + UserStorageVersion, + SettingsManagerProtocol + ) -> SettingsMigrating + private let stagedStoreWillValidate: ( + URL, + UserStorageVersion + ) throws -> Void + private let privateSourceObjectIDPageDidFetch: ( + Int, + Int + ) -> Void + private let integrityObjectPageDidFetch: ( + Int, + Int + ) -> Void + private let privateSourceCopyLimits: + SQLiteStoreFamilyCopyLimits + private let privateSourceAvailableCapacityProvider: + ((URL) throws -> UInt64)? + private let integrityValidationLimits: + UserStorageIntegrityValidationLimits init( targetVersion: UserStorageVersion, @@ -26,7 +272,65 @@ final class UserStorageMigrator { modelDirectory: String, keystore: KeystoreProtocol, settings: SettingsManagerProtocol, - fileManager: FileManager + fileManager: FileManager, + modelBundle: Bundle = .main, + integrityValidationLimits: + UserStorageIntegrityValidationLimits = .production, + privateSourceCopyLimits: + SQLiteStoreFamilyCopyLimits = + .userStorageProduction, + privateSourceAvailableCapacityProvider: + ((URL) throws -> UInt64)? = nil, + metadataReader: @escaping (URL) throws -> [String: Any] = { url in + try NSPersistentStoreCoordinator.metadataForPersistentStore( + ofType: NSSQLiteStoreType, + at: url, + options: nil + ) + }, + storeReplacer: @escaping (URL, URL) throws -> Void = { targetURL, sourceURL in + try NSPersistentStoreCoordinator.replaceStore( + at: targetURL, + withStoreAt: sourceURL + ) + }, + keystoreMigratorFactory: @escaping ( + UserStorageVersion, + UserStorageVersion, + KeystoreProtocol + ) -> KeystoreMigrating = { source, destination, keystore in + KeystoreMigrator( + sourceVersion: source, + destinationVersion: destination, + keystore: keystore + ) + }, + settingsMigratorFactory: @escaping ( + UserStorageVersion, + UserStorageVersion, + SettingsManagerProtocol + ) -> SettingsMigrating = { source, destination, settings in + SettingsMigrator( + sourceVersion: source, + destinationVersion: destination, + settings: settings + ) + }, + stagedStoreWillValidate: @escaping ( + URL, + UserStorageVersion + ) throws -> Void = { _, _ in }, + storeReplacementBoundaryHook: @escaping ( + CrashConsistentStoreReplacementBoundary + ) throws -> Void = { _ in }, + privateSourceObjectIDPageDidFetch: @escaping ( + Int, + Int + ) -> Void = { _, _ in }, + integrityObjectPageDidFetch: @escaping ( + Int, + Int + ) -> Void = { _, _ in } ) { self.targetVersion = targetVersion self.storeURL = storeURL @@ -34,69 +338,146 @@ final class UserStorageMigrator { self.keystore = keystore self.settings = settings self.fileManager = fileManager + self.modelBundle = modelBundle + self.integrityValidationLimits = integrityValidationLimits + self.privateSourceCopyLimits = + privateSourceCopyLimits + self.privateSourceAvailableCapacityProvider = + privateSourceAvailableCapacityProvider + self.metadataReader = metadataReader + crashConsistentStoreReplacer = CrashConsistentStoreReplacer( + storeURL: storeURL, + fileManager: fileManager, + storeReplacer: storeReplacer, + boundaryHook: storeReplacementBoundaryHook, + maximumStoreFamilyByteCount: + privateSourceCopyLimits.maximumFamilyByteCount, + minimumFreeStorageReserveByteCount: + privateSourceCopyLimits + .minimumFreeStorageReserveByteCount, + availableCapacityProvider: + privateSourceAvailableCapacityProvider + ) + self.keystoreMigratorFactory = keystoreMigratorFactory + self.settingsMigratorFactory = settingsMigratorFactory + self.stagedStoreWillValidate = stagedStoreWillValidate + self.privateSourceObjectIDPageDidFetch = + privateSourceObjectIDPageDidFetch + self.integrityObjectPageDidFetch = + integrityObjectPageDidFetch } - func performMigration() { - forceWALCheckpointingForStore(at: storeURL) - - let maybeMetadata = try? NSPersistentStoreCoordinator.metadataForPersistentStore( - ofType: NSSQLiteStoreType, - at: storeURL, - options: nil - ) + @discardableResult + func performMigration() throws -> Bool { + try reconcilePendingStoreReplacement() - guard - let metadata = maybeMetadata, - let sourceVersion = compatibleVersionForStoreMetadata(metadata) else { - fatalError("Unknown store version at URL \(storeURL)") + guard try crashConsistentStoreReplacer.liveStoreExistsSafely() else { + return false } - do { - let migrationDirName = UUID().uuidString - let tmpMigrationDirURL = URL( - fileURLWithPath: NSTemporaryDirectory(), - isDirectory: true - ).appendingPathComponent(migrationDirName) + return try withPrivateSourceCopy { privateSourceURL, tmpMigrationDirURL in + let sourceVersion = try readSourceVersion( + at: privateSourceURL + ) + + try KeystoreMigrator.recoverPendingCleanup( + keystore: keystore, + currentVersion: sourceVersion + ) + try SettingsMigrator.recoverPendingCleanup( + settings: settings, + currentVersion: sourceVersion + ) + + let privateSourceWasRepaired = + try sanitizePrivateSourceCopy( + at: privateSourceURL, + version: sourceVersion + ) + + guard sourceVersion != targetVersion else { + guard privateSourceWasRepaired else { + return false + } - try fileManager.createDirectory(at: tmpMigrationDirURL, withIntermediateDirectories: true) + try replaceCurrentVersionStore( + with: privateSourceURL, + version: sourceVersion + ) + return true + } try performMigration( from: sourceVersion, to: targetVersion, - storeURL: storeURL, + sourceStoreURL: privateSourceURL, + destinationStoreURL: storeURL, tmpMigrationDirURL: tmpMigrationDirURL ) - try fileManager.removeItem(at: tmpMigrationDirURL) - } catch { - fatalError("Migration failed with error \(error)") + return true } } private func performMigration( from sourceVersion: UserStorageVersion, to destinationVersion: UserStorageVersion, - storeURL: URL, + sourceStoreURL: URL, + destinationStoreURL: URL, tmpMigrationDirURL: URL ) throws { var currentVersion = sourceVersion - var currentURL = storeURL + var currentURL = sourceStoreURL - let keystoreMigrator = KeystoreMigrator( - sourceVersion: sourceVersion, - destinationVersion: destinationVersion, - keystore: keystore + let keystoreMigrator = keystoreMigratorFactory( + sourceVersion, + destinationVersion, + keystore ) - let settingsMigrator = SettingsMigrator( - sourceVersion: sourceVersion, - destinationVersion: destinationVersion, - settings: settings + let settingsMigrator = settingsMigratorFactory( + sourceVersion, + destinationVersion, + settings ) - while currentVersion != destinationVersion, let nextVersion = currentVersion.nextVersion() { - let currentModel = createManagedObjectModel(forResource: currentVersion.rawValue) - let nextModel = createManagedObjectModel(forResource: nextVersion.rawValue) + while currentVersion != destinationVersion { + guard let nextVersion = currentVersion.nextVersion() else { + throw UserStorageMigrationError.migrationPathUnavailable( + currentVersion, + destinationVersion + ) + } + + let currentModel = try createManagedObjectModel(for: currentVersion) + let nextModel = try createManagedObjectModel(for: nextVersion) + let integrityAllowlist = try commonIntegrityAllowlist( + from: currentVersion, + to: nextVersion + ) + let expectedHopIntegrity = try stagedStoreIntegritySnapshot( + at: currentURL, + model: currentModel, + comparedWith: nextModel, + allowlist: integrityAllowlist + ) + let expectedSemanticIntegrity = + try stagedStoreSemanticSnapshot( + at: currentURL, + model: currentModel, + storeVersion: currentVersion, + migratingFrom: currentVersion, + to: nextVersion + ) + let expectedMetaAccountCount: Int? + if shouldValidateMetaAccountCount(from: currentVersion) { + expectedMetaAccountCount = try stagedMetaAccountCount( + at: currentURL, + model: currentModel + ) + } else { + expectedMetaAccountCount = nil + } try keystoreMigrator.switchVersion() try settingsMigrator.switchVersion() @@ -112,138 +493,2317 @@ final class UserStorageMigrator { let nextStepURL = tmpMigrationDirURL.appendingPathComponent(UUID().uuidString) - try manager.migrateStore( - from: currentURL, - sourceType: NSSQLiteStoreType, - options: nil, - with: mapping, - toDestinationURL: nextStepURL, - destinationType: NSSQLiteStoreType, - destinationOptions: nil - ) + try performWithObjectiveCExceptionBoundary( + phase: "staged migration" + ) { + try manager.migrateStore( + from: currentURL, + sourceType: NSSQLiteStoreType, + options: nil, + with: mapping, + toDestinationURL: nextStepURL, + destinationType: NSSQLiteStoreType, + destinationOptions: nil + ) + } - if currentURL != storeURL { - try NSPersistentStoreCoordinator.destroyStore(at: currentURL) + try stagedStoreWillValidate(nextStepURL, nextVersion) + + if let expectedMetaAccountCount { + let actualMetaAccountCount = try stagedMetaAccountCount( + at: nextStepURL, + model: nextModel + ) + + guard + actualMetaAccountCount == expectedMetaAccountCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } + + let actualSemanticIntegrity = + try stagedStoreSemanticSnapshot( + at: nextStepURL, + model: nextModel, + storeVersion: nextVersion, + migratingFrom: currentVersion, + to: nextVersion + ) + guard + actualSemanticIntegrity == expectedSemanticIntegrity + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let actualHopIntegrity = + try stagedStoreIntegritySnapshot( + at: nextStepURL, + model: nextModel, + comparedWith: currentModel, + allowlist: integrityAllowlist + ) + + guard actualHopIntegrity == expectedHopIntegrity else { + throw UserStorageMigrationError + .stagedStoreValidationFailed } + try NSPersistentStoreCoordinator.destroyStore(at: currentURL) + currentVersion = nextVersion currentURL = nextStepURL } - try keystoreMigrator.finalize() - try settingsMigrator.finalize() + try keystoreMigrator.prepare() + try settingsMigrator.prepare() - try NSPersistentStoreCoordinator.replaceStore(at: storeURL, withStoreAt: currentURL) + let destinationModel = try createManagedObjectModel( + for: destinationVersion + ) + let expectedCommittedIntegrity = try stagedStoreIntegritySnapshot( + at: currentURL, + model: destinationModel, + comparedWith: destinationModel + ) + try crashConsistentStoreReplacer.replaceStore( + with: currentURL + ) { liveStoreURL in + let actualCommittedIntegrity = + try self.stagedStoreIntegritySnapshot( + at: liveStoreURL, + model: destinationModel, + comparedWith: destinationModel + ) - if currentURL != storeURL { - try NSPersistentStoreCoordinator.destroyStore(at: currentURL) + guard + actualCommittedIntegrity == + expectedCommittedIntegrity + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } } - } - private func checkIfMigrationNeeded(to version: UserStorageVersion) -> Bool { - let storageExists = fileManager.fileExists(atPath: storeURL.path) + do { + try keystoreMigrator.finalize() + } catch { + Logger.shared.error( + "Unable to finish user-storage key cleanup" + ) + throw error + } - guard storageExists else { - return false + do { + try settingsMigrator.finalize() + } catch { + Logger.shared.error( + "Unable to finish user-storage settings cleanup" + ) + throw error } - guard let metadata = NSPersistentStoreCoordinator.metadata(at: storeURL) else { - return false + if currentURL != destinationStoreURL { + do { + try NSPersistentStoreCoordinator.destroyStore(at: currentURL) + } catch { + Logger.shared.error( + "Unable to remove temporary user-storage migration store" + ) + } + } + } + + private func replaceCurrentVersionStore( + with sanitizedStoreURL: URL, + version: UserStorageVersion + ) throws { + let model = try createManagedObjectModel(for: version) + let expectedIntegrity = try stagedStoreIntegritySnapshot( + at: sanitizedStoreURL, + model: model, + comparedWith: model + ) + try stagedStoreWillValidate( + sanitizedStoreURL, + version + ) + let validatedIntegrity = try stagedStoreIntegritySnapshot( + at: sanitizedStoreURL, + model: model, + comparedWith: model + ) + guard validatedIntegrity == expectedIntegrity else { + throw UserStorageMigrationError + .stagedStoreValidationFailed } - let compatibleVersion = compatibleVersionForStoreMetadata(metadata) + try crashConsistentStoreReplacer.replaceStore( + with: sanitizedStoreURL + ) { liveStoreURL in + let actualIntegrity = + try self.stagedStoreIntegritySnapshot( + at: liveStoreURL, + model: model, + comparedWith: model + ) - return compatibleVersion != version + guard actualIntegrity == expectedIntegrity else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } } - private func compatibleVersionForStoreMetadata(_ metadata: [String: Any]) -> UserStorageVersion? { - let compatibleVersion = UserStorageVersion.allCases.first { - let model = createManagedObjectModel(forResource: $0.rawValue) - return model.isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) + /// Migration is always performed from a disposable source copy. Unsafe + /// preference archives are repaired only in that copy; the user's original + /// store remains untouched until a validated atomic replacement. + private func sanitizePrivateSourceCopy( + at privateSourceURL: URL, + version: UserStorageVersion + ) throws -> Bool { + let model = try createManagedObjectModel(for: version) + let rawRepairedValueCount: Int + + do { + rawRepairedValueCount = + try SQLiteTransformableArchivePreflight + .repairOversizedArchives( + at: privateSourceURL, + columns: preferenceTransformableArchiveColumns( + in: model + ), + maximumArchiveByteCount: + integrityValidationLimits + .maximumTransformableArchiveBytes + ) + } catch { + throw UserStorageMigrationError + .privateSourceRepairFailed } + var didRepair = rawRepairedValueCount > 0 - return compatibleVersion - } + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + var persistentStore: NSPersistentStore? + + try performWithObjectiveCExceptionBoundary( + phase: "private source open" + ) { + persistentStore = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: privateSourceURL, + options: [ + NSSQLitePragmasOption: ["journal_mode": "DELETE"], + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + } + + defer { + if let persistentStore { + try? coordinator.remove(persistentStore) + } + } - private func createManagedObjectModel(forResource resource: String) -> NSManagedObjectModel { - let bundle = Bundle.main - let omoURL = bundle.url( - forResource: resource, - withExtension: "omo", - subdirectory: modelDirectory + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType ) + context.persistentStoreCoordinator = coordinator + + if version == .version1 { + try enforceVersion1PrivateSourceRowLimits( + model: model, + context: context + ) + return didRepair + } + + guard model.entitiesByName["CDMetaAccount"] != nil else { + return didRepair + } + + var contextError: Error? + context.performAndWait { + do { + try self.performWithObjectiveCExceptionBoundary( + phase: "private source preference repair" + ) { + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + request.resultType = .managedObjectIDResultType + request.includesPendingChanges = false + request.includesSubentities = false + request.affectedStores = + persistentStore.map { [$0] } + + // Count and enforce the cap before fetching any IDs. The + // immutable exact-once cohort below can therefore never + // grow beyond a deterministic production bound. + let objectCount = try context.count(for: request) + guard + objectCount != NSNotFound, + objectCount <= + self.integrityValidationLimits + .maximumRowsPerEntity, + objectCount <= + self.integrityValidationLimits + .maximumRowsAcrossStore, + objectCount < Int.max + else { + throw UserStorageMigrationError + .privateSourceRepairFailed + } - let momURL = bundle.url( - forResource: resource, - withExtension: "mom", - subdirectory: modelDirectory + request.fetchLimit = objectCount + 1 + request.fetchBatchSize = min( + self.integrityValidationLimits.fetchBatchSize, + objectCount + 1 + ) + let cohortResults = try context.fetch(request) + let cohortObjectIDs = cohortResults.compactMap { + $0 as? NSManagedObjectID + } + guard + cohortObjectIDs.count == + cohortResults.count, + cohortObjectIDs.count == objectCount, + Set(cohortObjectIDs).count == objectCount + else { + throw UserStorageMigrationError + .privateSourceRepairFailed + } + + var pageStart = 0 + while pageStart < cohortObjectIDs.count { + let remainingObjectCount = + cohortObjectIDs.count - pageStart + let pageLength = min( + self.integrityValidationLimits + .fetchBatchSize, + remainingObjectCount + ) + let pageEnd = pageStart + pageLength + let pageObjectIDs = Array( + cohortObjectIDs[pageStart ..< pageEnd] + ) + let pageRequest = + NSFetchRequest( + entityName: "CDMetaAccount" + ) + pageRequest.resultType = + .managedObjectIDResultType + pageRequest.includesPendingChanges = false + pageRequest.includesSubentities = false + pageRequest.predicate = NSPredicate( + format: "SELF IN %@", + pageObjectIDs + ) + pageRequest.affectedStores = + persistentStore.map { [$0] } + pageRequest.fetchLimit = + pageObjectIDs.count + pageRequest.fetchBatchSize = + pageObjectIDs.count + + let fetchedResults = + try context.fetch(pageRequest) + let fetchedObjectIDs = + fetchedResults.compactMap { + $0 as? NSManagedObjectID + } + self.privateSourceObjectIDPageDidFetch( + fetchedObjectIDs.count, + pageObjectIDs.count + ) + guard + fetchedObjectIDs.count == + fetchedResults.count, + fetchedObjectIDs.count == + pageObjectIDs.count, + Set(fetchedObjectIDs) == + Set(pageObjectIDs) + else { + throw UserStorageMigrationError + .privateSourceRepairFailed + } + + for objectID in pageObjectIDs { + if try self.sanitizePreferenceTransformables( + objectID: objectID, + model: model, + context: context, + persistentStore: + persistentStore + ) { + didRepair = true + } + } + pageStart = pageEnd + } + + request.fetchLimit = 0 + request.fetchBatchSize = 0 + guard + pageStart == objectCount, + try context.count(for: request) == objectCount + else { + throw UserStorageMigrationError + .privateSourceRepairFailed + } + } + } catch { + contextError = error + } + } + + if let contextError { + throw contextError + } + + return didRepair + } + + private func enforceVersion1PrivateSourceRowLimits( + model: NSManagedObjectModel, + context: NSManagedObjectContext + ) throws { + guard model.entitiesByName["CDAccountItem"] != nil else { + throw UserStorageMigrationError + .privateSourceRepairFailed + } + let maximumLegacyAccountRows = min( + min( + integrityValidationLimits.maximumRowsPerEntity, + integrityValidationLimits.maximumRowsAcrossStore + ), + KeystoreMigrationResourceLimits.production + .maximumLegacyAccountRows ) + var contextError: Error? + context.performAndWait { + do { + try self.performWithObjectiveCExceptionBoundary( + phase: "private version-1 source row inspection" + ) { + let request = + NSFetchRequest( + entityName: "CDAccountItem" + ) + request.includesPendingChanges = false + request.includesSubentities = false + let rowCount = try context.count(for: request) + + guard + rowCount != NSNotFound, + rowCount <= maximumLegacyAccountRows + else { + throw UserStorageMigrationError + .privateSourceRepairFailed + } + } + } catch { + contextError = error + } + } + + if let contextError { + throw contextError + } + } + + private func preferenceTransformableArchiveColumns( + in model: NSManagedObjectModel + ) -> [SQLiteTransformableArchiveColumn] { guard - let modelURL = omoURL ?? momURL, - let model = NSManagedObjectModel(contentsOf: modelURL) else { - fatalError("Unable to load model in bundle for resource \(resource)") + let entity = model.entitiesByName["CDMetaAccount"] + else { + return [] } - return model + return Self.resilientMetaAccountTransformableKeys + .compactMap { + key in + + guard + let attribute = entity.attributesByName[key], + attribute.attributeType == + .transformableAttributeType + else { + return nil + } + + return SQLiteTransformableArchiveColumn( + entityName: "CDMetaAccount", + attributeName: key, + isOptional: attribute.isOptional, + valueTransformerName: + attribute.valueTransformerName + ) + } + .sorted { + $0.attributeName < $1.attributeName + } } - private func createMapping( - from sourceModel: NSManagedObjectModel, - nextModel: NSManagedObjectModel - ) throws -> NSMappingModel { - let maybeCustomMapping = NSMappingModel( - from: [Bundle.main], - forSourceModel: sourceModel, - destinationModel: nextModel + func copyStoreFamily( + from sourceURL: URL, + to destinationURL: URL + ) throws { + try SQLiteStoreFamilyCopier.copy( + from: sourceURL, + to: destinationURL, + includingSharedMemory: false, + fileManager: fileManager, + limits: privateSourceCopyLimits, + availableCapacityProvider: + privateSourceAvailableCapacityProvider ) + } - if let customMapping = maybeCustomMapping { - return customMapping + private func withPrivateSourceCopy( + _ operation: ( + URL, + URL + ) throws -> Result + ) throws -> Result { + let tmpMigrationDirURL = URL( + fileURLWithPath: NSTemporaryDirectory(), + isDirectory: true + ).appendingPathComponent(UUID().uuidString) + + try fileManager.createDirectory( + at: tmpMigrationDirURL, + withIntermediateDirectories: true + ) + defer { + try? fileManager.removeItem(at: tmpMigrationDirURL) } - return try NSMappingModel.inferredMappingModel( - forSourceModel: sourceModel, - destinationModel: nextModel + let privateSourceURL = tmpMigrationDirURL + .appendingPathComponent("SanitizedSource.sqlite") + try copyStoreFamily( + from: storeURL, + to: privateSourceURL ) - } - private func forceWALCheckpointingForStore(at storeURL: URL) { - let maybeMetadata = try? NSPersistentStoreCoordinator.metadataForPersistentStore( - ofType: NSSQLiteStoreType, - at: storeURL, - options: nil + return try operation( + privateSourceURL, + tmpMigrationDirURL ) + } - guard - let metadata = maybeMetadata, - let currentModel = NSManagedObjectModel.mergedModel( - from: [Bundle.main], - forStoreMetadata: metadata - ) else { - return - } + private func readSourceVersion( + at privateSourceURL: URL + ) throws -> UserStorageVersion { + var metadata: [String: Any]? do { - let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: currentModel) + try performWithObjectiveCExceptionBoundary( + phase: "private source metadata read" + ) { + metadata = try self.metadataReader(privateSourceURL) + } + } catch let error as UserStorageMigrationError { + guard case .objectiveCException = error else { + throw UserStorageMigrationError.metadataUnreadable( + storeURL, + error + ) + } - let options = [NSSQLitePragmasOption: ["journal_mode": "DELETE"]] - let store = try persistentStoreCoordinator.addPersistentStore(at: storeURL, options: options) - try persistentStoreCoordinator.remove(store) + throw error } catch { - fatalError("Failed to force WAL checkpointing, error: \(error)") + throw UserStorageMigrationError.metadataUnreadable( + storeURL, + error + ) + } + + guard + let metadata, + let sourceVersion = + compatibleVersionForStoreMetadata(metadata) + else { + throw UserStorageMigrationError.unknownStoreVersion( + storeURL + ) } + + return sourceVersion } -} -extension UserStorageMigrator: StorageMigrating { - func requiresMigration() -> Bool { - checkIfMigrationNeeded(to: targetVersion) + private func reconcilePendingStoreReplacement() throws { + try crashConsistentStoreReplacer.reconcile { + liveStoreURL in + + guard + try self.readSourceVersion(at: liveStoreURL) == + self.targetVersion + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } } - func migrate(_ completion: @escaping () -> Void) { - DispatchQueue.global(qos: .utility).async { [weak self] in - self?.performMigration() + private func commonIntegrityAllowlist( + from sourceVersion: UserStorageVersion, + to destinationVersion: UserStorageVersion + ) throws -> StagedStoreIntegrityAllowlist { + switch (sourceVersion, destinationVersion) { + case (.version1, .version2), + (.version2, .version3), + (.version3, .version4), + (.version4, .version5), + (.version5, .version6), + (.version6, .version7), + (.version7, .version8), + (.version8, .version9), + (.version9, .version10), + (.version10, .version11), + (.version11, .version12), + (.version12, .version14), + (.version13, .version14): + // Intentional renames, additions, and removals are outside the + // common-schema contract. No same-named field is allowed to + // change value on any supported hop. + return .none + default: + throw UserStorageMigrationError.migrationPathUnavailable( + sourceVersion, + destinationVersion + ) + } + } + + private func stagedStoreSemanticSnapshot( + at storeURL: URL, + model: NSManagedObjectModel, + storeVersion: UserStorageVersion, + migratingFrom sourceVersion: UserStorageVersion, + to destinationVersion: UserStorageVersion + ) throws -> StagedStoreSemanticSnapshot? { + switch (sourceVersion, destinationVersion) { + case (.version1, .version2): + guard + storeVersion == sourceVersion || + storeVersion == destinationVersion + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + return try readStagedStoreSemanticSnapshot( + at: storeURL, + model: model, + phase: "legacy account semantic validation" + ) { context in + if storeVersion == sourceVersion { + return try self.legacyAccountSourceSnapshot( + context: context + ) + } + + return try self.legacyAccountDestinationSnapshot( + context: context + ) + } + case (.version9, .version10): + guard + storeVersion == sourceVersion || + storeVersion == destinationVersion + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + return try readStagedStoreSemanticSnapshot( + at: storeURL, + model: model, + phase: "asset visibility semantic validation" + ) { context in + if storeVersion == sourceVersion { + return try self.assetVisibilitySourceSnapshot( + context: context + ) + } + + return try self.assetVisibilityDestinationSnapshot( + context: context + ) + } + case (.version11, .version12): + guard + storeVersion == sourceVersion || + storeVersion == destinationVersion + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + return try readStagedStoreSemanticSnapshot( + at: storeURL, + model: model, + phase: "network filter semantic validation" + ) { context in + if storeVersion == sourceVersion { + return try self.networkFilterSourceSnapshot( + context: context + ) + } + + return try self.networkFilterDestinationSnapshot( + context: context + ) + } + default: + return nil + } + } + + private func readStagedStoreSemanticSnapshot( + at storeURL: URL, + model: NSManagedObjectModel, + phase: String, + makeSnapshot: @escaping ( + NSManagedObjectContext + ) throws -> StagedStoreSemanticSnapshot + ) throws -> StagedStoreSemanticSnapshot { + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + var persistentStore: NSPersistentStore? + + try performWithObjectiveCExceptionBoundary( + phase: "\(phase) open" + ) { + persistentStore = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: [ + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + } + + defer { + if let persistentStore { + try? coordinator.remove(persistentStore) + } + } + + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + + var snapshot: StagedStoreSemanticSnapshot? + var contextError: Error? + context.performAndWait { + do { + try self.performWithObjectiveCExceptionBoundary( + phase: "\(phase) read" + ) { + snapshot = try makeSnapshot(context) + } + } catch { + contextError = error + } + } + + if let contextError { + throw contextError + } + + guard let snapshot else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + return snapshot + } + + private func legacyAccountSourceSnapshot( + context: NSManagedObjectContext + ) throws -> StagedStoreSemanticSnapshot { + let addressFactory = SS58AddressFactory() + var accountIds = Set() + + _ = try stagedSemanticDigest( + context: context, + entityName: "CDAccountItem" + ) { account in + guard + let address = account.value( + forKey: "identifier" + ) as? AccountAddress + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let accountId = try addressFactory.accountId( + from: address + ).toHex() + accountIds.insert(accountId) + + return try self.canonicalSemanticStrings( + [address, accountId] + ) + } + + return .legacyAccountIds(accountIds.sorted()) + } + + private func legacyAccountDestinationSnapshot( + context: NSManagedObjectContext + ) throws -> StagedStoreSemanticSnapshot { + var accountIds = Set() + let digest = try stagedSemanticDigest( + context: context, + entityName: "CDMetaAccount" + ) { account in + guard + let accountId = account.value( + forKey: "substrateAccountId" + ) as? String + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + accountIds.insert(accountId) + return try self.canonicalSemanticStrings([accountId]) + } + + guard digest.rowCount == accountIds.count else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let destinationModel = + context.persistentStoreCoordinator? + .managedObjectModel + guard let destinationModel else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + for entityName in destinationModel.entitiesByName.keys + where entityName != "CDMetaAccount" { + let request = + NSFetchRequest( + entityName: entityName + ) + request.includesPendingChanges = false + request.includesSubentities = false + guard try context.count(for: request) == 0 else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } + + return .legacyAccountIds(accountIds.sorted()) + } + + private func assetVisibilitySourceSnapshot( + context: NSManagedObjectContext + ) throws -> StagedStoreSemanticSnapshot { + var visibilityRowCount = 0 + let digest = try stagedSemanticDigest( + context: context, + entityName: "CDMetaAccount" + ) { wallet in + guard + let metaId = wallet.value( + forKey: "metaId" + ) as? String + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let assetIds: [String] = + try SafeTransformableValueReader.read( + from: wallet, + key: "assetIdsEnabled" + ) ?? [] + try self.validateSemanticStrings( + assetIds, + maximumCount: + self.integrityValidationLimits + .maximumTransformableElements + ) + guard + visibilityRowCount <= + self.integrityValidationLimits + .maximumRelationshipDestinationsAcrossStore - + assetIds.count + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + visibilityRowCount += assetIds.count + + return try self.canonicalSemanticStrings( + [metaId] + assetIds.sorted() + ) + } + + return .assetVisibility( + walletRows: digest, + visibilityRowCount: visibilityRowCount + ) + } + + private func assetVisibilityDestinationSnapshot( + context: NSManagedObjectContext + ) throws -> StagedStoreSemanticSnapshot { + var visibilityRowCount = 0 + let digest = try stagedSemanticDigest( + context: context, + entityName: "CDMetaAccount" + ) { wallet in + guard + let metaId = wallet.value( + forKey: "metaId" + ) as? String + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let preflightCount = + try self.preflightRelationshipDestinationCount( + for: wallet, + relationshipName: "assetsVisibility" + ) + guard + preflightCount <= + self.integrityValidationLimits + .maximumRelationshipDestinations, + visibilityRowCount <= + self.integrityValidationLimits + .maximumRelationshipDestinationsAcrossStore - + preflightCount, + let visibilitySet = wallet.value( + forKey: "assetsVisibility" + ) as? NSSet, + visibilitySet.count == preflightCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + var assetIds = [String]() + assetIds.reserveCapacity(preflightCount) + for case let visibility as NSManagedObject + in visibilitySet { + guard + let assetId = visibility.value( + forKey: "assetId" + ) as? String, + let hidden = visibility.value( + forKey: "hidden" + ) as? NSNumber, + hidden.boolValue + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + assetIds.append(assetId) + } + guard assetIds.count == preflightCount else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + try self.validateSemanticStrings( + assetIds, + maximumCount: + self.integrityValidationLimits + .maximumTransformableElements + ) + visibilityRowCount += assetIds.count + + return try self.canonicalSemanticStrings( + [metaId] + assetIds.sorted() + ) + } + + let visibilityRequest = + NSFetchRequest( + entityName: "CDAssetVisibility" + ) + visibilityRequest.includesPendingChanges = false + visibilityRequest.includesSubentities = false + let storedVisibilityRowCount = try context.count( + for: visibilityRequest + ) + guard + storedVisibilityRowCount != NSNotFound, + storedVisibilityRowCount == visibilityRowCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + return .assetVisibility( + walletRows: digest, + visibilityRowCount: visibilityRowCount + ) + } + + private func networkFilterSourceSnapshot( + context: NSManagedObjectContext + ) throws -> StagedStoreSemanticSnapshot { + let digest = try stagedSemanticDigest( + context: context, + entityName: "CDMetaAccount" + ) { wallet in + guard + let metaId = wallet.value( + forKey: "metaId" + ) as? String + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + let filter = wallet.value( + forKey: "chainIdForFilter" + ) as? String + + return try self.canonicalSemanticStrings( + [metaId, filter] + ) + } + + return .networkManagementFilters(digest) + } + + private func networkFilterDestinationSnapshot( + context: NSManagedObjectContext + ) throws -> StagedStoreSemanticSnapshot { + let digest = try stagedSemanticDigest( + context: context, + entityName: "CDMetaAccount" + ) { wallet in + guard + let metaId = wallet.value( + forKey: "metaId" + ) as? String + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + let filter = wallet.value( + forKey: "networkManagmentFilter" + ) as? String + let favouriteChainIds: [String]? = + try SafeTransformableValueReader.read( + from: wallet, + key: "favouriteChainIds" + ) + guard favouriteChainIds?.isEmpty == true else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + return try self.canonicalSemanticStrings( + [metaId, filter] + ) + } + + return .networkManagementFilters(digest) + } + + private func stagedSemanticDigest( + context: NSManagedObjectContext, + entityName: String, + canonicalRow: (NSManagedObject) throws -> String + ) throws -> IntegrityDigest { + guard + context.persistentStoreCoordinator? + .managedObjectModel.entitiesByName[entityName] != nil + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let countRequest = + NSFetchRequest( + entityName: entityName + ) + countRequest.includesPendingChanges = false + countRequest.includesSubentities = false + let rowCount = try context.count(for: countRequest) + guard + rowCount != NSNotFound, + rowCount <= + integrityValidationLimits.maximumRowsPerEntity, + rowCount <= + integrityValidationLimits.maximumRowsAcrossStore + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let identifierRequest = + NSFetchRequest( + entityName: entityName + ) + identifierRequest.resultType = + .managedObjectIDResultType + identifierRequest.includesPendingChanges = false + identifierRequest.includesSubentities = false + identifierRequest.fetchLimit = rowCount + 1 + identifierRequest.fetchBatchSize = min( + integrityValidationLimits.fetchBatchSize, + rowCount + 1 + ) + let fetchedIdentifiers = + try context.fetch(identifierRequest) + let objectIDs = fetchedIdentifiers.compactMap { + $0 as? NSManagedObjectID + } + guard + objectIDs.count == fetchedIdentifiers.count, + objectIDs.count == rowCount, + Set(objectIDs).count == rowCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + var accumulator = IntegrityDigestAccumulator() + var pageStart = 0 + while pageStart < objectIDs.count { + let pageEnd = min( + pageStart + + integrityValidationLimits.fetchBatchSize, + objectIDs.count + ) + let pageObjectIDs = Array( + objectIDs[pageStart ..< pageEnd] + ) + let request = NSFetchRequest( + entityName: entityName + ) + request.includesPendingChanges = false + request.includesSubentities = false + request.predicate = NSPredicate( + format: "SELF IN %@", + pageObjectIDs + ) + request.fetchLimit = pageObjectIDs.count + request.fetchBatchSize = pageObjectIDs.count + let objects = try context.fetch(request) + integrityObjectPageDidFetch( + objects.count, + pageObjectIDs.count + ) + guard + objects.count == pageObjectIDs.count, + Set(objects.map(\.objectID)) == + Set(pageObjectIDs) + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + for object in objects { + let row = try canonicalRow(object) + guard + row.utf8.count <= + integrityValidationLimits + .maximumCanonicalRowBytes + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + accumulator.append(canonicalRow: row) + } + + pageStart = pageEnd + context.reset() + } + + guard + accumulator.rowCount == rowCount, + try context.count(for: countRequest) == rowCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + return accumulator.digest + } + + private func validateSemanticStrings( + _ values: [String], + maximumCount: Int? = nil + ) throws { + if let maximumCount { + guard values.count <= maximumCount else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } + + var cumulativeByteCount = 0 + for value in values { + let byteCount = value.utf8.count + guard + byteCount <= + integrityValidationLimits.maximumAttributeBytes, + cumulativeByteCount <= + integrityValidationLimits.maximumCanonicalRowBytes - + byteCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + cumulativeByteCount += byteCount + } + } + + private func canonicalSemanticStrings( + _ values: [String?] + ) throws -> String { + try validateSemanticStrings(values.compactMap { $0 }) + + return values.map { value in + guard let value else { + return "nil" + } + + return "value:" + + Data(value.utf8).base64EncodedString() + }.joined(separator: "|") + } + + private func shouldValidateMetaAccountCount( + from sourceVersion: UserStorageVersion + ) -> Bool { + sourceVersion != .version1 + } + + private func stagedMetaAccountCount( + at storeURL: URL, + model: NSManagedObjectModel + ) throws -> Int { + guard model.entitiesByName["CDMetaAccount"] != nil else { + throw UserStorageMigrationError.stagedStoreValidationFailed + } + + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + var persistentStore: NSPersistentStore? + + try performWithObjectiveCExceptionBoundary( + phase: "staged wallet-count validation open" + ) { + persistentStore = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: [ + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + } + + defer { + if let persistentStore { + try? coordinator.remove(persistentStore) + } + } + + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + + var count: Int? + var contextError: Error? + context.performAndWait { + do { + try self.performWithObjectiveCExceptionBoundary( + phase: "staged wallet-count validation read" + ) { + let request = + NSFetchRequest( + entityName: "CDMetaAccount" + ) + request.includesPendingChanges = false + request.includesSubentities = false + let fetchedCount = try context.count(for: request) + + guard + fetchedCount != NSNotFound, + fetchedCount <= + self.integrityValidationLimits + .maximumRowsPerEntity, + fetchedCount <= + self.integrityValidationLimits + .maximumRowsAcrossStore + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + count = fetchedCount + } + } catch { + contextError = error + } + } + + if let contextError { + throw contextError + } + + guard let count else { + throw UserStorageMigrationError.stagedStoreValidationFailed + } + + return count + } + + private func stagedStoreIntegritySnapshot( + at storeURL: URL, + model: NSManagedObjectModel, + comparedWith comparisonModel: NSManagedObjectModel, + allowlist: StagedStoreIntegrityAllowlist = .none + ) throws -> StagedStoreIntegritySnapshot { + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + var persistentStore: NSPersistentStore? + + try performWithObjectiveCExceptionBoundary( + phase: "staged store validation open" + ) { + persistentStore = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: [ + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + } + + defer { + if let persistentStore { + try? coordinator.remove(persistentStore) + } + } + + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + + var snapshot: StagedStoreIntegritySnapshot? + var contextError: Error? + context.performAndWait { + do { + try self.performWithObjectiveCExceptionBoundary( + phase: "staged store validation read" + ) { + snapshot = try self.makeStagedStoreIntegritySnapshot( + context: context, + model: model, + comparedWith: comparisonModel, + allowlist: allowlist + ) + } + } catch { + contextError = error + } + } + + if let contextError { + throw contextError + } + + guard let snapshot else { + throw UserStorageMigrationError.stagedStoreValidationFailed + } + + return snapshot + } + + private func makeStagedStoreIntegritySnapshot( + context: NSManagedObjectContext, + model: NSManagedObjectModel, + comparedWith comparisonModel: NSManagedObjectModel, + allowlist: StagedStoreIntegrityAllowlist + ) throws -> StagedStoreIntegritySnapshot { + let commonEntityNames = Set(model.entitiesByName.keys) + .intersection(comparisonModel.entitiesByName.keys) + .subtracting(allowlist.entityNames) + .sorted() + var rowsByEntity = [String: IntegrityDigest]() + var totalRowCount = 0 + var totalRelationshipDestinationCount = 0 + + for entityName in commonEntityNames { + let attributeNames = try commonAttributeNames( + entityName: entityName, + model: model, + comparedWith: comparisonModel, + excluding: + allowlist.attributeNamesByEntity[entityName] ?? [] + ) + let relationshipNames = + try commonRelationshipNames( + entityName: entityName, + model: model, + comparedWith: comparisonModel, + excluding: + allowlist.relationshipNamesByEntity[entityName] ?? [] + ) + let countRequest = + NSFetchRequest( + entityName: entityName + ) + countRequest.includesPendingChanges = false + countRequest.includesSubentities = false + let rowCount = try context.count(for: countRequest) + guard + rowCount != NSNotFound, + rowCount < Int.max, + rowCount <= + integrityValidationLimits.maximumRowsPerEntity, + totalRowCount <= + integrityValidationLimits.maximumRowsAcrossStore - + rowCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + totalRowCount += rowCount + + let identifierRequest = + NSFetchRequest( + entityName: entityName + ) + identifierRequest.resultType = + .managedObjectIDResultType + identifierRequest.includesPendingChanges = false + identifierRequest.includesSubentities = false + identifierRequest.fetchLimit = rowCount + 1 + identifierRequest.fetchBatchSize = min( + integrityValidationLimits.fetchBatchSize, + rowCount + 1 + ) + let fetchedIdentifiers = + try context.fetch(identifierRequest) + let objectIDs = fetchedIdentifiers.compactMap { + $0 as? NSManagedObjectID + } + guard + objectIDs.count == fetchedIdentifiers.count, + objectIDs.count == rowCount, + Set(objectIDs).count == rowCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + var accumulator = IntegrityDigestAccumulator() + var pageStart = 0 + + while pageStart < objectIDs.count { + let remainingObjectCount = + objectIDs.count - pageStart + let pageLength = min( + integrityValidationLimits.fetchBatchSize, + remainingObjectCount + ) + let pageEnd = pageStart + pageLength + let pageObjectIDs = Array( + objectIDs[pageStart ..< pageEnd] + ) + let request = NSFetchRequest( + entityName: entityName + ) + request.includesPendingChanges = false + request.includesSubentities = false + request.predicate = NSPredicate( + format: "SELF IN %@", + pageObjectIDs + ) + request.fetchLimit = pageObjectIDs.count + request.fetchBatchSize = pageObjectIDs.count + let objects = try context.fetch(request) + integrityObjectPageDidFetch( + objects.count, + pageObjectIDs.count + ) + + guard + objects.count == pageObjectIDs.count, + Set(objects.map(\.objectID)) == + Set(pageObjectIDs) + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + for object in objects { + let row = try integrityRow( + for: object, + entityName: entityName, + attributeNames: attributeNames, + relationshipNames: relationshipNames, + model: model, + comparedWith: comparisonModel, + allowlist: allowlist, + totalRelationshipDestinationCount: + &totalRelationshipDestinationCount + ) + let canonicalRow = row.sortKey + guard + canonicalRow.utf8.count <= + integrityValidationLimits + .maximumCanonicalRowBytes + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + accumulator.append(canonicalRow: canonicalRow) + } + + pageStart = pageEnd + context.reset() + } + + guard + accumulator.rowCount == rowCount, + try context.count(for: countRequest) == rowCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + rowsByEntity[entityName] = accumulator.digest + } + + return StagedStoreIntegritySnapshot( + rowsByEntity: rowsByEntity + ) + } + + private func commonAttributeNames( + entityName: String, + model: NSManagedObjectModel, + comparedWith comparisonModel: NSManagedObjectModel, + excluding excludedNames: Set + ) throws -> [String] { + guard + let entity = model.entitiesByName[entityName], + let comparisonEntity = + comparisonModel.entitiesByName[entityName] + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let names = Set(entity.attributesByName.keys) + .intersection(comparisonEntity.attributesByName.keys) + .subtracting(excludedNames) + .sorted() + + for name in names { + guard + entity.attributesByName[name]?.attributeType == + comparisonEntity.attributesByName[name]?.attributeType + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } + + return names + } + + private func commonRelationshipNames( + entityName: String, + model: NSManagedObjectModel, + comparedWith comparisonModel: NSManagedObjectModel, + excluding excludedNames: Set + ) throws -> [String] { + guard + let entity = model.entitiesByName[entityName], + let comparisonEntity = + comparisonModel.entitiesByName[entityName] + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let names = Set(entity.relationshipsByName.keys) + .intersection( + comparisonEntity.relationshipsByName.keys + ) + .subtracting(excludedNames) + .sorted() + + for name in names { + guard + let relationship = + entity.relationshipsByName[name], + let comparisonRelationship = + comparisonEntity.relationshipsByName[name], + relationship.isToMany == + comparisonRelationship.isToMany, + relationship.isOrdered == + comparisonRelationship.isOrdered, + relationship.destinationEntity?.name == + comparisonRelationship.destinationEntity?.name, + let destinationName = + relationship.destinationEntity?.name, + model.entitiesByName[destinationName] != nil, + comparisonModel.entitiesByName[destinationName] != nil + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } + + return names + } + + private func integrityRow( + for object: NSManagedObject, + entityName: String, + attributeNames: [String], + relationshipNames: [String], + model: NSManagedObjectModel, + comparedWith comparisonModel: NSManagedObjectModel, + allowlist: StagedStoreIntegrityAllowlist, + totalRelationshipDestinationCount: inout Int + ) throws -> IntegrityRow { + let identity = try integrityIdentity( + for: object, + entityName: entityName, + attributeNames: attributeNames, + model: model + ) + let identityByteCount = identity.sortKey.utf8.count + guard + identityByteCount <= + integrityValidationLimits.maximumCanonicalRowBytes + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + var relationships = [IntegrityRelationship]() + var cumulativeByteCount = identityByteCount + for relationshipName in relationshipNames { + let relationship = try integrityRelationship( + for: object, + entityName: entityName, + relationshipName: relationshipName, + model: model, + comparedWith: comparisonModel, + allowlist: allowlist, + totalRelationshipDestinationCount: + &totalRelationshipDestinationCount + ) + let relationshipByteCount = + relationship.sortKey.utf8.count + guard + relationshipByteCount <= + integrityValidationLimits.maximumCanonicalRowBytes, + cumulativeByteCount <= + integrityValidationLimits.maximumCanonicalRowBytes - + relationshipByteCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + cumulativeByteCount += relationshipByteCount + relationships.append(relationship) + } + + return IntegrityRow( + identity: identity, + relationships: relationships + ) + } + + private func integrityRelationship( + for object: NSManagedObject, + entityName: String, + relationshipName: String, + model: NSManagedObjectModel, + comparedWith comparisonModel: NSManagedObjectModel, + allowlist: StagedStoreIntegrityAllowlist, + totalRelationshipDestinationCount: inout Int + ) throws -> IntegrityRelationship { + guard + let relationship = + model.entitiesByName[entityName]? + .relationshipsByName[relationshipName], + let comparisonRelationship = + comparisonModel.entitiesByName[entityName]? + .relationshipsByName[relationshipName], + relationship.isToMany == + comparisonRelationship.isToMany, + relationship.isOrdered == + comparisonRelationship.isOrdered, + let destinationName = + relationship.destinationEntity?.name, + destinationName == + comparisonRelationship.destinationEntity?.name + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let relatedObjects: [NSManagedObject] + if relationship.isToMany { + let preflightCount = + try preflightRelationshipDestinationCount( + for: object, + relationshipName: relationshipName + ) + guard + preflightCount <= + integrityValidationLimits + .maximumRelationshipDestinations + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + try accumulateRelationshipDestinationCount( + preflightCount, + total: &totalRelationshipDestinationCount + ) + + if preflightCount == 0 { + relatedObjects = [] + } else { + let value = object.value( + forKey: relationshipName + ) + if relationship.isOrdered, + let orderedSet = value as? NSOrderedSet { + relatedObjects = + orderedSet.array.compactMap { + $0 as? NSManagedObject + } + guard + orderedSet.count == preflightCount, + relatedObjects.count == preflightCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } else if !relationship.isOrdered, + let set = value as? NSSet { + relatedObjects = + set.allObjects.compactMap { + $0 as? NSManagedObject + } + guard + set.count == preflightCount, + relatedObjects.count == preflightCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } + } else { + let value = object.value(forKey: relationshipName) + if let relatedObject = value as? NSManagedObject { + relatedObjects = [relatedObject] + } else if value == nil { + relatedObjects = [] + } else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + } + + let destinationAttributeNames = + try commonAttributeNames( + entityName: destinationName, + model: model, + comparedWith: comparisonModel, + excluding: + allowlist.attributeNamesByEntity[destinationName] ?? [] + ) + var destinations = [IntegrityIdentity]() + var cumulativeDestinationByteCount = 0 + for relatedObject in relatedObjects { + guard relatedObject.entity.name == destinationName else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let destination = try integrityIdentity( + for: relatedObject, + entityName: destinationName, + attributeNames: destinationAttributeNames, + model: model + ) + let destinationByteCount = + destination.sortKey.utf8.count + guard + destinationByteCount <= + integrityValidationLimits.maximumCanonicalRowBytes, + cumulativeDestinationByteCount <= + integrityValidationLimits.maximumCanonicalRowBytes - + destinationByteCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + cumulativeDestinationByteCount += destinationByteCount + destinations.append(destination) + } + + if !relationship.isOrdered { + destinations.sort { + $0.sortKey < $1.sortKey + } + } + + return IntegrityRelationship( + name: relationshipName, + destinations: destinations + ) + } + + func accumulateRelationshipDestinationCount( + _ count: Int, + total: inout Int + ) throws { + guard count >= 0, total >= 0 else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + let addition = total.addingReportingOverflow(count) + guard + !addition.overflow, + addition.partialValue <= + integrityValidationLimits + .maximumRelationshipDestinationsAcrossStore + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + total = addition.partialValue + } + + func preflightRelationshipDestinationCount( + for object: NSManagedObject, + relationshipName: String + ) throws -> Int { + guard + let context = object.managedObjectContext, + let entityName = object.entity.name, + let relationship = + object.entity.relationshipsByName[relationshipName], + relationship.isToMany + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + guard + let persistentStore = + object.objectID.persistentStore + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let countDescription = NSExpressionDescription() + countDescription.name = "relationshipDestinationCount" + countDescription.expression = NSExpression( + forFunction: "count:", + arguments: [ + NSExpression(forKeyPath: relationshipName) + ] + ) + countDescription.expressionResultType = + .integer64AttributeType + + let request = NSFetchRequest( + entityName: entityName + ) + request.resultType = .dictionaryResultType + request.propertiesToFetch = [countDescription] + request.predicate = NSPredicate( + format: "SELF == %@", + object.objectID + ) + request.includesPendingChanges = false + request.includesSubentities = false + request.affectedStores = [persistentStore] + request.fetchLimit = 2 + + let rows = try context.fetch(request) + guard + rows.count == 1, + let number = + rows[0][countDescription.name] as? NSNumber + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let count = number.int64Value + guard + count >= 0, + UInt64(count) <= UInt64(Int.max) + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + return Int(count) + } + + private func integrityIdentity( + for object: NSManagedObject, + entityName: String, + attributeNames: [String], + model: NSManagedObjectModel + ) throws -> IntegrityIdentity { + guard + object.entity.name == entityName, + let entity = model.entitiesByName[entityName] + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + var fields = [IntegrityField]() + var cumulativeFieldByteCount = + Data(entityName.utf8).base64EncodedString().utf8.count + + for attributeName in attributeNames { + guard + let attribute = + entity.attributesByName[attributeName] + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let field = IntegrityField( + name: attributeName, + value: try canonicalIntegrityValue( + from: object, + entityName: entityName, + attribute: attribute + ) + ) + let fieldByteCount = field.sortKey.utf8.count + guard + fieldByteCount <= + integrityValidationLimits.maximumCanonicalRowBytes, + cumulativeFieldByteCount <= + integrityValidationLimits.maximumCanonicalRowBytes - + fieldByteCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + cumulativeFieldByteCount += fieldByteCount + fields.append(field) + } + + return IntegrityIdentity( + entityName: entityName, + fields: fields + ) + } + + private func canonicalIntegrityValue( + from object: NSManagedObject, + entityName: String, + attribute: NSAttributeDescription + ) throws -> String { + if attribute.attributeType == + .transformableAttributeType { + guard + entityName == "CDMetaAccount", + Self.resilientMetaAccountTransformableKeys + .contains(attribute.name) + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + + let value: [String]? = + try SafeTransformableValueReader.read( + from: object, + key: attribute.name + ) + + guard let value else { + return "nil" + } + + guard + value.count <= + integrityValidationLimits + .maximumTransformableElements + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + var cumulativeByteCount = 0 + for item in value { + let itemByteCount = item.utf8.count + guard + itemByteCount <= + integrityValidationLimits.maximumAttributeBytes, + cumulativeByteCount <= + integrityValidationLimits.maximumAttributeBytes - + itemByteCount + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + cumulativeByteCount += itemByteCount + } + + return "string-array:" + value.map { + Data($0.utf8).base64EncodedString() + }.joined(separator: ",") + } + + let value = object.value(forKey: attribute.name) + + guard let value else { + return "nil" + } + + if let value = value as? String { + guard + value.utf8.count <= + integrityValidationLimits.maximumAttributeBytes + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + return "string:\(Data(value.utf8).base64EncodedString())" + } + + if let value = value as? Data { + guard + value.count <= + integrityValidationLimits.maximumAttributeBytes + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + return "data:\(value.base64EncodedString())" + } + + if let value = value as? NSNumber { + return "number:\(value.stringValue)" + } + + if let value = value as? Date { + return "date:\(value.timeIntervalSinceReferenceDate.bitPattern)" + } + + if let value = value as? URL { + guard + value.absoluteString.utf8.count <= + integrityValidationLimits.maximumAttributeBytes + else { + throw UserStorageMigrationError + .stagedStoreValidationFailed + } + return "url:\(Data(value.absoluteString.utf8).base64EncodedString())" + } + + if let value = value as? UUID { + return "uuid:\(value.uuidString)" + } + + throw UserStorageMigrationError.stagedStoreValidationFailed + } + + private func sanitizePreferenceTransformables( + objectID: NSManagedObjectID, + model: NSManagedObjectModel, + context: NSManagedObjectContext, + persistentStore: NSPersistentStore? + ) throws -> Bool { + guard let entity = model.entitiesByName["CDMetaAccount"] else { + return false + } + + var didRepair = false + for key in Self.resilientMetaAccountTransformableKeys { + guard + let attribute = entity.attributesByName[key], + attribute.attributeType == .transformableAttributeType + else { + continue + } + + let needsRepair: Bool + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + request.resultType = .dictionaryResultType + request.propertiesToFetch = [key] + request.predicate = NSPredicate( + format: "SELF == %@", + objectID + ) + request.affectedStores = persistentStore.map { [$0] } + request.fetchLimit = 2 + + do { + var rows: [NSDictionary]? + try SafeObjectiveCExceptionBoundary.perform { + rows = try context.fetch(request) + } + + guard + let rows, + rows.count == 1 + else { + throw UserStorageMigrationError + .privateSourceRepairFailed + } + + let value = rows[0][key] + if value == nil || value is NSNull { + needsRepair = !attribute.isOptional + } else if let strings = value as? [String] { + needsRepair = + !isBoundedPreferenceStringArray(strings) + } else { + needsRepair = true + } + } catch is SafeTransformableValueReaderError { + needsRepair = true + } catch let error as NSError + where error.domain == NSCocoaErrorDomain && + error.code == NSCoderReadCorruptError { + needsRepair = true + } + + // A failed transformable decode can leave fetched state unusable. + // Discard it before issuing a store-level repair. + context.reset() + + guard needsRepair else { + continue + } + + // NSBatchUpdateRequest writes the replacement directly to the + // disposable store. No managed object is changed or saved, so + // Core Data never attempts to decode the corrupt prior archive. + guard !context.hasChanges else { + throw UserStorageMigrationError.privateSourceRepairFailed + } + + let update = NSBatchUpdateRequest( + entityName: "CDMetaAccount" + ) + update.affectedStores = persistentStore.map { [$0] } + update.predicate = NSPredicate( + format: "SELF == %@", + objectID + ) + update.propertiesToUpdate = [key: NSArray()] + update.resultType = .updatedObjectIDsResultType + + let result = try context.execute(update) + guard + let batchResult = result as? NSBatchUpdateResult, + let updatedObjectIDs = + batchResult.result as? [NSManagedObjectID], + updatedObjectIDs == [objectID] + else { + throw UserStorageMigrationError.privateSourceRepairFailed + } + + context.reset() + didRepair = true + } + + return didRepair + } + + private func isBoundedPreferenceStringArray( + _ value: [String] + ) -> Bool { + guard + value.count <= + integrityValidationLimits + .maximumTransformableElements + else { + return false + } + + var cumulativeByteCount = 0 + for item in value { + let itemByteCount = item.utf8.count + guard + itemByteCount <= + integrityValidationLimits.maximumAttributeBytes, + cumulativeByteCount <= + integrityValidationLimits.maximumAttributeBytes - + itemByteCount + else { + return false + } + cumulativeByteCount += itemByteCount + } + + return true + } + + private func performWithObjectiveCExceptionBoundary( + phase: String, + _ operation: @escaping () throws -> Void + ) throws { + do { + try SafeObjectiveCExceptionBoundary.perform(operation) + } catch SafeTransformableValueReaderError.objectiveCException { + Logger.shared.error( + "User-storage recovery safely stopped during \(phase)" + ) + throw UserStorageMigrationError.objectiveCException + } catch { + throw error + } + } + + private func checkIfMigrationNeeded(to version: UserStorageVersion) -> Bool { + if crashConsistentStoreReplacer.hasPendingTransaction { + return true + } + + do { + guard try crashConsistentStoreReplacer.liveStoreExistsSafely() else { + return false + } + } catch { + return true + } + + do { + return try withPrivateSourceCopy { + privateSourceURL, + _ in + + let sourceVersion = try readSourceVersion( + at: privateSourceURL + ) + guard sourceVersion == version else { + return true + } + + return try sanitizePrivateSourceCopy( + at: privateSourceURL, + version: sourceVersion + ) + } + } catch { + return true + } + } + + private func compatibleVersionForStoreMetadata(_ metadata: [String: Any]) -> UserStorageVersion? { + let compatibleVersion = UserStorageVersion.allCases.first { + guard let model = try? createManagedObjectModel(for: $0) else { + return false + } + + return model.isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) + } + + return compatibleVersion + } + + private func createManagedObjectModel( + for version: UserStorageVersion + ) throws -> NSManagedObjectModel { + guard + let modelURL = version.modelURL( + in: modelBundle, + legacyModelDirectory: modelDirectory + ), + let model = NSManagedObjectModel(contentsOf: modelURL) else { + throw UserStorageMigrationError.modelUnavailable(version) + } + + return model + } + + private func createMapping( + from sourceModel: NSManagedObjectModel, + nextModel: NSManagedObjectModel + ) throws -> NSMappingModel { + let maybeCustomMapping = NSMappingModel( + from: [modelBundle], + forSourceModel: sourceModel, + destinationModel: nextModel + ) + + if let customMapping = maybeCustomMapping { + return customMapping + } + + return try NSMappingModel.inferredMappingModel( + forSourceModel: sourceModel, + destinationModel: nextModel + ) + } +} + +extension UserStorageMigrator: StorageMigrating { + func requiresMigration() -> Bool { + checkIfMigrationNeeded(to: targetVersion) + } + + func migrate(_ completion: @escaping () -> Void) { + DispatchQueue.global(qos: .utility).async { [weak self] in + guard let self else { + return + } + + do { + try self.performMigration() + } catch { + Logger.shared.error( + "User-storage migration failed safely" + ) + return + } DispatchQueue.main.async { completion() diff --git a/fearless/Common/Storage/Migration/UserStorage/UserStorageVersion.swift b/fearless/Common/Storage/Migration/UserStorage/UserStorageVersion.swift index b1535d2386..9a3d6fe4d2 100644 --- a/fearless/Common/Storage/Migration/UserStorage/UserStorageVersion.swift +++ b/fearless/Common/Storage/Migration/UserStorage/UserStorageVersion.swift @@ -13,6 +13,12 @@ enum UserStorageVersion: String, CaseIterable { case version10 = "MultiassetUserDataModel_v9" case version11 = "MultiassetUserDataModel_v10" case version12 = "MultiassetUserDataModel_v11" + /// Schema shipped by the ecosystem/TON app line. It is a migration source, + /// not an active destination for this app. + case version13 = "LegacyEcosystemUserDataModel_v12" + /// Superset schema that accepts both the public v11 and ecosystem v12 + /// layouts without dropping ecosystem or TON fields. + case version14 = "CompatibleUserDataModel_v13" static var current: UserStorageVersion { guard let currentVersion = allCases.last else { @@ -47,7 +53,37 @@ enum UserStorageVersion: String, CaseIterable { case .version11: return .version12 case .version12: + return .version14 + case .version13: + return .version14 + case .version14: return nil } } + + var isCompatibilityResource: Bool { + switch self { + case .version13, .version14: + return true + default: + return false + } + } + + func modelURL( + in bundle: Bundle, + legacyModelDirectory: String + ) -> URL? { + let subdirectory = isCompatibilityResource ? nil : legacyModelDirectory + + return bundle.url( + forResource: rawValue, + withExtension: "omo", + subdirectory: subdirectory + ) ?? bundle.url( + forResource: rawValue, + withExtension: "mom", + subdirectory: subdirectory + ) + } } diff --git a/fearless/Common/Storage/MigrationMappings/SubstrateV2Mapping.xcmappingmodel/xcmapping.xml b/fearless/Common/Storage/MigrationMappings/SubstrateV2Mapping.xcmappingmodel/xcmapping.xml index bfda5f6d3b..fb4323cbc5 100644 --- a/fearless/Common/Storage/MigrationMappings/SubstrateV2Mapping.xcmappingmodel/xcmapping.xml +++ b/fearless/Common/Storage/MigrationMappings/SubstrateV2Mapping.xcmappingmodel/xcmapping.xml @@ -432,12 +432,12 @@ cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxEHMgALAAwAGwA3ADgAOQBVAFYAVwBY fearless/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel_v2.xcdatamodel YnBsaXN0MDDUAAEAAgADAAQABQAGAAcAClgkdmVyc2lvblkkYXJjaGl2ZXJUJHRvcFgkb2JqZWN0 -cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxEHRwALAAwAGwA3ADgAOQBXAFgAWQBaAFsAXABdAF4AXwBgAGEAYgBjAH4AfwCAAIYAhwCTAKkAqgCrAKwArQCuAK8AsACxALIAywDOANUA2wDqAPkA/AELARoBHQB9AS0BPAFAAUQBUwFZAVoBYgFxAXIBewGDAYQBhQGaAZsBowGkAaUBsQHFAcYBxwHIAckBygHLAcwBzQHcAesB+gH+Ag0CHAIdAiwCOwJKAlYCaAJpAmoCawJsAm0CbgJvAn4CjQKcAqsCrAK7AsoC2QLhAvYC9wL/AwsDHwMuAz0DTANQA18DbgN9A4wDmwOnA7kDyAPXA+YD9QP2BAUEFAQjBCQEJwQwBEoESwRRBF0EcwSCBIUElASjBKYEtQTEBMcE1gTlBOkE+AUHBQgFFgUXBRgFGQUaBRsFMAUxBTkFOgVGBVoFaQV4BYcFiwWaBakFuAXHBdYF4gXyBfMF9AX1BfYF9wX4BgcGIQYiBigGNAZKBlkGXAZrBnoGfQaMBpsGngatBrwGwAbPBt4G7AbtBu4G7wbwBvEHBgcHBw8HGwcvBz4HTQdcB2AHbwd+B40HnAerB7cHyQfYB+cH9ggFCBQIIwgyCEcISAhQCFwIcAh/CI4InQihCLAIvwjOCN0I7Aj4CQoJGQkoCTcJRglHCVYJZQl0CYkJigmSCZ4JsgnBCdAJ3wnjCfIKAQoQCh8KLgo6CkwKWwpqCnkKiAqXCqYKtQrKCssK0wrfCvMLAgsRCyALJAszC0ILUQtgC28LewuNC5wLnQusC7sLygvLC9oL6Qv4DA0MDgwWDCIMNgxFDFQMYwxnDHYMhQyUDKMMsgy+DNAM3wzuDP0NDA0bDSoNOQ08DUsAMQ1aDWkNag15DYgNkA2lDaYNrg26Dc4N3Q3sDfsN/w4ODh0OLA47DkoOVg5oDmkOeA6HDpYOpQ6/DsAOxg7SDugO9w76DwkPGA8cDyAPLw8+D0EPUA9fD2MPcg+BD60Prg+vD7APsQ+yD7MPtA+1D7YPtw+4D7kPug+7D7wPvQ++D78P1A/VD90P6Q/9EAwQGxAqEC4QPRBMEFsQahB5EIUQlxCmELUQxBDTEOIQ8REAERURFhEeESoRPhFNEVwRaxFvEX4RjRGcEasRuhHGEdgR5xH2EgUSFBIjEjISQRJWElcSXxJrEn8SjhKdEqwSsBK/Es4S3RLsEvsTBxMZEygTNxNGE1UTZBNzE4ITlxOYE6ATrBPAE88T3hPtE/EUABQPFB4ULRQ8FEgUWhRpFGoUeRSIFJcUmBSnFLYUxRTaFNsU4xTvFQMVEhUhFTAVNBVDFVIVYRVwFX8VixWdFawVuxXKFdkV6BX3FgYWGxYcFiQWMBZEFlMWYhZxFnUWhBaTFqIWsRbAFswW3hbtFvwXCxcaFykXOBdHF1wXXRdlF3EXhReUF6MXshe2F8UX1BfjF/IYARgNGB8YLhg9GEwYWxhqGHkYiBidGJ4YphiyGMYY1RjkGPMY9xkGGRUZJBkzGUIZThlgGW8ZfhmNGZwZqxm6GckZ3hnfGecZ8xoHGhYaJRo0GjgaRxpWGmUadBqDGo8aoRqwGr8azhrdGuwa+xsKGx8bIBsoGzQbSBtXG2YbdRt5G4gblxumG7UbxBvQG+Ib8RwAHA8cHhwtHDwcSxxgHGEcaRx1HIkcmBynHLYcuhzJHNgc5xz2HQUdER0hHTAdSh1LHVEdXR1zHYIdhR2UHaMdpx2rHawdux3KHc0d3B3rHe8d/h4NHg4eHB4dHh4eMx40HjweSB5cHmseeh6JHo0enB6rHroeyR7YHuQe9h8FHxQfIx8yH0EfUB9fH3QfdR99H4kfnR+sH7sfyh/OH90f7B/7IAogGSAlIDcgRiBVIGQgcyCCIJEgoCC1ILYgviDKIN4g7SD8IQshDyEeIS0hPCFLIVohZiF4IYchliGXIaYhtSHEIdMh4iH3IfgiACIMIiAiLyI+Ik0iUSJgIm8ifiKNIpwiqCK6IskiyiLZIugi9yMGIxUjJCM5IzojQiNOI2IjcSOAI48jkyOiI7EjwCPPI94j6iP8JAskGiQpJDgkRyRWJGUkeiR7JIMkjySjJLIkwSTQJNQk4yTyJQElECUfJSslPSVMJVslaiV5JYgllyWmJakluCXHJdYl5SX0JgkmCiYSJh4mMiZBJlAmXyZjJnImgSaQJp8mria6Jswm2ybqJvknCCcXJyYnNSdKJ0snUydfJ3MngieRJ6AnpCezJ8In0SfgJ+8n+ygNKBwoKyg6KEkoWChnKHYoiyiMKJQooCi0KMMo0ijhKOUo9CkDKRIpISkwKTwpTildKWwpeymKKZkpqCm3KcwpzSnVKeEp9SoEKhMqIiomKjUqRCpTKmIqcSp9Ko8qniqtKrwqyyraKukq+CsNKw4rFisiKzYrRStUK2MrZyt2K4UrlCujK7IrvivQK98r7iv9LAwsGywqLDksTixPLFcsYyx3LIYslSykLKgstyzGLNUs5CzzLP8tES0gLS8tPi1NLVwtay16LY8tkC2YLaQtuC3HLdYt5S3pLfguBy4WLiUuNC5ALlIuYS5wLn8uji6dLqwuuy7QLtEu2S7lLvkvCC8XLyYvKi85L0gvVy9mL3UvgS+RL6Avry++L80v3C/rL+4v/TAMMBswMDAxMDkwRTBZMGgwdzCGMIowmTCoMLcwxjDVMOEw8zECMRExIDEvMTAxPzFOMV0xcjFzMXsxhzGbMaoxuTHIMcwx2zHqMfkyCDIXMiMyNTJEMlMyYjJxMoAyjzKeMrMytDK8Msgy3DLrMvozCTMNMxwzKzM6M0kzWDNkM3YzhTOUM6MzsjPBM9Az3zPiM/wz/TQDNA80JTQ0NDc0RjRVNFg0ZzR2NHk0iDSXNJs0qjS5NLo0wjTDNNg02TThNO01ATUQNR81LjUyNUE1UDVfNW41fTWJNZs1qjW5Ncg11zXmNfU2BDYZNho2IjYuNkI2UTZgNm82czaCNpE2oDavNr42yjbcNus2+jcJNxg3Jzc2N0U3SDdiN2M3aTd1N4s3mjedN6w3uze+N8033DffN+43/TgBOBA4HzggOC44LzgwODE4MjhHOEg4UDhcOHA4fziOOJ04oTiwOL84zjjdOOw4+DkKORk5KDk3OUY5VTlkOXM5iDmJOZE5nTmxOcA5zzneOeI58ToAOg86HjotOjk6SzpaOmk6eDqHOpY6pTq0Osk6yjrSOt468jsBOxA7HzsjOzI7QTtQO187bjt6O4w7mzuqO7k7yDvJO9g75zv2PAs8DDwUPCA8NDxDPFI8YTxlPHQ8gzySPKE8sDy8PM483TzsPPs9Cj0ZPSg9Nz1MPU09VT1hPXU9hD2TPaI9pj21PcQ90z3iPfE9/T4PPh4+LT48Pks+Wj5pPng+ez6VPpY+nD6oPr4+zT7QPt8+7j7xPwA/Dz8SPyE/MD80P0M/Uj9TP1s/XD9dP3I/cz97P4c/mz+qP7k/yD/MP9s/6j/5QAhAF0AjQDVAREBTQGJAcUCAQI9AnkCzQLRAvEDIQNxA60D6QQlBDUEcQStBOkFJQVhBZEF2QYVBlEGjQbJBwUHQQd9B4kH8Qf1CA0IPQiVCNEI3QkZCVUJYQmdCdkJ5QohCl0KbQqpCuUK6QsZCx0LIQslC3kLfQudC80MHQxZDJUM0QzhDR0NWQ2VDdEODQ49DoUOwQ79DzkPdQ+xD+0QKRB9EIEQoRDRESERXRGZEdUR5RIhEl0SmRLVExETQROJE8UUARQ9FHkUfRS5FPUVMRWFFYkVqRXZFikWZRahFt0W7RcpF2UXoRfdGBkYSRiRGM0ZCRlFGYEZvRn5GjUaiRqNGq0a3RstG2kbpRvhG/EcLRxpHKUc4R0dHU0dlR3RHg0eSR6FHsEe/R85H0UfrR+xH8kf+SBRII0gmSDVIREhHSFZIZUhoSHdIhkiKSJlIqEipSMNIxEjFSMZIx0jISMlIykjLSMxIzUjiSONI60j3SQtJGkkpSThJPElLSVpJaUl4SYdJk0mlSbRJw0nSSeFJ8En/Sg5KI0okSixKOEpMSltKakp5Sn1KjEqbSqpKuUrIStRK5kr1SwRLE0siSzFLQEtPS2RLZUttS3lLjUucS6tLuku+S81L3EvrS/pMCUwVTCdMNkxFTFRMY0xyTIFMkEylTKZMrky6TM5M3UzsTPtM/00OTR1NLE07TUpNVk1oTXdNhk2VTaRNs03CTdFN5k3nTe9N+04PTh5OLU48TkBOT05eTm1OfE6LTpdOqU64TsdO1k7lTvRPA08STydPKE8wTzxPUE9fT25PfU+BT5BPn0+uT71PzE/YT+pP+VAIUBdQJlA1UERQU1BoUGlQcVB9UJFQoFCvUL5QwlDRUOBQ71D+UQ1RGVErUTpRSVFYUWdRdlGFUZRRqVGqUbJRvlHSUeFR8FH/UgNSElIhUjBSP1JOUlpSbFJ7UopSmVKoUrdSxlLVUupS61LzUv9TE1MiUzFTQFNEU1NTYlNxU4BTj1ObU61TvFPLU9pT6VP4VAdUFlQrVCxUNFRAVFRUY1RyVIFUhVSUVKNUslTBVNBU3FTuVP1VDFUbVSpVOVVIVVdVbFVtVXVVgVWVVaRVs1XCVcZV1VXkVfNWAlYRVh1WL1Y+Vk1WXFZrVnpWiVaYVptWrVauVrRWwFbWVuVW6Fb3VwZXCVcYVydXKlc5V0hXTFdbV2pXa1dvV4lXileQV5xXslfBV8RX01fiV+VX9FgDWAZYFVgkWChYN1hGWEdYUVhSWFNYaFhpWHFYfViRWKBYr1i+WMJY0VjgWO9Y/lkNWRlZK1k6WUlZWFlnWXZZhVmUWalZqlmyWb5Z0lnhWfBZ/1oDWhJaIVowWj9aTlpaWmxae1qKWplaqFq3WsZa1VrqWuta81r/WxNbIlsxW0BbRFtTW2JbcVuAW49bm1utW7xby1vaW+lb+FwHXBZcGVwdXCFcJVwtXDBcNFUkbnVsbNcADQAOAA8AEAARABIAEwAUABUAFgAXABgAFwAaXxAPX3hkX3Jvb3RQYWNrYWdlViRjbGFzc1xfeGRfY29tbWVudHNfEBBfeGRfbW9kZWxNYW5hZ2VyXxAVX2NvbmZpZ3VyYXRpb25zQnlOYW1lXV94ZF9tb2RlbE5hbWVfEBdfbW9kZWxWZXJzaW9uSWRlbnRpZmllcoACgQdGgQdEgACBB0WAAIEC7N4AHAAdAB4AHwAgACEAIgAOACMAJAAlACYAJwAoACkAKgArAAkAKQAXAC8AMAAxADIAMwApACkAF18QHFhEQnVja2V0Rm9yQ2xhc3Nlc3dhc0VuY29kZWRfEBpYREJ1Y2tldEZvclBhY2thZ2Vzc3RvcmFnZV8QHFhEQnVja2V0Rm9ySW50ZXJmYWNlc3N0b3JhZ2VfEA9feGRfb3duaW5nTW9kZWxfEB1YREJ1Y2tldEZvclBhY2thZ2Vzd2FzRW5jb2RlZFZfb3duZXJfEBtYREJ1Y2tldEZvckRhdGFUeXBlc3N0b3JhZ2VbX3Zpc2liaWxpdHlfEBlYREJ1Y2tldEZvckNsYXNzZXNzdG9yYWdlVV9uYW1lXxAfWERCdWNrZXRGb3JJbnRlcmZhY2Vzd2FzRW5jb2RlZF8QHlhEQnVja2V0Rm9yRGF0YVR5cGVzd2FzRW5jb2RlZF8QEF91bmlxdWVFbGVtZW50SUSABIEHQoEHQIABgASAAIEHQYEHQxAAgAWAA4AEgASAAFBTWUVT0wA6ADsADgA8AEkAVldOUy5rZXlzWk5TLm9iamVjdHOsAD0APgA/AEAAQQBCAEMARABFAEYARwBIgAaAB4AIgAmACoALgAyADYAOgA+AEIARrABKAEsATABNAE4ATwBQAFEAUgBTAFQAVYASgIGBBCmAsoEEbYEBXoEE+oEFP4ECfYEFtIEG0IEG5IAwXxASQ0RDaGFpblN0b3JhZ2VJdGVtXENEQ2hhaW5Bc3NldF1DRFNpbmdsZVZhbHVlV0NEQXNzZXRdQ0RDb250YWN0SXRlbVdDRENoYWluW0NEU3Rhc2hJdGVtXxAVQ0RSdW50aW1lTWV0YWRhdGFJdGVtW0NEQ2hhaW5Ob2RlXxAYQ0RUcmFuc2FjdGlvbkhpc3RvcnlJdGVtXENETW9ja0VudGl0eV5DRFBoaXNoaW5nSXRlbd8QEABkAGUAZgBnACEAaABpACMAagBrAA4AJQBsAG0AKABuAG8AcAApACkAFAB0AHUAMQApAG8AeAA9AG8AewB8AH1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2VbX2lzQWJzdHJhY3SAFIA4gASABIACgBWAfoAEgBSAgIAGgBSAf4ATCBMAAAABHlljYFdvcmRlcmVk0wA6ADsADgCBAIMAVqEAgoAWoQCEgBeAMF5YRF9QU3RlcmVvdHlwZdkAIQAlAIgADgAoAIkAIwBuAIoASgCCAG8AjgAXACkAMQB9AJJfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAEoAWgBSAN4AAgAQIgBjTADoAOwAOAJQAngBWqQCVAJYAlwCYAJkAmgCbAJwAnYAZgBqAG4AcgB2AHoAf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tAC1ACEAtgC3ALgAIwC5AA4AJQC6ALsAKAC8ABcAFwAXAv0AfQB9AH0AMQB9AMUCXgB9AH0AFwB9gACAAIAAgHQICAgIgCWAXAgIgAAIWmR1cGxpY2F0ZXPSADsADgQlAM2ggCTSAM8A0AQoBClaWERQTUVudGl0eacEKgQrBCwELQQuBC8A1FpYRFBNRW50aXR5XVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAQBDEEMgQzBDQAIQQ1BDYAIwQ3BDgADgAlBDkEOgAoAG4AbwQ8ACkAKQAUBEAAdQAxACkAbwB4AD4AbwRHBEgAfV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZYAUgJSABIAEgAKAg4B+gASAFICAgAeAFIEEKICCCBJ/s4PS0wA6ADsADgRMBE4AVqEAgoAWoQRPgISAMNkAIQAlBFIADgAoBFMAIwBuBFQASwCCAG8AjgAXACkAMQB9BFxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAgYAWgBSAN4AAgAQIgIXTADoAOwAO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cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAmyAnYAUgDeAAIAECIECe9MAOgA7AA4dEh0ZAFamBeQF5QXmBecF6AXpgKuArICtgK6Ar4Cwph0aHRsdHB0dHR4dH4ECfIEDIoEDI4EDJIEDJYEDJoAw3xAPALMAtAC1ACEAtgC3ALgAIwC5AA4AJQC6ALsAKAC8ABcAUgAXHGcAfQB9AH0AMQB9AMUF5AB9AH0AFwB9gACBAn2AAIECeggICAiAJYCrCAiAAAjfEBAdMR0yHTMdNAAhHTUdNgAjHTcdOAAOACUdOR06ACgAbgBvHTwAKQApABQdQAB1ADEAKQBvAHgARQBvHUcdSAB9XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgBSBApKABIAEgAKBAn+AfoAEgBSAgIAOgBSBAyGBAn4IElJaQ4jTADoAOwAOHUwdTgBWoQCCgBahHU+BAoCAMNkAIQAlHVIADgAoHVMAIwBuHVQAUgCCAG8AjgAXACkAMQB9HVxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAn2AFoAUgDeAAIAECIECgdMAOgA7AA4dXh1oAFapAJUA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ABlkAAAZZgAAGWgAABlqAAAZawAAGWwAABltAAAZbgAAGXAAABlyAAAZcwAAGXQAABl2AAAZdwAAGXgAABm3AAAZuQAAGbsAABm9AAAZvwAAGcAAABnBAAAZwgAAGcMAABnFAAAZxwAAGcgAABnJAAAZywAAGcwAABnZAAAZ2gAAGdsAABndAAAZ5gAAGfwAABoDAAAaEAAAGk8AABpRAAAaUwAAGlUAABpXAAAaWAAAGlkAABpaAAAaWwAAGl0AABpfAAAaYAAAGmEAABpjAAAaZAAAGn0AABp/AAAagQAAGoMAABqEAAAahgAAGp0AABqmAAAatAAAGsEAABrPAAAa5AAAGvgAABsPAAAbIQAAG2AAABtiAAAbZAAAG2YAABtoAAAbaQAAG2oAABtrAAAbbAAAG24AABtwAAAbcQAAG3IAABt0AAAbdQAAG4oAABuTAAAbqAAAG7cAABvMAAAb2gAAG+8AABwDAAAcGgAAHCwAABw5AAAcPgAAHEAAABxCAAAcRwAAHEkAABxLAAAcTQAAHFIAABxdAAAcqAAAHMsAABzrAAAdCwAAHQ0AAB0PAAAdEQAAHRMAAB0VAAAdFgAAHRcAAB0ZAAAdGgAAHRwAAB0dAAAdHwAAHSEAAB0iAAAdIwAAHSUAAB0mAAAdKwAAHTgAAB09AAAdPwAAHUEAAB1GAAAdSAAAHUoAAB1MAAAdYQAAHXYAAB2bAAAdvwAAHeYAAB4KAAAeDAAAHg4AAB4QAAAeEgAAHhQAAB4WAAAeFwAAHhkAAB4mAAAeNwAAHjkAAB47AAAePQAAHj8AAB5BAAAeQwAAHkUAAB5HAAAeWAAAHloAAB5cAAAeXgAAHmAAAB5iAAAeZAAAHmYAAB5oAAAeagAAHogAAB6mAAAeuQAAHs0AAB7iAAAe/wAAHxMAAB8pAAAfaAAAH2oAAB9sAAAfbgAAH3AAAB9xAAAfcgAAH3MAAB90AAAfdgAAH3gAAB95AAAfegAAH3wAAB99AAAfvAAAH74AAB/AAAAfwgAAH8QAAB/FAAAfxgAAH8cAAB/IAAAfygAAH8wAAB/NAAAfzgAAH9AAAB/RAAAgEAAAIBIAACAUAAAgFgAAIBgAACAZAAAgGgAAIBsAACAcAAAgHgAAICAAACAhAAAgIgAAICQAACAlAAAgMgAAIDMAACA0AAAgNgAAIHUAACB3AAAgeQAAIHsAACB9AAAgfgAAIH8AACCAAAAggQAAIIMAACCFAAAghgAAIIcAACCJAAAgigAAIMkAACDLAAAgzQAAIM8AACDRAAAg0gAAINMAACDUAAAg1QAAINcAACDZAAAg2gAAINsAACDdAAAg3gAAIN8AACEeAAAhIAAAISIAACEkAAAhJgAAIScAACEoAAAhKQAAISoAACEsAAAhLgAAIS8AACEwAAAhMgAAITMAACFyAAAhdAAAIXYAACF4AAAhegAAIXsAACF8AAAhfQAAIX4AACGAAAAhggAAIYMAACGEAAAhhgAAIYcAACHGAAAhyAAAIcoAACHMAAAhzgAAIc8AACHQAAAh0QAAIdIAACHUAAAh1gAAIdcAACHYAAAh2gAAIdsAACIAAAAiJAAAIksAACJvAAAicQAAInMAACJ1AAAidwAAInkAACJ7AAAifAAAIn4AACKLAAAimgAAIpwAACKeAAAioAAAIqIAACKkAAAipgAAIqgAACK3AAAiuQAAIrsAACK9AAAivwAAIsEAACLDAAAixQAAIscAACLnAAAjEgAAIywAACNFAAAjXwAAI38AACOiAAAj4QAAI+MAACPlAAAj5wAAI+kAACPqAAAj6wAAI+wAACPtAAAj7wAAI/EAACPyAAAj8wAAI/UAACP2AAAkNQAAJDcAACQ5AAAkOwAAJD0AACQ+AAAkPwAAJEAAACRBAAAkQwAAJEUAACRGAAAkRwAAJEkAACRKAAAkiQAAJIsAACSNAAAkjwAAJJEAACSSAAAkkwAAJJQAACSVAAAklwAAJJkAACSaAAAkmwAAJJ0AACSeAAAk3QAAJN8AACThAAAk4wAAJOUAACTmAAAk5wAAJOgAACTpAAAk6wAAJO0AACTuAAAk7wAAJPEAACTyAAAk9QAAJTQAACU2AAAlOAAAJToAACU8AAAlPQAAJT4AACU/AAAlQAAAJUIAACVEAAAlRQAAJUYAACVIAAAlSQAAJYgAACWKAAAljAAAJY4AACWQAAAlkQAAJZIAACWTAAAllAAAJZYAACWYAAAlmQAAJZoAACWcAAAlnQAAJdwAACXeAAAl4AAAJeIAACXkAAAl5QAAJeYAACXnAAAl6AAAJeoAACXsAAAl7QAAJe4AACXwAAAl8QAAJfoAACYIAAAmFQAAJiMAACYwAAAmQwAAJloAACZsAAAmtwAAJtoAACb6AAAnGgAAJxwAACceAAAnIAAAJyIAACckAAAnJQAAJyYAACcoAAAnKQAAJysAACcsAAAnLgAAJzAAACcxAAAnMgAAJzQAACc1AAAnOgAAJ0cAACdMAAAnTgAAJ1AAACdVAAAnVwAAJ1kAACdbAAAngAAAJ6QAACfLAAAn7wAAJ/EAACfzAAAn9QAAJ/cAACf5AAAn+wAAJ/wAACf+AAAoCwAAKBwAACgeAAAoIAAAKCIAACgkAAAoJgAAKCgAACgqAAAoLAAAKD0AACg/AAAoQQAAKEMAAChFAAAoRwAAKEkAAChLAAAoTQAAKE8AACiOAAAokAAAKJIAACiUAAAolgAAKJcAACiYAAAomQAAKJoAACicAAAongAAKJ8AACigAAAoogAAKKMAACjiAAAo5AAAKOYAACjoAAAo6gAAKOsAACjsAAAo7QAAKO4AACjwAAAo8gAAKPMAACj0AAAo9gAAKPcAACk2AAApOAAAKToAACk8AAApPgAAKT8AAClAAAApQQAAKUIAAClEAAApRgAAKUcAAClIAAApSgAAKUsAAClYAAApWQAAKVoAAClcAAApmwAAKZ0AACmfAAApoQAAKaMAACmkAAAppQAAKaYAACmnAAApqQAAKasAACmsAAAprQAAKa8AACmwAAAp7wAAKfEAACnzAAAp9QAAKfcAACn4AAAp+QAAKfoAACn7AAAp/QAAKf8AACoAAAAqAQAAKgMAACoEAAAqQwAAKkUAACpHAAAqSQAAKksAACpMAAAqTQAAKk4AACpPAAAqUQAAKlMAACpUAAAqVQAAKlcAACpYAAAqlwAAKpkAACqbAAAqnQAAKp8AACqgAAAqoQAAKqIAACqjAAAqpQAAKqcAACqoAAAqqQAAKqsAACqsAAAq6wAAKu0AACrvAAAq8QAAKvMAACr0AAAq9QAAKvYAACr3AAAq+QAAKvsAACr8AAAq/QAAKv8AACsAAAArJQAAK0kAACtwAAArlAAAK5YAACuYAAArmgAAK5wAACueAAAroAAAK6EAACujAAArsAAAK78AACvBAAArwwAAK8UAACvHAAAryQAAK8sAACvNAAAr3AAAK94AACvgAAAr4gAAK+QAACvmAAAr6AAAK+oAACvsAAAsKwAALC0AACwvAAAsMQAALDMAACw0AAAsNQAALDYAACw3AAAsOQAALDsAACw8AAAsPQAALD8AACxAAAAsfwAALIEAACyDAAAshQAALIcAACyIAAAsiQAALIoAACyLAAAsjQAALI8AACyQAAAskQAALJMAACyUAAAs0wAALNUAACzXAAAs2QAALNsAACzcAAAs3QAALN4AACzfAAAs4QAALOMAACzkAAAs5QAALOcAACzoAAAtJwAALSkAAC0rAAAtLQAALS8AAC0wAAAtMQAALTIAAC0zAAAtNQAALTcAAC04AAAtOQAALTsAAC08AAAtPwAALX4AAC2AAAAtggAALYQAAC2GAAAthwAALYgAAC2JAAAtigAALYwAAC2OAAAtjwAALZAAAC2SAAAtkwAALdIAAC3UAAAt1gAALdgAAC3aAAAt2wAALdwAAC3dAAAt3gAALeAAAC3iAAAt4wAALeQAAC3mAAAt5wAALiYAAC4oAAAuKgAALiwAAC4uAAAuLwAALjAAAC4xAAAuMgAALjQAAC42AAAuNwAALjgAAC46AAAuOwAALkYAAC5PAAAuUAAALlIAAC5bAAAuZgAALnUAAC6AAAAujgAALqMAAC63AAAuzgAALuAAAC8jAAAvRwAAL2sAAC+OAAAvtQAAL9UAAC/8AAAwIwAAMEMAADBnAAAwiwAAMI0AADCPAAAwkQAAMJMAADCVAAAwlwAAMJkAADCbAAAwnQAAMJ8AADChAAAwowAAMKYAADCoAAAwqQAAMK4AADC7AAAwvgAAMMAAADDDAAAwxQAAMMcAADDsAAAxEAAAMTcAADFbAAAxXQAAMV8AADFhAAAxYwAAMWUAADFnAAAxaAAAMWoAADF3AAAxigAAMYwAADGOAAAxkAAAMZIAADGUAAAxlgAAMZgAADGaAAAxnAAAMa8AADGxAAAxswAAMbUAADG3AAAxuQAAMbsAADG9AAAxvwAAMcEAADHDAAAyAgAAMgQAADIGAAAyCAAAMgoAADILAAAyDAAAMg0AADIOAAAyEAAAMhIAADITAAAyFAAAMhYAADIXAAAyIAAAMiEAADIjAAAyYgAAMmQAADJmAAAyaAAAMmoAADJrAAAybAAAMm0AADJuAAAycAAAMnIAADJzAAAydAAAMnYAADJ3AAAytgAAMrgAADK6AAAyvAAAMr4AADK/AAAywAAAMsEAADLCAAAyxAAAMsYAADLHAAAyyAAAMsoAADLLAAAy1AAAMtUAADLXAAAzFgAAMxgAADMaAAAzHAAAMx4AADMfAAAzIAAAMyEAADMiAAAzJAAAMyYAADMnAAAzKAAAMyoAADMrAAAzagAAM2wAADNuAAAzcAAAM3IAADNzAAAzdAAAM3UAADN2AAAzeAAAM3oAADN7AAAzfAAAM34AADN/AAAziAAAM4kAADOLAAAzygAAM8wAADPOAAAz0AAAM9IAADPTAAAz1AAAM9UAADPWAAAz2AAAM9oAADPbAAAz3AAAM94AADPfAAA0HgAANCAAADQiAAA0JAAANCYAADQnAAA0KAAANCkAADQqAAA0LAAANC4AADQvAAA0MAAANDIAADQzAAA0QAAANEEAADRCAAA0RAAANIMAADSFAAA0hwAANIkAADSLAAA0jAAANI0AADSOAAA0jwAANJEAADSTAAA0lAAANJUAADSXAAA0mAAANNcAADTZAAA02wAANN0AADTfAAA04AAANOEAADTiAAA04wAANOUAADTnAAA06AAANOkAADTrAAA07AAANPkAADUGAAA1EQAANRMAADUVAAA1FwAANRkAADUbAAA1JgAANSgAADUrAAA1LgAANTEAADU0AAA1NgAANTwAADVCAAA1VgAANV4AADVmAAA1sQAANdQAADX0AAA2FAAANhYAADYYAAA2GgAANhwAADYeAAA2HwAANiAAADYiAAA2IwAANiUAADYmAAA2KQAANisAADYsAAA2LQAANi8AADYwAAA2NQAANkIAADZHAAA2SQAANksAADZQAAA2UgAANlQAADZWAAA2aQAANo4AADayAAA22QAANv0AADb/AAA3AQAANwMAADcFAAA3BwAANwkAADcKAAA3DAAANxkAADcqAAA3LAAANy4AADcwAAA3MgAANzQAADc2AAA3OAAANzoAADdLAAA3TQAAN08AADdRAAA3UwAAN1UAADdXAAA3WQAAN1sAADddAAA3nAAAN54AADegAAA3ogAAN6QAADelAAA3pgAAN6cAADeoAAA3qgAAN6wAADetAAA3rgAAN7AAADexAAA38AAAN/IAADf0AAA39gAAN/gAADf5AAA3+gAAN/sAADf8AAA3/gAAOAAAADgBAAA4AgAAOAQAADgFAAA4RAAAOEYAADhIAAA4SgAAOEwAADhNAAA4TgAAOE8AADhQAAA4UgAAOFQA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AESjAABEpAAARKYAAESoAABEqQAARKoAAESsAABErQAAROwAAETuAABE8AAARPIAAET0AABE9QAARPYAAET3AABE+AAARPoAAET8AABE/QAARP4AAEUAAABFAQAARQ4AAEUPAABFEAAARRIAAEVRAABFUwAARVUAAEVXAABFWQAARVoAAEVbAABFXAAARV0AAEVfAABFYQAARWIAAEVjAABFZQAARWYAAEWlAABFpwAARakAAEWrAABFrQAARa4AAEWvAABFsAAARbEAAEWzAABFtQAARbYAAEW3AABFuQAARboAAEX5AABF+wAARf0AAEX/AABGAQAARgIAAEYDAABGBAAARgUAAEYHAABGCQAARgoAAEYLAABGDQAARg4AAEZNAABGTwAARlEAAEZTAABGVQAARlYAAEZXAABGWAAARlkAAEZbAABGXQAARl4AAEZfAABGYQAARmIAAEahAABGowAARqUAAEanAABGqQAARqoAAEarAABGrAAARq0AAEavAABGsQAARrIAAEazAABGtQAARrYAAEbbAABG/wAARyYAAEdKAABHTAAAR04AAEdQAABHUgAAR1QAAEdWAABHVwAAR1kAAEdmAABHdQAAR3cAAEd5AABHewAAR30AAEd/AABHgQAAR4MAAEeSAABHlAAAR5YAAEeYAABHmgAAR5wAAEeeAABHoAAAR6IAAEfhAABH4wAAR+UAAEfnAABH6QAAR+oAAEfrAABH7AAAR+0AAEfvAABH8QAAR/IAAEfzAABH9QAAR/YAAEg1AABINwAASDkAAEg7AABIPQAASD4AAEg/AABIQAAASEEAAEhDAABIRQAASEYAAEhHAABISQAASEoAAEiJAABIiwAASI0AAEiPAABIkQAASJIAAEiTAABIlAAASJUAAEiXAABImQAASJoAAEibAABInQAASJ4AAEjdAABI3wAASOEAAEjjAABI5QAASOYAAEjnAABI6AAASOkAAEjrAABI7QAASO4AAEjvAABI8QAASPIAAEkxAABJMwAASTUAAEk3AABJOQAASToAAEk7AABJPAAAST0AAEk/AABJQQAASUIAAElDAABJRQAASUYAAEmFAABJhwAASYkAAEmLAABJjQAASY4AAEmPAABJkAAASZEAAEmTAABJlQAASZYAAEmXAABJmQAASZoAAEnZAABJ2wAASd0AAEnfAABJ4QAASeIAAEnjAABJ5AAASeUAAEnnAABJ6QAASeoAAEnrAABJ7QAASe4AAEo5AABKXAAASnwAAEqcAABKngAASqAAAEqiAABKpAAASqYAAEqnAABKqAAASqoAAEqrAABKrQAASq4AAEqwAABKsgAASrMAAEq0AABKtgAASrcAAEq8AABKyQAASs4AAErQAABK0gAAStcAAErZAABK2wAASt0AAEsCAABLJgAAS00AAEtxAABLcwAAS3UAAEt3AABLeQAAS3sAAEt9AABLfgAAS4AAAEuNAABLngAAS6AAAEuiAABLpAAAS6YAAEuoAABLqgAAS6wAAEuuAABLvwAAS8EAAEvDAABLxQAAS8cAAEvJAABLywAAS80AAEvPAABL0QAATBAAAEwSAABMFAAATBYAAEwYAABMGQAATBoAAEwbAABMHAAATB4AAEwgAABMIQAATCIAAEwkAABMJQAATGQAAExmAABMaAAATGoAAExsAABMbQAATG4AAExvAABMcAAATHIAAEx0AABMdQAATHYAAEx4AABMeQAATLgAAEy6AABMvAAATL4AAEzAAABMwQAATMIAAEzDAABMxAAATMYAAEzIAABMyQAATMoAAEzMAABMzQAATNoAAEzbAABM3AAATN4AAE0dAABNHwAATSEAAE0jAABNJQAATSYAAE0nAABNKAAATSkAAE0rAABNLQAATS4AAE0vAABNMQAATTIAAE1xAABNcwAATXUAAE13AABNeQAATXoAAE17AABNfAAATX0AAE1/AABNgQAATYIAAE2DAABNhQAATYYAAE3FAABNxwAATckAAE3LAABNzQAATc4AAE3PAABN0AAATdEAAE3TAABN1QAATdYAAE3XAABN2QAATdoAAE4ZAABOGwAATh0AAE4fAABOIQAATiIAAE4jAABOJAAATiUAAE4nAABOKQAATioAAE4rAABOLQAATi4AAE5tAABObwAATnEAAE5zAABOdQAATnYAAE53AABOeAAATnkAAE57AABOfQAATn4AAE5/AABOgQAAToIAAE6nAABOywAATvIAAE8WAABPGAAATxoAAE8cAABPHgAATyAAAE8iAABPIwAATyUAAE8yAABPQQAAT0MAAE9FAABPRwAAT0kAAE9LAABPTQAAT08AAE9eAABPYAAAT2IAAE9kAABPZgAAT2gAAE9qAABPbAAAT24AAE+tAABPrwAAT7EAAE+zAABPtQAAT7YAAE+3AABPuAAAT7kAAE+7AABPvQAAT74AAE+/AABPwQAAT8IAAFABAABQAwAAUAUAAFAHAABQCQAAUAoAAFALAABQDAAAUA0AAFAPAABQEQAAUBIAAFATAABQFQAAUBYAAFBVAABQVwAAUFkAAFBbAABQXQAAUF4AAFBfAABQYAAAUGEAAFBjAABQZQAAUGYAAFBnAABQaQAAUGoAAFCpAABQqwAAUK0AAFCvAABQsQAAULIAAFCzAABQtAAAULUAAFC3AABQuQAAULoAAFC7AABQvQAAUL4AAFDBAABRAAAAUQIAAFEEAABRBgAAUQgAAFEJAABRCgAAUQsAAFEMAABRDgAAURAAAFERAABREgAAURQAAFEVAABRVAAAUVYAAFFYAABRWgAAUVwAAFFdAABRXgAAUV8AAFFgAABRYgAAUWQAAFFlAABRZgAAUWgAAFFpAABRqAAAUaoAAFGsAABRrgAAUbAAAFGxAABRsgAAUbMAAFG0AABRtgAAUbgAAFG5AABRugAAUbwAAFG9AABSCAAAUisAAFJLAABSawAAUm0AAFJvAABScQAAUnMAAFJ1AABSdgAAUncAAFJ5AABSegAAUnwAAFJ9AABSfwAAUoEAAFKCAABSgwAAUoUAAFKGAABSiwAAUpgAAFKdAABSnwAAUqEAAFKmAABSqAAAUqsAAFKtAABS0gAAUvYAAFMdAABTQQAAU0MAAFNFAABTRwAAU0kAAFNLAABTTQAAU04AAFNQAABTXQAAU24AAFNwAABTcgAAU3QAAFN2AABTeAAAU3oAAFN8AABTfgAAU48AAFORAABTkwAAU5YAAFOZAABTnAAAU58AAFOiAABTpQAAU6cAAFPmAABT6AAAU+oAAFPsAABT7gAAU+8AAFPwAABT8QAAU/IAAFP0AABT9gAAU/cAAFP4AABT+gAAU/sAAFQ6AABUPAAAVD4AAFRAAABUQgAAVEMAAFREAABURQAAVEYAAFRIAABUSgAAVEsAAFRMAABUTgAAVE8AAFSOAABUkAAAVJMAAFSVAABUlwAAVJgAAFSZAABUmgAAVJsAAFSdAABUnwAAVKAAAFShAABUowAAVKQAAFSxAABUsgAAVLMAAFS1AABU9AAAVPYAAFT4AABU+gAAVPwAAFT9AABU/gAAVP8AAFUAAABVAgAAVQQAAFUFAABVBgAAVQgAAFUJAABVSAAAVUoAAFVMAABVTgAAVVAAAFVRAABVUgAAVVMAAFVUAABVVgAAVVgAAFVZAABVWgAAVVwAAFVdAABVnAAAVZ4AAFWgAABVogAAVaQAAFWlAABVpgAAVacAAFWoAABVqgAAVawAAFWtAABVrgAAVbAAAFWxAABV8AAAVfIAAFX0AABV9gAAVfgAAFX5AABV+gAAVfsAAFX8AABV/gAAVgAAAFYBAABWAgAAVgQAAFYFAABWRAAAVkYAAFZIAABWSgAAVkwAAFZNAABWTgAAVk8AAFZQAABWUgAAVlQAAFZVAABWVgAAVlgAAFZZAABWfgAAVqIAAFbJAABW7QAAVu8AAFbxAABW8wAAVvUAAFb3AABW+QAAVvoAAFb9AABXCgAAVxkAAFcbAABXHQAAVx8AAFchAABXIwAAVyUAAFcnAABXNgAAVzkAAFc8AABXPwAAV0IAAFdFAABXSAAAV0sAAFdNAABXjAAAV44AAFeQAABXkgAAV5UAAFeWAABXlwAAV5gAAFeZAABXmwAAV50AAFeeAABXnwAAV6EAAFeiAABX4QAAV+MAAFflAABX5wAAV+oAAFfrAABX7AAAV+0AAFfuAABX8AAAV/IAAFfzAABX9AAAV/YAAFf3AABYNgAAWDgAAFg6AABYPAAAWD8AAFhAAABYQQAAWEIAAFhDAABYRQAAWEcAAFhIAABYSQAAWEsAAFhMAABYiwAAWI0AAFiPAABYkQAAWJQAAFiVAABYlgAAWJcAAFiYAABYmgAAWJwAAFidAABYngAAWKAAAFihAABY4AAAWOIAAFjkAABY5gAAWOkAAFjqAABY6wAAWOwAAFjtAABY7wAAWPEAAFjyAABY8wAAWPUAAFj2AABZNQAAWTcAAFk5AABZOwAAWT4AAFk/AABZQAAAWUEAAFlCAABZRAAAWUYAAFlHAABZSAAAWUoAAFlLAABZigAAWYwAAFmOAABZkAAAWZMAAFmUAABZlQAAWZYAAFmXAABZmQAAWZsAAFmcAABZnQAAWZ8AAFmgAABZ6wAAWg4AAFouAABaTgAAWlAAAFpSAABaVAAAWlYAAFpYAABaWQAAWloAAFpdAABaXgAAWmAAAFphAABaYwAAWmUAAFpmAABaZwAAWmoAAFprAABadAAAWoEAAFqGAABaiAAAWooAAFqPAABakgAAWpUAAFqXAABavAAAWuAAAFsHAABbKwAAWy4AAFswAABbMgAAWzQAAFs2AABbOAAAWzkAAFs8AABbSQAAW1oAAFtcAABbXgAAW2AAAFtiAABbZAAAW2YAAFtoAABbagAAW3sAAFt+AABbgQAAW4QAAFuHAABbigAAW40AAFuQAABbkwAAW5UAAFvUAABb1gAAW9gAAFvaAABb3QAAW94AAFvfAABb4AAAW+EAAFvjAABb5QAAW+YAAFvnAABb6QAAW+oAAFwpAABcKwAAXC0AAFwvAABcMgAAXDMAAFw0AABcNQAAXDYAAFw4AABcOgAAXDsAAFw8AABcPgAAXD8AAFx+AABcgAAAXIMAAFyFAABciAAAXIkAAFyKAABciwAAXIwAAFyOAABckAAAXJEAAFySAABclAAAXJUAAFyiAABcowAAXKQAAFymAABc5QAAXOcAAFzpAABc6wAAXO4AAFzvAABc8AAAXPEAAFzyAABc9AAAXPYAAFz3AABc+AAAXPoAAFz7AABdOgAAXTwAAF0+AABdQAAAXUMAAF1EAABdRQAAXUYAAF1HAABdSQAAXUsAAF1MAABdTQAAXU8AAF1QAABdjwAAXZEAAF2TAABdlQAAXZgAAF2ZAABdmgAAXZsAAF2cAABdngAAXaAAAF2hAABdogAAXaQAAF2lAABd5AAAXeYAAF3oAABd6gAAXe0AAF3uAABd7wAAXfAAAF3xAABd8wAAXfUAAF32AABd9wAAXfkAAF36AABeOQAAXjsAAF49AABePwAAXkIAAF5DAABeRAAAXkUAAF5GAABeSAAAXkoAAF5LAABeTAAAXk4AAF5PAABedAAAXpgAAF6/AABe4wAAXuYAAF7oAABe6gAAXuwAAF7uAABe8AAAXvEAAF70AABfAQAAXxAAAF8SAABfFAAAXxYAAF8YAABfGgAAXxwAAF8eAABfLQAAXzAAAF8zAABfNgAAXzkAAF88AABfPwAAX0IAAF9EAABfgwAAX4UAAF+IAABfigAAX40AAF+OAABfjwAAX5AAAF+RAABfkwAAX5UAAF+WAABflwAAX5kAAF+aAABfnAAAX9sAAF/dAABf3wAAX+EAAF/kAABf5QAAX+YAAF/nAABf6AAAX+oAAF/sAABf7QAAX+4AAF/wAABf8QAAYDAAAGAyAABgNAAAYDYAAGA5AABgOgAAYDsAAGA8AABgPQAAYD8AAGBBAABgQgAAYEMAAGBFAABgRgAAYIUAAGCHAABgigAAYIwAAGCPAABgkAAAYJEAAGCSAABgkwAAYJUAAGCXAABgmAAAYJkAAGCbAABgnAAAYJ4AAGDdAABg3wAAYOEAAGDjAABg5gAAYOcAAGDoAABg6QAAYOoAAGDsAABg7gAAYO8AAGDwAABg8gAAYPMAAGEyAABhNAAAYTYAAGE4AABhOwAAYTwAAGE9AABhPgAAYT8AAGFBAABhQwAAYUQAAGFFAABhRwAAYUgAAGGHAABhiQAAYYsAAGGNAABhkAAAYZEAAGGSAABhkwAAYZQAAGGWAABhmAAAYZkAAGGaAABhnAAAYZ0AAGHoAABiCwAAYisAAGJLAABiTQAAYk8AAGJRAABiUwAAYlUAAGJWAABiVwAAYloAAGJbAABiXQAAYl4AAGJgAABiYgAAYmMAAGJkAABiZwAAYmgAAGJxAABifgAAYoMAAGKFAABihwAAYowAAGKPAABikgAAYpQAAGK5AABi3QAAYwQAAGMoAABjKwAAYy0AAGMvAABjMQAAYzMAAGM1AABjNgAAYzkAAGNGAABjVwAAY1kAAGNbAABjXQAAY18AAGNhAABjYwAAY2UAAGNnAABjeAAAY3sAAGN+AABjgQAAY4QAAGOHAABjigAAY40AAGOQAABjkgAAY9EAAGPTAABj1QAAY9cAAGPaAABj2wAAY9wAAGPdAABj3gAAY+AAAGPiAABj4wAAY+QAAGPmAABj5wAAZCYAAGQoAABkKgAAZCwAAGQvAABkMAAAZDEAAGQyAABkMwAAZDUAAGQ3AABkOAAAZDkAAGQ7AABkPAAAZHsAAGR9AABkgAAAZIIAAGSFAABkhgAAZIcAAGSIAABkiQAAZIsAAGSNAABkjgAAZI8AAGSRAABkkgAAZJ8AAGSgAABkoQAAZKMAAGTiAABk5AAAZOYAAGToAABk6wAAZOwAAGTtAABk7gAAZO8AAGTxAABk8wAAZPQAAGT1AABk9wAAZPgAAGU3AABlOQAAZTsAAGU9AABlQAAAZUEAAGVCAABlQwAAZUQAAGVGAABlSAAAZUkAAGVKAABlTAAAZU0AAGWMAABljgAAZZAAAGWSAABllQAAZZYAAGWXAABlmAAAZZkAAGWbAABlnQAAZZ4AAGWfAABloQAAZaIAAGXhAABl4wAAZeUAAGXnAABl6gAAZesAAGXsAABl7QAAZe4AAGXwAABl8gAAZfMAAGX0AABl9gAAZfcAAGY2AABmOAAAZjoAAGY8AABmPwAAZkAAAGZBAABmQgAAZkMAAGZFAABmRwAAZkgAAGZJAABmSwAAZkwAAGZxAABmlQAAZrwAAGbgAABm4wAAZuUAAGbnAABm6QAAZusAAGbtAABm7gAAZvEAAGb+AABnDQAAZw8AAGcRAABnEwAAZxUAAGcXAABnGQAAZxsAAGcqAABnLQAAZzAAAGczAABnNgAAZzkAAGc8AABnPwAAZ0EAAGeAAABnggAAZ4QAAGeGAABniQAAZ4oAAGeLAABnjAAAZ40AAGePAABnkQAAZ5IAAGeTAABnlQAAZ5YAAGfVAABn1wAAZ9kAAGfbAABn3gAAZ98AAGfgAABn4QAAZ+IAAGfkAABn5gAAZ+cAAGfoAABn6gAAZ+sAAGgqAABoLAAAaC4AAGgwAABoMwAAaDQAAGg1AABoNgAAaDcAAGg5AABoOwAAaDwAAGg9AABoPwAAaEAAAGh/AABogQAAaIMAAGiFAABoiAAAaIkAAGiKAABoiwAAaIwAAGiOAABokAAAaJEAAGiSAABolAAAaJUAAGjUAABo1gAAaNgAAGjaAABo3QAAaN4AAGjfAABo4AAAaOEAAGjjAABo5QAAaOYAAGjnAABo6QAAaOoAAGkpAABpKwAAaS0AAGkvAABpMgAAaTMAAGk0AABpNQAAaTYAAGk4AABpOgAAaTsAAGk8AABpPgAAaT8AAGl+AABpgAAAaYIAAGmEAABphwAAaYgAAGmJAABpigAAaYsAAGmNAABpjwAAaZAAAGmRAABpkwAAaZQAAGmdAABpngAAaaAAAGnfAABp4QAAaeMAAGnlAABp5wAAaegAAGnpAABp6gAAaesAAGntAABp7wAAafAAAGnxAABp8wAAafQAAGozAABqNQAAajgAAGo6AABqPAAAaj0AAGo+AABqPwAAakAAAGpCAABqRAAAakUAAGpGAABqSAAAakkAAGqIAABqigAAao0AAGqPAABqkQAAapIAAGqTAABqlAAAapUAAGqXAABqmQAAapoAAGqbAABqnQAAap4AAGqgAABq3wAAauEAAGrkAABq5gAAaugAAGrpAABq6gAAausAAGrsAABq7gAAavAAAGrxAABq8gAAavQAAGr1AABrNAAAazYAAGs4AABrOgAAazwAAGs9AABrPgAAaz8AAGtAAABrQgAAa0QAAGtFAABrRgAAa0gAAGtJAABrUgAAa2UAAGtyAABrhQAAa5IAAGulAABrvAAAa84AAGwZAABsPAAAbFwAAGx8AABsfgAAbIAAAGyCAABshAAAbIYAAGyHAABsiAAAbIsAAGyMAABsjgAAbI8AAGySAABslAAAbJUAAGyWAABsmQAAbJoAAGyfAABsrAAAbLEAAGyzAABstQAAbLoAAGy9AABswAAAbMIAAGznAABtCwAAbTIAAG1WAABtWQAAbVsAAG1dAABtXwAAbWEAAG1jAABtZAAAbWcAAG10AABthQAAbYcAAG2JAABtiwAAbY0AAG2PAABtkQAAbZMAAG2VAABtpgAAbakAAG2sAABtrwAAbbIAAG21AABtuAAAbbsAAG2+AABtwAAAbf8AAG4BAABuAwAAbgUAAG4IAABuCQAAbgoAAG4LAABuDAAAbg4AAG4QAABuEQAAbhIAAG4UAABuFQAAblQAAG5WAABuWAAAbloAAG5dAABuXgAAbl8AAG5gAABuYQAAbmMAAG5lAABuZgAAbmcAAG5pAABuagAAbqkAAG6rAABurgAAbrAAAG6zAAButAAAbrUAAG62AAButwAAbrkAAG67AABuvAAAbr0AAG6/AABuwAAAbs0AAG7OAABuzwAAbtEAAG8QAABvEgAAbxQAAG8WAABvGQAAbxoAAG8bAABvHAAAbx0AAG8fAABvIQAAbyIAAG8jAABvJQAAbyYAAG9lAABvZwAAb2kAAG9rAABvbgAAb28AAG9wAABvcQAAb3IAAG90AABvdgAAb3cAAG94AABvegAAb3sAAG+6AABvvAAAb74AAG/AAABvwwAAb8QAAG/FAABvxgAAb8cAAG/JAABvywAAb8wAAG/NAABvzwAAb9AAAHAPAABwEQAAcBMAAHAVAABwGAAAcBkAAHAaAABwGwAAcBwAAHAeAABwIAAAcCEAAHAiAABwJAAAcCUAAHBkAABwZgAAcGgAAHBqAABwbQAAcG4AAHBvAABwcAAAcHEAAHBzAABwdQAAcHYAAHB3AABweQAAcHoAAHCfAABwwwAAcOoAAHEOAABxEQAAcRMAAHEVAABxFwAAcRkAAHEbAABxHAAAcR8AAHEsAABxOwAAcT0AAHE/AABxQQAAcUMAAHFFAABxRwAAcUoAAHFZAABxXAAAcV8AAHFiAABxZQAAcWgAAHFrAABxbgAAcXAAAHGNAABxzAAAcc4AAHHRAABx0wAAcdYAAHHXAABx2AAAcdkAAHHaAABx3AAAcd4AAHHfAABx4AAAceIAAHHjAAByIgAAciQAAHInAAByKQAAciwAAHItAAByLgAAci8AAHIwAAByMgAAcjQAAHI1AAByNgAAcjgAAHI5AAByeAAAcnoAAHJ9AAByfwAAcoIAAHKDAAByhAAAcoUAAHKGAAByiAAAcooAAHKLAAByjAAAco4AAHKPAAByzgAActAAAHLTAABy1QAActgAAHLZAABy2gAActsAAHLcAABy3gAAcuAAAHLhAABy4gAAcuQAAHLlAABzKAAAc0wAAHNwAABzkwAAc7oAAHPaAAB0AQAAdCgAAHRIAAB0bAAAdJAAAHSSAAB0lQAAdJcAAHSZAAB0mwAAdJ4AAHSgAAB0ogAAdKQAAHSmAAB0qAAAdKoAAHStAAB0sAAAdLEAAHS6AAB0xwAAdMoAAHTMAAB0zwAAdNIAAHTUAAB0+QAAdR0AAHVEAAB1aAAAdWsAAHVtAAB1bwAAdXEAAHVzAAB1dQAAdXYAAHV5AAB1hgAAdZkAAHWbAAB1nQAAdZ8AAHWhAAB1owAAdaUAAHWnAAB1qQAAdasAAHW+AAB1wQAAdcQAAHXHAAB1ygAAdc0AAHXQAAB10wAAddYAAHXZAAB12wAAdhoAAHYcAAB2HwAAdiEAAHYkAAB2JQAAdiYAAHYnAAB2KAAAdioAAHYsAAB2LQAAdi4AAHYwAAB2MQAAdjoAAHY7AAB2PQAAdnwAAHZ+AAB2gAAAdoIAAHaFAAB2hgAAdocAAHaIAAB2iQAAdosAAHaNAAB2jgAAdo8AAHaRAAB2kgAAdtEAAHbTAAB21gAAdtgAAHbbAAB23AAAdt0AAHbeAAB23wAAduEAAHbjAAB25AAAduUAAHbnAAB26AAAdvEAAHb0AAB29wAAdvkAAHcCAAB3BQAAdwcAAHcJAAB3SAAAd0oAAHdMAAB3TgAAd1EAAHdSAAB3UwAAd1QAAHdVAAB3VwAAd1kAAHdaAAB3WwAAd10AAHdeAAB3nQAAd58AAHeiAAB3pAAAd6cAAHeoAAB3qQAAd6oAAHerAAB3rQAAd68AAHewAAB3sQAAd7MAAHe0AAB3vQAAd74AAHfAAAB3/wAAeAEAAHgDAAB4BQAAeAgAAHgJAAB4CgAAeAsAAHgMAAB4DgAAeBAAAHgRAAB4EgAAeBQAAHgVAAB4VAAAeFYAAHhZAAB4WwAAeF4AAHhfAAB4YAAAeGEAAHhiAAB4ZAAAeGYAAHhnAAB4aAAAeGoAAHhrAAB4eAAAeHkAAHh6AAB4fAAAeLsAAHi9AAB4vwAAeMEAAHjEAAB4xQAAeMYAAHjHAAB4yAAAeMoAAHjMAAB4zQAAeM4AAHjQAAB40QAAeRAAAHkSAAB5FAAAeRYAAHkZAAB5GgAAeRsAAHkcAAB5HQAAeR8AAHkhAAB5IgAAeSMAAHklAAB5JgAAeTMAAHleAAB5YQAAeWMAAHlmAAB5aQAAeWsAAHluAAB5cQAAeXQAAHl3AAB5egAAeX0AAHmAAAB5gwAAeYYAAHmJAAB5jAAAeY8AAHmSAAB5lQAAeZgAAHnDAAB5xgAAeckAAHnMAAB5zwAAedIAAHnVAAB52AAAedsAAHneAAB54QAAeeQAAHnnAAB56gAAee0AAHnwAAB58wAAefYAAHn5AAB5/AAAef8AAHoBAAB6DwAAeh0AAHorAAB6OgAAekEAAHpGAAB6XAAAemIAAHpvAAB6dQAAen8AAHqOAAB6lwAAeqsAAHq+AAB60AAAet4AAHrqAAB7NQAAe1gAAHt4AAB7mAAAe5oAAHucAAB7ngAAe6AAAHujAAB7pAAAe6UAAHuoAAB7qQAAe6sAAHusAAB7rgAAe7EAAHuyAAB7swAAe7YAAHu3AAB7vAAAe8kAAHvOAAB70AAAe9IAAHvXAAB72gAAe90AAHvfAAB8BAAAfCgAAHxPAAB8cwAAfHYAAHx4AAB8egAAfHwAAHx+AAB8gAAAfIEAAHyEAAB8kQAAfKIAAHykAAB8pgAAfKgAAHyqAAB8rAAAfK4AAHywAAB8sgAAfMMAAHzGAAB8yQAAfMwAAHzPAAB80gAAfNUAAHzYAAB82wAAfN0AAH0cAAB9HgAAfSAAAH0iAAB9JQAAfSYAAH0nAAB9KAAAfSkAAH0rAAB9LQAAfS4AAH0vAAB9MQAAfTIAAH1xAAB9cwAAfXUAAH13AAB9egAAfXsAAH18AAB9fQAAfX4AAH2AAAB9ggAAfYMAAH2EAAB9hgAAfYcAAH3GAAB9yAAAfcsAAH3NAAB90AAAfdEAAH3SAAB90wAAfdQAAH3WAAB92AAAfdkAAH3aAAB93AAAfd0AAH3qAAB96wAAfewAAH3uAAB+LQAAfi8AAH4xAAB+MwAAfjYAAH43AAB+OAAAfjkAAH46AAB+PAAAfj4AAH4/AAB+QAAAfkIAAH5DAAB+ggAAfoQAAH6GAAB+iAAAfosAAH6MAAB+jQAAfo4AAH6PAAB+kQAAfpMAAH6UAAB+lQAAfpcAAH6YAAB+1wAAftkAAH7bAAB+3QAAfuAAAH7hAAB+4gAAfuMAAH7kAAB+5gAAfugAAH7pAAB+6gAAfuwAAH7tAAB/LAAAfy4AAH8wAAB/MgAAfzUAAH82AAB/NwAAfzgAAH85AAB/OwAAfz0AAH8+AAB/PwAAf0EAAH9CAAB/gQAAf4MAAH+FAAB/hwAAf4oAAH+LAAB/jAAAf40AAH+OAAB/kAAAf5IAAH+TAAB/lAAAf5YAAH+XAAB/vAAAf+AAAIAHAACAKwAAgC4AAIAwAACAMgAAgDQAAIA2AACAOAAAgDkAAIA8AACASQAAgFgAAIBaAACAXAAAgF4AAIBgAACAYgAAgGQAAIBmAACAdQAAgHgAAIB7AACAfgAAgIEAAICEAACAhwAAgIoAAICMAACAywAAgM0AAIDQAACA0gAAgNUAAIDWAACA1wAAgNgAAIDZAACA2wAAgN0AAIDeAACA3wAAgOEAAIDiAACBIQAAgSMAAIElAACBJwAAgSoAAIErAACBLAAAgS0AAIEuAACBMAAAgTIAAIEzAACBNAAAgTYAAIE3AACBdgAAgXgAAIF6AACBfAAAgX8AAIGAAACBgQAAgYIAAIGDAACBhQAAgYcAAIGIAACBiQAAgYsAAIGMAACBywAAgc0AAIHQAACB0gAAgdUAAIHWAACB1wAAgdgAAIHZAACB2wAAgd0AAIHeAACB3wAAgeEAAIHiAACCIQAAgiMAAIIlAACCJwAAgioAAIIrAACCLAAAgi0AAIIuAACCMAAAgjIAAIIzAACCNAAAgjYAAII3AACCdgAAgngAAIJ6AACCfAAAgn8AAIKAAACCgQAAgoIAAIKDAACChQAAgocAAIKIAACCiQAAgosAAIKMAACCywAAgs0AAILPAACC0QAAgtQAAILVAACC1gAAgtcAAILYAACC2gAAgtwAAILdAACC3gAAguAAAILhAACDLAAAg08AAINvAACDjwAAg5EAAIOTAACDlQAAg5cAAIOaAACDmwAAg5wAAIOfAACDoAAAg6IAAIOjAACDpQAAg6cAAIOoAACDqQAAg6wAAIOtAACDsgAAg78AAIPEAACDxgAAg8gAAIPNAACD0AAAg9MAAIPVAACD+gAAhB4AAIRFAACEaQAAhGwAAIRuAACEcAAAhHIAAIR0AACEdgAAhHcAAIR6AACEhwAAhJgAAISaAACEnAAAhJ4AAISgAACEogAAhKQAAISmAACEqAAAhLkAAIS8AACEvwAAhMIAAITFAACEyAAAhMsAAITOAACE0QAAhNMAAIUSAACFFAAAhRYAAIUYAACFGwAAhRwAAIUdAACFHgAAhR8AAIUhAACFIwAAhSQAAIUlAACFJwAAhSgAAIVnAACFaQAAhWsAAIVtAACFcAAAhXEAAIVyAACFcwAAhXQAAIV2AACFeAAAhXkAAIV6AACFfAAAhX0AAIW8AACFvgAAhcEAAIXDAACFxgAAhccAAIXIAACFyQAAhcoAAIXMAACFzgAAhc8AAIXQAACF0gAAhdMAAIXgAACF4QAAheIAAIXkAACGIwAAhiUAAIYnAACGKQAAhiwAAIYtAACGLgAAhi8AAIYwAACGMgAAhjQAAIY1AACGNgAAhjgAAIY5AACGeAAAhnoAAIZ8AACGfgAAhoEAAIaCAACGgwAAhoQAAIaFAACGhwAAhokAAIaKAACGiwAAho0AAIaOAACGzQAAhs8AAIbRAACG0wAAhtYAAIbXAACG2AAAhtkAAIbaAACG3AAAht4AAIbfAACG4AAAhuIAAIbjAACHIgAAhyQAAIcmAACHKAAAhysAAIcsAACHLQAAhy4AAIcvAACHMQAAhzMAAIc0AACHNQAAhzcAAIc4AACHdwAAh3kAAId7AACHfQAAh4AAAIeBAACHggAAh4MAAIeEAACHhgAAh4gAAIeJAACHigAAh4wAAIeNAACHsgAAh9YAAIf9AACIIQAAiCQAAIgmAACIKAAAiCoAAIgsAACILgAAiC8AAIgyAACIPwAAiE4AAIhQAACIUgAAiFQAAIhWAACIWAAAiFoAAIhcAACIawAAiG4AAIhxAACIdAAAiHcAAIh6AACIfQAAiIAAAIiCAACIwQAAiMMAAIjFAACIxwAAiMoAAIjLAACIzAAAiM0AAIjOAACI0AAAiNIAAIjTAACI1AAAiNYAAIjXAACJFgAAiRgAAIkaAACJHAAAiR8AAIkgAACJIQAAiSIAAIkjAACJJQAAiScAAIkoAACJKQAAiSsAAIksAACJawAAiW0AAIlvAACJcQAAiXQAAIl1AACJdgAAiXcAAIl4AACJegAAiXwAAIl9AACJfgAAiYAAAImBAACJwAAAicIAAInEAACJxgAAickAAInKAACJywAAicwAAInNAACJzwAAidEAAInSAACJ0wAAidUAAInWAACKFQAAihcAAIoZAACKGwAAih4AAIofAACKIAAAiiEAAIoiAACKJAAAiiYAAIonAACKKAAAiioAAIorAACKagAAimwAAIpuAACKcAAAinMAAIp0AACKdQAAinYAAIp3AACKeQAAinsAAIp8AACKfQAAin8AAIqAAACKvwAAisEAAIrDAACKxQAAisgAAIrJAACKygAAissAAIrMAACKzgAAitAAAIrRAACK0gAAitQAAIrVAACLIAAAi0MAAItjAACLgwAAi4UAAIuHAACLiQAAi4sAAIuOAACLjwAAi5AAAIuTAACLlAAAi5YAAIuXAACLmQAAi5wAAIudAACLngAAi6EAAIuiAACLpwAAi7QAAIu5AACLuwAAi70AAIvCAACLxQAAi8gAAIvKAACL7wAAjBMAAIw6AACMXgAAjGEAAIxjAACMZQAAjGcAAIxpAACMawAAjGwAAIxvAACMfAAAjI0AAIyPAACMkQAAjJMAAIyVAACMlwAAjJkAAIybAACMnQAAjK4AAIyxAACMtAAAjLcAAIy6AACMvQAAjMAAAIzDAACMxgAAjMgAAI0HAACNCQAAjQsAAI0NAACNEAAAjREAAI0SAACNEwAAjRQAAI0WAACNGAAAjRkAAI0aAACNHAAAjR0AAI1cAACNXgAAjWAAAI1iAACNZQAAjWYAAI1nAACNaAAAjWkAAI1rAACNbQAAjW4AAI1vAACNcQAAjXIAAI2xAACNswAAjbYAAI24AACNuwAAjbwAAI29AACNvgAAjb8AAI3BAACNwwAAjcQAAI3FAACNxwAAjcgAAI3VAACN1gAAjdcAAI3ZAACOGAAAjhoAAI4cAACOHgAAjiEAAI4iAACOIwAAjiQAAI4lAACOJwAAjikAAI4qAACOKwAAji0AAI4uAACObQAAjm8AAI5xAACOcwAAjnYAAI53AACOeAAAjnkAAI56AACOfAAAjn4AAI5/AACOgAAAjoIAAI6DAACOwgAAjsQAAI7GAACOyAAAjssAAI7MAACOzQAAjs4AAI7PAACO0QAAjtMAAI7UAACO1QAAjtcAAI7YAACPFwAAjxkAAI8bAACPHQAAjyAAAI8hAACPIgAAjyMAAI8kAACPJgAAjygAAI8pAACPKgAAjywAAI8tAACPbAAAj24AAI9wAACPcgAAj3UAAI92AACPdwAAj3gAAI95AACPewAAj30AAI9+AACPfwAAj4EAAI+CAACPpwAAj8sAAI/yAACQFgAAkBkAAJAbAACQHQAAkB8AAJAhAACQIwAAkCQAAJAnAACQNAAAkEMAAJBFAACQRwAAkEkAAJBLAACQTQAAkE8AAJBRAACQYAAAkGMAAJBmAACQaQAAkGwAAJBvAACQcgAAkHUAAJB3AACQtgAAkLgAAJC6AACQvAAAkL8AAJDAAACQwQAAkMIAAJDDAACQxQAAkMcAAJDIAACQyQAAkMsAAJDMAACRCwAAkQ0AAJEPAACREQAAkRQAAJEVAACRFgAAkRcAAJEYAACRGgAAkRwAAJEdAACRHgAAkSAAAJEhAACRYAAAkWIAAJFkAACRZgAAkWkAAJFqAACRawAAkWwAAJFtAACRbwAAkXEAAJFyAACRcwAAkXUAAJF2AACRtQAAkbcAAJG5AACRuwAAkb4AAJG/AACRwAAAkcEAAJHCAACRxAAAkcYAAJHHAACRyAAAkcoAAJHLAACSCgAAkgwAAJIOAACSEAAAkhMAAJIUAACSFQAAkhYAAJIXAACSGQAAkhsAAJIcAACSHQAAkh8AAJIgAACSXwAAkmEAAJJjAACSZQAAkmgAAJJpAACSagAAkmsAAJJsAACSbgAAknAAAJJxAACScgAAknQAAJJ1AACStAAAkrYAAJK4AACSugAAkr0AAJK+AACSvwAAksAAAJLBAACSwwAAksUAAJLGAACSxwAAkskAAJLKAACTFQAAkzgAAJNYAACTeAAAk3oAAJN8AACTfgAAk4AAAJODAACThAAAk4UAAJOIAACTiQAAk4sAAJOMAACTjgAAk5EAAJOSAACTkwAAk5YAAJOXAACTnAAAk6kAAJOuAACTsAAAk7IAAJO3AACTugAAk70AAJO/AACT5AAAlAgAAJQvAACUUwAAlFYAAJRYAACUWgAAlFwAAJReAACUYAAAlGEAAJRkAACUcQAAlIIAAJSEAACUhgAAlIgAAJSKAACUjAAAlI4AAJSQAACUkgAAlKMAAJSmAACUqQAAlKwAAJSvAACUsgAAlLUAAJS4AACUuwAAlL0AAJT8AACU/gAAlQAAAJUCAACVBQAAlQYAAJUHAACVCAAAlQkAAJULAACVDQAAlQ4AAJUPAACVEQAAlRIAAJVRAACVUwAAlVUAAJVXAACVWgAAlVsAAJVcAACVXQAAlV4AAJVgAACVYgAAlWMAAJVkAACVZgAAlWcAAJWmAACVqAAAlasAAJWtAACVsAAAlbEAAJWyAACVswAAlbQAAJW2AACVuAAAlbkAAJW6AACVvAAAlb0AAJXKAACVywAAlcwAAJXOAACWDQAAlg8AAJYRAACWEwAAlhYAAJYXAACWGAAAlhkAAJYaAACWHAAAlh4AAJYfAACWIAAAliIAAJYjAACWYgAAlmQAAJZmAACWaAAAlmsAAJZsAACWbQAAlm4AAJZvAACWcQAAlnMAAJZ0AACWdQAAlncAAJZ4AACWtwAAlrkAAJa7AACWvQAAlsAAAJbBAACWwgAAlsMAAJbEAACWxgAAlsgAAJbJAACWygAAlswAAJbNAACXDAAAlw4AAJcQAACXEgAAlxUAAJcWAACXFwAAlxgAAJcZAACXGwAAlx0AAJceAACXHwAAlyEAAJciAACXYQAAl2MAAJdlAACXZwAAl2oAAJdrAACXbAAAl20AAJduAACXcAAAl3IAAJdzAACXdAAAl3YAAJd3AACXnAAAl8AAAJfnAACYCwAAmA4AAJgQAACYEgAAmBQAAJgWAACYGAAAmBkAAJgcAACYKQAAmDgAAJg6AACYPAAAmD4AAJhAAACYQgAAmEQAAJhGAACYVQAAmFgAAJhbAACYXgAAmGEAAJhkAACYZwAAmGoAAJhsAACYqwAAmK0AAJiwAACYsgAAmLUAAJi2AACYtwAAmLgAAJi5AACYuwAAmL0AAJi+AACYvwAAmMEAAJjCAACYxQAAmQQAAJkGAACZCAAAmQoAAJkNAACZDgAAmQ8AAJkQAACZEQAAmRMAAJkVAACZFgAAmRcAAJkZAACZGgAAmVkAAJlbAACZXQAAmV8AAJliAACZYwAAmWQAAJllAACZZgAAmWgAAJlqAACZawAAmWwAAJluAACZbwAAma4AAJmwAACZswAAmbUAAJm4AACZuQAAmboAAJm7AACZvAAAmb4AAJnAAACZwQAAmcIAAJnEAACZxQAAmcgAAJoHAACaCQAAmgsAAJoNAACaEAAAmhEAAJoSAACaEwAAmhQAAJoWAACaGAAAmhkAAJoaAACaHAAAmh0AAJpcAACaXgAAmmAAAJpiAACaZQAAmmYAAJpnAACaaAAAmmkAAJprAACabQAAmm4AAJpvAACacQAAmnIAAJqxAACaswAAmrUAAJq3AACaugAAmrsAAJq8AACavQAAmr4AAJrAAACawgAAmsMAAJrEAACaxgAAmscAAJsSAACbNQAAm1UAAJt1AACbdwAAm3kAAJt7AACbfQAAm4AAAJuBAACbggAAm4UAAJuGAACbiAAAm4kAAJuLAACbjQAAm44AAJuPAACbkgAAm5MAAJuYAACbpQAAm6oAAJusAACbrgAAm7MAAJu2AACbuQAAm7sAAJvgAACcBAAAnCsAAJxPAACcUgAAnFQAAJxWAACcWAAAnFoAAJxcAACcXQAAnGAAAJxtAACcfgAAnIAAAJyCAACchAAAnIYAAJyIAACcigAAnIwAAJyOAACcnwAAnKIAAJylAACcqAAAnKsAAJyuAACcsQAAnLQAAJy3AACcuQAAnPgAAJz6AACc/AAAnP4AAJ0BAACdAgAAnQMAAJ0EAACdBQAAnQcAAJ0JAACdCgAAnQsAAJ0NAACdDgAAnU0AAJ1PAACdUQAAnVMAAJ1WAACdVwAAnVgAAJ1ZAACdWgAAnVwAAJ1eAACdXwAAnWAAAJ1iAACdYwAAnaIAAJ2kAACdpwAAnakAAJ2sAACdrQAAna4AAJ2vAACdsAAAnbIAAJ20AACdtQAAnbYAAJ24AACduQAAncYAAJ3HAACdyAAAncoAAJ4JAACeCwAAng0AAJ4PAACeEgAAnhMAAJ4UAACeFQAAnhYAAJ4YAACeGgAAnhsAAJ4cAACeHgAAnh8AAJ5eAACeYAAAnmIAAJ5kAACeZwAAnmgAAJ5pAACeagAAnmsAAJ5tAACebwAAnnAAAJ5xAACecwAAnnQAAJ6zAACetQAAnrcAAJ65AACevAAAnr0AAJ6+AACevwAAnsAAAJ7CAACexAAAnsUAAJ7GAACeyAAAnskAAJ8IAACfCgAAnwwAAJ8OAACfEQAAnxIAAJ8TAACfFAAAnxUAAJ8XAACfGQAAnxoAAJ8bAACfHQAAnx4AAJ9dAACfXwAAn2EAAJ9jAACfZgAAn2cAAJ9oAACfaQAAn2oAAJ9sAACfbgAAn28AAJ9wAACfcgAAn3MAAJ+YAACfvAAAn+MAAKAHAACgCgAAoAwAAKAOAACgEAAAoBIAAKAUAACgFQAAoBgAAKAlAACgNAAAoDYAAKA4AACgOgAAoDwAAKA+AACgQAAAoEIAAKBRAACgVAAAoFcAAKBaAACgXQAAoGAAAKBjAACgZgAAoGgAAKCnAACgqQAAoKsAAKCtAACgsAAAoLEAAKCyAACgswAAoLQAAKC2AACguAAAoLkAAKC6AACgvAAAoL0AAKD8AACg/gAAoQAAAKECAAChBQAAoQYAAKEHAAChCAAAoQkAAKELAAChDQAAoQ4AAKEPAAChEQAAoRIAAKFRAAChUwAAoVUAAKFXAAChWgAAoVsAAKFcAAChXQAAoV4AAKFgAAChYgAAoWMAAKFkAAChZgAAoWcAAKGmAAChqAAAoaoAAKGsAAChrwAAobAAAKGxAAChsgAAobMAAKG1AAChtwAAobgAAKG5AAChuwAAobwAAKH7AACh/QAAof8AAKIBAACiBAAAogUAAKIGAACiBwAAoggAAKIKAACiDAAAog0AAKIOAACiEAAAohEAAKJQAACiUgAAolQAAKJWAACiWQAAoloAAKJbAACiXAAAol0AAKJfAACiYQAAomIAAKJjAACiZQAAomYAAKKlAACipwAAoqkAAKKrAACirgAAoq8AAKKwAACisQAAorIAAKK0AACitgAAorcAAKK4AACiugAAorsAAKMGAACjKQAAo0kAAKNpAACjawAAo20AAKNvAACjcQAAo3QAAKN1AACjdgAAo3kAAKN6AACjfAAAo30AAKN/AACjggAAo4MAAKOEAACjhwAAo4gAAKORAACjngAAo6MAAKOlAACjpwAAo6wAAKOvAACjsgAAo7QAAKPZAACj/QAApCQAAKRIAACkSwAApE0AAKRPAACkUQAApFMAAKRVAACkVgAApFkAAKRmAACkdwAApHkAAKR7AACkfQAApH8AAKSBAACkgwAApIUAAKSHAACkmAAApJsAAKSeAACkoQAApKQAAKSnAACkqgAApK0AAKSwAACksgAApPEAAKTzAACk9QAApPcAAKT6AACk+wAApPwAAKT9AACk/gAApQAAAKUCAAClAwAApQQAAKUGAAClBwAApUYAAKVIAAClSgAApUwAAKVPAAClUAAApVEAAKVSAAClUwAApVUAAKVXAAClWAAApVkAAKVbAAClXAAApZsAAKWdAACloAAApaIAAKWlAAClpgAApacAAKWoAAClqQAApasAAKWtAAClrgAApa8AAKWxAAClsgAApb8AAKXAAAClwQAApcMAAKYCAACmBAAApgYAAKYIAACmCwAApgwAAKYNAACmDgAApg8AAKYRAACmEwAAphQAAKYVAACmFwAAphgAAKZXAACmWQAAplsAAKZdAACmYAAApmEAAKZiAACmYwAApmQAAKZmAACmaAAApmkAAKZqAACmbAAApm0AAKasAACmrgAAprAAAKayAACmtQAAprYAAKa3AACmuAAAprkAAKa7AACmvQAApr4AAKa/AACmwQAApsIAAKcBAACnAwAApwUAAKcHAACnCgAApwsAAKcMAACnDQAApw4AAKcQAACnEgAApxMAAKcUAACnFgAApxcAAKdWAACnWAAAp1oAAKdcAACnXwAAp2AAAKdhAACnYgAAp2MAAKdlAACnZwAAp2gAAKdpAACnawAAp2wAAKeRAACntQAAp9wAAKgAAACoAwAAqAUAAKgHAACoCQAAqAsAAKgNAACoDgAAqBEAAKgeAACoLQAAqC8AAKgxAACoMwAAqDUAAKg3AACoOQAAqDsAAKhKAACoTQAAqFAAAKhTAACoVgAAqFkAAKhcAACoXwAAqGEAAKigAACoogAAqKQAAKimAACoqQAAqKoAAKirAACorAAAqK0AAKivAACosQAAqLIAAKizAACotQAAqLYAAKj1AACo9wAAqPkAAKj7AACo/gAAqP8AAKkAAACpAQAAqQIAAKkEAACpBgAAqQcAAKkIAACpCgAAqQsAAKlKAACpTAAAqU4AAKlQAACpUwAAqVQAAKlVAACpVgAAqVcAAKlZAACpWwAAqVwAAKldAACpXwAAqWAAAKmfAACpoQAAqaMAAKmlAACpqAAAqakAAKmqAACpqwAAqawAAKmuAACpsAAAqbEAAKmyAACptAAAqbUAAKn0AACp9gAAqfgAAKn6AACp/QAAqf4AAKn/AACqAAAAqgEAAKoDAACqBQAAqgYAAKoHAACqCQAAqgoAAKpJAACqSwAAqk0AAKpPAACqUgAAqlMAAKpUAACqVQAAqlYAAKpYAACqWgAAqlsAAKpcAACqXgAAql8AAKqeAACqoAAAqqIAAKqkAACqpwAAqqgAAKqpAACqqgAAqqsAAKqtAACqrwAAqrAAAKqxAACqswAAqrQAAKr/AACrIgAAq0IAAKtiAACrZAAAq2YAAKtoAACragAAq20AAKtuAACrbwAAq3IAAKtzAACrdQAAq3YAAKt5AACrfAAAq30AAKt+AACrgQAAq4IAAKuHAACrlAAAq5kAAKubAACrnQAAq6IAAKulAACrqAAAq6oAAKvPAACr8wAArBoAAKw+AACsQQAArEMAAKxFAACsRwAArEkAAKxLAACsTAAArE8AAKxcAACsbQAArG8AAKxxAACscwAArHUAAKx3AACseQAArHsAAKx9AACsjgAArJEAAKyUAACslwAArJoAAKydAACsoAAArKMAAKymAACsqAAArOcAAKzpAACs6wAArO0AAKzwAACs8QAArPIAAKzzAACs9AAArPYAAKz4AACs+QAArPoAAKz8AACs/QAArTwAAK0+AACtQAAArUIAAK1FAACtRgAArUcAAK1IAACtSQAArUsAAK1NAACtTgAArU8AAK1RAACtUgAArZEAAK2TAACtlgAArZgAAK2bAACtnAAArZ0AAK2eAACtnwAAraEAAK2jAACtpAAAraUAAK2nAACtqAAArbUAAK22AACttwAArbkAAK34AACt+gAArfwAAK3+AACuAQAArgIAAK4DAACuBAAArgUAAK4HAACuCQAArgoAAK4LAACuDQAArg4AAK5NAACuTwAArlEAAK5TAACuVgAArlcAAK5YAACuWQAArloAAK5cAACuXgAArl8AAK5gAACuYgAArmMAAK6iAACupAAArqYAAK6oAACuqwAArqwAAK6tAACurgAArq8AAK6xAACuswAArrQAAK61AACutwAArrgAAK73AACu+QAArvsAAK79AACvAAAArwEAAK8CAACvAwAArwQAAK8GAACvCAAArwkAAK8KAACvDAAArw0AAK9MAACvTgAAr1AAAK9SAACvVQAAr1YAAK9XAACvWAAAr1kAAK9bAACvXQAAr14AAK9fAACvYQAAr2IAAK+HAACvqwAAr9IAAK/2AACv+QAAr/sAAK/9AACv/wAAsAEAALADAACwBAAAsAcAALAUAACwIwAAsCUAALAnAACwKQAAsCsAALAtAACwLwAAsDIAALBBAACwRAAAsEcAALBKAACwTQAAsFAAALBTAACwVgAAsFgAALCXAACwmQAAsJwAALCeAACwoQAAsKIAALCjAACwpAAAsKUAALCnAACwqQAAsKoAALCrAACwrQAAsK4AALDtAACw7wAAsPIAALD0AACw9wAAsPgAALD5AACw+gAAsPsAALD9AACw/wAAsQAAALEBAACxAwAAsQQAALFDAACxRQAAsUgAALFKAACxTQAAsU4AALFPAACxUAAAsVEAALFTAACxVQAAsVYAALFXAACxWQAAsVoAALGZAACxmwAAsZ0AALGfAACxogAAsaMAALGkAACxpQAAsaYAALGoAACxqgAAsasAALGsAACxrgAAsa8AALHuAACx8AAAsfIAALH0AACx9wAAsfgAALH5AACx+gAAsfsAALH9AACx/wAAsgAAALIBAACyAwAAsgQAALJDAACyRQAAskcAALJJAACyTAAAsk0AALJOAACyTwAAslAAALJSAACyVAAAslUAALJWAACyWAAAslkAALKYAACymgAAsp0AALKfAACyogAAsqMAALKkAACypQAAsqYAALKoAACyqwAAsqwAALKtAACyrwAAsrAAALL7AACzHgAAsz4AALNeAACzYAAAs2IAALNkAACzZgAAs2kAALNqAACzawAAs24AALNvAACzcQAAs3IAALN0AACzdwAAs3gAALN5AACzfAAAs30AALOGAACzkwAAs5gAALOaAACznAAAs6EAALOkAACzpwAAs6kAALPOAACz8gAAtBkAALQ9AAC0QAAAtEIAALREAAC0RgAAtEgAALRKAAC0SwAAtE4AALRbAAC0bAAAtG4AALRwAAC0cgAAtHQAALR2AAC0eAAAtHoAALR8AAC0jQAAtJAAALSTAAC0lgAAtJkAALScAAC0nwAAtKIAALSlAAC0pwAAtOYAALToAAC06gAAtOwAALTvAAC08AAAtPEAALTyAAC08wAAtPUAALT3AAC0+AAAtPkAALT7AAC0/AAAtTsAALU9AAC1PwAAtUEAALVEAAC1RQAAtUYAALVHAAC1SAAAtUoAALVMAAC1TQAAtU4AALVQAAC1UQAAtZAAALWSAAC1lQAAtZcAALWaAAC1mwAAtZwAALWdAAC1ngAAtaAAALWiAAC1owAAtaQAALWmAAC1pwAAtbQAALW1AAC1tgAAtbgAALX3AAC1+QAAtfsAALX9AAC2AAAAtgEAALYCAAC2AwAAtgQAALYGAAC2CAAAtgkAALYKAAC2DAAAtg0AALZMAAC2TgAAtlAAALZSAAC2VQAAtlYAALZXAAC2WAAAtlkAALZbAAC2XQAAtl4AALZfAAC2YQAAtmIAALahAAC2owAAtqUAALanAAC2qgAAtqsAALasAAC2rQAAtq4AALawAAC2sgAAtrMAALa0AAC2tgAAtrcAALb2AAC2+AAAtvoAALb8AAC2/wAAtwAAALcBAAC3AgAAtwMAALcFAAC3BwAAtwgAALcJAAC3CwAAtwwAALdLAAC3TQAAt08AALdRAAC3VAAAt1UAALdWAAC3VwAAt1gAALdaAAC3XAAAt10AALdeAAC3YAAAt2EAALeGAAC3qgAAt9EAALf1AAC3+AAAt/oAALf8AAC3/gAAuAAAALgCAAC4AwAAuAYAALgTAAC4IgAAuCQAALgmAAC4KAAAuCoAALgsAAC4LgAAuDAAALg/AAC4QgAAuEUAALhIAAC4SwAAuE4AALhRAAC4VAAAuFYAALiVAAC4lwAAuJkAALibAAC4ngAAuJ8AALigAAC4oQAAuKIAALikAAC4pgAAuKcAALioAAC4qgAAuKsAALjqAAC47AAAuO4AALjwAAC48wAAuPQAALj1AAC49gAAuPcAALj5AAC4+wAAuPwAALj9AAC4/wAAuQAAALk/AAC5QQAAuUMAALlFAAC5SAAAuUkAALlKAAC5SwAAuUwAALlOAAC5UAAAuVEAALlSAAC5VAAAuVUAALmUAAC5lgAAuZgAALmaAAC5nQAAuZ4AALmfAAC5oAAAuaEAALmjAAC5pQAAuaYAALmnAAC5qQAAuaoAALnpAAC56wAAue0AALnvAAC58gAAufMAALn0AAC59QAAufYAALn4AAC5+gAAufsAALn8AAC5/gAAuf8AALo+AAC6QAAAukIAALpEAAC6RwAAukgAALpJAAC6SgAAuksAALpNAAC6TwAAulAAALpRAAC6UwAAulQAALqTAAC6lQAAupcAALqZAAC6nAAAup0AALqeAAC6nwAAuqAAALqiAAC6pAAAuqUAALqmAAC6qAAAuqkAALr0AAC7FwAAuzcAALtXAAC7WQAAu1sAALtdAAC7XwAAu2IAALtjAAC7ZAAAu2cAALtoAAC7agAAu2sAALttAAC7cAAAu3EAALtyAAC7dQAAu3YAALt7AAC7iAAAu40AALuPAAC7kQAAu5YAALuZAAC7nAAAu54AALvDAAC75wAAvA4AALwyAAC8NQAAvDcAALw5AAC8OwAAvD0AALw/AAC8QAAAvEMAALxQAAC8YQAAvGMAALxlAAC8ZwAAvGkAALxrAAC8bQAAvG8AALxxAAC8ggAAvIUAALyIAAC8iwAAvI4AALyRAAC8lAAAvJcAALyaAAC8nAAAvNsAALzdAAC83wAAvOEAALzkAAC85QAAvOYAALznAAC86AAAvOoAALzsAAC87QAAvO4AALzwAAC88QAAvTAAAL0yAAC9NAAAvTYAAL05AAC9OgAAvTsAAL08AAC9PQAAvT8AAL1BAAC9QgAAvUMAAL1FAAC9RgAAvYUAAL2HAAC9igAAvYwAAL2PAAC9kAAAvZEAAL2SAAC9kwAAvZUAAL2XAAC9mAAAvZkAAL2bAAC9nAAAvakAAL2qAAC9qwAAva0AAL3sAAC97gAAvfAAAL3yAAC99QAAvfYAAL33AAC9+AAAvfkAAL37AAC9/QAAvf4AAL3/AAC+AQAAvgIAAL5BAAC+QwAAvkUAAL5HAAC+SgAAvksAAL5MAAC+TQAAvk4AAL5QAAC+UgAAvlMAAL5UAAC+VgAAvlcAAL6WAAC+mAAAvpoAAL6cAAC+nwAAvqAAAL6hAAC+ogAAvqMAAL6lAAC+pwAAvqgAAL6pAAC+qwAAvqwAAL7rAAC+7QAAvu8AAL7xAAC+9AAAvvUAAL72AAC+9wAAvvgAAL76AAC+/AAAvv0AAL7+AAC/AAAAvwEAAL9AAAC/QgAAv0QAAL9GAAC/SQAAv0oAAL9LAAC/TAAAv00AAL9PAAC/UQAAv1IAAL9TAAC/VQAAv1YAAL97AAC/nwAAv8YAAL/qAAC/7QAAv+8AAL/xAAC/8wAAv/UAAL/3AAC/+AAAv/sAAMAIAADAFwAAwBkAAMAbAADAHQAAwB8AAMAhAADAIwAAwCUAAMA0AADANwAAwDoAAMA9AADAQAAAwEMAAMBGAADASQAAwEsAAMCKAADAjAAAwI4AAMCQAADAkwAAwJQAAMCVAADAlgAAwJcAAMCZAADAmwAAwJwAAMCdAADAnwAAwKAAAMDfAADA4QAAwOMAAMDlAADA6AAAwOkAAMDqAADA6wAAwOwAAMDuAADA8AAAwPEAAMDyAADA9AAAwPUAAME0AADBNgAAwTgAAME6AADBPQAAwT4AAME/AADBQAAAwUEAAMFDAADBRQAAwUYAAMFHAADBSQAAwUoAAMGJAADBiwAAwY4AAMGQAADBkwAAwZQAAMGVAADBlgAAwZcAAMGZAADBmwAAwZwAAMGdAADBnwAAwaAAAMHfAADB4QAAweMAAMHlAADB6AAAwekAAMHqAADB6wAAwewAAMHuAADB8AAAwfEAAMHyAADB9AAAwfUAAMI0AADCNgAAwjgAAMI6AADCPQAAwj4AAMI/AADCQAAAwkEAAMJDAADCRQAAwkYAAMJHAADCSQAAwkoAAMKJAADCiwAAwo0AAMKPAADCkgAAwpMAAMKUAADClQAAwpYAAMKYAADCmgAAwpsAAMKcAADCngAAwp8AAMLqAADDDQAAwy0AAMNNAADDTwAAw1EAAMNTAADDVQAAw1gAAMNZAADDWgAAw10AAMNeAADDYAAAw2EAAMNjAADDZgAAw2cAAMNoAADDawAAw2wAAMNxAADDfgAAw4MAAMOFAADDhwAAw4wAAMOPAADDkgAAw5QAAMO5AADD3QAAxAQAAMQoAADEKwAAxC0AAMQvAADEMQAAxDMAAMQ1AADENgAAxDkAAMRGAADEVwAAxFkAAMRbAADEXQAAxF8AAMRhAADEYwAAxGUAAMRnAADEeAAAxHsAAMR+AADEgQAAxIQAAMSHAADEigAAxI0AAMSQAADEkgAAxNEAAMTTAADE1QAAxNcAAMTaAADE2wAAxNwAAMTdAADE3gAAxOAAAMTiAADE4wAAxOQAAMTmAADE5wAAxSYAAMUoAADFKgAAxSwAAMUvAADFMAAAxTEAAMUyAADFMwAAxTUAAMU3AADFOAAAxTkAAMU7AADFPAAAxXsAAMV9AADFgAAAxYIAAMWFAADFhgAAxYcAAMWIAADFiQAAxYsAAMWNAADFjgAAxY8AAMWRAADFkgAAxZ8AAMWgAADFoQAAxaMAAMXiAADF5AAAxeYAAMXoAADF6wAAxewAAMXtAADF7gAAxe8AAMXxAADF8wAAxfQAAMX1AADF9wAAxfgAAMY3AADGOQAAxjsAAMY9AADGQAAAxkEAAMZCAADGQwAAxkQAAMZGAADGSAAAxkkAAMZKAADGTAAAxk0AAMaMAADGjgAAxpAAAMaSAADGlQAAxpYAAMaXAADGmAAAxpkAAMabAADGnQAAxp4AAMafAADGoQAAxqIAAMbhAADG4wAAxuUAAMbnAADG6gAAxusAAMbsAADG7QAAxu4AAMbwAADG8gAAxvMAAMb0AADG9gAAxvcAAMc2AADHOAAAxzoAAMc8AADHPwAAx0AAAMdBAADHQgAAx0MAAMdFAADHRwAAx0gAAMdJAADHSwAAx0wAAMdxAADHlQAAx7wAAMfgAADH4wAAx+UAAMfnAADH6QAAx+sAAMftAADH7gAAx/EAAMf+AADIDQAAyA8AAMgRAADIEwAAyBUAAMgXAADIGQAAyBsAAMgqAADILQAAyDAAAMgzAADINgAAyDkAAMg8AADIPwAAyEEAAMiAAADIggAAyIQAAMiGAADIiQAAyIoAAMiLAADIjAAAyI0AAMiPAADIkQAAyJIAAMiTAADIlQAAyJYAAMjVAADI1wAAyNkAAMjbAADI3gAAyN8AAMjgAADI4QAAyOIAAMjkAADI5gAAyOcAAMjoAADI6gAAyOsAAMkqAADJLAAAyS4AAMkwAADJMwAAyTQAAMk1AADJNgAAyTcAAMk5AADJOwAAyTwAAMk9AADJPwAAyUAAAMl/AADJgQAAyYMAAMmFAADJiAAAyYkAAMmKAADJiwAAyYwAAMmOAADJkAAAyZEAAMmSAADJlAAAyZUAAMnUAADJ1gAAydgAAMnaAADJ3QAAyd4AAMnfAADJ4AAAyeEAAMnjAADJ5QAAyeYAAMnnAADJ6QAAyeoAAMopAADKKwAAyi0AAMovAADKMgAAyjMAAMo0AADKNQAAyjYAAMo4AADKOgAAyjsAAMo8AADKPgAAyj8AAMp+AADKgAAAyoIAAMqEAADKhwAAyogAAMqJAADKigAAyosAAMqNAADKjwAAypAAAMqRAADKkwAAypQAAMrfAADLAgAAyyIAAMtCAADLRAAAy0YAAMtIAADLSgAAy00AAMtOAADLTwAAy1IAAMtTAADLVQAAy1YAAMtZAADLXAAAy10AAMteAADLYQAAy2IAAMtrAADLeAAAy30AAMt/AADLgQAAy4YAAMuJAADLjAAAy44AAMuzAADL1wAAy/4AAMwiAADMJQAAzCcAAMwpAADMKwAAzC0AAMwvAADMMAAAzDMAAMxAAADMUQAAzFMAAMxVAADMVwAAzFkAAMxbAADMXQAAzF8AAMxhAADMcgAAzHUAAMx4AADMewAAzH4AAMyBAADMhAAAzIcAAMyKAADMjAAAzMsAAMzNAADMzwAAzNEAAMzUAADM1QAAzNYAAMzXAADM2AAAzNoAAMzcAADM3QAAzN4AAMzgAADM4QAAzSAAAM0iAADNJAAAzSYAAM0pAADNKgAAzSsAAM0sAADNLQAAzS8AAM0xAADNMgAAzTMAAM01AADNNgAAzXUAAM13AADNegAAzXwAAM1/AADNgAAAzYEAAM2CAADNgwAAzYUAAM2HAADNiAAAzYkAAM2LAADNjAAAzZkAAM2aAADNmwAAzZ0AAM3cAADN3gAAzeAAAM3iAADN5QAAzeYAAM3nAADN6AAAzekAAM3rAADN7QAAze4AAM3vAADN8QAAzfIAAM4xAADOMwAAzjUAAM43AADOOgAAzjsAAM48AADOPQAAzj4AAM5AAADOQgAAzkMAAM5EAADORgAAzkcAAM6GAADOiAAAzooAAM6MAADOjwAAzpAAAM6RAADOkgAAzpMAAM6VAADOlwAAzpgAAM6ZAADOmwAAzpwAAM7bAADO3QAAzt8AAM7hAADO5AAAzuUAAM7mAADO5wAAzugAAM7qAADO7AAAzu0AAM7uAADO8AAAzvEAAM8wAADPMgAAzzQAAM82AADPOQAAzzoAAM87AADPPAAAzz0AAM8/AADPQQAAz0IAAM9DAADPRQAAz0YAAM9rAADPjwAAz7YAAM/aAADP3QAAz98AAM/hAADP4wAAz+UAAM/nAADP6AAAz+sAAM/4AADQBQAA0AcAANAJAADQCwAA0A0AANAPAADQEQAA0B4AANAhAADQJAAA0CcAANAqAADQLQAA0DAAANAyAADQcQAA0HMAANB2AADQeAAA0HsAANB8AADQfQAA0H4AANB/AADQgQAA0IMAANCEAADQhQAA0IcAANCIAADQywAA0O8AANETAADRNgAA0V0AANF9AADRpAAA0csAANHrAADSDwAA0jMAANI1AADSOAAA0joAANI8AADSPgAA0kEAANJDAADSRQAA0kcAANJJAADSSwAA0k0AANJQAADSUwAA0lQAANJZAADSZgAA0mkAANJrAADSbgAA0nEAANJzAADSmAAA0rwAANLjAADTBwAA0woAANMMAADTDgAA0xAAANMSAADTFAAA0xUAANMYAADTJQAA0zgAANM6AADTPAAA0z4AANNAAADTQgAA00QAANNGAADTSAAA00oAANNdAADTYAAA02MAANNmAADTaQAA02wAANNvAADTcgAA03UAANN4AADTegAA07kAANO7AADTvgAA08AAANPDAADTxAAA08UAANPGAADTxwAA08kAANPLAADTzAAA080AANPPAADT0AAA09kAANPaAADT3AAA1BsAANQdAADUHwAA1CEAANQkAADUJQAA1CYAANQnAADUKAAA1CoAANQsAADULQAA1C4AANQwAADUMQAA1HAAANRyAADUdQAA1HcAANR6AADUewAA1HwAANR9AADUfgAA1IAAANSCAADUgwAA1IQAANSGAADUhwAA1JAAANSTAADUlgAA1JgAANShAADUpAAA1KcAANSpAADUrQAA1OwAANTuAADU8AAA1PIAANT1AADU9gAA1PcAANT4AADU+QAA1PsAANT9AADU/gAA1P8AANUBAADVAgAA1UEAANVDAADVRgAA1UgAANVLAADVTAAA1U0AANVOAADVTwAA1VEAANVTAADVVAAA1VUAANVXAADVWAAA1WEAANViAADVZAAA1aMAANWlAADVpwAA1akAANWsAADVrQAA1a4AANWvAADVsAAA1bIAANW0AADVtQAA1bYAANW4AADVuQAA1fgAANX6AADV/QAA1f8AANYCAADWAwAA1gQAANYFAADWBgAA1ggAANYKAADWCwAA1gwAANYOAADWDwAA1hwAANYdAADWHgAA1iAAANZfAADWYQAA1mMAANZlAADWaAAA1mkAANZqAADWawAA1mwAANZuAADWcAAA1nEAANZyAADWdAAA1nUAANa0AADWtgAA1rkAANa7AADWvgAA1r8AANbAAADWwQAA1sIAANbEAADWxgAA1scAANbIAADWygAA1ssAANbXAADW5AAA1u8AANbyAADW9AAA1vcAANb6AADW/QAA1wgAANcLAADXDgAA1xEAANcUAADXFwAA1xkAANckAADXMQAA13wAANefAADXvwAA198AANfhAADX4wAA1+UAANfnAADX6gAA1+sAANfsAADX7wAA1/AAANfyAADX8wAA1/UAANf4AADX+QAA1/oAANf9AADX/gAA2AMAANgQAADYFQAA2BcAANgZAADYHgAA2CEAANgkAADYJgAA2EsAANhvAADYlgAA2LoAANi9AADYvwAA2MEAANjDAADYxQAA2McAANjIAADYywAA2NgAANjpAADY6wAA2O0AANjvAADY8QAA2PMAANj1AADY9wAA2PkAANkKAADZDQAA2RAAANkTAADZFgAA2RkAANkcAADZHwAA2SIAANkkAADZYwAA2WUAANlnAADZaQAA2WwAANltAADZbgAA2W8AANlwAADZcgAA2XQAANl1AADZdgAA2XgAANl5AADZuAAA2boAANm8AADZvgAA2cEAANnCAADZwwAA2cQAANnFAADZxwAA2ckAANnKAADZywAA2c0AANnOAADaDQAA2g8AANoSAADaFAAA2hcAANoYAADaGQAA2hoAANobAADaHQAA2h8AANogAADaIQAA2iMAANokAADaMQAA2jIAANozAADaNQAA2nQAANp2AADaeAAA2noAANp9AADafgAA2n8AANqAAADagQAA2oMAANqFAADahgAA2ocAANqJAADaigAA2skAANrLAADazQAA2s8AANrSAADa0wAA2tQAANrVAADa1gAA2tgAANraAADa2wAA2twAANreAADa3wAA2x4AANsgAADbIgAA2yQAANsnAADbKAAA2ykAANsqAADbKwAA2y0AANsvAADbMAAA2zEAANszAADbNAAA23MAANt1AADbdwAA23kAANt8AADbfQAA234AANt/AADbgAAA24IAANuEAADbhQAA24YAANuIAADbiQAA28gAANvKAADbzAAA284AANvRAADb0gAA29MAANvUAADb1QAA29cAANvZAADb2gAA29sAANvdAADb3gAA3AMAANwnAADcTgAA3HIAANx1AADcdwAA3HkAANx7AADcfQAA3H8AANyAAADcgwAA3JAAANyfAADcoQAA3KMAANylAADcpwAA3KkAANyrAADcrQAA3LwAANy/AADcwgAA3MUAANzIAADcywAA3M4AANzRAADc0wAA3RIAAN0UAADdFgAA3RgAAN0bAADdHAAA3R0AAN0eAADdHwAA3SEAAN0jAADdJAAA3SUAAN0nAADdKAAA3WcAAN1pAADdawAA3W0AAN1wAADdcQAA3XIAAN1zAADddAAA3XYAAN14AADdeQAA3XoAAN18AADdfQAA3bwAAN2+AADdwAAA3cIAAN3FAADdxgAA3ccAAN3IAADdyQAA3csAAN3NAADdzgAA3c8AAN3RAADd0gAA3hEAAN4TAADeFQAA3hcAAN4aAADeGwAA3hwAAN4dAADeHgAA3iAAAN4iAADeIwAA3iQAAN4mAADeJwAA3mYAAN5oAADeagAA3mwAAN5vAADecAAA3nEAAN5yAADecwAA3nUAAN53AADeeAAA3nkAAN57AADefAAA3rsAAN69AADevwAA3sEAAN7EAADexQAA3sYAAN7HAADeyAAA3soAAN7MAADezQAA3s4AAN7QAADe0QAA3xAAAN8SAADfFAAA3xYAAN8ZAADfGgAA3xsAAN8cAADfHQAA3x8AAN8hAADfIgAA3yMAAN8lAADfJgAA33EAAN+UAADftAAA39QAAN/WAADf2AAA39oAAN/cAADf3wAA3+AAAN/hAADf5AAA3+UAAN/nAADf6AAA3+sAAN/tAADf7gAA3+8AAN/yAADf8wAA3/gAAOAFAADgCgAA4AwAAOAOAADgEwAA4BYAAOAZAADgGwAA4EAAAOBkAADgiwAA4K8AAOCyAADgtAAA4LYAAOC4AADgugAA4LwAAOC9AADgwAAA4M0AAODeAADg4AAA4OIAAODkAADg5gAA4OgAAODqAADg7AAA4O4AAOD/AADhAgAA4QUAAOEIAADhCwAA4Q4AAOERAADhFAAA4RcAAOEZAADhWAAA4VoAAOFcAADhXgAA4WEAAOFiAADhYwAA4WQAAOFlAADhZwAA4WkAAOFqAADhawAA4W0AAOFuAADhrQAA4a8AAOGxAADhswAA4bYAAOG3AADhuAAA4bkAAOG6AADhvAAA4b4AAOG/AADhwAAA4cIAAOHDAADiAgAA4gQAAOIHAADiCQAA4gwAAOINAADiDgAA4g8AAOIQAADiEgAA4hQAAOIVAADiFgAA4hgAAOIZAADiJgAA4icAAOIoAADiKgAA4mkAAOJrAADibQAA4m8AAOJyAADicwAA4nQAAOJ1AADidgAA4ngAAOJ6AADiewAA4nwAAOJ+AADifwAA4r4AAOLAAADiwgAA4sQAAOLHAADiyAAA4skAAOLKAADiywAA4s0AAOLPAADi0AAA4tEAAOLTAADi1AAA4xMAAOMVAADjFwAA4xkAAOMcAADjHQAA4x4AAOMfAADjIAAA4yIAAOMkAADjJQAA4yYAAOMoAADjKQAA42gAAONqAADjbAAA424AAONxAADjcgAA43MAAON0AADjdQAA43cAAON5AADjegAA43sAAON9AADjfgAA470AAOO/AADjwQAA48MAAOPGAADjxwAA48gAAOPJAADjygAA48wAAOPOAADjzwAA49AAAOPSAADj0wAA4/gAAOQcAADkQwAA5GcAAORqAADkbAAA5G4AAORwAADkcgAA5HQAAOR1AADkeAAA5IUAAOSUAADklgAA5JgAAOSaAADknAAA5J4AAOSgAADkowAA5LIAAOS1AADkuAAA5LsAAOS+AADkwQAA5MQAAOTHAADkyQAA5QgAAOUKAADlDQAA5Q8AAOUSAADlEwAA5RQAAOUVAADlFgAA5RgAAOUaAADlGwAA5RwAAOUeAADlHwAA5V4AAOVgAADlYwAA5WUAAOVoAADlaQAA5WoAAOVrAADlbAAA5W4AAOVwAADlcQAA5XIAAOV0AADldQAA5bQAAOW2AADluQAA5bsAAOW+AADlvwAA5cAAAOXBAADlwgAA5cQAAOXGAADlxwAA5cgAAOXKAADlywAA5goAAOYMAADmDwAA5hEAAOYUAADmFQAA5hYAAOYXAADmGAAA5hoAAOYcAADmHQAA5h4AAOYgAADmIQAA5mAAAOZiAADmZAAA5mYAAOZpAADmagAA5msAAOZsAADmbQAA5m8AAOZxAADmcgAA5nMAAOZ1AADmdgAA5rUAAOa3AADmuQAA5rsAAOa+AADmvwAA5sAAAObBAADmwgAA5sQAAObGAADmxwAA5sgAAObKAADmywAA5woAAOcMAADnDwAA5xEAAOcUAADnFQAA5xYAAOcXAADnGAAA5xoAAOcdAADnHgAA5x8AAOchAADnIgAA520AAOeQAADnsAAA59AAAOfSAADn1AAA59YAAOfYAADn2wAA59wAAOfdAADn4AAA5+EAAOfjAADn5AAA5+cAAOfqAADn6wAA5+wAAOfvAADn8AAA5/UAAOgCAADoBwAA6AkAAOgLAADoEAAA6BMAAOgWAADoGAAA6D0AAOhhAADoiAAA6KwAAOivAADosQAA6LMAAOi1AADotwAA6LkAAOi6AADovQAA6MoAAOjbAADo3QAA6N8AAOjhAADo4wAA6OUAAOjnAADo6QAA6OsAAOj8AADo/wAA6QIAAOkFAADpCAAA6QsAAOkOAADpEQAA6RQAAOkWAADpVQAA6VcAAOlZAADpWwAA6V4AAOlfAADpYAAA6WEAAOliAADpZAAA6WYAAOlnAADpaAAA6WoAAOlrAADpqgAA6awAAOmuAADpsAAA6bMAAOm0AADptQAA6bYAAOm3AADpuQAA6bsAAOm8AADpvQAA6b8AAOnAAADp/wAA6gEAAOoEAADqBgAA6gkAAOoKAADqCwAA6gwAAOoNAADqDwAA6hEAAOoSAADqEwAA6hUAAOoWAADqIwAA6iQAAOolAADqJwAA6mYAAOpoAADqagAA6mwAAOpvAADqcAAA6nEAAOpyAADqcwAA6nUAAOp3AADqeAAA6nkAAOp7AADqfAAA6rsAAOq9AADqvwAA6sEAAOrEAADqxQAA6sYAAOrHAADqyAAA6soAAOrMAADqzQAA6s4AAOrQAADq0QAA6xAAAOsSAADrFAAA6xYAAOsZAADrGgAA6xsAAOscAADrHQAA6x8AAOshAADrIgAA6yMAAOslAADrJgAA62UAAOtnAADraQAA62sAAOtuAADrbwAA63AAAOtxAADrcgAA63QAAOt2AADrdwAA63gAAOt6AADrewAA67oAAOu8AADrvgAA68AAAOvDAADrxAAA68UAAOvGAADrxwAA68kAAOvLAADrzAAA680AAOvPAADr0AAA6/UAAOwZAADsQAAA7GQAAOxnAADsaQAA7GsAAOxtAADsbwAA7HEAAOxyAADsdQAA7IIAAOyRAADskwAA7JUAAOyXAADsmQAA7JsAAOydAADsoAAA7K8AAOyyAADstQAA7LgAAOy7AADsvgAA7MEAAOzEAADsxgAA7QUAAO0HAADtCgAA7QwAAO0PAADtEAAA7REAAO0SAADtEwAA7RUAAO0XAADtGAAA7RkAAO0bAADtHAAA7VsAAO1dAADtYAAA7WIAAO1lAADtZgAA7WcAAO1oAADtaQAA7WsAAO1tAADtbgAA7W8AAO1xAADtcgAA7XQAAO2zAADttQAA7bgAAO26AADtvQAA7b4AAO2/AADtwAAA7cEAAO3DAADtxQAA7cYAAO3HAADtyQAA7coAAO4JAADuCwAA7g4AAO4QAADuEwAA7hQAAO4VAADuFgAA7hcAAO4ZAADuGwAA7hwAAO4dAADuHwAA7iAAAO5fAADuYQAA7mMAAO5lAADuaAAA7mkAAO5qAADuawAA7mwAAO5uAADucAAA7nEAAO5yAADudAAA7nUAAO60AADutgAA7rgAAO66AADuvQAA7r4AAO6/AADuwAAA7sEAAO7DAADuxQAA7sYAAO7HAADuyQAA7soAAO8JAADvCwAA7w4AAO8QAADvEwAA7xQAAO8VAADvFgAA7xcAAO8ZAADvHAAA7x0AAO8eAADvIAAA7yEAAO9sAADvjwAA768AAO/PAADv0QAA79MAAO/VAADv1wAA79oAAO/bAADv3AAA798AAO/gAADv4gAA7+MAAO/lAADv6AAA7+kAAO/qAADv7QAA7+4AAO/zAADwAAAA8AUAAPAHAADwCQAA8A4AAPARAADwFAAA8BYAAPA7AADwXwAA8IYAAPCqAADwrQAA8K8AAPCxAADwswAA8LUAAPC3AADwuAAA8LsAAPDIAADw2QAA8NsAAPDdAADw3wAA8OEAAPDjAADw5QAA8OcAAPDpAADw+gAA8P0AAPEAAADxAwAA8QYAAPEJAADxDAAA8Q8AAPESAADxFAAA8VMAAPFVAADxVwAA8VkAAPFcAADxXQAA8V4AAPFfAADxYAAA8WIAAPFkAADxZQAA8WYAAPFoAADxaQAA8agAAPGqAADxrAAA8a4AAPGxAADxsgAA8bMAAPG0AADxtQAA8bcAAPG5AADxugAA8bsAAPG9AADxvgAA8f0AAPH/AADyAgAA8gQAAPIHAADyCAAA8gkAAPIKAADyCwAA8g0AAPIPAADyEAAA8hEAAPITAADyFAAA8iEAAPIiAADyIwAA8iUAAPJkAADyZgAA8mgAAPJqAADybQAA8m4AAPJvAADycAAA8nEAAPJzAADydQAA8nYAAPJ3AADyeQAA8noAAPK5AADyuwAA8r0AAPK/AADywgAA8sMAAPLEAADyxQAA8sYAAPLIAADyygAA8ssAAPLMAADyzgAA8s8AAPMOAADzEAAA8xIAAPMUAADzFwAA8xgAAPMZAADzGgAA8xsAAPMdAADzHwAA8yAAAPMhAADzIwAA8yQAAPNjAADzZQAA82cAAPNpAADzbAAA820AAPNuAADzbwAA83AAAPNyAADzdAAA83UAAPN2AADzeAAA83kAAPO4AADzugAA87wAAPO+AADzwQAA88IAAPPDAADzxAAA88UAAPPHAADzyQAA88oAAPPLAADzzQAA884AAPPzAAD0FwAA9D4AAPRiAAD0ZQAA9GcAAPRpAAD0awAA9G0AAPRvAAD0cAAA9HMAAPSAAAD0jwAA9JEAAPSTAAD0lQAA9JcAAPSZAAD0mwAA9J0AAPSsAAD0rwAA9LIAAPS1AAD0uAAA9LsAAPS+AAD0wQAA9MMAAPUCAAD1BAAA9QcAAPUJAAD1DAAA9Q0AAPUOAAD1DwAA9RAAAPUSAAD1FAAA9RUAAPUWAAD1GAAA9RkAAPUaAAD1WQAA9VsAAPVdAAD1XwAA9WIAAPVjAAD1ZAAA9WUAAPVmAAD1aAAA9WoAAPVrAAD1bAAA9W4AAPVvAAD1rgAA9bAAAPWyAAD1tAAA9bcAAPW4AAD1uQAA9boAAPW7AAD1vQAA9b8AAPXAAAD1wQAA9cMAAPXEAAD2AwAA9gUAAPYHAAD2CQAA9gwAAPYNAAD2DgAA9g8AAPYQAAD2EgAA9hQAAPYVAAD2FgAA9hgAAPYZAAD2WAAA9loAAPZcAAD2XgAA9mEAAPZiAAD2YwAA9mQAAPZlAAD2ZwAA9mkAAPZqAAD2awAA9m0AAPZuAAD2rQAA9q8AAPaxAAD2swAA9rYAAPa3AAD2uAAA9rkAAPa6AAD2vAAA9r4AAPa/AAD2wAAA9sIAAPbDAAD3AgAA9wQAAPcGAAD3CAAA9wsAAPcMAAD3DQAA9w4AAPcPAAD3EQAA9xMAAPcUAAD3FQAA9xcAAPcYAAD3YwAA94YAAPemAAD3xgAA98gAAPfKAAD3zAAA984AAPfRAAD30gAA99MAAPfWAAD31wAA99kAAPfaAAD33AAA998AAPfgAAD34QAA9+QAAPflAAD36gAA9/cAAPf8AAD3/gAA+AAAAPgFAAD4CAAA+AsAAPgNAAD4MgAA+FYAAPh9AAD4oQAA+KQAAPimAAD4qAAA+KoAAPisAAD4rgAA+K8AAPiyAAD4vwAA+NAAAPjSAAD41AAA+NYAAPjYAAD42gAA+NwAAPjeAAD44AAA+PEAAPj0AAD49wAA+PoAAPj9AAD5AAAA+QMAAPkGAAD5CQAA+QsAAPlKAAD5TAAA+U4AAPlQAAD5UwAA+VQAAPlVAAD5VgAA+VcAAPlZAAD5WwAA+VwAAPldAAD5XwAA+WAAAPmfAAD5oQAA+aMAAPmlAAD5qAAA+akAAPmqAAD5qwAA+awAAPmuAAD5sAAA+bEAAPmyAAD5tAAA+bUAAPn0AAD59gAA+fkAAPn7AAD5/gAA+f8AAPoAAAD6AQAA+gIAAPoEAAD6BgAA+gcAAPoIAAD6CgAA+gsAAPoYAAD6GQAA+hoAAPocAAD6WwAA+l0AAPpfAAD6YQAA+mQAAPplAAD6ZgAA+mcAAPpoAAD6agAA+mwAAPptAAD6bgAA+nAAAPpxAAD6sAAA+rIAAPq0AAD6tgAA+rkAAPq6AAD6uwAA+rwAAPq9AAD6vwAA+sEAAPrCAAD6wwAA+sUAAPrGAAD7BQAA+wcAAPsJAAD7CwAA+w4AAPsPAAD7EAAA+xEAAPsSAAD7FAAA+xYAAPsXAAD7GAAA+xoAAPsbAAD7WgAA+1wAAPteAAD7YAAA+2MAAPtkAAD7ZQAA+2YAAPtnAAD7aQAA+2sAAPtsAAD7bQAA+28AAPtwAAD7rwAA+7EAAPuzAAD7tQAA+7gAAPu5AAD7ugAA+7sAAPu8AAD7vgAA+8AAAPvBAAD7wgAA+8QAAPvFAAD76gAA/A4AAPw1AAD8WQAA/FwAAPxeAAD8YAAA/GIAAPxkAAD8ZgAA/GcAAPxqAAD8dwAA/IYAAPyIAAD8igAA/IwAAPyOAAD8kAAA/JIAAPyUAAD8owAA/KYAAPypAAD8rAAA/K8AAPyyAAD8tQAA/LgAAPy6AAD8+QAA/PsAAPz9AAD8/wAA/QIAAP0DAAD9BAAA/QUAAP0GAAD9CAAA/QoAAP0LAAD9DAAA/Q4AAP0PAAD9TgAA/VAAAP1SAAD9VAAA/VcAAP1YAAD9WQAA/VoAAP1bAAD9XQAA/V8AAP1gAAD9YQAA/WMAAP1kAAD9owAA/aUAAP2nAAD9qQAA/awAAP2tAAD9rgAA/a8AAP2wAAD9sgAA/bQAAP21AAD9tgAA/bgAAP25AAD9+AAA/foAAP38AAD9/gAA/gEAAP4CAAD+AwAA/gQAAP4FAAD+BwAA/gkAAP4KAAD+CwAA/g0AAP4OAAD+TQAA/k8AAP5RAAD+UwAA/lYAAP5XAAD+WAAA/lkAAP5aAAD+XAAA/l4AAP5fAAD+YAAA/mIAAP5jAAD+ogAA/qQAAP6mAAD+qAAA/qsAAP6sAAD+rQAA/q4AAP6vAAD+sQAA/rMAAP60AAD+tQAA/rcAAP64AAD+9wAA/vkAAP77AAD+/QAA/wAAAP8BAAD/AgAA/wMAAP8EAAD/BgAA/wgAAP8JAAD/CgAA/wwAAP8NAAD/WAAA/3sAAP+bAAD/uwAA/70AAP+/AAD/wQAA/8MAAP/GAAD/xwAA/8gAAP/LAAD/zAAA/84AAP/PAAD/0QAA/9QAAP/VAAD/1gAA/9kAAP/aAAD/3wAA/+wAAP/xAAD/8wAA//UAAP/6AAD//QABAAAAAQACAAEAJwABAEsAAQByAAEAlgABAJkAAQCbAAEAnQABAJ8AAQChAAEAowABAKQAAQCnAAEAtAABAMUAAQDHAAEAyQABAMsAAQDNAAEAzwABANEAAQDTAAEA1QABAOYAAQDpAAEA7AABAO8AAQDyAAEA9QABAPgAAQD7AAEA/gABAQAAAQE/AAEBQQABAUMAAQFFAAEBSAABAUkAAQFKAAEBSwABAUwAAQFOAAEBUAABAVEAAQFSAAEBVAABAVUAAQGUAAEBlgABAZgAAQGaAAEBnQABAZ4AAQGfAAEBoAABAaEAAQGjAAEBpQABAaYAAQGnAAEBqQABAaoAAQHpAAEB6wABAe4AAQHwAAEB8wABAfQAAQH1AAEB9gABAfcAAQH5AAEB+wABAfwAAQH9AAEB/wABAgAAAQINAAECDgABAg8AAQIRAAECUAABAlIAAQJUAAECVgABAlkAAQJaAAECWwABAlwAAQJdAAECXwABAmEAAQJiAAECYwABAmUAAQJmAAECpQABAqcAAQKpAAECqwABAq4AAQKvAAECsAABArEAAQKyAAECtAABArYAAQK3AAECuAABAroAAQK7AAEC+gABAvwAAQL+AAEDAAABAwMAAQMEAAEDBQABAwYAAQMHAAEDCQABAwsAAQMMAAEDDQABAw8AAQMQAAEDTwABA1EAAQNTAAEDVQABA1gAAQNZAAEDWgABA1sAAQNcAAEDXgABA2AAAQNhAAEDYgABA2QAAQNlAAEDpAABA6YAAQOoAAEDqgABA60AAQOuAAEDrwABA7AAAQOxAAEDswABA7UAAQO2AAEDtwABA7kAAQO6AAED3wABBAMAAQQqAAEETgABBFEAAQRTAAEEVQABBFcAAQRZAAEEWwABBFwAAQRfAAEEbAABBHsAAQR9AAEEfwABBIEAAQSDAAEEhQABBIcAAQSJAAEEmAABBJsAAQSeAAEEoQABBKQAAQSnAAEEqgABBK0AAQSvAAEE7gABBPAAAQTyAAEE9AABBPcAAQT4AAEE+QABBPoAAQT7AAEE/QABBP8AAQUAAAEFAQABBQMAAQUEAAEFQwABBUUAAQVHAAEFSQABBUwAAQVNAAEFTgABBU8AAQVQAAEFUgABBVQAAQVVAAEFVgABBVgAAQVZAAEFmAABBZoAAQWcAAEFngABBaEAAQWiAAEFowABBaQAAQWlAAEFpwABBakAAQWqAAEFqwABBa0AAQWuAAEF7QABBe8AAQXxAAEF8wABBfYAAQX3AAEF+AABBfkAAQX6AAEF/AABBf4AAQX/AAEGAAABBgIAAQYDAAEGQgABBkQAAQZGAAEGSAABBksAAQZMAAEGTQABBk4AAQZPAAEGUQABBlMAAQZUAAEGVQABBlcAAQZYAAEGlwABBpkAAQabAAEGnQABBqAAAQahAAEGogABBqMAAQakAAEGpgABBqgAAQapAAEGqgABBqwAAQatAAEG7AABBu4AAQbwAAEG8gABBvUAAQb2AAEG9wABBvgAAQb5AAEG+wABBv0AAQb+AAEG/wABBwEAAQcCAAEHCwABBwwAAQcOAAEHTQABB08AAQdRAAEHUwABB1YAAQdXAAEHWAABB1kAAQdaAAEHXAABB14AAQdfAAEHYAABB2IAAQdjAAEHogABB6QAAQenAAEHqQABB6wAAQetAAEHrgABB68AAQewAAEHsgABB7QAAQe1AAEHtgABB7gAAQe5AAEH+AABB/oAAQf9AAEH/wABCAIAAQgDAAEIBAABCAUAAQgGAAEICAABCAoAAQgLAAEIDAABCA4AAQgPAAEITgABCFAAAQhTAAEIVQABCFgAAQhZAAEIWgABCFsAAQhcAAEIXgABCGAAAQhhAAEIYgABCGQAAQhlAAEIpAABCKYAAQioAAEIqgABCK0AAQiuAAEIrwABCLAAAQixAAEIswABCLUAAQi2AAEItwABCLkAAQi6AAEJBQABCSgAAQlIAAEJaAABCWoAAQlsAAEJbgABCXAAAQlzAAEJdAABCXUAAQl4AAEJeQABCXsAAQl8AAEJfgABCYEAAQmCAAEJgwABCYYAAQmHAAEJkAABCZ0AAQmiAAEJpAABCaYAAQmrAAEJrgABCbEAAQmzAAEJ2AABCfwAAQojAAEKRwABCkoAAQpMAAEKTgABClAAAQpSAAEKVAABClUAAQpYAAEKZQABCnYAAQp4AAEKegABCnwAAQp+AAEKgAABCoIAAQqEAAEKhgABCpcAAQqaAAEKnQABCqAAAQqjAAEKpgABCqkAAQqsAAEKrwABCrEAAQrwAAEK8gABCvQAAQr2AAEK+QABCvoAAQr7AAEK/AABCv0AAQr/AAELAQABCwIAAQsDAAELBQABCwYAAQtFAAELRwABC0kAAQtLAAELTgABC08AAQtQAAELUQABC1IAAQtUAAELVgABC1cAAQtYAAELWgABC1sAAQuaAAELnAABC58AAQuhAAELpAABC6UAAQumAAELpwABC6gAAQuqAAELrAABC60AAQuuAAELsAABC7EAAQu+AAELvwABC8AAAQvCAAEMAQABDAMAAQwFAAEMBwABDAoAAQwLAAEMDAABDA0AAQwOAAEMEAABDBIAAQwTAAEMFAABDBYAAQwXAAEMVgABDFgAAQxaAAEMXAABDF8AAQxgAAEMYQABDGIAAQxjAAEMZQABDGcAAQxoAAEMaQABDGsAAQxsAAEMqwABDK0AAQyvAAEMsQABDLQAAQy1AAEMtgABDLcAAQy4AAEMugABDLwAAQy9AAEMvgABDMAAAQzBAAENAAABDQIAAQ0EAAENBgABDQkAAQ0KAAENCwABDQwAAQ0NAAENDwABDREAAQ0SAAENEwABDRUAAQ0WAAENVQABDVcAAQ1ZAAENWwABDV4AAQ1fAAENYAABDWEAAQ1iAAENZAABDWYAAQ1nAAENaAABDWoAAQ1rAAENkAABDbQAAQ3bAAEN/wABDgIAAQ4EAAEOBgABDggAAQ4KAAEODAABDg0AAQ4QAAEOHQABDiwAAQ4uAAEOMAABDjIAAQ40AAEONgABDjgAAQ46AAEOSQABDkwAAQ5PAAEOUgABDlUAAQ5YAAEOWwABDl4AAQ5gAAEOnwABDqEAAQ6kAAEOpgABDqkAAQ6qAAEOqwABDqwAAQ6tAAEOrwABDrEAAQ6yAAEOswABDrUAAQ62AAEO9QABDvcAAQ75AAEO+wABDv4AAQ7/AAEPAAABDwEAAQ8CAAEPBAABDwYAAQ8HAAEPCAABDwoAAQ8LAAEPSgABD0wAAQ9OAAEPUAABD1MAAQ9UAAEPVQABD1YAAQ9XAAEPWQABD1sAAQ9cAAEPXQABD18AAQ9gAAEPnwABD6EAAQ+kAAEPpgABD6kAAQ+qAAEPqwABD6wAAQ+tAAEPrwABD7EAAQ+yAAEPswABD7UAAQ+2AAEP9QABD/cAAQ/5AAEP+wABD/4AAQ//AAEQAAABEAEAARACAAEQBAABEAYAARAHAAEQCAABEAoAARALAAEQSgABEEwAARBOAAEQUAABEFMAARBUAAEQVQABEFYAARBXAAEQWQABEFsAARBcAAEQXQABEF8AARBgAAEQnwABEKEAARCjAAEQpQABEKgAARCpAAEQqgABEKsAARCsAAEQrgABELAAARCxAAEQsgABELQAARC1AAERAAABESMAARFDAAERYwABEWUAARFnAAERaQABEWsAARFuAAERbwABEXAAARFzAAERdAABEXYAARF3AAEReQABEXwAARF9AAERfgABEYEAARGCAAERhwABEZQAARGZAAERmwABEZ0AARGiAAERpQABEagAARGqAAERzwABEfMAARIaAAESPgABEkEAARJDAAESRQABEkcAARJJAAESSwABEkwAARJPAAESXAABEm0AARJvAAEScQABEnMAARJ1AAESdwABEnkAARJ7AAESfQABEo4AARKRAAESlAABEpcAARKaAAESnQABEqAAARKjAAESpgABEqgAARLnAAES6QABEusAARLtAAES8AABEvEAARLyAAES8wABEvQAARL2AAES+AABEvkAARL6AAES/AABEv0AARM8AAETPgABE0AAARNCAAETRQABE0YAARNHAAETSAABE0kAARNLAAETTQABE04AARNPAAETUQABE1IAARORAAETkwABE5YAAROYAAETmwABE5wAAROdAAETngABE58AAROhAAETowABE6QAAROlAAETpwABE6gAARO1AAETtgABE7cAARO5AAET+AABE/oAARP8AAET/gABFAEAARQCAAEUAwABFAQAARQFAAEUBwABFAkAARQKAAEUCwABFA0AARQOAAEUTQABFE8AARRRAAEUUwABFFYAARRXAAEUWAABFFkAARRaAAEUXAABFF4AARRfAAEUYAABFGIAARRjAAEUogABFKQAARSmAAEUqAABFKsAARSsAAEUrQABFK4AARSvAAEUsQABFLMAARS0AAEUtQABFLcAARS4AAEU9wABFPkAART7AAEU/QABFQAAARUBAAEVAgABFQMAARUEAAEVBgABFQgAARUJAAEVCgABFQwAARUNAAEVTAABFU4AARVQAAEVUgABFVUAARVWAAEVVwABFVgAARVZAAEVWwABFV0AARVeAAEVXwABFWEAARViAAEVhwABFasAARXSAAEV9gABFfkAARX7AAEV/QABFf8AARYBAAEWAwABFgQAARYHAAEWFAABFiMAARYlAAEWJwABFikAARYrAAEWLQABFi8AARYxAAEWQAABFkMAARZGAAEWSQABFkwAARZPAAEWUgABFlUAARZXAAEWlgABFpgAARaaAAEWnAABFp8AARagAAEWoQABFqIAARajAAEWpQABFqcAARaoAAEWqQABFqsAARasAAEW6wABFu0AARbvAAEW8QABFvQAARb1AAEW9gABFvcAARb4AAEW+gABFvwAARb9AAEW/gABFwAAARcBAAEXQAABF0IAARdEAAEXRgABF0kAARdKAAEXSwABF0wAARdNAAEXTwABF1EAARdSAAEXUwABF1UAARdWAAEXlQABF5cAAReZAAEXmwABF54AARefAAEXoAABF6EAAReiAAEXpAABF6YAARenAAEXqAABF6oAARerAAEX6gABF+wAARfuAAEX8AABF/MAARf0AAEX9QABF/YAARf3AAEX+QABF/sAARf8AAEX/QABF/8AARgAAAEYPwABGEEAARhDAAEYRQABGEgAARhJAAEYSgABGEsAARhMAAEYTgABGFAAARhRAAEYUgABGFQAARhVAAEYlAABGJYAARiYAAEYmgABGJ0AARieAAEYnwABGKAAARihAAEYowABGKUAARimAAEYpwABGKkAARiqAAEY9QABGRgAARk4AAEZWAABGVoAARlcAAEZXgABGWAAARljAAEZZAABGWUAARloAAEZaQABGWsAARlsAAEZbgABGXEAARlyAAEZcwABGXYAARl3AAEZfAABGYkAARmOAAEZkAABGZIAARmXAAEZmgABGZ0AARmfAAEZxAABGegAARoPAAEaMwABGjYAARo4AAEaOgABGjwAARo+AAEaQAABGkEAARpEAAEaUQABGmIAARpkAAEaZgABGmgAARpqAAEabAABGm4AARpwAAEacgABGoMAARqGAAEaiQABGowAARqPAAEakgABGpUAARqYAAEamwABGp0AARrcAAEa3gABGuAAARriAAEa5QABGuYAARrnAAEa6AABGukAARrrAAEa7QABGu4AARrvAAEa8QABGvIAARsxAAEbMwABGzUAARs3AAEbOgABGzsAARs8AAEbPQABGz4AARtAAAEbQgABG0MAARtEAAEbRgABG0cAARuGAAEbiAABG4sAARuNAAEbkAABG5EAARuSAAEbkwABG5QAARuWAAEbmAABG5kAARuaAAEbnAABG50AARuqAAEbqwABG6wAARuuAAEb7QABG+8AARvxAAEb8wABG/YAARv3AAEb+AABG/kAARv6AAEb/AABG/4AARv/AAEcAAABHAIAARwDAAEcQgABHEQAARxGAAEcSAABHEsAARxMAAEcTQABHE4AARxPAAEcUQABHFMAARxUAAEcVQABHFcAARxYAAEclwABHJkAARybAAEcnQABHKAAARyhAAEcogABHKMAARykAAEcpgABHKgAARypAAEcqgABHKwAARytAAEc7AABHO4AARzwAAEc8gABHPUAARz2AAEc9wABHPgAARz5AAEc+wABHP0AARz+AAEc/wABHQEAAR0CAAEdQQABHUMAAR1FAAEdRwABHUoAAR1LAAEdTAABHU0AAR1OAAEdUAABHVIAAR1TAAEdVAABHVYAAR1XAAEdfAABHaAAAR3HAAEd6wABHe4AAR3wAAEd8gABHfQAAR32AAEd+AABHfkAAR38AAEeCQABHhgAAR4aAAEeHAABHh4AAR4gAAEeIgABHiQAAR4mAAEeNQABHjgAAR47AAEePgABHkEAAR5EAAEeRwABHkoAAR5MAAEeiwABHo0AAR6PAAEekQABHpQAAR6VAAEelgABHpcAAR6YAAEemgABHpwAAR6dAAEengABHqAAAR6hAAEe4AABHuIAAR7kAAEe5gABHukAAR7qAAEe6wABHuwAAR7tAAEe7wABHvEAAR7yAAEe8wABHvUAAR72AAEfNQABHzcAAR85AAEfOwABHz4AAR8/AAEfQAABH0EAAR9CAAEfRAABH0YAAR9HAAEfSAABH0oAAR9LAAEfigABH4wAAR+OAAEfkAABH5MAAR+UAAEflQABH5YAAR+XAAEfmQABH5sAAR+cAAEfnQABH58AAR+gAAEf3wABH+EAAR/jAAEf5QABH+gAAR/pAAEf6gABH+sAAR/sAAEf7gABH/AAAR/xAAEf8gABH/QAAR/1AAEgNAABIDYAASA4AAEgOgABID0AASA+AAEgPwABIEAAASBBAAEgQwABIEUAASBGAAEgRwABIEkAASBKAAEgiQABIIsAASCNAAEgjwABIJIAASCTAAEglAABIJUAASCWAAEgmAABIJoAASCbAAEgnAABIJ4AASCfAAEg6gABIQ0AASEtAAEhTQABIU8AASFRAAEhUwABIVUAASFYAAEhWQABIVoAASFdAAEhXgABIWAAASFhAAEhYwABIWYAASFnAAEhaAABIWsAASFsAAEhcQABIX4AASGDAAEhhQABIYcAASGMAAEhjwABIZIAASGUAAEhuQABId0AASIEAAEiKAABIisAASItAAEiLwABIjEAASIzAAEiNQABIjYAASI5AAEiRgABIlcAASJZAAEiWwABIl0AASJfAAEiYQABImMAASJlAAEiZwABIngAASJ7AAEifgABIoEAASKEAAEihwABIooAASKNAAEikAABIpIAASLRAAEi0wABItUAASLXAAEi2gABItsAASLcAAEi3QABIt4AASLgAAEi4gABIuMAASLkAAEi5gABIucAASMmAAEjKAABIyoAASMsAAEjLwABIzAAASMxAAEjMgABIzMAASM1AAEjNwABIzgAASM5AAEjOwABIzwAASN7AAEjfQABI4AAASOCAAEjhQABI4YAASOHAAEjiAABI4kAASOLAAEjjQABI44AASOPAAEjkQABI5IAASOfAAEjoAABI6EAASOjAAEj4gABI+QAASPmAAEj6AABI+sAASPsAAEj7QABI+4AASPvAAEj8QABI/MAASP0AAEj9QABI/cAASP4AAEkNwABJDkAASQ7AAEkPQABJEAAASRBAAEkQgABJEMAASREAAEkRgABJEgAASRJAAEkSgABJEwAASRNAAEkjAABJI4AASSQAAEkkgABJJUAASSWAAEklwABJJgAASSZAAEkmwABJJ0AASSeAAEknwABJKEAASSiAAEk4QABJOMAASTlAAEk5wABJOoAASTrAAEk7AABJO0AASTuAAEk8AABJPIAASTzAAEk9AABJPYAAST3AAElNgABJTgAASU6AAElPAABJT8AASVAAAElQQABJUIAASVDAAElRQABJUcAASVIAAElSQABJUsAASVMAAElcQABJZUAASW8AAEl4AABJeMAASXlAAEl5wABJekAASXrAAEl7QABJe4AASXxAAEl/gABJg0AASYPAAEmEQABJhMAASYVAAEmFwABJhkAASYbAAEmKgABJi0AASYwAAEmMwABJjYAASY5AAEmPAABJj8AASZBAAEmgAABJoIAASaEAAEmhgABJokAASaKAAEmiwABJowAASaNAAEmjwABJpEAASaSAAEmkwABJpUAASaWAAEm1QABJtcAASbZAAEm2wABJt4AASbfAAEm4AABJuEAASbiAAEm5AABJuYAASbnAAEm6AABJuoAASbrAAEnKgABJywAAScuAAEnMAABJzMAASc0AAEnNQABJzYAASc3AAEnOQABJzsAASc8AAEnPQABJz8AASdAAAEnfwABJ4EAASeDAAEnhQABJ4gAASeJAAEnigABJ4sAASeMAAEnjgABJ5AAASeRAAEnkgABJ5QAASeVAAEn1AABJ9YAASfYAAEn2gABJ90AASfeAAEn3wABJ+AAASfhAAEn4wABJ+UAASfmAAEn5wABJ+kAASfqAAEoKQABKCsAASgtAAEoLwABKDIAASgzAAEoNAABKDUAASg2AAEoOAABKDoAASg7AAEoPAABKD4AASg/AAEofgABKIAAASiCAAEohAABKIcAASiIAAEoiQABKIoAASiLAAEojQABKI8AASiQAAEokQABKJMAASiUAAEo3wABKQIAASkiAAEpQgABKUQAASlGAAEpSAABKUoAASlNAAEpTgABKU8AASlSAAEpUwABKVUAASlWAAEpWAABKVsAASlcAAEpXQABKWAAASlhAAEpZgABKXMAASl4AAEpegABKXwAASmBAAEphAABKYcAASmJAAEprgABKdIAASn5AAEqHQABKiAAASoiAAEqJAABKiYAASooAAEqKgABKisAASouAAEqOwABKkwAASpOAAEqUAABKlIAASpUAAEqVgABKlgAASpaAAEqXAABKm0AASpwAAEqcwABKnYAASp5AAEqfAABKn8AASqCAAEqhQABKocAASrGAAEqyAABKsoAASrMAAEqzwABKtAAASrRAAEq0gABKtMAASrVAAEq1wABKtgAASrZAAEq2wABKtwAASsbAAErHQABKx8AASshAAErJAABKyUAASsmAAErJwABKygAASsqAAErLAABKy0AASsuAAErMAABKzEAAStwAAErcgABK3UAASt3AAEregABK3sAASt8AAErfQABK34AASuAAAErggABK4MAASuEAAErhgABK4cAASuUAAErlQABK5YAASuYAAEr1wABK9kAASvbAAEr3QABK+AAASvhAAEr4gABK+MAASvkAAEr5gABK+gAASvpAAEr6gABK+wAASvtAAEsLAABLC4AASwwAAEsMgABLDUAASw2AAEsNwABLDgAASw5AAEsOwABLD0AASw+AAEsPwABLEEAASxCAAEsgQABLIMAASyFAAEshwABLIoAASyLAAEsjAABLI0AASyOAAEskAABLJIAASyTAAEslAABLJYAASyXAAEs1gABLNgAASzaAAEs3AABLN8AASzgAAEs4QABLOIAASzjAAEs5QABLOcAASzoAAEs6QABLOsAASzsAAEtKwABLS0AAS0vAAEtMQABLTQAAS01AAEtNgABLTcAAS04AAEtOgABLTwAAS09AAEtPgABLUAAAS1BAAEtZgABLYoAAS2xAAEt1QABLdgAAS3aAAEt3AABLd4AAS3gAAEt4gABLeMAAS3mAAEt8wABLgIAAS4EAAEuBgABLggAAS4KAAEuDAABLg4AAS4QAAEuHwABLiIAAS4lAAEuKAABLisAAS4uAAEuMQABLjQAAS42AAEudQABLncAAS55AAEuewABLn4AAS5/AAEugAABLoEAAS6CAAEuhAABLoYAAS6HAAEuiAABLooAAS6LAAEuygABLswAAS7OAAEu0AABLtMAAS7UAAEu1QABLtYAAS7XAAEu2QABLtsAAS7cAAEu3QABLt8AAS7gAAEvHwABLyEAAS8jAAEvJQABLygAAS8pAAEvKgABLysAAS8sAAEvLgABLzAAAS8xAAEvMgABLzQAAS81AAEvdAABL3YAAS94AAEvegABL30AAS9+AAEvfwABL4AAAS+BAAEvgwABL4UAAS+GAAEvhwABL4kAAS+KAAEvyQABL8sAAS/NAAEvzwABL9IAAS/TAAEv1AABL9UAAS/WAAEv2AABL9oAAS/bAAEv3AABL94AAS/fAAEwHgABMCAAATAiAAEwJAABMCcAATAoAAEwKQABMCoAATArAAEwLQABMC8AATAwAAEwMQABMDMAATA0AAEwcwABMHUAATB3AAEweQABMHwAATB9AAEwfgABMH8AATCAAAEwggABMIQAATCFAAEwhgABMIgAATCJAAEw1AABMPcAATEXAAExNwABMTkAATE7AAExPQABMT8AATFCAAExQwABMUQAATFHAAExSAABMUoAATFLAAExTQABMVAAATFRAAExUgABMVUAATFWAAExWwABMWgAATFtAAExbwABMXEAATF2AAExeQABMXwAATF+AAExowABMccAATHuAAEyEgABMhUAATIXAAEyGQABMhsAATIdAAEyHwABMiAAATIjAAEyMAABMkEAATJDAAEyRQABMkcAATJJAAEySwABMk0AATJPAAEyUQABMmIAATJlAAEyaAABMmsAATJuAAEycQABMnQAATJ3AAEyegABMnwAATK7AAEyvQABMr8AATLBAAEyxAABMsUAATLGAAEyxwABMsgAATLKAAEyzAABMs0AATLOAAEy0AABMtEAATMQAAEzEgABMxQAATMWAAEzGQABMxoAATMbAAEzHAABMx0AATMfAAEzIQABMyIAATMjAAEzJQABMyYAATNlAAEzZwABM2oAATNsAAEzbwABM3AAATNxAAEzcgABM3MAATN1AAEzdwABM3gAATN5AAEzewABM3wAATOJAAEzigABM4sAATONAAEzzAABM84AATPQAAEz0gABM9UAATPWAAEz1wABM9gAATPZAAEz2wABM90AATPeAAEz3wABM+EAATPiAAE0IQABNCMAATQlAAE0JwABNCoAATQrAAE0LAABNC0AATQuAAE0MAABNDIAATQzAAE0NAABNDYAATQ3AAE0dgABNHgAATR6AAE0fAABNH8AATSAAAE0gQABNIIAATSDAAE0hQABNIcAATSIAAE0iQABNIsAATSMAAE0ywABNM0AATTPAAE00QABNNQAATTVAAE01gABNNcAATTYAAE02gABNNwAATTdAAE03gABNOAAATThAAE1IAABNSIAATUkAAE1JgABNSkAATUqAAE1KwABNSwAATUtAAE1LwABNTEAATUyAAE1MwABNTUAATU2AAE1WwABNX8AATWmAAE1ygABNc0AATXPAAE10QABNdMAATXVAAE11wABNdgAATXbAAE16AABNfcAATX5AAE1+wABNf0AATX/AAE2AQABNgMAATYFAAE2FAABNhcAATYaAAE2HQABNiAAATYjAAE2JgABNikAATYrAAE2agABNmwAATZvAAE2cQABNnQAATZ1AAE2dgABNncAATZ4AAE2egABNnwAATZ9AAE2fgABNoAAATaBAAE2wAABNsIAATbEAAE2xgABNskAATbKAAE2ywABNswAATbNAAE2zwABNtEAATbSAAE20wABNtUAATbWAAE3FQABNxcAATcZAAE3GwABNx4AATcfAAE3IAABNyEAATciAAE3JAABNyYAATcnAAE3KAABNyoAATcrAAE3agABN2wAATdvAAE3cQABN3QAATd1AAE3dgABN3cAATd4AAE3egABN3wAATd9AAE3fgABN4AAATeBAAE3wAABN8IAATfEAAE3xgABN8kAATfKAAE3ywABN8wAATfNAAE3zwABN9EAATfSAAE30wABN9UAATfWAAE4FQABOBcAATgZAAE4GwABOB4AATgfAAE4IAABOCEAATgiAAE4JAABOCYAATgnAAE4KAABOCoAATgrAAE4agABOGwAAThuAAE4cAABOHMAATh0AAE4dQABOHYAATh3AAE4eQABOHsAATh8AAE4fQABOH8AATiAAAE4ywABOO4AATkOAAE5LgABOTAAATkyAAE5NAABOTYAATk5AAE5OgABOTsAATk+AAE5PwABOUEAATlCAAE5RAABOUcAATlIAAE5SQABOUwAATlNAAE5VgABOWMAATloAAE5agABOWwAATlxAAE5dAABOXcAATl5AAE5ngABOcIAATnpAAE6DQABOhAAAToSAAE6FAABOhYAAToYAAE6GgABOhsAAToeAAE6KwABOjwAATo+AAE6QAABOkIAATpEAAE6RgABOkgAATpKAAE6TAABOl0AATpgAAE6YwABOmYAATppAAE6bAABOm8AATpyAAE6dQABOncAATq2AAE6uAABOroAATq8AAE6vwABOsAAATrBAAE6wgABOsMAATrFAAE6xwABOsgAATrJAAE6ywABOswAATsLAAE7DQABOw8AATsRAAE7FAABOxUAATsWAAE7FwABOxgAATsaAAE7HAABOx0AATseAAE7IAABOyEAATtgAAE7YgABO2UAATtnAAE7agABO2sAATtsAAE7bQABO24AATtwAAE7cgABO3MAATt0AAE7dgABO3cAATuEAAE7hQABO4YAATuIAAE7xwABO8kAATvLAAE7zQABO9AAATvRAAE70gABO9MAATvUAAE71gABO9gAATvZAAE72gABO9wAATvdAAE8HAABPB4AATwgAAE8IgABPCUAATwmAAE8JwABPCgAATwpAAE8KwABPC0AATwuAAE8LwABPDEAATwyAAE8cQABPHMAATx1AAE8dwABPHoAATx7AAE8fAABPH0AATx+AAE8gAABPIIAATyDAAE8hAABPIYAATyHAAE8xgABPMgAATzKAAE8zAABPM8AATzQAAE80QABPNIAATzTAAE81QABPNcAATzYAAE82QABPNsAATzcAAE9GwABPR0AAT0fAAE9IQABPSQAAT0lAAE9JgABPScAAT0oAAE9KgABPSwAAT0tAAE9LgABPTAAAT0xAAE9VgABPXoAAT2hAAE9xQABPcgAAT3KAAE9zAABPc4AAT3QAAE90gABPdMAAT3WAAE94wABPfIAAT30AAE99gABPfgAAT36AAE9/AABPf4AAT4AAAE+DwABPhIAAT4VAAE+GAABPhsAAT4eAAE+IQABPiQAAT4mAAE+ZQABPmcAAT5pAAE+awABPm4AAT5vAAE+cAABPnEAAT5yAAE+dAABPnYAAT53AAE+eAABPnoAAT57AAE+ugABPrwAAT6+AAE+wAABPsMAAT7EAAE+xQABPsYAAT7HAAE+yQABPssAAT7MAAE+zQABPs8AAT7QAAE/DwABPxEAAT8TAAE/FQABPxgAAT8ZAAE/GgABPxsAAT8cAAE/HgABPyAAAT8hAAE/IgABPyQAAT8lAAE/ZAABP2YAAT9oAAE/agABP20AAT9uAAE/bwABP3AAAT9xAAE/cwABP3UAAT92AAE/dwABP3kAAT96AAE/uQABP7sAAT+9AAE/vwABP8IAAT/DAAE/xAABP8UAAT/GAAE/yAABP8oAAT/LAAE/zAABP84AAT/PAAFADgABQBAAAUASAAFAFAABQBcAAUAYAAFAGQABQBoAAUAbAAFAHQABQB8AAUAgAAFAIQABQCMAAUAkAAFAYwABQGUAAUBnAAFAaQABQGwAAUBtAAFAbgABQG8AAUBwAAFAcgABQHQAAUB1AAFAdgABQHgAAUB5AAFAxAABQOcAAUEHAAFBJwABQSkAAUErAAFBLQABQS8AAUEyAAFBMwABQTQAAUE3AAFBOAABQToAAUE7AAFBPgABQUEAAUFCAAFBQwABQUYAAUFHAAFBTAABQVkA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AVH9AAFR/wABUgQAAVIHAAFSCgABUgwAAVIxAAFSVQABUnwAAVKgAAFSowABUqUAAVKnAAFSqQABUqsAAVKtAAFSrgABUrEAAVK+AAFSzwABUtEAAVLTAAFS1QABUtcAAVLZAAFS2wABUt0AAVLfAAFS8AABUvMAAVL2AAFS+QABUvwAAVL/AAFTAgABUwUAAVMIAAFTCgABU0kAAVNLAAFTTQABU08AAVNSAAFTUwABU1QAAVNVAAFTVgABU1gAAVNaAAFTWwABU1wAAVNeAAFTXwABU54AAVOgAAFTogABU6QAAVOnAAFTqAABU6kAAVOqAAFTqwABU60AAVOvAAFTsAABU7EAAVOzAAFTtAABU/MAAVP1AAFT+AABU/oAAVP9AAFT/gABU/8AAVQAAAFUAQABVAMAAVQFAAFUBgABVAcAAVQJAAFUCgABVBcAAVQYAAFUGQABVBsAAVRaAAFUXAABVF4AAVRgAAFUYwABVGQAAVRlAAFUZgABVGcAAVRpAAFUawABVGwAAVRtAAFUbwABVHAAAVSvAAFUsQABVLMAAVS1AAFUuAABVLkAAVS6AAFUuwABVLwAAVS+AAFUwAABVMEAAVTCAAFUxAABVMUAAVUEAAFVBgABVQgAAVUKAAFVDQABVQ4AAVUPAAFVEAABVREAAVUTAAFVFQABVRYAAVUXAAFVGQABVRoAAVVZAAFVWwABVV0AAVVfAAFVYgABVWMAAVVkAAFVZQABVWYAAVVoAAFVagABVWsAAVVsAAFVbgABVW8AAVWuAAFVsAABVbIAAVW0AAFVtwABVbgAAVW5AAFVugABVbsAAVW9AAFVvwABVcAAAVXBAAFVwwABVcQAAVXpAAFWDQABVjQAAVZYAAFWWwABVl0AAVZfAAFWYQABVmMAAVZlAAFWZgABVmkAAVZ2AAFWhQABVocAAVaJAAFWiwABVo0AAVaPAAFWkQABVpMAAVaiAAFWpQABVqgAAVarAAFWrgABVrEAAVa0AAFWtwABVrkAAVb4AAFW+gABVvwAAVb+AAFXAQABVwIAAVcDAAFXBAABVwUAAVcHAAFXCQABVwoAAVcLAAFXDQABVw4AAVdNAAFXTwABV1EAAVdTAAFXVgABV1cAAVdYAAFXWQABV1oAAVdcAAFXXgABV18AAVdgAAFXYgABV2MAAVeiAAFXpAABV6YAAVeoAAFXqwABV6wAAVetAAFXrgABV68AAVexAAFXswABV7QAAVe1AAFXtwABV7gAAVf3AAFX+QABV/sAAVf9AAFYAAABWAEAAVgCAAFYAwABWAQAAVgGAAFYCAABWAkAAVgKAAFYDAABWA0AAVhMAAFYTgABWFAAAVhSAAFYVQABWFYAAVhXAAFYWAABWFkAAVhbAAFYXQABWF4AAVhfAAFYYQABWGIAAVihAAFYowABWKUAAVinAAFYqgABWKsAAVisAAFYrQABWK4AAViwAAFYsgABWLMAAVi0AAFYtgABWLcAAVj2AAFY+AABWPoAAVj8AAFY/wABWQAAAVkBAAFZAgABWQMAAVkFAAFZBwABWQgAAVkJAAFZCwABWQwAAVlXAAFZegABWZoAAVm6AAFZvAABWb4AAVnAAAFZwgABWcQAAVnFAAFZxgABWckAAVnKAAFZzAABWc0AAVnPAAFZ0QABWdIAAVnTAAFZ1gABWdcAAVncAAFZ6QABWe4AAVnwAAFZ8gABWfcAAVn6AAFZ/QABWf8AAVokAAFaSAABWm8AAVqTAAFalgABWpgAAVqaAAFanAABWp4AAVqgAAFaoQABWqQAAVqxAAFawgABWsQAAVrGAAFayAABWsoAAVrMAAFazgABWtAAAVrSAAFa4wABWuYAAVrpAAFa7AABWu8AAVryAAFa9QABWvgAAVr7AAFa/QABWzwAAVs+AAFbQAABW0IAAVtFAAFbRgABW0cAAVtIAAFbSQABW0sAAVtNAAFbTgABW08AAVtRAAFbUgABW5EAAVuTAAFblQABW5cAAVuaAAFbmwABW5wAAVudAAFbngABW6AAAVuiAAFbowABW6QAAVumAAFbpwABW+YAAVvoAAFb6wABW+0AAVvwAAFb8QABW/IAAVvzAAFb9AABW/YAAVv4AAFb+QABW/oAAVv8AAFb/QABXAoAAVwLAAFcDAABXA4AAVxNAAFcTwABXFEAAVxTAAFcVgABXFcAAVxYAAFcWQABXFoAAVxcAAFcXgABXF8AAVxgAAFcYgABXGMAAVyiAAFcpAABXKYAAVyoAAFcqwABXKwAAVytAAFcrgABXK8AAVyxAAFcswABXLQAAVy1AAFctwABXLgAAVz3AAFc+QABXPsAAVz9AAFdAAABXQEAAV0CAAFdAwABXQQAAV0GAAFdCAABXQkAAV0KAAFdDAABXQ0AAV1MAAFdTgABXVAAAV1SAAFdVQABXVYAAV1XAAFdWAABXVkAAV1bAAFdXQABXV4AAV1fAAFdYQABXWIAAV2hAAFdowABXaUAAV2nAAFdqgABXasAAV2sAAFdrQABXa4AAV2wAAFdsgABXbMAAV20AAFdtgABXbcAAV3cAAFeAAABXicAAV5LAAFeTgABXlAAAV5SAAFeVAABXlYAAV5YAAFeWQABXlwAAV5pAAFeeAABXnoAAV58AAFefgABXoAAAV6CAAFehAABXoYAAV6VAAFemAABXpsAAV6eAAFeoQABXqQAAV6nAAFeqgABXqwAAV7rAAFe7QABXu8AAV7xAAFe9AABXvUAAV72AAFe9wABXvgAAV76AAFe/AABXv0AAV7+AAFfAAABXwEAAV9AAAFfQgABX0QAAV9GAAFfSQABX0oAAV9LAAFfTAABX00AAV9PAAFfUQABX1IAAV9TAAFfVQABX1YAAV+VAAFflwABX5kAAV+bAAFfngABX58AAV+gAAFfoQABX6IAAV+kAAFfpgABX6cAAV+oAAFfqgABX6sAAV/qAAFf7AABX+4AAV/wAAFf8wABX/QAAV/1AAFf9gABX/cAAV/5AAFf+wABX/wAAV/9AAFf/wABYAAAAWA/AAFgQQABYEMAAWBFAAFgSAABYEkAAWBKAAFgSwABYEwAAWBOAAFgUAABYFEAAWBSAAFgVAABYFUAAWCUAAFglgABYJgAAWCaAAFgnQABYJ4AAWCfAAFgoAABYKEAAWCjAAFgpQABYKYAAWCnAAFgqQABYKoAAWDpAAFg6wABYO0AAWDvAAFg8gABYPMAAWD0AAFg9QABYPYAAWD4AAFg+gABYPsAAWD8AAFg/gABYP8AAWEIAAFhCQABYQsAAWFOAAFhcgABYZYAAWG5AAFh4AABYgAAAWInAAFiTgABYm4AAWKSAAFitgABYrgAAWK7AAFivQABYr8AAWLBAAFixAABYsYAAWLIAAFiygABYswAAWLOAAFi0AABYtMAAWLWAAFi1wABYuAAAWLtAAFi8AABYvIAAWL1AAFi+AABYvoAAWMfAAFjQwABY2oAAWOOAAFjkQABY5MAAWOVAAFjlwABY5kAAWObAAFjnAABY58AAWOsAAFjvwABY8EAAWPDAAFjxQABY8cAAWPJAAFjywABY80AAWPPAAFj0QABY+QAAWPnAAFj6gABY+0AAWPwAAFj8wABY/YAAWP5AAFj/AABY/8AAWQBAAFkQAABZEIAAWRFAAFkRwABZEoAAWRLAAFkTAABZE0AAWROAAFkUAABZFIAAWRTAAFkVAABZFYAAWRXAAFkYAABZGEAAWRjAAFkogABZKQAAWSmAAFkqAABZKsAAWSsAAFkrQABZK4AAWSvAAFksQABZLMAAWS0AAFktQABZLcAAWS4AAFk9wABZPkAAWT8AAFk/gABZQEAAWUCAAFlAwABZQQAAWUFAAFlBwABZQkAAWUKAAFlCwABZQ0AAWUOAAFlFwABZRgAAWUaAAFlWQABZVsAAWVdAAFlXwABZWIAAWVjAAFlZAABZWUAAWVmAAFlaAABZWoAAWVrAAFlbAABZW4AAWVvAAFlrgABZbAAAWWzAAFltQABZbgAAWW5AAFlugABZbsAAWW8AAFlvgABZcAAAWXBAAFlwgABZcQAAWXFAAFlzgABZc8AAWXRAAFmEAABZhIAAWYUAAFmFgABZhkAAWYaAAFmGwABZhwAAWYdAAFmHwABZiEAAWYiAAFmIwABZiUAAWYmAAFmZQABZmcAAWZqAAFmbAABZm8AAWZwAAFmcQABZnIAAWZzAAFmdQABZncAAWZ4AAFmeQABZnsAAWZ8AAFmiQABZooAAWaLAAFmjQABZswAAWbOAAFm0AABZtIAAWbVAAFm1gABZtcAAWbYAAFm2QABZtsAAWbdAAFm3gABZt8AAWbhAAFm4gABZyEAAWcjAAFnJgABZygAAWcrAAFnLAABZy0AAWcuAAFnLwABZzEAAWczAAFnNAABZzUAAWc3AAFnOAABZ0YAAWdTAAFnWAABZ1sAAWddAAFnYgABZ2UAAWdoAAFnagABZ3IAAWe9AAFn4AABaAAAAWggAAFoIgABaCQAAWgmAAFoKAABaCsAAWgsAAFoLQABaDAAAWgxAAFoMwABaDQAAWg2AAFoOQABaDoAAWg7AAFoPgABaD8AAWhEAAFoUQABaFYAAWhYAAFoWgABaF8AAWhiAAFoZQABaGcAAWiMAAFosAABaNcAAWj7AAFo/gABaQAAAWkCAAFpBAABaQYAAWkIAAFpCQABaQwAAWkZAAFpKgABaSwAAWkuAAFpMAABaTIAAWk0AAFpNgABaTgAAWk6AAFpSwABaU4AAWlRAAFpVAABaVcAAWlaAAFpXQABaWAAAWljAAFpZQABaaQAAWmmAAFpqAABaaoAAWmtAAFprgABaa8AAWmwAAFpsQABabMAAWm1AAFptgABabcAAWm5AAFpugABafkAAWn7AAFp/QABaf8AAWoCAAFqAwABagQAAWoFAAFqBgABaggAAWoKAAFqCwABagwAAWoOAAFqDwABak4AAWpQAAFqUwABalUAAWpYAAFqWQABaloAAWpbAAFqXAABal4AAWpgAAFqYQABamIAAWpkAAFqZQABanIAAWpzAAFqdAABanYAAWq1AAFqtwABarkAAWq7AAFqvgABar8AAWrAAAFqwQABasIAAWrEAAFqxgABascAAWrIAAFqygABassAAWsKAAFrDAABaw4AAWsQAAFrEwABaxQAAWsVAAFrFgABaxcAAWsZAAFrGwABaxwAAWsdAAFrHwABayAAAWtfAAFrYQABa2MAAWtlAAFraAABa2kAAWtqAAFrawABa2wAAWtuAAFrcAABa3EAAWtyAAFrdAABa3UAAWu0AAFrtgABa7gAAWu6AAFrvQABa74AAWu/AAFrwAABa8EAAWvDAAFrxQABa8YAAWvHAAFryQABa8oAAWwJAAFsCwABbA0AAWwPAAFsEgABbBMAAWwUAAFsFQABbBYAAWwYAAFsGgABbBsAAWwcAAFsHgABbB8AAWxEAAFsaAABbI8AAWyzAAFstgABbLgAAWy6AAFsvAABbL4AAWzAAAFswQABbMQAAWzRAAFs4AABbOIAAWzkAAFs5gABbOgAAWzqAAFs7AABbO4AAWz9AAFtAAABbQMAAW0GAAFtCQABbQwAAW0PAAFtEgABbRQAAW1TAAFtVQABbVcAAW1ZAAFtXAABbV0AAW1eAAFtXwABbWAAAW1iAAFtZAABbWUAAW1mAAFtaAABbWkAAW2oAAFtqgABbawAAW2uAAFtsQABbbIAAW2zAAFttAABbbUAAW23AAFtuQABbboAAW27AAFtvQABbb4AAW39AAFt/wABbgEAAW4DAAFuBgABbgcAAW4IAAFuCQABbgoAAW4MAAFuDgABbg8AAW4QAAFuEgABbhMAAW5SAAFuVAABblYAAW5YAAFuWwABblwAAW5dAAFuXgABbl8AAW5hAAFuYwABbmQAAW5lAAFuZwABbmgAAW6nAAFuqQABbqsAAW6tAAFusAABbrEAAW6yAAFuswABbrQAAW62AAFuuAABbrkAAW66AAFuvAABbr0AAW78AAFu/gABbwAAAW8CAAFvBQABbwYAAW8HAAFvCAABbwkAAW8LAAFvDQABbw4AAW8PAAFvEQABbxIAAW9RAAFvUwABb1UAAW9XAAFvWgABb1sAAW9cAAFvXQABb14AAW9gAAFvYgABb2MAAW9kAAFvZgABb2cAAW+yAAFv1QABb/UAAXAVAAFwFwABcBkAAXAbAAFwHQABcCAAAXAhAAFwIgABcCUAAXAmAAFwKAABcCkAAXArAAFwLQABcC4AAXAvAAFwMgABcDMAAXA8AAFwSQABcE4AAXBQAAFwUgABcFcAAXBaAAFwXQABcF8AAXCEAAFwqAABcM8AAXDzAAFw9gABcPgAAXD6AAFw/AABcP4AAXEAAAFxAQABcQQAAXERAAFxIgABcSQAAXEmAAFxKAABcSoAAXEsAAFxLgABcTAAAXEyAAFxQwABcUYAAXFJAAFxTAABcU8AAXFSAAFxVQABcVgAAXFbAAFxXQABcZwAAXGeAAFxoAABcaIAAXGlAAFxpgABcacAAXGoAAFxqQABcasAAXGtAAFxrgABca8AAXGxAAFxsgABcfEAAXHzAAFx9QABcfcAAXH6AAFx+wABcfwAAXH9AAFx/gABcgAAAXICAAFyAwABcgQAAXIGAAFyBwABckYAAXJIAAFySwABck0AAXJQAAFyUQABclIAAXJTAAFyVAABclYAAXJYAAFyWQABcloAAXJcAAFyXQABcmoAAXJrAAFybAABcm4AAXKtAAFyrwABcrEAAXKzAAFytgABcrcAAXK4AAFyuQABcroAAXK8AAFyvgABcr8AAXLAAAFywgABcsMAAXMCAAFzBAABcwYAAXMIAAFzCwABcwwAAXMNAAFzDgABcw8AAXMRAAFzEwABcxQAAXMVAAFzFwABcxgAAXNXAAFzWQABc1sAAXNdAAFzYAABc2EAAXNiAAFzYwABc2QAAXNmAAFzaAABc2kAAXNqAAFzbAABc20AAXOsAAFzrgABc7AAAXOyAAFztQABc7YAAXO3AAFzuAABc7kAAXO7AAFzvQABc74AAXO/AAFzwQABc8IAAXQBAAF0AwABdAUAAXQHAAF0CgABdAsAAXQMAAF0DQABdA4AAXQQAAF0EgABdBMAAXQUAAF0FgABdBcAAXQ8AAF0YAABdIcAAXSrAAF0rgABdLAAAXSyAAF0tAABdLYAAXS4AAF0uQABdLwAAXTJAAF02AABdNoAAXTcAAF03gABdOAAAXTiAAF05AABdOYAAXT1AAF0+AABdPsAAXT+AAF1AQABdQQAAXUHAAF1CgABdQwAAXVLAAF1TQABdU8AAXVRAAF1VAABdVUAAXVWAAF1VwABdVgAAXVaAAF1XAABdV0AAXVeAAF1YAABdWEAAXWgAAF1ogABdaQAAXWmAAF1qQABdaoAAXWrAAF1rAABda0AAXWvAAF1sQABdbIAAXWzAAF1tQABdbYAAXX1AAF19wABdfkAAXX7AAF1/gABdf8AAXYAAAF2AQABdgIAAXYEAAF2BgABdgcAAXYIAAF2CgABdgsAAXZKAAF2TAABdk4AAXZQAAF2UwABdlQAAXZVAAF2VgABdlcAAXZZAAF2WwABdlwAAXZdAAF2XwABdmAAAXafAAF2oQABdqMAAXalAAF2qAABdqkAAXaqAAF2qwABdqwAAXauAAF2sAABdrEAAXayAAF2tAABdrUAAXb0AAF29gABdvgAAXb6AAF2/QABdv4AAXb/AAF3AAABdwEAAXcDAAF3BQABdwYAAXcHAAF3CQABdwoAAXdJAAF3SwABd00AAXdPAAF3UgABd1MAAXdUAAF3VQABd1YAAXdYAAF3WgABd1sAAXdcAAF3XgABd18AAXdoAAF3aQABd2sAAXeuAAF30gABd/YAAXgZAAF4QAABeGAAAXiHAAF4rgABeM4AAXjyAAF5FgABeRgAAXkbAAF5HQABeR8AAXkhAAF5JAABeSYAAXkoAAF5KgABeSwAAXkuAAF5MAABeTMAAXk2AAF5NwABeTwAAXlJAAF5TAABeU4AAXlRAAF5VAABeVYAAXl7AAF5nwABecYAAXnqAAF57QABee8AAXnxAAF58wABefUAAXn3AAF5+AABefsAAXoIAAF6GwABeh0AAXofAAF6IQABeiMAAXolAAF6JwABeikAAXorAAF6LQABekAAAXpDAAF6RgABekkAAXpMAAF6TwABelIAAXpVAAF6WAABelsAAXpdAAF6nAABep4AAXqhAAF6owABeqYAAXqnAAF6qAABeqkAAXqqAAF6rAABeq4AAXqvAAF6sAABerIAAXqzAAF6vAABer0AAXq/AAF6/gABewAAAXsCAAF7BAABewcAAXsIAAF7CQABewoAAXsLAAF7DQABew8AAXsQAAF7EQABexMAAXsUAAF7UwABe1UAAXtYAAF7WgABe10AAXteAAF7XwABe2AAAXthAAF7YwABe2UAAXtmAAF7ZwABe2kAAXtqAAF7cwABe3QAAXt2AAF7tQABe7cAAXu5AAF7uwABe74AAXu/AAF7wAABe8EAAXvCAAF7xAABe8YAAXvHAAF7yAABe8oAAXvLAAF8CgABfAwAAXwPAAF8EQABfBQAAXwVAAF8FgABfBcAAXwYAAF8GgABfBwAAXwdAAF8HgABfCAAAXwhAAF8KgABfCsAAXwtAAF8bAABfG4AAXxwAAF8cgABfHUAAXx2AAF8dwABfHgAAXx5AAF8ewABfH0AAXx+AAF8fwABfIEAAXyCAAF8wQABfMMAAXzGAAF8yAABfMsAAXzMAAF8zQABfM4AAXzPAAF80QABfNMAAXzUAAF81QABfNcAAXzYAAF85QABfOYAAXznAAF86QABfSgAAX0qAAF9LAABfS4AAX0xAAF9MgABfTMAAX00AAF9NQABfTcAAX05AAF9OgABfTsAAX09AAF9PgABfX0AAX1/AAF9ggABfYQAAX2HAAF9iAABfYkAAX2KAAF9iwABfY0AAX2PAAF9kAABfZEAAX2TAAF9lAABfaIAAX2vAAF9ugABfb0AAX3AAAF9wwABfcUAAX3IAAF90wABfdYAAX3ZAAF93AABfd8AAX3iAAF95AABffAAAX3+AAF+CAABfhEAAX5cAAF+fwABfp8AAX6/AAF+wQABfsMAAX7FAAF+xwABfsoAAX7LAAF+zAABfs8AAX7QAAF+0gABftMAAX7VAAF+2AABftkAAX7aAAF+3QABft4AAX7jAAF+8AABfvUAAX73AAF++QABfv4AAX8BAAF/BAABfwYAAX8rAAF/TwABf3YAAX+aAAF/nQABf58AAX+hAAF/owABf6UAAX+nAAF/qAABf6sAAX+4AAF/yQABf8sAAX/NAAF/zwABf9EAAX/TAAF/1QABf9cAAX/ZAAF/6gABf+0AAX/wAAF/8wABf/YAAX/5AAF//AABf/8AAYACAAGABAABgEMAAYBFAAGARwABgEkAAYBMAAGATQABgE4AAYBPAAGAUAABgFIAAYBUAAGAVQABgFYAAYBYAAGAWQABgJgAAYCaAAGAnAABgJ4AAYChAAGAogABgKMAAYCkAAGApQABgKcAAYCpAAGAqgABgKsAAYCtAAGArgABgO0AAYDvAAGA8gABgPQAAYD3AAGA+AABgPkAAYD6AAGA+wABgP0AAYD/AAGBAAABgQEAAYEDAAGBBAABgREAAYESAAGBEwABgRUAAYFUAAGBVgABgVgAAYFaAAGBXQABgV4AAYFfAAGBYAABgWEAAYFjAAGBZQABgWYAAYFnAAGBaQABgWoAAYGpAAGBqwABga0AAYGvAAGBsgABgbMAAYG0AAGBtQABgbYAAYG4AAGBugABgbsAAYG8AAGBvgABgb8AAYH+AAGCAAABggIAAYIEAAGCBwABgggAAYIJAAGCCgABggsAAYINAAGCDwABghAAAYIRAAGCEwABghQAAYJTAAGCVQABglcAAYJZAAGCXAABgl0AAYJeAAGCXwABgmAAAYJiAAGCZAABgmUAAYJmAAGCaAABgmkAAYKoAAGCqgABgqwAAYKuAAGCsQABgrIAAYKzAAGCtAABgrUAAYK3AAGCuQABgroAAYK7AAGCvQABgr4AAYLjAAGDBwABgy4AAYNSAAGDVQABg1cAAYNZAAGDWwABg10AAYNfAAGDYAABg2MAAYNwAAGDfwABg4EAAYODAAGDhQABg4cAAYOJAAGDiwABg40AAYOcAAGDnwABg6IAAYOlAAGDqAABg6sAAYOuAAGDsQABg7MAAYPyAAGD9AABg/YAAYP4AAGD+wABg/wAAYP9AAGD/gABg/8AAYQBAAGEAwABhAQAAYQFAAGEBwABhAgAAYRHAAGESQABhEsAAYRNAAGEUAABhFEAAYRSAAGEUwABhFQAAYRWAAGEWAABhFkAAYRaAAGEXAABhF0AAYScAAGEngABhKAAAYSiAAGEpQABhKYAAYSnAAGEqAABhKkAAYSrAAGErQABhK4AAYSvAAGEsQABhLIAAYTxAAGE8wABhPUAAYT3AAGE+gABhPsAAYT8AAGE/QABhP4AAYUAAAGFAgABhQMAAYUEAAGFBgABhQcAAYVGAAGFSAABhUoAAYVMAAGFTwABhVAAAYVRAAGFUgABhVMAAYVVAAGFVwABhVgAAYVZAAGFWwABhVwAAYWbAAGFnQABhZ8AAYWhAAGFpAABhaUAAYWmAAGFpwABhagAAYWqAAGFrAABha0AAYWuAAGFsAABhbEAAYXwAAGF8gABhfQAAYX2AAGF+QABhfoAAYX7AAGF/AABhf0AAYX/AAGGAQABhgIAAYYDAAGGBQABhgYAAYZRAAGGdAABhpQAAYa0AAGGtgABhrgAAYa6AAGGvAABhr8AAYbAAAGGwQABhsQAAYbFAAGGxwABhsgAAYbKAAGGzQABhs4AAYbPAAGG0gABhtMAAYbYAAGG5QABhuoAAYbsAAGG7gABhvMAAYb2AAGG+QABhvsAAYcgAAGHRAABh2sAAYePAAGHkgABh5QAAYeWAAGHmAABh5oAAYecAAGHnQABh6AAAYetAAGHvgABh8AAAYfCAAGHxAABh8YAAYfIAAGHygABh8wAAYfOAAGH3wABh+IAAYflAAGH6AABh+sAAYfuAAGH8QABh/QAAYf3AAGH+QABiDgAAYg6AAGIPAABiD4AAYhBAAGIQgABiEMAAYhEAAGIRQABiEcAAYhJAAGISgABiEsAAYhNAAGITgABiI0AAYiPAAGIkQABiJMAAYiWAAGIlwABiJgAAYiZAAGImgABiJwAAYieAAGInwABiKAAAYiiAAGIowABiOIAAYjkAAGI5wABiOkAAYjsAAGI7QABiO4AAYjvAAGI8AABiPIAAYj0AAGI9QABiPYAAYj4AAGI+QABiQYAAYkHAAGJCAABiQoAAYlJAAGJSwABiU0AAYlPAAGJUgABiVMAAYlUAAGJVQABiVYAAYlYAAGJWgABiVsAAYlcAAGJXgABiV8AAYmeAAGJoAABiaIAAYmkAAGJpwABiagAAYmpAAGJqgABiasAAYmtAAGJrwABibAAAYmxAAGJswABibQAAYnzAAGJ9QABifcAAYn5AAGJ/AABif0AAYn+AAGJ/wABigAAAYoCAAGKBAABigUAAYoGAAGKCAABigkAAYpIAAGKSgABikwAAYpOAAGKUQABilIAAYpTAAGKVAABilUAAYpXAAGKWQABiloAAYpbAAGKXQABil4AAYqdAAGKnwABiqEAAYqjAAGKpgABiqcAAYqoAAGKqQABiqoAAYqsAAGKrgABiq8AAYqwAAGKsgABirMAAYrYAAGK/AABiyMAAYtHAAGLSgABi0wAAYtOAAGLUAABi1IAAYtUAAGLVQABi1gAAYtlAAGLdAABi3YAAYt4AAGLegABi3wAAYt+AAGLgAABi4IAAYuRAAGLlAABi5cAAYuaAAGLnQABi6AAAYujAAGLpgABi6gAAYvnAAGL6QABi+sAAYvtAAGL8AABi/EAAYvyAAGL8wABi/QAAYv2AAGL+AABi/kAAYv6AAGL/AABi/0AAYw8AAGMPgABjEAAAYxCAAGMRQABjEYAAYxHAAGMSAABjEkAAYxLAAGMTQABjE4AAYxPAAGMUQABjFIAAYyRAAGMkwABjJUAAYyXAAGMmgABjJsAAYycAAGMnQABjJ4AAYygAAGMogABjKMAAYykAAGMpgABjKcAAYzmAAGM6AABjOoAAYzsAAGM7wABjPAAAYzxAAGM8gABjPMAAYz1AAGM9wABjPgAAYz5AAGM+wABjPwAAY07AAGNPQABjT8AAY1BAAGNRAABjUUAAY1GAAGNRwABjUgAAY1KAAGNTAABjU0AAY1OAAGNUAABjVEAAY2QAAGNkgABjZQAAY2WAAGNmQABjZoAAY2bAAGNnAABjZ0AAY2fAAGNoQABjaIAAY2jAAGNpQABjaYAAY3lAAGN5wABjekAAY3rAAGN7gABje8AAY3wAAGN8QABjfIAAY30AAGN9gABjfcAAY34AAGN+gABjfsAAY5GAAGOaQABjokAAY6pAAGOqwABjq0AAY6vAAGOsQABjrQAAY61AAGOtgABjrkAAY66AAGOvAABjr0AAY6/AAGOwgABjsMAAY7EAAGOxwABjsgAAY7NAAGO2gABjt8AAY7hAAGO4wABjugAAY7rAAGO7gABjvAAAY8VAAGPOQABj2AAAY+EAAGPhwABj4kAAY+LAAGPjQABj48AAY+RAAGPkgABj5UAAY+iAAGPswABj7UAAY+3AAGPuQABj7sAAY+9AAGPvwABj8EAAY/DAAGP1AABj9cAAY/aAAGP3QABj+AAAY/jAAGP5gABj+kAAY/sAAGP7gABkC0AAZAvAAGQMQABkDMAAZA2AAGQNwABkDgAAZA5AAGQOgABkDwAAZA+AAGQPwABkEAAAZBCAAGQQwABkIIAAZCEAAGQhgABkIgAAZCLAAGQjAABkI0AAZCOAAGQjwABkJEAAZCTAAGQlAABkJUAAZCXAAGQmAABkNcAAZDZAAGQ3AABkN4AAZDhAAGQ4gABkOMAAZDkAAGQ5QABkOcAAZDpAAGQ6gABkOsAAZDtAAGQ7gABkPsAAZD8AAGQ/QABkP8AAZE+AAGRQAABkUIAAZFEAAGRRwABkUgAAZFJAAGRSgABkUsAAZFNAAGRTwABkVAAAZFRAAGRUwABkVQAAZGTAAGRlQABkZcAAZGZAAGRnAABkZ0AAZGeAAGRnwABkaAAAZGiAAGRpAABkaUAAZGmAAGRqAABkakAAZHoAAGR6gABkewAAZHuAAGR8QABkfIAAZHzAAGR9AABkfUAAZH3AAGR+QABkfoAAZH7AAGR/QABkf4AAZI9AAGSPwABkkEAAZJDAAGSRgABkkcAAZJIAAGSSQABkkoAAZJMAAGSTgABkk8AAZJQAAGSUgABklMAAZKSAAGSlAABkpYAAZKYAAGSmwABkpwAAZKdAAGSngABkp8AAZKhAAGSowABkqQAAZKlAAGSpwABkqgAAZLNAAGS8QABkxgAAZM8AAGTPwABk0EAAZNDAAGTRQABk0cAAZNJAAGTSgABk00AAZNaAAGTaQABk2sAAZNtAAGTbwABk3EAAZNzAAGTdQABk3cAAZOGAAGTiQABk4wAAZOPAAGTkgABk5UAAZOYAAGTmwABk50AAZPcAAGT3gABk+EAAZPjAAGT5gABk+cAAZPoAAGT6QABk+oAAZPsAAGT7gABk+8AAZPwAAGT8gABk/MAAZQyAAGUNAABlDYAAZQ4AAGUOwABlDwAAZQ9AAGUPgABlD8AAZRBAAGUQwABlEQAAZRFAAGURwABlEgAAZSHAAGUiQABlIsAAZSNAAGUkAABlJEAAZSSAAGUkwABlJQAAZSWAAGUmAABlJkAAZSaAAGUnAABlJ0AAZTcAAGU3gABlOEAAZTjAAGU5gABlOcAAZToAAGU6QABlOoAAZTsAAGU7gABlO8AAZTwAAGU8gABlPMAAZT2AAGVNQABlTcAAZU5AAGVOwABlT4AAZU/AAGVQAABlUEAAZVCAAGVRAABlUYAAZVHAAGVSAABlUoAAZVLAAGVigABlYwAAZWOAAGVkAABlZMAAZWUAAGVlQABlZYAAZWXAAGVmQABlZsAAZWcAAGVnQABlZ8AAZWgAAGV3wABleEAAZXjAAGV5QABlegAAZXpAAGV6gABlesAAZXsAAGV7gABlfAAAZXxAAGV8gABlfQAAZX1AAGWQAABlmMAAZaDAAGWowABlqUAAZanAAGWqQABlqsAAZauAAGWrwABlrAAAZazAAGWtAABlrYAAZa3AAGWuQABlrsAAZa8AAGWvQABlsAAAZbBAAGWygABltcAAZbcAAGW3gABluAAAZblAAGW6AABlusAAZbtAAGXEgABlzYAAZddAAGXgQABl4QAAZeGAAGXiAABl4oAAZeMAAGXjgABl48AAZeSAAGXnwABl7AAAZeyAAGXtAABl7YAAZe4AAGXugABl7wAAZe+AAGXwAABl9EAAZfUAAGX1wABl9oAAZfdAAGX4AABl+MAAZfmAAGX6QABl+sAAZgqAAGYLAABmC4AAZgwAAGYMwABmDQAAZg1AAGYNgABmDcAAZg5AAGYOwABmDwAAZg9AAGYPwABmEAAAZh/AAGYgQABmIMAAZiFAAGYiAABmIkAAZiKAAGYiwABmIwAAZiOAAGYkAABmJEAAZiSAAGYlAABmJUAAZjUAAGY1gABmNkAAZjbAAGY3gABmN8AAZjgAAGY4QABmOIAAZjkAAGY5gABmOcAAZjoAAGY6gABmOsAAZj4AAGY+QABmPoAAZj8AAGZOwABmT0AAZk/AAGZQQABmUQAAZlFAAGZRgABmUcAAZlIAAGZSgABmUwAAZlNAAGZTgABmVAAAZlRAAGZkAABmZIAAZmUAAGZlgABmZkAAZmaAAGZmwABmZwAAZmdAAGZnwABmaEAAZmiAAGZowABmaUAAZmmAAGZ5QABmecAAZnpAAGZ6wABme4AAZnvAAGZ8AABmfEAAZnyAAGZ9AABmfYAAZn3AAGZ+AABmfoAAZn7AAGaOgABmjwAAZo+AAGaQAABmkMAAZpEAAGaRQABmkYAAZpHAAGaSQABmksAAZpMAAGaTQABmk8AAZpQAAGajwABmpEAAZqTAAGalQABmpgAAZqZAAGamgABmpsAAZqcAAGangABmqAAAZqhAAGaogABmqQAAZqlAAGaygABmu4AAZsVAAGbOQABmzwAAZs+AAGbQAABm0IAAZtEAAGbRgABm0cAAZtKAAGbVwABm2YAAZtoAAGbagABm2wAAZtuAAGbcAABm3IAAZt0AAGbgwABm4YAAZuJAAGbjAABm48AAZuSAAGblQABm5gAAZuaAAGb2QABm9sAAZvdAAGb3wABm+IAAZvjAAGb5AABm+UAAZvmAAGb6AABm+oAAZvrAAGb7AABm+4AAZvvAAGcLgABnDAAAZwyAAGcNAABnDcAAZw4AAGcOQABnDoAAZw7AAGcPQABnD8AAZxAAAGcQQABnEMAAZxEAAGcgwABnIUAAZyHAAGciQABnIwAAZyNAAGcjgABnI8AAZyQAAGckgABnJQAAZyVAAGclgABnJgAAZyZAAGc2AABnNoAAZzcAAGc3gABnOEAAZziAAGc4wABnOQAAZzlAAGc5wABnOkAAZzqAAGc6wABnO0AAZzuAAGdLQABnS8AAZ0xAAGdMwABnTYAAZ03AAGdOAABnTkAAZ06AAGdPAABnT4AAZ0/AAGdQAABnUIAAZ1DAAGdggABnYQAAZ2GAAGdiAABnYsAAZ2MAAGdjQABnY4AAZ2PAAGdkQABnZMAAZ2UAAGdlQABnZcAAZ2YAAGd1wABndkAAZ3bAAGd3QABneAAAZ3hAAGd4gABneMAAZ3kAAGd5gABnegAAZ3pAAGd6gABnewAAZ3tAAGeOAABnlsAAZ57AAGemwABnp0AAZ6fAAGeoQABnqMAAZ6mAAGepwABnqgAAZ6rAAGerAABnq4AAZ6vAAGesQABnrQAAZ61AAGetgABnrkAAZ66AAGewwABntAAAZ7VAAGe1wABntkAAZ7eAAGe4QABnuQAAZ7mAAGfCwABny8AAZ9WAAGfegABn30AAZ9/AAGfgQABn4MAAZ+FAAGfhwABn4gAAZ+LAAGfmAABn6kAAZ+rAAGfrQABn68AAZ+xAAGfswABn7UAAZ+3AAGfuQABn8oAAZ/NAAGf0AABn9MAAZ/WAAGf2QABn9wAAZ/fAAGf4gABn+QAAaAjAAGgJQABoCcAAaApAAGgLAABoC0AAaAuAAGgLwABoDAAAaAyAAGgNAABoDUAAaA2AAGgOAABoDkAAaB4AAGgegABoHwAAaB+AAGggQABoIIAAaCDAAGghAABoIUAAaCHAAGgiQABoIoAAaCLAAGgjQABoI4AAaDNAAGgzwABoNIAAaDUAAGg1wABoNgAAaDZAAGg2gABoNsAAaDdAAGg3wABoOAAAaDhAAGg4wABoOQAAaDxAAGg8gABoPMAAaD1AAGhNAABoTYAAaE4AAGhOgABoT0AAaE+AAGhPwABoUAAAaFBAAGhQwABoUUAAaFGAAGhRwABoUkAAaFKAAGhiQABoYsAAaGNAAGhjwABoZIAAaGTAAGhlAABoZUAAaGWAAGhmAABoZoAAaGbAAGhnAABoZ4AAaGfAAGh3gABoeAAAaHiAAGh5AABoecAAaHoAAGh6QABoeoAAaHrAAGh7QABoe8AAaHwAAGh8QABofMAAaH0AAGiMwABojUAAaI3AAGiOQABojwAAaI9AAGiPgABoj8AAaJAAAGiQgABokQAAaJFAAGiRgABokgAAaJJAAGiiAABoooAAaKMAAGijgABopEAAaKSAAGikwABopQAAaKVAAGilwABopkAAaKaAAGimwABop0AAaKeAAGiwwABoucAAaMOAAGjMgABozUAAaM3AAGjOQABozsAAaM9AAGjPwABo0AAAaNDAAGjUAABo18AAaNhAAGjYwABo2UAAaNnAAGjaQABo2sAAaNtAAGjfAABo38AAaOCAAGjhQABo4gAAaOLAAGjjgABo5EAAaOTAAGj0gABo9QAAaPWAAGj2AABo9sAAaPcAAGj3QABo94AAaPfAAGj4QABo+MAAaPkAAGj5QABo+cAAaPoAAGkJwABpCkAAaQrAAGkLQABpDAAAaQxAAGkMgABpDMAAaQ0AAGkNgABpDgAAaQ5AAGkOgABpDwAAaQ9AAGkfAABpH4AAaSAAAGkggABpIUAAaSGAAGkhwABpIgAAaSJAAGkiwABpI0AAaSOAAGkjwABpJEAAaSSAAGk0QABpNMAAaTVAAGk1wABpNoAAaTbAAGk3AABpN0AAaTeAAGk4AABpOIAAaTjAAGk5AABpOYAAaTnAAGlJgABpSgAAaUqAAGlLAABpS8AAaUwAAGlMQABpTIAAaUzAAGlNQABpTcAAaU4AAGlOQABpTsAAaU8AAGlewABpX0AAaV/AAGlgQABpYQAAaWFAAGlhgABpYcAAaWIAAGligABpYwAAaWNAAGljgABpZAAAaWRAAGl0AABpdIAAaXUAAGl1gABpdkAAaXaAAGl2wABpdwAAaXdAAGl3wABpeEAAaXiAAGl4wABpeUAAaXmAAGl7wABpfAAAaXyAAGmNQABplkAAaZ9AAGmoAABpscAAabnAAGnDgABpzUAAadVAAGneQABp50AAaefAAGnogABp6QAAaemAAGnqAABp6sAAaetAAGnrwABp7EAAaezAAGntQABp7cAAae6AAGnvQABp74AAafDAAGn0AABp9MAAafVAAGn2AABp9sAAafdAAGoAgABqCYAAahNAAGocQABqHQAAah2AAGoeAABqHoAAah8AAGofgABqH8AAaiCAAGojwABqKIAAaikAAGopgABqKgAAaiqAAGorAABqK4AAaiwAAGosgABqLQAAajHAAGoygABqM0AAajQAAGo0wABqNYAAajZAAGo3AABqN8AAajiAAGo5AABqSMAAaklAAGpKAABqSoAAaktAAGpLgABqS8AAakwAAGpMQABqTMAAak1AAGpNgABqTcAAak5AAGpOgABqUMAAalEAAGpRgABqYUAAamHAAGpiQABqYsAAamOAAGpjwABqZAAAamRAAGpkgABqZQAAamWAAGplwABqZgAAamaAAGpmwABqdoAAancAAGp3wABqeEAAankAAGp5QABqeYAAannAAGp6AABqeoAAansAAGp7QABqe4AAanwAAGp8QABqfoAAan7AAGp/QABqjwAAao+AAGqQAABqkIAAapFAAGqRgABqkcAAapIAAGqSQABqksAAapNAAGqTgABqk8AAapRAAGqUgABqpEAAaqTAAGqlgABqpgAAaqbAAGqnAABqp0AAaqeAAGqnwABqqEAAaqjAAGqpAABqqUAAaqnAAGqqAABqrEAAaqyAAGqtAABqvMAAar1AAGq9wABqvkAAar8AAGq/QABqv4AAar/AAGrAAABqwIAAasEAAGrBQABqwYAAasIAAGrCQABq0gAAatKAAGrTQABq08AAatSAAGrUwABq1QAAatVAAGrVgABq1gAAataAAGrWwABq1wAAateAAGrXwABq2wAAattAAGrbgABq3AAAauvAAGrsQABq7MAAau1AAGruAABq7kAAau6AAGruwABq7wAAau+AAGrwAABq8EAAavCAAGrxAABq8UAAawEAAGsBgABrAkAAawLAAGsDgABrA8AAawQAAGsEQABrBIAAawUAAGsFgABrBcAAawYAAGsGgABrBsAAawnAAGsNAABrDkAAaw8AAGsPwABrEQAAaxHAAGsSgABrEwAAaxSAAGsXQABrKgAAazLAAGs6wABrQsAAa0NAAGtDwABrREAAa0TAAGtFgABrRcAAa0YAAGtGwABrRwAAa0eAAGtHwABrSEAAa0kAAGtJQABrSYAAa0pAAGtKgABrS8AAa08AAGtQQABrUMAAa1FAAGtSgABrU0AAa1QAAGtUgABrXcAAa2bAAGtwgABreYAAa3pAAGt6wABre0AAa3vAAGt8QABrfMAAa30AAGt9wABrgQAAa4VAAGuFwABrhkAAa4bAAGuHQABrh8AAa4hAAGuIwABriUAAa42AAGuOQABrjwAAa4/AAGuQgABrkUAAa5IAAGuSwABrk4AAa5QAAGujwABrpEAAa6TAAGulQABrpgAAa6ZAAGumgABrpsAAa6cAAGungABrqAAAa6hAAGuogABrqQAAa6lAAGu5AABruYAAa7oAAGu6gABru0AAa7uAAGu7wABrvAAAa7xAAGu8wABrvUAAa72AAGu9wABrvkAAa76AAGvOQABrzsAAa8+AAGvQAABr0MAAa9EAAGvRQABr0YAAa9HAAGvSQABr0sAAa9MAAGvTQABr08AAa9QAAGvXQABr14AAa9fAAGvYQABr6AAAa+iAAGvpAABr6YAAa+pAAGvqgABr6sAAa+sAAGvrQABr68AAa+xAAGvsgABr7MAAa+1AAGvtgABr/UAAa/3AAGv+QABr/sAAa/+AAGv/wABsAAAAbABAAGwAgABsAQAAbAGAAGwBwABsAgAAbAKAAGwCwABsEoAAbBMAAGwTgABsFAAAbBTAAGwVAABsFUAAbBWAAGwVwABsFkAAbBbAAGwXAABsF0AAbBfAAGwYAABsJ8AAbChAAGwowABsKUAAbCoAAGwqQABsKoAAbCrAAGwrAABsK4AAbCwAAGwsQABsLIAAbC0AAGwtQABsPQAAbD2AAGw+AABsPoAAbD9AAGw/gABsP8AAbEAAAGxAQABsQMAAbEFAAGxBgABsQcAAbEJAAGxCgABsS8AAbFTAAGxegABsZ4AAbGhAAGxowABsaUAAbGnAAGxqQABsasAAbGsAAGxrwABsbwAAbHLAAGxzQABsc8AAbHRAAGx0wABsdUAAbHXAAGx2QABsegAAbHrAAGx7gABsfEAAbH0AAGx9wABsfoAAbH9AAGx/wABsj4AAbJAAAGyQgABskQAAbJHAAGySAABskkAAbJKAAGySwABsk0AAbJPAAGyUAABslEAAbJTAAGyVAABspMAAbKVAAGylwABspkAAbKcAAGynQABsp4AAbKfAAGyoAABsqIAAbKkAAGypQABsqYAAbKoAAGyqQABsugAAbLqAAGy7AABsu4AAbLxAAGy8gABsvMAAbL0AAGy9QABsvcAAbL5AAGy+gABsvsAAbL9AAGy/gABsz0AAbM/AAGzQQABs0MAAbNGAAGzRwABs0gAAbNJAAGzSgABs0wAAbNOAAGzTwABs1AAAbNSAAGzUwABs5IAAbOUAAGzlgABs5gAAbObAAGznAABs50AAbOeAAGznwABs6EAAbOjAAGzpAABs6UAAbOnAAGzqAABs+cAAbPpAAGz6wABs+0AAbPwAAGz8QABs/IAAbPzAAGz9AABs/YAAbP4AAGz+QABs/oAAbP8AAGz/QABtDwAAbQ+AAG0QAABtEIAAbRFAAG0RgABtEcAAbRIAAG0SQABtEsAAbRNAAG0TgABtE8AAbRRAAG0UgABtJ0AAbTAAAG04AABtQAAAbUCAAG1BAABtQYAAbUIAAG1CwABtQwAAbUNAAG1EAABtREAAbUTAAG1FAABtRYAAbUZAAG1GgABtRsAAbUeAAG1HwABtSgAAbU1AAG1OgABtTwAAbU+AAG1QwABtUYAAbVJAAG1SwABtXAAAbWUAAG1uwABtd8AAbXiAAG15AABteYAAbXoAAG16gABtewAAbXtAAG18AABtf0AAbYOAAG2EAABthIAAbYUAAG2FgABthgAAbYaAAG2HAABth4AAbYvAAG2MgABtjUAAbY4AAG2OwABtj4AAbZBAAG2RAABtkcAAbZJAAG2iAABtooAAbaMAAG2jgABtpEAAbaSAAG2kwABtpQAAbaVAAG2lwABtpkAAbaaAAG2mwABtp0AAbaeAAG23QABtt8AAbbhAAG24wABtuYAAbbnAAG26AABtukAAbbqAAG27AABtu4AAbbvAAG28AABtvIAAbbzAAG3MgABtzQAAbc3AAG3OQABtzwAAbc9AAG3PgABtz8AAbdAAAG3QgABt0QAAbdFAAG3RgABt0gAAbdJAAG3VgABt1cAAbdYAAG3WgABt5kAAbebAAG3nQABt58AAbeiAAG3owABt6QAAbelAAG3pgABt6gAAbeqAAG3qwABt6wAAbeuAAG3rwABt+4AAbfwAAG38gABt/QAAbf3AAG3+AABt/kAAbf6AAG3+wABt/0AAbf/AAG4AAABuAEAAbgDAAG4BAABuEMAAbhFAAG4RwABuEkAAbhMAAG4TQABuE4AAbhPAAG4UAABuFIAAbhUAAG4VQABuFYAAbhYAAG4WQABuJgAAbiaAAG4nAABuJ4AAbihAAG4ogABuKMAAbikAAG4pQABuKcAAbipAAG4qgABuKsAAbitAAG4rgABuO0AAbjvAAG48QABuPMAAbj2AAG49wABuPgAAbj5AAG4+gABuPwAAbj+AAG4/wABuQAAAbkCAAG5AwABuSgAAblMAAG5cwABuZcAAbmaAAG5nAABuZ4AAbmgAAG5ogABuaQAAbmlAAG5qAABubUAAbnEAAG5xgABucgAAbnKAAG5zAABuc4AAbnQAAG50gABueEAAbnkAAG55wABueoAAbntAAG58AABufMAAbn2AAG5+AABujcAAbo5AAG6OwABuj0AAbpAAAG6QQABukIAAbpDAAG6RAABukYAAbpIAAG6SQABukoAAbpMAAG6TQABuowAAbqOAAG6kAABupIAAbqVAAG6lgABupcAAbqYAAG6mQABupsAAbqdAAG6ngABup8AAbqhAAG6ogABuuEAAbrjAAG65QABuucAAbrqAAG66wABuuwAAbrtAAG67gABuvAAAbryAAG68wABuvQAAbr2AAG69wABuzYAAbs4AAG7OgABuzwAAbs/AAG7QAABu0EAAbtCAAG7QwABu0UAAbtHAAG7SAABu0kAAbtLAAG7TAABu4sAAbuNAAG7jwABu5EAAbuUAAG7lQABu5YAAbuXAAG7mAABu5oAAbucAAG7nQABu54AAbugAAG7oQABu+AAAbviAAG75AABu+YAAbvpAAG76gABu+sAAbvsAAG77QABu+8AAbvxAAG78gABu/MAAbv1AAG79gABvDUAAbw3AAG8OQABvDsAAbw+AAG8PwABvEAAAbxBAAG8QgABvEQAAbxGAAG8RwABvEgAAbxKAAG8SwABvFQAAbxVAAG8VwABvJoAAby+AAG84gABvQUAAb0sAAG9TAABvXMAAb2aAAG9ugABvd4AAb4CAAG+BAABvgcAAb4JAAG+CwABvg0AAb4QAAG+EgABvhQAAb4WAAG+GAABvhoAAb4cAAG+HwABviIAAb4jAAG+KAABvjUAAb44AAG+OgABvj0AAb5AAAG+QgABvmcAAb6LAAG+sgABvtYAAb7ZAAG+2wABvt0AAb7fAAG+4QABvuMAAb7kAAG+5wABvvQAAb8HAAG/CQABvwsAAb8NAAG/DwABvxEAAb8TAAG/FQABvxcAAb8ZAAG/LAABvy8AAb8yAAG/NQABvzgAAb87AAG/PgABv0EAAb9EAAG/RwABv0kAAb+IAAG/igABv40AAb+PAAG/kgABv5MAAb+UAAG/lQABv5YAAb+YAAG/mgABv5sAAb+cAAG/ngABv58AAb+oAAG/qQABv6sAAb/qAAG/7AABv+4AAb/wAAG/8wABv/QAAb/1AAG/9gABv/cAAb/5AAG/+wABv/wAAb/9AAG//wABwAAAAcA/AAHAQQABwEQAAcBGAAHASQABwEoAAcBLAAHATAABwE0AAcBPAAHAUQABwFIAAcBTAAHAVQABwFYAAcBfAAHAYAABwGIAAcChAAHAowABwKUAAcCnAAHAqgABwKsAAcCsAAHArQABwK4AAcCwAAHAsgABwLMAAcC0AAHAtgABwLcAAcD2AAHA+AABwPsAAcD9AAHBAAABwQEAAcECAAHBAwABwQQAAcEGAAHBCAABwQkAAcEKAAHBDAABwQ0AAcEWAAHBFwABwRkAAcFYAAHBWgABwVwAAcFeAAHBYQABwWIAAcFjAAHBZAABwWUAAcFnAAHBaQABwWoAAcFrAAHBbQABwW4AAcGtAAHBrwABwbIAAcG0AAHBtwABwbgAAcG5AAHBugABwbsAAcG9AAHBvwABwcAAAcHBAAHBwwABwcQAAcHRAAHB0gABwdMAAcHVAAHCFAABwhYAAcIYAAHCGgABwh0AAcIeAAHCHwABwiAAAcIhAAHCIwABwiUAAcImAAHCJwABwikAAcIqAAHCaQABwmsAAcJuAAHCcAABwnMAAcJ0AAHCdQABwnYAAcJ3AAHCeQABwnsAAcJ8AAHCfQABwn8AAcKAAAHCmAABwqUAAcKuAAHCsQABwrQAAcK2AAHCuQABwsIAAcLFAAHCyAABwssAAcLOAAHC0AABwtkAAcLjAAHC6wABwzYAAcNZAAHDeQABw5kAAcObAAHDnQABw58AAcOhAAHDpAABw6UAAcOmAAHDqQABw6oAAcOsAAHDrQABw68AAcOyAAHDswABw7QAAcO3AAHDuAABw70AAcPKAAHDzwABw9EAAcPTAAHD2AABw9sAAcPeAAHD4AABxAUAAcQpAAHEUAABxHQAAcR3AAHEeQABxHsAAcR9AAHEfwABxIEAAcSCAAHEhQABxJIAAcSjAAHEpQABxKcAAcSpAAHEqwABxK0AAcSvAAHEsQABxLMAAcTEAAHExwABxMoAAcTNAAHE0AABxNMAAcTWAAHE2QABxNwAAcTeAAHFHQABxR8AAcUhAAHFIwABxSYAAcUnAAHFKAABxSkAAcUqAAHFLAABxS4AAcUvAAHFMAABxTIAAcUzAAHFcgABxXQAAcV2AAHFeAABxXsAAcV8AAHFfQABxX4AAcV/AAHFgQABxYMAAcWEAAHFhQABxYcAAcWIAAHFxwABxckAAcXMAAHFzgABxdEAAcXSAAHF0wABxdQAAcXVAAHF1wABxdkAAcXaAAHF2wABxd0AAcXeAAHF6wABxewAAcXtAAHF7wABxi4AAcYwAAHGMgABxjQAAcY3AAHGOAABxjkAAcY6AAHGOwABxj0AAcY/AAHGQAABxkEAAcZDAAHGRAABxoMAAcaFAAHGhwABxokAAcaMAAHGjQABxo4AAcaPAAHGkAABxpIAAcaUAAHGlQABxpYAAcaYAAHGmQABxtgAAcbaAAHG3AABxt4AAcbhAAHG4gABxuMAAcbkAAHG5QABxucAAcbpAAHG6gABxusAAcbtAAHG7gABxy0AAccvAAHHMQABxzMAAcc2AAHHNwABxzgAAcc5AAHHOgABxzwAAcc+AAHHPwABx0AAAcdCAAHHQwABx4IAAceEAAHHhgABx4gAAceLAAHHjAABx40AAceOAAHHjwABx5EAAceTAAHHlAABx5UAAceXAAHHmAABx70AAcfhAAHICAAByCwAAcgvAAHIMQAByDMAAcg1AAHINwAByDkAAcg6AAHIPQAByEoAAchZAAHIWwAByF0AAchfAAHIYQAByGMAAchlAAHIZwAByHYAAch5AAHIfAAByH8AAciCAAHIhQAByIgAAciLAAHIjQAByMwAAcjOAAHI0AAByNIAAcjVAAHI1gAByNcAAcjYAAHI2QAByNsAAcjdAAHI3gAByN8AAcjhAAHI4gABySEAAckjAAHJJQAByScAAckqAAHJKwABySwAAcktAAHJLgAByTAAAckyAAHJMwAByTQAAck2AAHJNwAByXYAAcl4AAHJegAByXwAAcl/AAHJgAAByYEAAcmCAAHJgwAByYUAAcmHAAHJiAAByYkAAcmLAAHJjAABycsAAcnNAAHJzwABydEAAcnUAAHJ1QABydYAAcnXAAHJ2AABydoAAcncAAHJ3QAByd4AAcngAAHJ4QAByiAAAcoiAAHKJAAByiYAAcopAAHKKgAByisAAcosAAHKLQAByi8AAcoxAAHKMgAByjMAAco1AAHKNgABynUAAcp3AAHKeQABynsAAcp+AAHKfwAByoAAAcqBAAHKggAByoQAAcqGAAHKhwAByogAAcqKAAHKiwABysoAAcrMAAHKzgABytAAAcrTAAHK1AABytUAAcrWAAHK1wABytkAAcrbAAHK3AAByt0AAcrfAAHK4AAByysAActOAAHLbgABy44AAcuQAAHLkgABy5QAAcuWAAHLmQABy5oAAcubAAHLngABy58AAcuhAAHLogABy6QAAcunAAHLqAABy6kAAcusAAHLrQABy7IAAcu/AAHLxAABy8YAAcvIAAHLzQABy9AAAcvTAAHL1QABy/oAAcweAAHMRQABzGkAAcxsAAHMbgABzHAAAcxyAAHMdAABzHYAAcx3AAHMegABzIcAAcyYAAHMmgABzJwAAcyeAAHMoAABzKIAAcykAAHMpgABzKgAAcy5AAHMvAABzL8AAczCAAHMxQABzMgAAczLAAHMzgABzNEAAczTAAHNEgABzRQAAc0WAAHNGAABzRsAAc0cAAHNHQABzR4AAc0fAAHNIQABzSMAAc0kAAHNJQABzScAAc0oAAHNZwABzWkAAc1rAAHNbQABzXAAAc1xAAHNcgABzXMAAc10AAHNdgABzXgAAc15AAHNegABzXwAAc19AAHNvAABzb4AAc3BAAHNwwABzcYAAc3HAAHNyAABzckAAc3KAAHNzAABzc4AAc3PAAHN0AABzdIAAc3TAAHN4AABzeEAAc3iAAHN5AABziMAAc4lAAHOJwABzikAAc4sAAHOLQABzi4AAc4vAAHOMAABzjIAAc40AAHONQABzjYAAc44AAHOOQABzngAAc56AAHOfAABzn4AAc6BAAHOggABzoMAAc6EAAHOhQABzocAAc6JAAHOigABzosAAc6NAAHOjgABzs0AAc7PAAHO0QABztMAAc7WAAHO1wABztgAAc7ZAAHO2gABztwAAc7eAAHO3wABzuAAAc7iAAHO4wABzyIAAc8kAAHPJgABzygAAc8rAAHPLAABzy0AAc8uAAHPLwABzzEAAc8zAAHPNAABzzUAAc83AAHPOAABz3cAAc95AAHPewABz30AAc+AAAHPgQABz4IAAc+DAAHPhAABz4YAAc+IAAHPiQABz4oAAc+MAAHPjQABz7IAAc/WAAHP/QAB0CEAAdAkAAHQJgAB0CgAAdAqAAHQLAAB0C4AAdAvAAHQMgAB0D8AAdBOAAHQUAAB0FIAAdBUAAHQVgAB0FgAAdBaAAHQXAAB0GsAAdBuAAHQcQAB0HQAAdB3AAHQegAB0H0AAdCAAAHQggAB0MEAAdDDAAHQxgAB0MgAAdDLAAHQzAAB0M0AAdDOAAHQzwAB0NEAAdDTAAHQ1AAB0NUAAdDXAAHQ2AAB0RcAAdEZAAHRGwAB0R0AAdEgAAHRIQAB0SIAAdEjAAHRJAAB0SYAAdEoAAHRKQAB0SoAAdEsAAHRLQAB0WwAAdFuAAHRcAAB0XIAAdF1AAHRdgAB0XcAAdF4AAHReQAB0XsAAdF9AAHRfgAB0X8AAdGBAAHRggAB0cEAAdHDAAHRxgAB0cgAAdHLAAHRzAAB0c0AAdHOAAHRzwAB0dEAAdHTAAHR1AAB0dUAAdHXAAHR2AAB0doAAdIZAAHSGwAB0h0AAdIfAAHSIgAB0iMAAdIkAAHSJQAB0iYAAdIoAAHSKgAB0isAAdIsAAHSLgAB0i8AAdJuAAHScAAB0nIAAdJ0AAHSdwAB0ngAAdJ5AAHSegAB0nsAAdJ9AAHSfwAB0oAAAdKBAAHSgwAB0oQAAdLDAAHSxQAB0scAAdLJAAHSzAAB0s0AAdLOAAHSzwAB0tAAAdLSAAHS1AAB0tUAAdLWAAHS2AAB0tkAAdMkAAHTRwAB02cAAdOHAAHTiQAB04sAAdONAAHTjwAB05IAAdOTAAHTlAAB05cAAdOYAAHTmgAB05sAAdOdAAHTnwAB06AAAdOhAAHTpAAB06UAAdOqAAHTtwAB07wAAdO+AAHTwAAB08UAAdPIAAHTywAB080AAdPyAAHUFgAB1D0AAdRhAAHUZAAB1GYAAdRoAAHUagAB1GwAAdRuAAHUbwAB1HIAAdR/AAHUkAAB1JIAAdSUAAHUlgAB1JgAAdSaAAHUnAAB1J4AAdSgAAHUsQAB1LQAAdS3AAHUugAB1L0AAdTAAAHUwwAB1MYAAdTJAAHUywAB1QoAAdUMAAHVDgAB1RAAAdUTAAHVFAAB1RUAAdUWAAHVFwAB1RkAAdUbAAHVHAAB1R0AAdUfAAHVIAAB1V8AAdVhAAHVYwAB1WUAAdVoAAHVaQAB1WoAAdVrAAHVbAAB1W4AAdVwAAHVcQAB1XIAAdV0AAHVdQAB1bQAAdW2AAHVuQAB1bsAAdW+AAHVvwAB1cAAAdXBAAHVwgAB1cQAAdXGAAHVxwAB1cgAAdXKAAHVywAB1dgAAdXZAAHV2gAB1dwAAdYbAAHWHQAB1h8AAdYhAAHWJAAB1iUAAdYmAAHWJwAB1igAAdYqAAHWLAAB1i0AAdYuAAHWMAAB1jEAAdZwAAHWcgAB1nQAAdZ2AAHWeQAB1noAAdZ7AAHWfAAB1n0AAdZ/AAHWgQAB1oIAAdaDAAHWhQAB1oYAAdbFAAHWxwAB1skAAdbLAAHWzgAB1s8AAdbQAAHW0QAB1tIAAdbUAAHW1gAB1tcAAdbYAAHW2gAB1tsAAdcaAAHXHAAB1x4AAdcgAAHXIwAB1yQAAdclAAHXJgAB1ycAAdcpAAHXKwAB1ywAAdctAAHXLwAB1zAAAddvAAHXcQAB13MAAdd1AAHXeAAB13kAAdd6AAHXewAB13wAAdd+AAHXgAAB14EAAdeCAAHXhAAB14UAAdeqAAHXzgAB1/UAAdgZAAHYHAAB2B4AAdggAAHYIgAB2CQAAdgmAAHYJwAB2CoAAdg3AAHYRgAB2EgAAdhKAAHYTAAB2E4AAdhQAAHYUgAB2FQAAdhjAAHYZgAB2GkAAdhsAAHYbwAB2HIAAdh1AAHYeAAB2HoAAdi5AAHYuwAB2L0AAdi/AAHYwgAB2MMAAdjEAAHYxQAB2MYAAdjIAAHYygAB2MsAAdjMAAHYzgAB2M8AAdkOAAHZEAAB2RIAAdkUAAHZFwAB2RgAAdkZAAHZGgAB2RsAAdkdAAHZHwAB2SAAAdkhAAHZIwAB2SQAAdljAAHZZQAB2WcAAdlpAAHZbAAB2W0AAdluAAHZbwAB2XAAAdlyAAHZdAAB2XUAAdl2AAHZeAAB2XkAAdm4AAHZugAB2bwAAdm+AAHZwQAB2cIAAdnDAAHZxAAB2cUAAdnHAAHZyQAB2coAAdnLAAHZzQAB2c4AAdoNAAHaDwAB2hEAAdoTAAHaFgAB2hcAAdoYAAHaGQAB2hoAAdocAAHaHgAB2h8AAdogAAHaIgAB2iMAAdpiAAHaZAAB2mYAAdpoAAHaawAB2mwAAdptAAHabgAB2m8AAdpxAAHacwAB2nQAAdp1AAHadwAB2ngAAdq3AAHauQAB2rsAAdq9AAHawAAB2sEAAdrCAAHawwAB2sQAAdrGAAHayAAB2skAAdrKAAHazAAB2s0AAdsYAAHbOwAB21sAAdt7AAHbfQAB238AAduBAAHbgwAB24YAAduHAAHbiAAB24sAAduMAAHbjgAB248AAduRAAHblAAB25UAAduWAAHbmQAB25oAAdufAAHbrAAB27EAAduzAAHbtQAB27oAAdu9AAHbwAAB28IAAdvnAAHcCwAB3DIAAdxWAAHcWQAB3FsAAdxdAAHcXwAB3GEAAdxjAAHcZAAB3GcAAdx0AAHchQAB3IcAAdyJAAHciwAB3I0AAdyPAAHckQAB3JMAAdyVAAHcpgAB3KkAAdysAAHcrwAB3LIAAdy1AAHcuAAB3LsAAdy+AAHcwAAB3P8AAd0BAAHdAwAB3QUAAd0IAAHdCQAB3QoAAd0LAAHdDAAB3Q4AAd0QAAHdEQAB3RIAAd0UAAHdFQAB3VQAAd1WAAHdWAAB3VoAAd1dAAHdXgAB3V8AAd1gAAHdYQAB3WMAAd1lAAHdZgAB3WcAAd1pAAHdagAB3akAAd2rAAHdrgAB3bAAAd2zAAHdtAAB3bUAAd22AAHdtwAB3bkAAd27AAHdvAAB3b0AAd2/AAHdwAAB3c0AAd3OAAHdzwAB3dEAAd4QAAHeEgAB3hQAAd4WAAHeGQAB3hoAAd4bAAHeHAAB3h0AAd4fAAHeIQAB3iIAAd4jAAHeJQAB3iYAAd5lAAHeZwAB3mkAAd5rAAHebgAB3m8AAd5wAAHecQAB3nIAAd50AAHedgAB3ncAAd54AAHeegAB3nsAAd66AAHevAAB3r4AAd7AAAHewwAB3sQAAd7FAAHexgAB3scAAd7JAAHeywAB3swAAd7NAAHezwAB3tAAAd8PAAHfEQAB3xMAAd8VAAHfGAAB3xkAAd8aAAHfGwAB3xwAAd8eAAHfIAAB3yEAAd8iAAHfJAAB3yUAAd9kAAHfZgAB32gAAd9qAAHfbQAB324AAd9vAAHfcAAB33EAAd9zAAHfdQAB33YAAd93AAHfeQAB33oAAd+fAAHfwwAB3+oAAeAOAAHgEQAB4BMAAeAVAAHgFwAB4BkAAeAbAAHgHAAB4B8AAeAsAAHgOwAB4D0AAeA/AAHgQQAB4EMAAeBFAAHgRwAB4EkAAeBYAAHgWwAB4F4AAeBhAAHgZAAB4GcAAeBqAAHgbQAB4G8AAeCuAAHgsAAB4LMAAeC1AAHguAAB4LkAAeC6AAHguwAB4LwAAeC+AAHgwAAB4MEAAeDCAAHgxAAB4MUAAeEEAAHhBgAB4QgAAeEKAAHhDQAB4Q4AAeEPAAHhEAAB4REAAeETAAHhFQAB4RYAAeEXAAHhGQAB4RoAAeFZAAHhWwAB4V0AAeFfAAHhYgAB4WMAAeFkAAHhZQAB4WYAAeFoAAHhagAB4WsAAeFsAAHhbgAB4W8AAeGuAAHhsAAB4bMAAeG1AAHhuAAB4bkAAeG6AAHhuwAB4bwAAeG+AAHhwAAB4cEAAeHCAAHhxAAB4cUAAeIEAAHiBgAB4ggAAeIKAAHiDQAB4g4AAeIPAAHiEAAB4hEAAeITAAHiFQAB4hYAAeIXAAHiGQAB4hoAAeJZAAHiWwAB4l0AAeJfAAHiYgAB4mMAAeJkAAHiZQAB4mYAAeJoAAHiagAB4msAAeJsAAHibgAB4m8AAeKuAAHisAAB4rIAAeK0AAHitwAB4rgAAeK5AAHiugAB4rsAAeK9AAHivwAB4sAAAeLBAAHiwwAB4sQAAeLNAAHizgAB4tAAAeMTAAHjNwAB41sAAeN+AAHjpQAB48UAAePsAAHkEwAB5DMAAeRXAAHkewAB5H0AAeSAAAHkggAB5IQAAeSGAAHkiQAB5IsAAeSNAAHkjwAB5JEAAeSTAAHklQAB5JgAAeSbAAHknAAB5KEAAeSuAAHksQAB5LMAAeS2AAHkuQAB5LsAAeTgAAHlBAAB5SsAAeVPAAHlUgAB5VQAAeVWAAHlWAAB5VoAAeVcAAHlXQAB5WAAAeVtAAHlgAAB5YIAAeWEAAHlhgAB5YgAAeWKAAHljAAB5Y4AAeWQAAHlkgAB5aUAAeWoAAHlqwAB5a4AAeWxAAHltAAB5bcAAeW6AAHlvQAB5cAAAeXCAAHmAQAB5gMAAeYGAAHmCAAB5gsAAeYMAAHmDQAB5g4AAeYPAAHmEQAB5hMAAeYUAAHmFQAB5hcAAeYYAAHmIQAB5iIAAeYkAAHmYwAB5mUAAeZnAAHmaQAB5mwAAeZtAAHmbgAB5m8AAeZwAAHmcgAB5nQAAeZ1AAHmdgAB5ngAAeZ5AAHmuAAB5roAAea9AAHmvwAB5sIAAebDAAHmxAAB5sUAAebGAAHmyAAB5soAAebLAAHmzAAB5s4AAebPAAHm2AAB5tkAAebbAAHnGgAB5xwAAeceAAHnIAAB5yMAAeckAAHnJQAB5yYAAecnAAHnKQAB5ysAAecsAAHnLQAB5y8AAecwAAHnbwAB53EAAed0AAHndgAB53kAAed6AAHnewAB53wAAed9AAHnfwAB54EAAeeCAAHngwAB54UAAeeGAAHnjwAB55AAAeeSAAHn0QAB59MAAefVAAHn1wAB59oAAefbAAHn3AAB590AAefeAAHn4AAB5+IAAefjAAHn5AAB5+YAAefnAAHoJgAB6CgAAegrAAHoLQAB6DAAAegxAAHoMgAB6DMAAeg0AAHoNgAB6DgAAeg5AAHoOgAB6DwAAeg9AAHoSgAB6EsAAehMAAHoTgAB6I0AAeiPAAHokQAB6JMAAeiWAAHolwAB6JgAAeiZAAHomgAB6JwAAeieAAHonwAB6KAAAeiiAAHoowAB6OIAAejkAAHo5wAB6OkAAejsAAHo7QAB6O4AAejvAAHo8AAB6PIAAej0AAHo9QAB6PYAAej4AAHo+QAB6RQAAekhAAHpOAAB6TsAAek+AAHpQQAB6UQAAelHAAHpSgAB6U0AAelPAAHpUgAB6VUAAelYAAHpbwAB6XIAAel1AAHpeAAB6XsAAel+AAHpgQAB6YQAAemHAAHpigAB6Y0AAemQAAHpkgAB6ZkAAemgAAHpqQAB6a4AAem5AAHpxQAB6c4AAenSAAHp3AAB6eQAAeovAAHqUgAB6nIAAeqSAAHqlAAB6pYAAeqYAAHqmgAB6p0AAeqeAAHqnwAB6qIAAeqjAAHqpQAB6qYAAeqoAAHqqwAB6qwAAeqtAAHqsAAB6rEAAeq2AAHqwwAB6sgAAerKAAHqzAAB6tEAAerUAAHq1wAB6tkAAer+AAHrIgAB60kAAettAAHrcAAB63IAAet0AAHrdgAB63gAAet6AAHrewAB634AAeuLAAHrnAAB654AAeugAAHrogAB66QAAeumAAHrqAAB66oAAeusAAHrvQAB68AAAevDAAHrxgAB68kAAevMAAHrzwAB69IAAevVAAHr1wAB7BYAAewYAAHsGgAB7BwAAewfAAHsIAAB7CEAAewiAAHsIwAB7CUAAewnAAHsKAAB7CkAAewrAAHsLAAB7GsAAextAAHsbwAB7HEAAex0AAHsdQAB7HYAAex3AAHseAAB7HoAAex8AAHsfQAB7H4AAeyAAAHsgQAB7MAAAezCAAHsxQAB7McAAezKAAHsywAB7MwAAezNAAHszgAB7NAAAezSAAHs0wAB7NQAAezWAAHs1wAB7OQAAezlAAHs5gAB7OgAAe0nAAHtKQAB7SsAAe0tAAHtMAAB7TEAAe0yAAHtMwAB7TQAAe02AAHtOAAB7TkAAe06AAHtPAAB7T0AAe18AAHtfgAB7YAAAe2CAAHthQAB7YYAAe2HAAHtiAAB7YkAAe2LAAHtjQAB7Y4AAe2PAAHtkQAB7ZIAAe3RAAHt0wAB7dUAAe3XAAHt2gAB7dsAAe3cAAHt3QAB7d4AAe3gAAHt4gAB7eMAAe3kAAHt5gAB7ecAAe4mAAHuKAAB7ioAAe4sAAHuLwAB7jAAAe4xAAHuMgAB7jMAAe41AAHuNwAB7jgAAe45AAHuOwAB7jwAAe57AAHufQAB7n8AAe6BAAHuhAAB7oUAAe6GAAHuhwAB7ogAAe6KAAHujAAB7o0AAe6OAAHukAAB7pEAAe62AAHu2gAB7wEAAe8lAAHvKAAB7yoAAe8sAAHvLgAB7zAAAe8yAAHvMwAB7zYAAe9DAAHvUgAB71QAAe9WAAHvWAAB71oAAe9cAAHvXgAB72AAAe9vAAHvcgAB73UAAe94AAHvewAB734AAe+BAAHvhAAB74YAAe/FAAHvxwAB78kAAe/LAAHvzgAB788AAe/QAAHv0QAB79IAAe/UAAHv1gAB79cAAe/YAAHv2gAB79sAAfAaAAHwHAAB8B4AAfAgAAHwIwAB8CQAAfAlAAHwJgAB8CcAAfApAAHwKwAB8CwAAfAtAAHwLwAB8DAAAfBvAAHwcQAB8HMAAfB1AAHweAAB8HkAAfB6AAHwewAB8HwAAfB+AAHwgAAB8IEAAfCCAAHwhAAB8IUAAfDEAAHwxgAB8MgAAfDKAAHwzQAB8M4AAfDPAAHw0AAB8NEAAfDTAAHw1QAB8NYAAfDXAAHw2QAB8NoAAfEZAAHxGwAB8R0AAfEfAAHxIgAB8SMAAfEkAAHxJQAB8SYAAfEoAAHxKgAB8SsAAfEsAAHxLgAB8S8AAfFuAAHxcAAB8XIAAfF0AAHxdwAB8XgAAfF5AAHxegAB8XsAAfF9AAHxfwAB8YAAAfGBAAHxgwAB8YQAAfHDAAHxxQAB8ccAAfHJAAHxzAAB8c0AAfHOAAHxzwAB8dAAAfHSAAHx1AAB8dUAAfHWAAHx2AAB8dkAAfIkAAHyRwAB8mcAAfKHAAHyiQAB8osAAfKNAAHyjwAB8pIAAfKTAAHylAAB8pcAAfKYAAHymgAB8psAAfKdAAHyoAAB8qEAAfKiAAHypQAB8qYAAfKrAAHyuAAB8r0AAfK/AAHywQAB8sYAAfLJAAHyzAAB8s4AAfLzAAHzFwAB8z4AAfNiAAHzZQAB82cAAfNpAAHzawAB820AAfNvAAHzcAAB83MAAfOAAAHzkQAB85MAAfOVAAHzlwAB85kAAfObAAHznQAB858AAfOhAAHzsgAB87UAAfO4AAHzuwAB874AAfPBAAHzxAAB88cAAfPKAAHzzAAB9AsAAfQNAAH0DwAB9BEAAfQUAAH0FQAB9BYAAfQXAAH0GAAB9BoAAfQcAAH0HQAB9B4AAfQgAAH0IQAB9GAAAfRiAAH0ZAAB9GYAAfRpAAH0agAB9GsAAfRsAAH0bQAB9G8AAfRxAAH0cgAB9HMAAfR1AAH0dgAB9LUAAfS3AAH0ugAB9LwAAfS/AAH0wAAB9MEAAfTCAAH0wwAB9MUAAfTHAAH0yAAB9MkAAfTLAAH0zAAB9NkAAfTaAAH02wAB9N0AAfUcAAH1HgAB9SAAAfUiAAH1JQAB9SYAAfUnAAH1KAAB9SkAAfUrAAH1LQAB9S4AAfUvAAH1MQAB9TIAAfVxAAH1cwAB9XUAAfV3AAH1egAB9XsAAfV8AAH1fQAB9X4AAfWAAAH1ggAB9YMAAfWEAAH1hgAB9YcAAfXGAAH1yAAB9coAAfXMAAH1zwAB9dAAAfXRAAH10gAB9dMAAfXVAAH11wAB9dgAAfXZAAH12wAB9dwAAfYbAAH2HQAB9h8AAfYhAAH2JAAB9iUAAfYmAAH2JwAB9igAAfYqAAH2LAAB9i0AAfYuAAH2MAAB9jEAAfZwAAH2cgAB9nQAAfZ2AAH2eQAB9noAAfZ7AAH2fAAB9n0AAfZ/AAH2gQAB9oIAAfaDAAH2hQAB9oYAAfarAAH2zwAB9vYAAfcaAAH3HQAB9x8AAfchAAH3IwAB9yUAAfcnAAH3KAAB9ysAAfc4AAH3RwAB90kAAfdLAAH3TQAB908AAfdRAAH3UwAB91UAAfdkAAH3ZwAB92oAAfdtAAH3cAAB93MAAfd2AAH3eQAB93sAAfe6AAH3vAAB978AAffBAAH3xAAB98UAAffGAAH3xwAB98gAAffKAAH3zAAB980AAffOAAH30AAB99EAAfgQAAH4EgAB+BQAAfgWAAH4GQAB+BoAAfgbAAH4HAAB+B0AAfgfAAH4IQAB+CIAAfgjAAH4JQAB+CYAAfhlAAH4ZwAB+GkAAfhrAAH4bgAB+G8AAfhwAAH4cQAB+HIAAfh0AAH4dgAB+HcAAfh4AAH4egAB+HsAAfi6AAH4vAAB+L8AAfjBAAH4xAAB+MUAAfjGAAH4xwAB+MgAAfjKAAH4zAAB+M0AAfjOAAH40AAB+NEAAfkQAAH5EgAB+RQAAfkWAAH5GQAB+RoAAfkbAAH5HAAB+R0AAfkfAAH5IQAB+SIAAfkjAAH5JQAB+SYAAfllAAH5ZwAB+WkAAflrAAH5bgAB+W8AAflwAAH5cQAB+XIAAfl0AAH5dgAB+XcAAfl4AAH5egAB+XsAAfm6AAH5vAAB+b4AAfnAAAH5wwAB+cQAAfnFAAH5xgAB+ccAAfnJAAH5ywAB+cwAAfnNAAH5zwAB+dAAAfobAAH6PgAB+l4AAfp+AAH6gAAB+oIAAfqEAAH6hgAB+okAAfqKAAH6iwAB+o4AAfqPAAH6kQAB+pIAAfqUAAH6lwAB+pgAAfqZAAH6nAAB+p0AAfqiAAH6rwAB+rQAAfq2AAH6uAAB+r0AAfrAAAH6wwAB+sUAAfrqAAH7DgAB+zUAAftZAAH7XAAB+14AAftgAAH7YgAB+2QAAftmAAH7ZwAB+2oAAft3AAH7iAAB+4oAAfuMAAH7jgAB+5AAAfuSAAH7lAAB+5YAAfuYAAH7qQAB+6wAAfuvAAH7sgAB+7UAAfu4AAH7uwAB+74AAfvBAAH7wwAB/AIAAfwEAAH8BgAB/AgAAfwLAAH8DAAB/A0AAfwOAAH8DwAB/BEAAfwTAAH8FAAB/BUAAfwXAAH8GAAB/FcAAfxZAAH8WwAB/F0AAfxgAAH8YQAB/GIAAfxjAAH8ZAAB/GYAAfxoAAH8aQAB/GoAAfxsAAH8bQAB/KwAAfyuAAH8sQAB/LMAAfy2AAH8twAB/LgAAfy5AAH8ugAB/LwAAfy+AAH8vwAB/MAAAfzCAAH8wwAB/NAAAfzRAAH80gAB/NQAAf0TAAH9FQAB/RcAAf0ZAAH9HAAB/R0AAf0eAAH9HwAB/SAAAf0iAAH9JAAB/SUAAf0mAAH9KAAB/SkAAf1oAAH9agAB/WwAAf1uAAH9cQAB/XIAAf1zAAH9dAAB/XUAAf13AAH9eQAB/XoAAf17AAH9fQAB/X4AAf29AAH9vwAB/cEAAf3DAAH9xgAB/ccAAf3IAAH9yQAB/coAAf3MAAH9zgAB/c8AAf3QAAH90gAB/dMAAf4SAAH+FAAB/hYAAf4YAAH+GwAB/hwAAf4dAAH+HgAB/h8AAf4hAAH+IwAB/iQAAf4lAAH+JwAB/igAAf5nAAH+aQAB/msAAf5tAAH+cAAB/nEAAf5yAAH+cwAB/nQAAf52AAH+eAAB/nkAAf56AAH+fAAB/n0AAf6iAAH+xgAB/u0AAf8RAAH/FAAB/xYAAf8YAAH/GgAB/xwAAf8eAAH/HwAB/yIAAf8vAAH/PgAB/0AAAf9CAAH/RAAB/0YAAf9IAAH/SgAB/0wAAf9bAAH/XgAB/2EAAf9kAAH/ZwAB/2oAAf9tAAH/cAAB/3IAAf+xAAH/swAB/7UAAf+3AAH/ugAB/7sAAf+8AAH/vQAB/74AAf/AAAH/wgAB/8MAAf/EAAH/xgAB/8cAAgAGAAIACAACAAoAAgAMAAIADwACABAAAgARAAIAEgACABMAAgAVAAIAFwACABgAAgAZAAIAGwACABwAAgBbAAIAXQACAF8AAgBhAAIAZAACAGUAAgBmAAIAZwACAGgAAgBqAAIAbAACAG0AAgBuAAIAcAACAHEAAgCwAAIAsgACALQAAgC2AAIAuQACALoAAgC7AAIAvAACAL0AAgC/AAIAwQACAMIAAgDDAAIAxQACAMYAAgEFAAIBBwACAQkAAgELAAIBDgACAQ8AAgEQAAIBEQACARIAAgEUAAIBFgACARcAAgEYAAIBGgACARsAAgFaAAIBXAACAV4AAgFgAAIBYwACAWQAAgFlAAIBZgACAWcAAgFpAAIBawACAWwAAgFtAAIBbwACAXAAAgGvAAIBsQACAbMAAgG1AAIBuAACAbkAAgG6AAIBuwACAbwAAgG+AAIBwAACAcEAAgHCAAIBxAACAcUAAgIQAAICMwACAlMAAgJzAAICdQACAncAAgJ5AAICewACAn4AAgJ/AAICgAACAoMAAgKEAAIChgACAocAAgKJAAICjAACAo0AAgKOAAICkQACApIAAgKbAAICqAACAq0AAgKvAAICsQACArYAAgK5AAICvAACAr4AAgLjAAIDBwACAy4AAgNSAAIDVQACA1cAAgNZAAIDWwACA10AAgNfAAIDYAACA2MAAgNwAAIDgQACA4MAAgOFAAIDhwACA4kAAgOLAAIDjQACA48AAgORAAIDogACA6UAAgOoAAIDqwACA64AAgOxAAIDtAACA7cAAgO6AAIDvAACA/sAAgP9AAID/wACBAEAAgQEAAIEBQACBAYAAgQHAAIECAACBAoAAgQMAAIEDQACBA4AAgQQAAIEEQACBFAAAgRSAAIEVAACBFYAAgRZAAIEWgACBFsAAgRcAAIEXQACBF8AAgRhAAIEYgACBGMAAgRlAAIEZgACBKUAAgSnAAIEqgACBKwAAgSvAAIEsAACBLEAAgSyAAIEswACBLUAAgS3AAIEuAACBLkAAgS7AAIEvAACBMkAAgTKAAIEywACBM0AAgUMAAIFDgACBRAAAgUSAAIFFQACBRYAAgUXAAIFGAACBRkAAgUbAAIFHQACBR4AAgUfAAIFIQACBSIAAgVhAAIFYwACBWUAAgVnAAIFagACBWsAAgVsAAIFbQACBW4AAgVwAAIFcgACBXMAAgV0AAIFdgACBXcAAgW2AAIFuAACBboAAgW8AAIFvwACBcAAAgXBAAIFwgACBcMAAgXFAAIFxwACBcgAAgXJAAIFywACBcwAAgYLAAIGDQACBg8AAgYRAAIGFAACBhUAAgYWAAIGFwACBhgAAgYaAAIGHAACBh0AAgYeAAIGIAACBiEAAgZgAAIGYgACBmQAAgZmAAIGaQACBmoAAgZrAAIGbAACBm0AAgZvAAIGcQACBnIAAgZzAAIGdQACBnYAAgabAAIGvwACBuYAAgcKAAIHDQACBw8AAgcRAAIHEwACBxUAAgcXAAIHGAACBxsAAgcoAAIHNwACBzkAAgc7AAIHPQACBz8AAgdBAAIHQwACB0UAAgdUAAIHVwACB1oAAgddAAIHYAACB2MAAgdmAAIHaQACB2sAAgeqAAIHrAACB64AAgewAAIHswACB7QAAge1AAIHtgACB7cAAge5AAIHuwACB7wAAge9AAIHvwACB8AAAgf/AAIIAQACCAMAAggFAAIICAACCAkAAggKAAIICwACCAwAAggOAAIIEAACCBEAAggSAAIIFAACCBUAAghUAAIIVgACCFgAAghaAAIIXQACCF4AAghfAAIIYAACCGEAAghjAAIIZQACCGYAAghnAAIIaQACCGoAAgipAAIIqwACCK0AAgivAAIIsgACCLMAAgi0AAIItQACCLYAAgi4AAIIugACCLsAAgi8AAIIvgACCL8AAgj+AAIJAAACCQIAAgkEAAIJBwACCQgAAgkJAAIJCgACCQsAAgkNAAIJDwACCRAAAgkRAAIJEwACCRQAAglTAAIJVQACCVcAAglZAAIJXAACCV0AAgleAAIJXwACCWAAAgliAAIJZAACCWUAAglmAAIJaAACCWkAAgmoAAIJqgACCawAAgmuAAIJsQACCbIAAgmzAAIJtAACCbUAAgm3AAIJuQACCboAAgm7AAIJvQACCb4AAgoJAAIKLAACCkwAAgpsAAIKbgACCnAAAgpyAAIKdAACCncAAgp4AAIKeQACCnwAAgp9AAIKfwACCoAAAgqCAAIKhQACCoYAAgqHAAIKigACCosAAgqQAAIKnQACCqIAAgqkAAIKpgACCqsAAgquAAIKsQACCrMAAgrYAAIK/AACCyMAAgtHAAILSgACC0wAAgtOAAILUAACC1IAAgtUAAILVQACC1gAAgtlAAILdgACC3gAAgt6AAILfAACC34AAguAAAILggACC4QAAguGAAILlwACC5oAAgudAAILoAACC6MAAgumAAILqQACC6wAAguvAAILsQACC/AAAgvyAAIL9AACC/YAAgv5AAIL+gACC/sAAgv8AAIL/QACC/8AAgwBAAIMAgACDAMAAgwFAAIMBgACDEUAAgxHAAIMSQACDEsAAgxOAAIMTwACDFAAAgxRAAIMUgACDFQAAgxWAAIMVwACDFgAAgxaAAIMWwACDJoAAgycAAIMnwACDKEAAgykAAIMpQACDKYAAgynAAIMqAACDKoAAgysAAIMrQACDK4AAgywAAIMsQACDL4AAgy/AAIMwAACDMIAAg0BAAINAwACDQUAAg0HAAINCgACDQsAAg0MAAINDQACDQ4AAg0QAAINEgACDRMAAg0UAAINFgACDRcAAg1WAAINWAACDVoAAg1cAAINXwACDWAAAg1hAAINYgACDWMAAg1lAAINZwACDWgAAg1pAAINawACDWwAAg2rAAINrQACDa8AAg2xAAINtAACDbUAAg22AAINtwACDbgAAg26AAINvAACDb0AAg2+AAINwAACDcEAAg4AAAIOAgACDgQAAg4GAAIOCQACDgoAAg4LAAIODAACDg0AAg4PAAIOEQACDhIAAg4TAAIOFQACDhYAAg5VAAIOVwACDlkAAg5bAAIOXgACDl8AAg5gAAIOYQACDmIAAg5kAAIOZgACDmcAAg5oAAIOagACDmsAAg6QAAIOtAACDtsAAg7/AAIPAgACDwQAAg8GAAIPCAACDwoAAg8MAAIPDQACDxAAAg8dAAIPLAACDy4AAg8wAAIPMgACDzQAAg82AAIPOAACDzoAAg9JAAIPTAACD08AAg9SAAIPVQACD1gAAg9bAAIPXgACD2AAAg+fAAIPoQACD6MAAg+lAAIPqAACD6kAAg+qAAIPqwACD6wAAg+uAAIPsAACD7EAAg+yAAIPtAACD7UAAg/0AAIP9gACD/gAAg/6AAIP/QACD/4AAg//AAIQAAACEAEAAhADAAIQBQACEAYAAhAHAAIQCQACEAoAAhBJAAIQSwACEE0AAhBPAAIQUgACEFMAAhBUAAIQVQACEFYAAhBYAAIQWgACEFsAAhBcAAIQXgACEF8AAhCeAAIQoAACEKIAAhCkAAIQpwACEKgAAhCpAAIQqgACEKsAAhCtAAIQrwACELAAAhCxAAIQswACELQAAhDzAAIQ9QACEPcAAhD5AAIQ/AACEP0AAhD+AAIQ/wACEQAAAhECAAIRBAACEQUAAhEGAAIRCAACEQkAAhFIAAIRSgACEUwAAhFOAAIRUQACEVIAAhFTAAIRVAACEVUAAhFXAAIRWQACEVoAAhFbAAIRXQACEV4AAhGdAAIRnwACEaEAAhGjAAIRpgACEacAAhGoAAIRqQACEaoAAhGsAAIRrgACEa8AAhGwAAIRsgACEbMAAhH+AAISIQACEkEAAhJhAAISYwACEmUAAhJnAAISaQACEmwAAhJtAAISbgACEnEAAhJyAAISdAACEnUAAhJ3AAISegACEnsAAhJ8AAISfwACEoAAAhKFAAISkgACEpcAAhKZAAISmwACEqAAAhKjAAISpgACEqgAAhLNAAIS8QACExgAAhM8AAITPwACE0EAAhNDAAITRQACE0cAAhNJAAITSgACE00AAhNaAAITawACE20AAhNvAAITcQACE3MAAhN1AAITdwACE3kAAhN7AAITjAACE48AAhOSAAITlQACE5gAAhObAAITngACE6EAAhOkAAITpgACE+UAAhPnAAIT6QACE+sAAhPuAAIT7wACE/AAAhPxAAIT8gACE/QAAhP2AAIT9wACE/gAAhP6AAIT+wACFDoAAhQ8AAIUPgACFEAAAhRDAAIURAACFEUAAhRGAAIURwACFEkAAhRLAAIUTAACFE0AAhRPAAIUUAACFI8AAhSRAAIUlAACFJYAAhSZAAIUmgACFJsAAhScAAIUnQACFJ8AAhShAAIUogACFKMAAhSlAAIUpgACFLMAAhS0AAIUtQACFLcAAhT2AAIU+AACFPoAAhT8AAIU/wACFQAAAhUBAAIVAgACFQMAAhUFAAIVBwACFQgAAhUJAAIVCwACFQwAAhVLAAIVTQACFU8AAhVRAAIVVAACFVUAAhVWAAIVVwACFVgAAhVaAAIVXAACFV0AAhVeAAIVYAACFWEAAhWgAAIVogACFaQAAhWmAAIVqQACFaoAAhWrAAIVrAACFa0AAhWvAAIVsQACFbIAAhWzAAIVtQACFbYAAhX1AAIV9wACFfkAAhX7AAIV/gACFf8AAhYAAAIWAQACFgIAAhYEAAIWBgACFgcAAhYIAAIWCgACFgsAAhZKAAIWTAACFk4AAhZQAAIWUwACFlQAAhZVAAIWVgACFlcAAhZZAAIWWwACFlwAAhZdAAIWXwACFmAAAhaFAAIWqQACFtAAAhb0AAIW9wACFvkAAhb7AAIW/QACFv8AAhcBAAIXAgACFwUAAhcSAAIXIQACFyMAAhclAAIXJwACFykAAhcrAAIXLQACFy8AAhc+AAIXQQACF0QAAhdHAAIXSgACF00AAhdQAAIXUwACF1UAAheUAAIXlgACF5gAAheaAAIXnQACF54AAhefAAIXoAACF6EAAhejAAIXpQACF6YAAhenAAIXqQACF6oAAhfpAAIX6wACF+0AAhfvAAIX8gACF/MAAhf0AAIX9QACF/YAAhf4AAIX+gACF/sAAhf8AAIX/gACF/8AAhg+AAIYQAACGEIAAhhEAAIYRwACGEgAAhhJAAIYSgACGEsAAhhNAAIYTwACGFAAAhhRAAIYUwACGFQAAhiTAAIYlQACGJgAAhiaAAIYnQACGJ4AAhifAAIYoAACGKEAAhijAAIYpQACGKYAAhinAAIYqQACGKoAAhjpAAIY6wACGO0AAhjvAAIY8gACGPMAAhj0AAIY9QACGPYAAhj4AAIY+gACGPsAAhj8AAIY/gACGP8AAhk+AAIZQAACGUIAAhlEAAIZRwACGUgAAhlJAAIZSgACGUsAAhlNAAIZTwACGVAAAhlRAAIZUwACGVQAAhmTAAIZlQACGZcAAhmZAAIZnAACGZ0AAhmeAAIZnwACGaAAAhmiAAIZpAACGaUAAhmmAAIZqAACGakAAhn0AAIaFwACGjcAAhpXAAIaWQACGlsAAhpdAAIaXwACGmIAAhpjAAIaZAACGmcAAhpoAAIaagACGmsAAhptAAIacAACGnEAAhpyAAIadQACGnYAAhp7AAIaiAACGo0AAhqPAAIakQACGpYAAhqZAAIanAACGp4AAhrDAAIa5wACGw4AAhsyAAIbNQACGzcAAhs5AAIbOwACGz0AAhs/AAIbQAACG0MAAhtQAAIbYQACG2MAAhtlAAIbZwACG2kAAhtrAAIbbQACG28AAhtxAAIbggACG4UAAhuIAAIbiwACG44AAhuRAAIblAACG5cAAhuaAAIbnAACG9sAAhvdAAIb3wACG+EAAhvkAAIb5QACG+YAAhvnAAIb6AACG+oAAhvsAAIb7QACG+4AAhvwAAIb8QACHDAAAhwyAAIcNAACHDYAAhw5AAIcOgACHDsAAhw8AAIcPQACHD8AAhxBAAIcQgACHEMAAhxFAAIcRgACHIUAAhyHAAIcigACHIwAAhyPAAIckAACHJEAAhySAAIckwACHJUAAhyXAAIcmAACHJkAAhybAAIcnAACHKkAAhyqAAIcqwACHK0AAhzsAAIc7gACHPAAAhzyAAIc9QACHPYAAhz3AAIc+AACHPkAAhz7AAIc/QACHP4AAhz/AAIdAQACHQIAAh1BAAIdQwACHUUAAh1HAAIdSgACHUsAAh1MAAIdTQACHU4AAh1QAAIdUgACHVMAAh1UAAIdVgACHVcAAh2WAAIdmAACHZoAAh2cAAIdnwACHaAAAh2hAAIdogACHaMAAh2lAAIdpwACHagAAh2pAAIdqwACHawAAh3rAAId7QACHe8AAh3xAAId9AACHfUAAh32AAId9wACHfgAAh36AAId/AACHf0AAh3+AAIeAAACHgEAAh5AAAIeQgACHkQAAh5GAAIeSQACHkoAAh5LAAIeTAACHk0AAh5PAAIeUQACHlIAAh5TAAIeVQACHlYAAh57AAIenwACHsYAAh7qAAIe7QACHu8AAh7xAAIe8wACHvUAAh73AAIe+AACHvsAAh8IAAIfFwACHxkAAh8bAAIfHQACHx8AAh8hAAIfIwACHyUAAh80AAIfNwACHzoAAh89AAIfQAACH0MAAh9GAAIfSQACH0sAAh+KAAIfjAACH44AAh+QAAIfkwACH5QAAh+VAAIflgACH5cAAh+ZAAIfmwACH5wAAh+dAAIfnwACH6AAAh/fAAIf4QACH+MAAh/lAAIf6AACH+kAAh/qAAIf6wACH+wAAh/uAAIf8AACH/EAAh/yAAIf9AACH/UAAiA0AAIgNgACIDgAAiA6AAIgPQACID4AAiA/AAIgQAACIEEAAiBDAAIgRQACIEYAAiBHAAIgSQACIEoAAiCJAAIgiwACII0AAiCPAAIgkgACIJMAAiCUAAIglQACIJYAAiCYAAIgmgACIJsAAiCcAAIgngACIJ8AAiDeAAIg4AACIOIAAiDkAAIg5wACIOgAAiDpAAIg6gACIOsAAiDtAAIg7wACIPAAAiDxAAIg8wACIPQAAiEzAAIhNQACITcAAiE5AAIhPAACIT0AAiE+AAIhPwACIUAAAiFCAAIhRAACIUUAAiFGAAIhSAACIUkAAiGIAAIhigACIYwAAiGOAAIhkQACIZIAAiGTAAIhlAACIZUAAiGXAAIhmQACIZoAAiGbAAIhnQACIZ4AAiHpAAIiDAACIiwAAiJMAAIiTgACIlAAAiJSAAIiVAACIlcAAiJYAAIiWQACIlwAAiJdAAIiXwACImAAAiJiAAIiZAACImUAAiJmAAIiaQACImoAAiJzAAIigAACIoUAAiKHAAIiiQACIo4AAiKRAAIilAACIpYAAiK7AAIi3wACIwYAAiMqAAIjLQACIy8AAiMxAAIjMwACIzUAAiM3AAIjOAACIzsAAiNIAAIjWQACI1sAAiNdAAIjXwACI2EAAiNjAAIjZQACI2cAAiNpAAIjegACI30AAiOAAAIjgwACI4YAAiOJAAIjjAACI48AAiOSAAIjlAACI9MAAiPVAAIj1wACI9kAAiPcAAIj3QACI94AAiPfAAIj4AACI+IAAiPkAAIj5QACI+YAAiPoAAIj6QACJCgAAiQqAAIkLAACJC4AAiQxAAIkMgACJDMAAiQ0AAIkNQACJDcAAiQ5AAIkOgACJDsAAiQ9AAIkPgACJH0AAiR/AAIkggACJIQAAiSHAAIkiAACJIkAAiSKAAIkiwACJI0AAiSPAAIkkAACJJEAAiSTAAIklAACJKEAAiSiAAIkowACJKUAAiTkAAIk5gACJOgAAiTqAAIk7QACJO4AAiTvAAIk8AACJPEAAiTzAAIk9QACJPYAAiT3AAIk+QACJPoAAiU5AAIlOwACJT0AAiU/AAIlQgACJUMAAiVEAAIlRQACJUYAAiVIAAIlSgACJUsAAiVMAAIlTgACJU8AAiWOAAIlkAACJZIAAiWUAAIllwACJZgAAiWZAAIlmgACJZsAAiWdAAIlnwACJaAAAiWhAAIlowACJaQAAiXjAAIl5QACJecAAiXpAAIl7AACJe0AAiXuAAIl7wACJfAAAiXyAAIl9AACJfUAAiX2AAIl+AACJfkAAiY4AAImOgACJjwAAiY+AAImQQACJkIAAiZDAAImRAACJkUAAiZHAAImSQACJkoAAiZLAAImTQACJk4AAiZzAAImlwACJr4AAibiAAIm5QACJucAAibpAAIm6wACJu0AAibvAAIm8AACJvMAAicAAAInDwACJxEAAicTAAInFQACJxcAAicZAAInGwACJx0AAicsAAInLwACJzIAAic1AAInOAACJzsAAic+AAInQQACJ0MAAieCAAInhAACJ4YAAieIAAIniwACJ4wAAieNAAInjgACJ48AAieRAAInkwACJ5QAAieVAAInlwACJ5gAAifXAAIn2QACJ9sAAifdAAIn4AACJ+EAAifiAAIn4wACJ+QAAifmAAIn6AACJ+kAAifqAAIn7AACJ+0AAigsAAIoLgACKDAAAigyAAIoNQACKDYAAig3AAIoOAACKDkAAig7AAIoPQACKD4AAig/AAIoQQACKEIAAiiBAAIogwACKIUAAiiHAAIoigACKIsAAiiMAAIojQACKI4AAiiQAAIokgACKJMAAiiUAAIolgACKJcAAijWAAIo2AACKNoAAijcAAIo3wACKOAAAijhAAIo4gACKOMAAijlAAIo5wACKOgAAijpAAIo6wACKOwAAikrAAIpLQACKS8AAikxAAIpNAACKTUAAik2AAIpNwACKTgAAik6AAIpPAACKT0AAik+AAIpQAACKUEAAimAAAIpggACKYQAAimGAAIpiQACKYoAAimLAAIpjAACKY0AAimPAAIpkQACKZIAAimTAAIplQACKZYAAinhAAIqBAACKiQAAipEAAIqRgACKkgAAipKAAIqTAACKk8AAipQAAIqUQACKlQAAipVAAIqVwACKlgAAipaAAIqXQACKl4AAipfAAIqYgACKmMAAipoAAIqdQACKnoAAip8AAIqfgACKoMAAiqGAAIqiQACKosAAiqwAAIq1AACKvsAAisfAAIrIgACKyQAAismAAIrKAACKyoAAissAAIrLQACKzAAAis9AAIrTgACK1AAAitSAAIrVAACK1YAAitYAAIrWgACK1wAAiteAAIrbwACK3IAAit1AAIreAACK3sAAit+AAIrgQACK4QAAiuHAAIriQACK8gAAivKAAIrzAACK84AAivRAAIr0gACK9MAAivUAAIr1QACK9cAAivZAAIr2gACK9sAAivdAAIr3gACLB0AAiwfAAIsIQACLCMAAiwmAAIsJwACLCgAAiwpAAIsKgACLCwAAiwuAAIsLwACLDAAAiwyAAIsMwACLHIAAix0AAIsdwACLHkAAix8AAIsfQACLH4AAix/AAIsgAACLIIAAiyEAAIshQACLIYAAiyIAAIsiQACLJYAAiyXAAIsmAACLJoAAizZAAIs2wACLN0AAizfAAIs4gACLOMAAizkAAIs5QACLOYAAizoAAIs6gACLOsAAizsAAIs7gACLO8AAi0uAAItMAACLTIAAi00AAItNwACLTgAAi05AAItOgACLTsAAi09AAItPwACLUAAAi1BAAItQwACLUQAAi2DAAIthQACLYcAAi2JAAItjAACLY0AAi2OAAItjwACLZAAAi2SAAItlAACLZUAAi2WAAItmAACLZkAAi3YAAIt2gACLdwAAi3eAAIt4QACLeIAAi3jAAIt5AACLeUAAi3nAAIt6QACLeoAAi3rAAIt7QACLe4AAi4tAAIuLwACLjEAAi4zAAIuNgACLjcAAi44AAIuOQACLjoAAi48AAIuPgACLj8AAi5AAAIuQgACLkMAAi5oAAIujAACLrMAAi7XAAIu2gACLtwAAi7eAAIu4AACLuIAAi7kAAIu5QACLugAAi71AAIvBAACLwYAAi8IAAIvCgACLwwAAi8OAAIvEAACLxIAAi8hAAIvJAACLycAAi8qAAIvLQACLzAAAi8zAAIvNgACLzgAAi93AAIveQACL3sAAi99AAIvgAACL4EAAi+CAAIvgwACL4QAAi+GAAIviAACL4kAAi+KAAIvjAACL40AAi/MAAIvzgACL9AAAi/SAAIv1QACL9YAAi/XAAIv2AACL9kAAi/bAAIv3QACL94AAi/fAAIv4QACL+IAAjAhAAIwIwACMCUAAjAnAAIwKgACMCsAAjAsAAIwLQACMC4AAjAwAAIwMgACMDMAAjA0AAIwNgACMDcAAjB2AAIweAACMHoAAjB8AAIwfwACMIAAAjCBAAIwggACMIMAAjCFAAIwhwACMIgAAjCJAAIwiwACMIwAAjDLAAIwzQACMM8AAjDRAAIw1AACMNUAAjDWAAIw1wACMNgAAjDaAAIw3AACMN0AAjDeAAIw4AACMOEAAjEgAAIxIgACMSQAAjEmAAIxKQACMSoAAjErAAIxLAACMS0AAjEvAAIxMQACMTIAAjEzAAIxNQACMTYAAjF1AAIxdwACMXkAAjF7AAIxfgACMX8AAjGAAAIxgQACMYIAAjGEAAIxhgACMYcAAjGIAAIxigACMYsAAjHWAAIx+QACMhkAAjI5AAIyOwACMj0AAjI/AAIyQQACMkQAAjJFAAIyRgACMkkAAjJKAAIyTAACMk0AAjJPAAIyUgACMlMAAjJUAAIyVwACMlgAAjJhAAIybgACMnMAAjJ1AAIydwACMnwAAjJ/AAIyggACMoQAAjKpAAIyzQACMvQAAjMYAAIzGwACMx0AAjMfAAIzIQACMyMAAjMlAAIzJgACMykAAjM2AAIzRwACM0kAAjNLAAIzTQACM08AAjNRAAIzUwACM1UAAjNXAAIzaAACM2sAAjNuAAIzcQACM3QAAjN3AAIzegACM30AAjOAAAIzggACM8EAAjPDAAIzxQACM8cAAjPKAAIzywACM8wAAjPNAAIzzgACM9AAAjPSAAIz0wACM9QAAjPWAAIz1wACNBYAAjQYAAI0GgACNBwAAjQfAAI0IAACNCEAAjQiAAI0IwACNCUAAjQnAAI0KAACNCkAAjQrAAI0LAACNGsAAjRtAAI0cAACNHIAAjR1AAI0dgACNHcAAjR4AAI0eQACNHsAAjR9AAI0fgACNH8AAjSBAAI0ggACNI8AAjSQAAI0kQACNJMAAjTSAAI01AACNNYAAjTYAAI02wACNNwAAjTdAAI03gACNN8AAjThAAI04wACNOQAAjTlAAI05wACNOgAAjUnAAI1KQACNSsAAjUtAAI1MAACNTEAAjUyAAI1MwACNTQAAjU2AAI1OAACNTkAAjU6AAI1PAACNT0AAjV8AAI1fgACNYAAAjWCAAI1hQACNYYAAjWHAAI1iAACNYkAAjWLAAI1jQACNY4AAjWPAAI1kQACNZIAAjXRAAI10wACNdUAAjXXAAI12gACNdsAAjXcAAI13QACNd4AAjXgAAI14gACNeMAAjXkAAI15gACNecAAjYmAAI2KAACNioAAjYsAAI2LwACNjAAAjYxAAI2MgACNjMAAjY1AAI2NwACNjgAAjY5AAI2OwACNjwAAjZhAAI2hQACNqwAAjbQAAI20wACNtUAAjbXAAI22QACNtsAAjbdAAI23gACNuEAAjbuAAI2/QACNv8AAjcBAAI3AwACNwUAAjcHAAI3CQACNwsAAjcaAAI3HQACNyAAAjcjAAI3JgACNykAAjcsAAI3LwACNzEAAjdwAAI3cgACN3UAAjd3AAI3egACN3sAAjd8AAI3fQACN34AAjeAAAI3ggACN4MAAjeEAAI3hgACN4cAAjfGAAI3yAACN8oAAjfMAAI3zwACN9AAAjfRAAI30gACN9MAAjfVAAI31wACN9gAAjfZAAI32wACN9wAAjgbAAI4HQACOB8AAjghAAI4JAACOCUAAjgmAAI4JwACOCgAAjgqAAI4LAACOC0AAjguAAI4MAACODEAAjhwAAI4cgACOHUAAjh3AAI4egACOHsAAjh8AAI4fQACOH4AAjiAAAI4ggACOIMAAjiEAAI4hgACOIcAAjjGAAI4yAACOMoAAjjMAAI4zwACONAAAjjRAAI40gACONMAAjjVAAI41wACONgAAjjZAAI42wACONwAAjkbAAI5HQACOR8AAjkhAAI5JAACOSUAAjkmAAI5JwACOSgAAjkqAAI5LAACOS0AAjkuAAI5MAACOTEAAjlwAAI5cgACOXQAAjl2AAI5eQACOXoAAjl7AAI5fAACOX0AAjl/AAI5gQACOYIAAjmDAAI5hQACOYYAAjnRAAI59AACOhQAAjo0AAI6NgACOjgAAjo6AAI6PAACOj8AAjpAAAI6QQACOkQAAjpFAAI6RwACOkgAAjpKAAI6TQACOk4AAjpPAAI6UgACOlMAAjpcAAI6aQACOm4AAjpwAAI6cgACOncAAjp6AAI6fQACOn8AAjqkAAI6yAACOu8AAjsTAAI7FgACOxgAAjsaAAI7HAACOx4A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AkY+AAJGPwACRkEAAkZDAAJGRAACRkUAAkZHAAJGSAACRlUAAkZWAAJGVwACRlkAAkaYAAJGmgACRpwAAkaeAAJGoQACRqIAAkajAAJGpAACRqUAAkanAAJGqQACRqoAAkarAAJGrQACRq4AAkbtAAJG7wACRvIAAkb0AAJG9wACRvgAAkb5AAJG+gACRvsAAkb9AAJG/wACRwAAAkcBAAJHAwACRwQAAkcRAAJHHgACRx8AAkcgAAJHIgACR2UAAkeJAAJHrQACR9AAAkf3AAJIFwACSD4AAkhlAAJIhQACSKkAAkjNAAJIzwACSNIAAkjUAAJI1gACSNgAAkjbAAJI3QACSN8AAkjhAAJI4wACSOUAAkjnAAJI6gACSO0AAkjuAAJI8wACSQAAAkkDAAJJBQACSQgAAkkLAAJJDQACSTIAAklWAAJJfQACSaEAAkmkAAJJpgACSagAAkmqAAJJrAACSa4AAkmvAAJJsgACSb8AAknSAAJJ1AACSdYAAknYAAJJ2gACSdwAAkneAAJJ4AACSeIAAknkAAJJ9wACSfoAAkn9AAJKAAACSgMAAkoGAAJKCQACSgwAAkoPAAJKEgACShQAAkpTAAJKVQACSlgAAkpaAAJKXQACSl4AAkpfAAJKYAACSmEAAkpjAAJKZQACSmYAAkpnAAJKaQACSmoAAkpzAAJKdAACSnYAAkq1AAJKtwACSrkAAkq7AAJKvgACSr8AAkrAAAJKwQACSsIAAkrEAAJKxgACSscAAkrIAAJKygACSssAAksKAAJLDAACSw8AAksRAAJLFAACSxUAAksWAAJLFwACSxgAAksaAAJLHAACSx0AAkseAAJLIAACSyEAAksqAAJLKwACSy0AAktsAAJLbgACS3AAAktyAAJLdQACS3YAAkt3AAJLeAACS3kAAkt7AAJLfQACS34AAkt/AAJLgQACS4IAAkvBAAJLwwACS8YAAkvIAAJLywACS8wAAkvNAAJLzgACS88AAkvRAAJL0wACS9QAAkvVAAJL1wACS9gAAkvhAAJL4gACS+QAAkwjAAJMJQACTCcAAkwpAAJMLAACTC0AAkwuAAJMLwACTDAAAkwyAAJMNAACTDUAAkw2AAJMOAACTDkAAkx4AAJMegACTH0AAkx/AAJMggACTIMAAkyEAAJMhQACTIYAAkyIAAJMigACTIsAAkyMAAJMjgACTI8AAkycAAJMnQACTJ4AAkygAAJM3wACTOEAAkzjAAJM5QACTOgAAkzpAAJM6gACTOsAAkzsAAJM7gACTPAAAkzxAAJM8gACTPQAAkz1AAJNNAACTTYAAk05AAJNOwACTT4AAk0/AAJNQAACTUEAAk1CAAJNRAACTUYAAk1HAAJNSAACTUoAAk1LAAJNWgACTWcAAk1uAAJNcQACTXQAAk12AAJNfQACTYAAAk2DAAJNhgACTYgAAk2PAAJNmQACTeQAAk4HAAJOJwACTkcAAk5JAAJOSwACTk0AAk5PAAJOUgACTlMAAk5UAAJOVwACTlgAAk5aAAJOWwACTl0AAk5gAAJOYQACTmIAAk5lAAJOZgACTmsAAk54AAJOfQACTn8AAk6BAAJOhgACTokAAk6MAAJOjgACTrMAAk7XAAJO/gACTyIAAk8lAAJPJwACTykAAk8rAAJPLQACTy8AAk8wAAJPMwACT0AAAk9RAAJPUwACT1UAAk9XAAJPWQACT1sAAk9dAAJPXwACT2EAAk9yAAJPdQACT3gAAk97AAJPfgACT4EAAk+EAAJPhwACT4oAAk+MAAJPywACT80AAk/PAAJP0QACT9QAAk/VAAJP1gACT9cAAk/YAAJP2gACT9wAAk/dAAJP3gACT+AAAk/hAAJQIAACUCIAAlAkAAJQJgACUCkAAlAqAAJQKwACUCwAAlAtAAJQLwACUDEAAlAyAAJQMwACUDUAAlA2AAJQdQACUHcAAlB6AAJQfAACUH8AAlCAAAJQgQACUIIAAlCDAAJQhQACUIcAAlCIAAJQiQACUIsAAlCMAAJQmQACUJoAAlCbAAJQnQACUNwAAlDeAAJQ4AACUOIAAlDlAAJQ5gACUOcAAlDoAAJQ6QACUOsAAlDtAAJQ7gACUO8AAlDxAAJQ8gACUTEAAlEzAAJRNQACUTcAAlE6AAJROwACUTwAAlE9AAJRPgACUUAAAlFCAAJRQwACUUQAAlFGAAJRRwACUYYAAlGIAAJRigACUYwAAlGPAAJRkAACUZEAAlGSAAJRkwACUZUAAlGXAAJRmAACUZkAAlGbAAJRnAACUdsAAlHdAAJR3wACUeEAAlHkAAJR5QACUeYAAlHnAAJR6AACUeoAAlHsAAJR7QACUe4AAlHwAAJR8QACUjAAAlIyAAJSNAACUjYAAlI5AAJSOgACUjsAAlI8AAJSPQACUj8AAlJBAAJSQgACUkMAAlJFAAJSRgACUmsAAlKPAAJStgACUtoAAlLdAAJS3wACUuEAAlLjAAJS5QACUucAAlLoAAJS6wACUvgAAlMHAAJTCQACUwsAAlMNAAJTDwACUxEAAlMTAAJTFQACUyQAAlMnAAJTKgACUy0AAlMwAAJTMwACUzYAAlM5AAJTOwACU3oAAlN8AAJTfgACU4AAAlODAAJThAACU4UAAlOGAAJThwACU4kAAlOLAAJTjAACU40AAlOPAAJTkAACU88AAlPRAAJT0wACU9UAAlPYAAJT2QACU9oAAlPbAAJT3AACU94AAlPgAAJT4QACU+IAAlPkAAJT5QACVCQAAlQmAAJUKAACVCoAAlQtAAJULgACVC8AAlQwAAJUMQACVDMAAlQ1AAJUNgACVDcAAlQ5AAJUOgACVHkAAlR7AAJUfQACVH8AAlSCAAJUgwACVIQAAlSFAAJUhgACVIgAAlSKAAJUiwACVIwAAlSOAAJUjwACVM4AAlTQAAJU0gACVNQAAlTXAAJU2AACVNkAAlTaAAJU2wACVN0AAlTfAAJU4AACVOEAAlTjAAJU5AACVSMAAlUlAAJVJwACVSkAAlUsAAJVLQACVS4AAlUvAAJVMAACVTIAAlU0AAJVNQACVTYAAlU4AAJVOQACVXgAAlV6AAJVfAACVX4AAlWBAAJVggACVYMAAlWEAAJVhQACVYcAAlWJAAJVigACVYsAAlWNAAJVjgACVdkAAlX8AAJWHAACVjwAAlY+AAJWQAACVkIAAlZEAAJWRwACVkgAAlZJAAJWTAACVk0AAlZPAAJWUAACVlIAAlZVAAJWVgACVlcAAlZaAAJWWwACVmAAAlZtAAJWcgACVnQAAlZ2AAJWewACVn4AAlaBAAJWgwACVqgAAlbMAAJW8wACVxcAAlcaAAJXHAACVx4AAlcgAAJXIgACVyQAAlclAAJXKAACVzUAAldGAAJXSAACV0oAAldMAAJXTgACV1AAAldSAAJXVAACV1YAAldnAAJXagACV20AAldwAAJXcwACV3YAAld5AAJXfAACV38AAleBAAJXwAACV8IAAlfEAAJXxgACV8kAAlfKAAJXywACV8wAAlfNAAJXzwACV9EAAlfSAAJX0wACV9UAAlfWAAJYFQACWBcAAlgZAAJYGwACWB4AAlgfAAJYIAACWCEAAlgiAAJYJAACWCYAAlgnAAJYKAACWCoAAlgrAAJYagACWGwAAlhvAAJYcQACWHQAAlh1AAJYdgACWHcAAlh4AAJYegACWHwAAlh9AAJYfgACWIAAAliBAAJYjgACWI8AAliQAAJYkgACWNEAAljTAAJY1QACWNcAAljaAAJY2wACWNwAAljdAAJY3gACWOAAAljiAAJY4wACWOQAAljmAAJY5wACWSYAAlkoAAJZKgACWSwAAlkvAAJZMAACWTEAAlkyAAJZMwACWTUAAlk3AAJZOAACWTkAAlk7AAJZPAACWXsAAll9AAJZfwACWYEAAlmEAAJZhQACWYYAAlmHAAJZiAACWYoAAlmMAAJZjQACWY4AAlmQAAJZkQACWdAAAlnSAAJZ1AACWdYAAlnZAAJZ2gACWdsAAlncAAJZ3QACWd8AAlnhAAJZ4gACWeMAAlnlAAJZ5gACWiUAAlonAAJaKQACWisAAlouAAJaLwACWjAAAloxAAJaMgACWjQAAlo2AAJaNwACWjgAAlo6AAJaOwACWmAAAlqEAAJaqwACWs8AAlrSAAJa1AACWtYAAlrYAAJa2gACWtwAAlrdAAJa4AACWu0AAlr8AAJa/gACWwAAAlsCAAJbBAACWwYAAlsIAAJbCgACWxkAAlscAAJbHwACWyIAAlslAAJbKAACWysAAlsuAAJbMAACW28AAltxAAJbcwACW3UAAlt4AAJbeQACW3oAAlt7AAJbfAACW34AAluAAAJbgQACW4IAAluEAAJbhQACW8QAAlvGAAJbyAACW8oAAlvNAAJbzgACW88AAlvQAAJb0QACW9MAAlvVAAJb1gACW9cAAlvZAAJb2gACXBkAAlwbAAJcHQACXB8AAlwiAAJcIwACXCQAAlwlAAJcJgACXCgAAlwqAAJcKwACXCwAAlwuAAJcLwACXG4AAlxwAAJccgACXHQAAlx3AAJceAACXHkAAlx6AAJcewACXH0AAlx/AAJcgAACXIEAAlyDAAJchAACXMMAAlzFAAJcxwACXMkAAlzMAAJczQACXM4AAlzPAAJc0AACXNIAAlzUAAJc1QACXNYAAlzYAAJc2QACXRgAAl0aAAJdHAACXR4AAl0hAAJdIgACXSMAAl0kAAJdJQACXScAAl0pAAJdKgACXSsAAl0tAAJdLgACXW0AAl1vAAJdcQACXXMAAl12AAJddwACXXgAAl15AAJdegACXXwAAl1+AAJdfwACXYAAAl2CAAJdgwACXc4AAl3xAAJeEQACXjEAAl4zAAJeNQACXjcAAl45AAJePAACXj0AAl4+AAJeQQACXkIAAl5EAAJeRQACXkcAAl5JAAJeSgACXksAAl5OAAJeTwACXlgAAl5lAAJeagACXmwAAl5uAAJecwACXnYAAl55AAJeewACXqAAAl7EAAJe6wACXw8AAl8SAAJfFAACXxYAAl8YAAJfGgACXxwAAl8dAAJfIAACXy0AAl8+AAJfQAACX0IAAl9EAAJfRgACX0gAAl9KAAJfTAACX04AAl9fAAJfYgACX2UAAl9oAAJfawACX24AAl9xAAJfdAACX3cAAl95AAJfuAACX7oAAl+8AAJfvgACX8EAAl/CAAJfwwACX8QAAl/FAAJfxwACX8kAAl/KAAJfywACX80AAl/OAAJgDQACYA8AAmARAAJgEwACYBYAAmAXAAJgGAACYBkAAmAaAAJgHAACYB4AAmAfAAJgIAACYCIAAmAjAAJgYgACYGQAAmBnAAJgaQACYGwAAmBtAAJgbgACYG8AAmBwAAJgcgACYHQAAmB1AAJgdgACYHgAAmB5AAJghgACYIcAAmCIAAJgigACYMkAAmDLAAJgzQACYM8AAmDSAAJg0wACYNQAAmDVAAJg1gACYNgAAmDaAAJg2wACYNwAAmDeAAJg3wACYR4AAmEgAAJhIgACYSQAAmEnAAJhKAACYSkAAmEqAAJhKwACYS0AAmEvAAJhMAACYTEAAmEzAAJhNAACYXMAAmF1AAJhdwACYXkAAmF8AAJhfQACYX4AAmF/AAJhgAACYYIAAmGEAAJhhQACYYYAAmGIAAJhiQACYcgAAmHKAAJhzAACYc4AAmHRAAJh0gACYdMAAmHUAAJh1QACYdcAAmHZAAJh2gACYdsAAmHdAAJh3gACYh0AAmIfAAJiIQACYiMAAmImAAJiJwACYigAAmIpAAJiKgACYiwAAmIuAAJiLwACYjAAAmIyAAJiMwACYlgAAmJ8AAJiowACYscAAmLKAAJizAACYs4AAmLQAAJi0gACYtQAAmLVAAJi2AACYuUAAmL0AAJi9gACYvgAAmL6AAJi/AACYv4AAmMAAAJjAgACYxEAAmMUAAJjFwACYxoAAmMdAAJjIAACYyMAAmMmAAJjKAACY2cAAmNpAAJjawACY20AAmNwAAJjcQACY3IAAmNzAAJjdAACY3YAAmN4AAJjeQACY3oAAmN8AAJjfQACY7wAAmO+AAJjwAACY8IAAmPFAAJjxgACY8cAAmPIAAJjyQACY8sAAmPNAAJjzgACY88AAmPRAAJj0gACZBEAAmQTAAJkFQACZBcAAmQaAAJkGwACZBwAAmQdAAJkHgACZCAAAmQiAAJkIwACZCQAAmQmAAJkJwACZGYAAmRoAAJkagACZGwAAmRvAAJkcAACZHEAAmRyAAJkcwACZHUAAmR3AAJkeAACZHkAAmR7AAJkfAACZLsAAmS9AAJkvwACZMEAAmTEAAJkxQACZMYAAmTHAAJkyAACZMoAAmTMAAJkzQACZM4AAmTQAAJk0QACZRAAAmUSAAJlFAACZRYAAmUZAAJlGgACZRsAAmUcAAJlHQACZR8AAmUhAAJlIgACZSMAAmUlAAJlJgACZWUAAmVnAAJlaQACZWsAAmVuAAJlbwACZXAAAmVxAAJlcgACZXQAAmV2AAJldwACZXgAAmV6AAJlewACZYQAAmWFAAJlhwACZZQAAmWVAAJllgACZZgAAmWlAAJlpgACZacAAmWpAAJltgACZbcAAmW4AAJlugACZcMAAmXSAAJl3wACZe4AAmYAAAJmFAACZisAAmY9AAJmRgACZkcAAmZJAAJmVgACZlcAAmZYAAJmWgACZmMAAmZtAAJmdAAAAAAAAAQCAAAAAAAAXDgAAAAAAAAAAAAAAAAAAmZ8 +cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxEK+QALAAwAGwA3ADgAOQBfAGAAYQBiAGMAZABlAGYAZwBoAGkAagBrAGwAbQBuAG8AigCLAIwAkgCTAJ8AtQC2ALcAuAC5ALoAuwC8AL0AvgDXANoA4QDnAPYBBQEIARcBJgEpAIkBOQFIAUwBUAFfAWUBZgFuAX0BfgGHAZMBlAGVAZYBlwGsAa0BtQG2AbcBwwHXAdgB2QHaAdsB3AHdAd4B3wHuAf0CDAIQAh8CLgIvAj4CTQJcAmgCegJ7AnwCfQJ+An8CgAKBADECkAKfAqACrwK+AtgC2QLfAusDAQMQAxMDIgMxAzUDOQM6A0kDWANbA2oDeQN9A4wDmwPRA9ID0wPUA9UD1gPXA9gD2QPaA9sD3APdA94D3wPgA+ED4gPjA+QD5QPmA+cD6AP9A/4EBgQSBCYENQREBFMEVwRmBHUEhASTBKIErgTABM8E3gTtBPwFCwUaBSkFMQVGBUcFTwVQBVwFcAV/BY4FnQWhBbAFvwXOBd0F7AX4BgoGCwYMBg0GDgYPBhAGEQYgBiEGMAY/Bk4GTwZeBm0GfAaEBpkGmgaiBq4GwgbRBuAG7wbzBwIHEQcgBy8HPgdKB1wHawd6B4kHmAeZB6gHtwfGB9sH3AfkB/AIBAgTCCIIMQg1CEQIUwhiCHEIgAiMCJ4IrQi8CMsI2gjbCOoI+QkICR0JHgkmCTIJRglVCWQJcwl3CYYJlQmkCbMJwgnOCeAJ7wn+Cg0KHAodCiwKOwo8CksKYAphCmkKdQqJCpgKpwq2CroKyQrYCucK9gsFCxELIwsyCzMLQgtRC2ALYQtwC38LjgujC6QLrAu4C8wL2wvqC/kL/QwMDBsMKgw5DEgMVAxmDHUMhAyTDKIMsQzADM8M5AzlDO0M+Q0NDRwNKw06DT4NTQ1cDWsNeg2JDZUNpw22DcUN1A3jDfIOAQ4QDiUOJg4uDjoOTg5dDmwOew5/Do4OnQ6sDrsOyg7WDugO9w8GDxUPJA8zD0IPUQ9mD2cPbw97D48Png+tD7wPwA/PD94P7Q/8EAsQFxApEDgQRxBWEGUQdBCDEJIQpxCoELAQvBDQEN8Q7hD9EQEREBEfES4RPRFMEVgRahF5EYgRlxGmEbURxBHTEegR6RHxEf0SERIgEi8SPhJ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4WIBYjFigWK9YvljNWNFY4FjvWP5ZDVkcWShZOllJWVhZZ1l2WYVZlFmjWbhZuVnBWc1Z4VnwWf9aDloSWiFaMFo/Wk5aXVppWntailqZWqhat1rGWtVa5Fr5WvpbAlsOWyJbMVtAW09bU1tiW3FbgFuPW55bqlu8W8tb2lvpW/hb+VwIXBdcJlwpXDhcR1xWXGVcdFyJXIpcklyeXLJcwVzQXN9c41zyXQFdEF0fXS5dOl1MXVtdal15XYhdl12mXbVduF3SXdNd2V3lXfteCl4NXhxeK14uXj1eTF5PXl5ebV5xXoBej16QXphemV6uXq9et17DXtde5l71XwRfCF8XXyZfNV9EX1NfX19xX4Bfj1+eX61frl+9X8xf21/wX/Ff+WAFYBlgKGA3YEZgSmBZYGhgd2CGYJVgoWCzYMJg0WDgYO9g/mENYRxhH2E5YTphQGFMYWJhcWF0YYNhkmGVYaRhs2G2YcVh1GHYYedh9mH3Yf9iAGIBYhZiF2IfYitiP2JOYl1ibGJwYn9ijmKdYqxiu2LHYtli6GL3YwZjFWMkYzNjQmNXY1hjYGNsY4Bjj2OeY61jsWPAY89j3mPtY/xkCGQaZClkOGRHZFZkZWR0ZINkhmSgZKFkp2SzZMlk2GTbZOpk+WT8ZQtlGmUdZSxlO2U/ZU5lXWVeZWxlbWVuZW9lhGWFZY1lmWWtZbxly2XaZd5l7WX8ZgtmGmYpZjVmR2ZWZmVmdGaDZpJmoWawZsVmxmbOZtpm7mb9ZwxnG2cfZy5nPWdMZ1tnamd2Z4hnl2emZ7VnxGfTZ+Jn8WgGaAdoD2gbaC9oPmhNaFxoYGhvaH5ojWicaKtot2jJaNho52j2aQVpFGkjaTJpR2lIaVBpXGlwaX9pjmmdaaFpsGm/ac5p3WnsafhqCmoZaihqN2pGalVqZGpzaohqiWqRap1qsWrAas9q3mriavFrAGsPax5rLWs5a0trWmtpa3hrh2uWa6VrtGu3a9Fr0mvYa+Rr+mwJbAxsG2wqbC1sPGxLbE5sXWxsbHBsf2yObI9sm2ycbJ1ssmyzbLtsx2zbbOps+W0IbQxtG20qbTltSG1XbWNtdW2EbZNtom2xbcBtz23ebfNt9G38bghuHG4rbjpuSW5Nblxua256bolumG6kbrZuxW7UbuNu8m8BbxBvH280bzVvPW9Jb11vbG97b4pvjm+db6xvu2/Kb9lv5W/3cAZwFXAkcDNwQnBRcGBwdXB2cH5winCecK1wvHDLcM9w3nDtcPxxC3EacSZxOHFHcVZxZXF0cYNxknGhcaRxvnG/ccVx0XHncfZx+XIIchdyGnIpcjhyO3JKcllyXXJscntyfHKWcpdymHKZcppym3Kccp1ynnKfcqBytXK2cr5yynLecu1y/HMLcw9zHnMtczxzS3Nac2ZzeHOHc5ZzpXO0c8Nz0nPhc/Zz93P/dAt0H3QudD10THRQdF90bnR9dIx0m3SndLl0yHTXdOZ09XUEdRN1InU3dTh1QHVMdWB1b3V+dY11kXWgda91vnXNddx16HX6dgl2GHYndjZ2RXZUdmN2eHZ5doF2jXahdrB2v3bOdtJ24Xbwdv93Dncddyl3O3dKd1l3aHd3d4Z3lXekd7l3unfCd8534nfxeAB4D3gTeCJ4MXhAeE94XnhqeHx4i3iaeKl4uHjHeNZ45Xj6ePt5A3kPeSN5MnlBeVB5VHljeXJ5gXmQeZ95q3m9ecx523nqefl6CHoXeiZ6O3o8ekR6UHpkenN6gnqRepV6pHqzesJ60Xrgeux6/nsNexx7K3s6e0l7WHtne3x7fXuFe5F7pXu0e8N70nvWe+V79HwDfBJ8IXwtfD98TnxdfGx8e3yKfJl8qHy9fL58xnzSfOZ89X0EfRN9F30mfTV9RH1TfWJ9bn2AfY99nn2tfbx9y33afel9/n3/fgd+E34nfjZ+RX5Uflh+Z352foV+lH6jfq9+wX7Qft9+7n79fwx/G38qfz9/QH9If1R/aH93f4Z/lX+Zf6h/t3/Gf9V/5H/wgAKAEYAggC+APoBNgFyAa4BugIiAiYCPgJuAsYDAgMOA0oDhgOSA84ECgQWBFIEjgSeBNoFFgU+BZIFlgW2BeYGNgZyBq4G6gb6BzYHcgeuB+oIJghWCJ4I2gkWCVIJjgnKCgYKQgqWCpoKugrqCzoLdguyC+4L/gw6DHYMsgzuDSoNWg2iDd4OGg5WDpIOzg8KD0YPmg+eD74P7hA+EHoQthDyEQIRPhF6EbYR8hIuEl4SphLiEx4TWhOWE9IUDhRKFFYUvhTCFNoVChViFZ4VqhXmFiIWLhZqFqYWshbuFyoXOhd2F7IXthfeF+IX5hg6GD4YXhiOGN4ZGhlWGZIZohneGhoaVhqSGs4a/htGG4Ibvhv6HDYcchyuHOodPh1CHWIdkh3iHh4eWh6WHqYe4h8eH1oflh/SIAIgSiCGIMIg/iE6IXYhsiHuIkIiRiJmIpYi5iMiI14jmiOqI+YkIiReJJok1iUGJU4liiXGJgImPiZ6JrYm8ib+J2YnaieCJ7IoCihGKFIojijKKNYpEilOKVoplinSKeIqHipaKl4qfiqCKtYq2ir6Kyoreiu2K/IsLiw+LHostizyLS4tai2aLeIuHi5aLpYu0i8OL0ovhi/aL94v/jAuMH4wujD2MTIxQjF+Mbox9jIyMm4ynjLmMyIzXjOaM9Y0EjRONIo0ljSmNLY0xjTmNPI1AVSRudWxs1wANAA4ADwAQABEAEgATABQAFQAWABcAGAAXABpfEA9feGRfcm9vdFBhY2thZ2VWJGNsYXNzXF94ZF9jb21tZW50c18QEF94ZF9tb2RlbE1hbmFnZXJfEBVfY29uZmlndXJhdGlvbnNCeU5hbWVdX3hkX21vZGVsTmFtZV8QF19tb2RlbFZlcnNpb25JZGVudGlmaWVygAKBCviBCvaAAIEK94AAgQSj3gAcAB0AHgAfACAAIQAiAA4AIwAkACUAJgAnACgAKQAqACsACQApABcALwAwADEAMgAzACkAKQAXXxAcWERCdWNrZXRGb3JDbGFzc2Vzd2FzRW5jb2RlZF8QGlhEQnVja2V0Rm9yUGFja2FnZXNzdG9yYWdlXxAcWERCdWNrZXRGb3JJbnRlcmZhY2Vzc3RvcmFnZV8QD194ZF9vd25pbmdNb2RlbF8QHVhEQnVja2V0Rm9yUGFja2FnZXN3YXNFbmNvZGVkVl9vd25lcl8QG1hEQnVja2V0Rm9yRGF0YVR5cGVzc3RvcmFnZVtfdmlzaWJpbGl0eV8QGVhEQnVja2V0Rm9yQ2xhc3Nlc3N0b3JhZ2VVX25hbWVfEB9YREJ1Y2tldEZvckludGVyZmFjZXN3YXNFbmNvZGVkXxAeWERCdWNrZXRGb3JEYXRhVHlwZXN3YXNFbmNvZGVkXxAQX3VuaXF1ZUVsZW1lbnRJRIAEgQr0gQrygAGABIAAgQrzgQr1EACABYADgASABIAAUFNZRVPTADoAOwAOADwATQBeV05TLmtleXNaTlMub2JqZWN0c68QEAA9AD4APwBAAEEAQgBDAEQARQBGAEcASABJAEoASwBMgAaAB4AIgAmACoALgAyADYAOgA+AEIARgBKAE4AUgBWvEBAATgBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXYAWgQG4gGmBAm6BBd2BBmuBB1WBB5qBB9+BBtyBCGqBBE2BCN2BCfmBClKBCq6ANF1DREV4dGVybmFsQXBpXENEQ2hhaW5Bc3NldFdDRENoYWluV0NEQXNzZXRdQ0RDb250YWN0SXRlbV8QGUNEUG9sa2Fzd2FwUmVtb3RlU2V0dGluZ3NdQ0RTaW5nbGVWYWx1ZVtDRFN0YXNoSXRlbV8QFUNEUnVudGltZU1ldGFkYXRhSXRlbV5DRFBvbGthc3dhcERleFpDRFNjYW1JbmZvW0NEQ2hhaW5Ob2RlXxAYQ0RUcmFuc2FjdGlvbkhpc3RvcnlJdGVtWUNEQ29udGFjdF5DRFBoaXNoaW5nSXRlbV8QEkNEQ2hhaW5TdG9yYWdlSXRlbd8QEABwAHEAcgBzACEAdAB1ACMAdgB3AA4AJQB4AHkAKAB6AHsAfAApACkAFACAAIEAMQApAHsAhAA9AHsAhwCIAIlfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2VbX2lzQWJzdHJhY3SAGIA8gASABIACgBmBA7mABIAYgQO7gAaAGIEF3IAXCBMAAAABDKV2PFdvcmRlcmVk0wA6ADsADgCNAI8AXqEAjoAaoQCQgBuANF5YRF9QU3RlcmVvdHlwZdkAIQAlAJQADgAoAJUAIwB6AJYATgCOAHsAmgAXACkAMQCJAJ5fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAFoAagBiAO4AAgAQIgBzTADoAOwAOAKAAqgBeqQChAKIAowCkAKUApgCnAKgAqYAdgB6AH4AggCGAIoAjgCSAJakAqwCsAK0ArgCvALAAsQCyALOAJoAqgCuALYAugDCAMoA1gDmANF8QE1hEUE1Db21wb3VuZEluZGV4ZXNfEBBYRF9QU0tfZWxlbWVudElEXxAZWERQTVVuaXF1ZW5lc3NDb25zdHJhaW50c18QGlhEX1BTS192ZXJzaW9uSGFzaE1vZGlmaWVyXxAZWERfUFNLX2ZldGNoUmVxdWVzdHNBcnJheV8QEVhEX1BTS19pc0Fic3RyYWN0XxAPWERfUFNLX3VzZXJJbmZvXxATWERfUFNLX2NsYXNzTWFwcGluZ18QFlhEX1BTS19lbnRpdHlDbGFzc05hbWXfEA8AvwDAAMEAIQDCAMMAxAAjAMUADgAlAMYAxwAoAMgAFwDKABcAkACJAIkAiQAxAIkA0QChAIkAiQAXAIlVX3R5cGVYX2RlZmF1bHRcX2Fzc29jaWF0aW9uW19pc1JlYWRPbmx5WV9pc1N0YXRpY1lfaXNVbmlxdWVaX2lzRGVyaXZlZFpfaXNPcmRlcmVkXF9pc0NvbXBvc2l0ZVdfaXNMZWFmgACAJ4AAgBsICAgIgCmAHQgIgAAI0gA7AA4A2ADZoIAo0gDbANwA3QDeWiRjbGFzc25hbWVYJGNsYXNzZXNeTlNNdXRhYmxlQXJyYXmjAN0A3wDgV05TQXJyYXlYTlNPYmplY3TSANsA3ADiAONfEBBYRFVNTFByb3BlcnR5SW1wpADkAOUA5gDgXxAQWERVTUxQcm9wZXJ0eUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcAFwAXAJAAiQCJAIkAMQCJANEAogCJAIkAFwCJgACAAIAAgBsICAgIgCmAHggIgAAI3xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcA+AAXAJAAiQCJAIkAMQCJANEAowCJAIkAFwCJgACALIAAgBsICAgIgCmAHwgIgAAI0gA7AA4BBgDZoIAo3xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcAFwAXAJAAiQCJAIkAMQCJANEApACJAIkAFwCJgACAAIAAgBsICAgIgCmAIAgIgAAI3xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcBGQAXAJAAiQCJAIkAMQCJANEApQCJAIkAFwCJgACAL4AAgBsICAgIgCmAIQgIgAAI0gA7AA4BJwDZoIAo3xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcBKwAXAJAAiQCJAIkAMQCJANEApgCJAIkAFwCJgACAMYAAgBsICAgIgCmAIggIgAAICN8QDwC/AMAAwQAhAMIAwwDEACMAxQAOACUAxgDHACgAyAAXATsAFwCQAIkAiQCJADEAiQDRAKcAiQCJABcAiYAAgDOAAIAbCAgICIApgCMICIAACNMAOgA7AA4BSQFKAF6goIA00gDbANwBTQFOXxATTlNNdXRhYmxlRGljdGlvbmFyeaMBTQFPAOBcTlNEaWN0aW9uYXJ53xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcBUgAXAJAAiQCJAIkAMQCJANEAqACJAIkAFwCJgACANoAAgBsICAgIgCmAJAgIgAAI1gAlAA4AKAB6ACEAIwFgAWEAFwCJABcAMYA3gDiAAAiAAF8QFFhER2VuZXJpY1JlY29yZENsYXNz0gDbANwBZwFoXVhEVU1MQ2xhc3NJbXCmAWkBagFrAWwBbQDgXVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcBcAAXAJAAiQCJAIkAMQCJANEAqQCJAIkAFwCJgACAOoAAgBsICAgIgCmAJQgIgAAIXUNERXh0ZXJuYWxBcGnSANsA3AF/AYBfEBJYRFVNTFN0ZXJlb3R5cGVJbXCnAYEBggGDAYQBhQGGAOBfEBJYRFVNTFN0ZXJlb3R5cGVJbXBdWERVTUxDbGFzc0ltcF8QElhEVU1MQ2xhc3NpZmllckltcF8QEVhEVU1MTmFtZXNwYWNlSW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDTADoAOwAOAYgBjQBepAGJAYoBiwGMgD2APoA/gECkAY4BjwGQAZGAQYEFloEFroEFxYA0VWNoYWluVXR5cGVzVHR5cGVTdXJs3xASAL8AwADBAZgAIQDDAMQBmQAjAMIBmgDFAA4AJQDGAMcAKADIABcAFwAXACkATgCJAIkBogAxAIkAewCJAaYBiQCJAIkBqgCJXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASAFggIgEMIgBgIgKyAPQgIgEIIEwAAAAEQUsGd0wA6ADsADgGuAbEAXqIBrwGwgESARaIBsgGzgEaAWoA0XxASWERfUFByb3BTdGVyZW90eXBlXxAQWERfUFJfU3RlcmVvdHlwZdkAIQAlAbgADgAoAbkAIwB6AboBjgGvAHsAmgAXACkAMQCJAcJfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAQYBEgBiAO4AAgAQIgEfTADoAOwAOAcQBzQBeqAHFAcYBxwHIAckBygHLAcyASIBJgEqAS4BMgE2AToBPqAHOAc8B0AHRAdIB0wHUAdWAUIBRgFKAVIBVgFeAWIBZgDRfEBtYRF9QUFNLX2lzU3RvcmVkSW5UcnV0aEZpbGVfEBtYRF9QUFNLX3ZlcnNpb25IYXNoTW9kaWZpZXJfEBBYRF9QUFNLX3VzZXJJbmZvXxARWERfUFBTS19pc0luZGV4ZWRfEBJYRF9QUFNLX2lzT3B0aW9uYWxfEBpYRF9QUFNLX2lzU3BvdGxpZ2h0SW5kZXhlZF8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Gb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIECbggIgQKlCIAYCIDOgQKCCAiBAqQIElruAS/TADoAOwAOHp0eoABeogGvBUqARICwoh6hHqKBAqaBArGANNkAIQAlHqUADgAoHqYAIwB6HqcdLQGvAHsAmgAXACkAMQCJHq9fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAqOARIAYgDuAAIAECIECp9MAOgA7AA4esR66AF6oAcUBxgHHAcgByQHKAcsBzIBIgEmASoBLgEyATYBOgE+oHrsevB69Hr4evx7AHsEewoECqIECqYECqoECrIECrYECroECr4ECsIA03xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcBKwAXHqEAiQCJAIkAMQCJANEBxQCJAIkAFwCJgACAMYAAgQKmCAgICIApgEgICIAACN8QDwC/AMAAwQAhAMIAwwDEACMAxQAOACUAxgDHACgAyAAXABcAFx6hAIkAiQCJADEAiQDRAcYAiQCJABcAiYAAgACAAIECpggICAiAKYBJCAiAAAjfEA8AvwDAAMEAIQDCAMMAxAAjAMUADgAlAMYAxwAoAMgAFx7kABceoQCJAIkAiQAxAIkA0QHHAIkAiQAXAImAAIECq4AAgQKmCAgICIApgEoICIAACNMAOgA7AA4e8h7zAF6goIA03xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcBKwAXHqEAiQCJAIkAMQCJANEByACJAIkAFwCJgACAMYAAgQKmCAgICIApgEsICIAACN8QDwC/AMAAwQAhAMIAwwDEACMAxQAOACUAxgDHACgAyAAXAiEAFx6hAIkAiQCJADEAiQDRAckAiQCJABcAiYAAgFaAAIECpggICAiAKYBMCAiAAAjfEA8AvwDAAMEAIQDCAMMAxAAjAMUADgAlAMYAxwAoAMgAFwErABceoQCJAIkAiQAxAIkA0QHKAIkAiQAXAImAAIAxgACBAqYICAgIgCmATQgIgAAI3xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQD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AxAAjAMUADgAlAMYAxwAoAMgAFzVKABc0fQCJAIkAiQAxAIkA0QJrAIkAiQAXAImAAIEESoAAgQRGCAgICIApgF0ICIAACBAC3xAPAL8AwADBACEAwgDDAMQAIwDFAA4AJQDGAMcAKADIABcCgwAXNH0AiQCJAIkAMQCJANECbACJAIkAFwCJgACAZIAAgQRGCAgICIApgF4ICIAACN8QDwC/AMAAwQAhAMIAwwDEACMAxQAOACUAxgDHACgAyAAXAFkAFzR9AIkAiQCJADEAiQDRAm0AiQCJABcAiYAAgQRNgACBBEYICAgIgCmAXwgIgAAI3xAQNXc1eDV5NXoAITV7NXwAIzV9NX4ADgAlNX81gAAoAHoAezWCACkAKQAUNYYAgQAxACkAewCEAEgAezWNNY4AiV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZYAYgQRhgASABIACgQRPgQO5gASAGIEDu4ARgBiBBNiBBE4IEwAAAAEPEWM+0wA6ADsADjWSNZQAXqEAjoAaoTWVgQRQgDTZACEAJTWYAA4AKDWZACMAejWaAFkAjgB7AJoAFwApADEAiTWiXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQRNgBqAGIA7gAC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AGPIAABj0AAAY9gAAGPgAABkbAAAZHQAAGSAAABkiAAAZJQAAGSgAABkrAAAZLgAAGTEAABk0AAAZNwAAGToAABk9AAAZQAAAGUMAABlGAAAZSQAAGUsAABlZAAAZZgAAGW4AABl2AAAZhAAAGaAAABmuAAAZugAAGdIAABnhAAAZ7AAAGfgAABoTAAAaHQAAGiwAABpBAAAahAAAGqgAABrMAAAa7wAAGxYAABs2AAAbXQAAG4QAABukAAAbyAAAG+wAABv4AAAb+gAAG/wAABv+AAAcAAAAHAIAABwEAAAcBwAAHAkAABwLAAAcDgAAHBAAABwSAAAcFQAAHBcAABwYAAAcIQAAHCkAABw2AAAcOQAAHDsAABw+AAAcQAAAHEIAABxRAAAcdgAAHJoAABzBAAAc5QAAHOcAABzpAAAc6wAAHO0AABzvAAAc8QAAHPIAABz0AAAdAQAAHRQAAB0WAAAdGAAAHRoAAB0cAAAdHgAAHSAAAB0iAAAdJAAAHSYAAB05AAAdOwAAHT0AAB0/AAAdQQAAHUMAAB1FAAAdRwAAHUkAAB1LAAAdTQAAHWMAAB12AAAdkgAAHa8AAB3LAAAd3wAAHfEAAB4HAAAeIAAAHl8AAB5lAAAebgAAHnsAAB6HAAAekQAAHpsAAB6mAAAesQAAHr4AAB7GAAAeyAAAHsoAAB7MAAAezgAAHs8AAB7QAAAe0QAAHtIAAB7UAAAe1gAAHtcAAB7YAAAe2gAAHtsAAB7kAAAe5QAAHucAAB7wAAAe+wAAHwQAAB8TAAAfGgAAHyIAAB8rAAAfNAAAH0cAAB9QAAAfYwAAH3oAAB+MAAAfywAAH80AAB/PAAAf0QAAH9MAAB/UAAAf1QAAH9YAAB/XAAAf2QAAH9sAAB/cAAAf3QAAH98AAB/gAAAgHwAAICEAACAjAAAgJQAAICcAACAoAAAgKQAAICoAACArAAAgLQAAIC8AACAwAAAgMQAAIDMAACA0AAAgPQAAID4AACBAAAAgfwAAIIEAACCDAAAghQAAIIcAACCIAAAgiQAAIIoAACCLAAAgjQAAII8AACCQAAAgkQAAIJMAACCUAAAg0wAAINUAACDXAAAg2QAAINsAACDcAAAg3QAAIN4AACDfAAAg4QAAIOMAACDkAAAg5QAAIOcAACDoAAAg8QAAIPIAACD0AAAhMwAAITUAACE3AAAhOQAAITsAACE8AAAhPQAAIT4AACE/AAAhQQAAIUMAACFEAAAhRQAAIUcAACFIAAAhSQAAIYgAACGKAAAhjAAAIY4AACGQAAAhkQAAIZIAACGTAAAhlAAAIZYAACGYAAAhmQAAIZoAACGcAAAhnQAAIaoAACGrAAAhrAAAIa4AACG3AAAhzQAAIdQAACHhAAAiIAAAIiIAACIkAAAiJgAAIigAACIpAAAiKgAAIisAACIsAAAiLgAAIjAAACIxAAAiMgAAIjQAACI1AAAiTgAAIlAAACJSAAAiVAAAIlUAACJXAAAibgAAIncAACKFAAAikgAAIqAAACK1AAAiyQAAIuAAACLyAAAjMQAAIzMAACM1AAAjNwAAIzkAACM6AAAjOwAAIzwAACM9AAAjPwAAI0EAACNCAAAjQwAAI0UAACNGAAAjVAAAI10AACNyAAAjgQAAI5YAACOkAAAjuQAAI80AACPkAAAj9gAAJAMAACQMAAAkDgAAJBAAACQSAAAkFAAAJB0AACQfAAAkIgAAJCUAACQoAAAkKgAAJDAAACQ2AAAkOwAAJD8AACSKAAAkrQAAJM0AACTtAAAk7wAAJPEAACTzAAAk9QAAJPcAACT4AAAk+QAAJPsAACT8AAAk/gAAJP8AACUBAAAlAwAAJQQAACUFAAAlBwAAJQgAACURAAAlHgAAJSMAACUlAAAlJwAAJSwAACUuAAAlMAAAJTIAACVHAAAlWgAAJX8AACWjAAAlygAAJe4AACXwAAAl8gAAJfQAACX2AAAl+AAAJfoAACX7AAAl/QAAJgoAACYbAAAmHQAAJh8AACYhAAAmIwAAJiUAACYnAAAmKQAAJisAACY8AAAmPgAAJkAAACZCAAAmRAAAJkYAACZIAAAmSgAAJkwAACZOAAAmbAAAJooAACadAAAmsQAAJsYAACbjAAAm9wAAJw0AACdMAAAnTgAAJ1AAACdSAAAnVAAAJ1UAACdWAAAnVwAAJ1gAACdaAAAnXAAAJ10AACdeAAAnYAAAJ2EAACegAAAnogAAJ6QAACemAAAnqAAAJ6kAACeqAAAnqwAAJ6wAACeuAAAnsAAAJ7EAACeyAAAntAAAJ7UAACf0AAAn9gAAJ/gAACf6AAAn/AAAJ/0AACf+AAAn/wAAKAAAACgCAAAoBAAAKAUAACgGAAAoCAAAKAkAACgWAAAoFwAAKBgAACgaAAAoWQAAKFsAAChdAAAoXwAAKGEAAChiAAAoYwAAKGQAAChlAAAoZwAAKGkAAChqAAAoawAAKG0AAChuAAAorQAAKK8AACixAAAoswAAKLUAACi2AAAotwAAKLgAACi5AAAouwAAKL0AACi+AAAovwAAKMEAACjCAAAowwAAKQIAACkEAAApBgAAKQgAACkKAAApCwAAKQwAACkNAAApDgAAKRAAACkSAAApEwAAKRQAACkWAAApFwAAKVYAAClYAAApWgAAKVwAACleAAApXwAAKWAAAClhAAApYgAAKWQAAClmAAApZwAAKWgAAClqAAApawAAKaoAACmsAAAprgAAKbAAACmyAAApswAAKbQAACm1AAAptgAAKbgAACm6AAApuwAAKbwAACm+AAApvwAAKeQAACoIAAAqLwAAKlMAACpVAAAqVwAAKlkAACpbAAAqXQAAKl8AACpgAAAqYgAAKm8AACp+AAAqgAAAKoIAACqEAAAqhgAAKogAACqKAAAqjAAAKpsAACqdAAAqnwAAKqEAACqjAAAqpgAAKqkAACqsAAAqrgAAKsAAACrUAAAq5gAAKvsAACsNAAArHAAAKzkAACt4AAAregAAK3wAACt+AAArgAAAK4EAACuCAAArgwAAK4QAACuGAAAriAAAK4kAACuKAAArjAAAK40AACvMAAArzgAAK9AAACvSAAAr1AAAK9UAACvWAAAr1wAAK9gAACvaAAAr3AAAK90AACveAAAr4AAAK+EAACvjAAAsIgAALCQAACwmAAAsKAAALCoAACwrAAAsLAAALC0AACwuAAAsMAAALDIAACwzAAAsNAAALDYAACw3AAAsdgAALHgAACx6AAAsfAAALH4AACx/AAAsgAAALIEAACyCAAAshAAALIYAACyHAAAsiAAALIoAACyLAAAszgAALPIAAC0WAAAtOQAALWAAAC2AAAAtpwAALc4AAC3uAAAuEgAALjYAAC44AAAuOgAALjwAAC4+AAAuQAAALkIAAC5FAAAuRwAALkkAAC5MAAAuTgAALlAAAC5TAAAuVQAALlYAAC5bAAAuaAAALmsAAC5tAAAucAAALnIAAC50AAAumQAALr0AAC7kAAAvCAAALwoAAC8MAAAvDgAALxAAAC8SAAAvFAAALxUAAC8XAAAvJAAALzcAAC85AAAvOwAALz0AAC8/AAAvQQAAL0MAAC9FAAAvRwAAL0kAAC9cAAAvXgAAL2AAAC9iAAAvZAAAL2YAAC9oAAAvagAAL2wAAC9uAAAvcAAAL68AAC+xAAAvswAAL7UAAC+3AAAvuAAAL7kAAC+6AAAvuwAAL70AAC+/AAAvwAAAL8EAAC/DAAAvxAAAL80AAC/OAAAv0AAAMA8AADARAAAwEwAAMBUAADAXAAAwGAAAMBkAADAaAAAwGwAAMB0AADAfAAAwIAAAMCEAADAjAAAwJAAAMGMAADBlAAAwZwAAMGkAADBrAAAwbAAAMG0AADBuAAAwbwAAMHEAADBzAAAwdAAAMHUAADB3AAAweAAAMIEAADCEAAAwhgAAMIgAADCRAAAwlAAAMJYAADCYAAAwoAAAMN8AADDhAAAw4wAAMOUAADDnAAAw6AAAMOkAADDqAAAw6wAAMO0AADDvAAAw8AAAMPEAADDzAAAw9AAAMTMAADE1AAAxNwAAMTkAADE7AAAxPAAAMT0AADE+AAAxPwAAMUEAADFDAAAxRAAAMUUAADFHAAAxSAAAMVEAADFSAAAxVAAAMZMAADGVAAAxlwAAMZkAADGbAAAxnAAAMZ0AADGeAAAxnwAAMaEAADGjAAAxpAAAMaUAADGnAAAxqAAAMecAADHpAAAx6wAAMe0AADHvAAAx8AAAMfEAADHyAAAx8wAAMfUAADH3AAAx+AAAMfkAADH7AAAx/AAAMgkAADIKAAAyCwAAMg0AADJMAAAyTgAAMlAAADJSAAAyVAAAMlUAADJWAAAyVwAAMlgAADJaAAAyXAAAMl0AADJeAAAyYAAAMmEAADKgAAAyogAAMqQAADKmAAAyqAAAMqkAADKqAAAyqwAAMqwAADKuAAAysAAAMrEAADKyAAAytAAAMrUAADLCAAAy9wAAMvkAADL7AAAy/QAAMv8AADMBAAAzAwAAMwUAADMHAAAzCQAAMwsAADMNAAAzDwAAMxEAADMTAAAzFQAAMxcAADMZAAAzGwAAMx0AADMfAAAzIQAAMyMAADMlAAAzJwAAMykAADNeAAAzYAAAM2IAADNkAAAzZgAAM2gAADNrAAAzbgAAM3EAADN0AAAzdwAAM3oAADN9AAAzgAAAM4MAADOGAAAziQAAM4wAADOPAAAzkgAAM5UAADOYAAAzmwAAM54AADOhAAAzpAAAM6YAADOwAAAzvgAAM8wAADPUAAAz4gAAM+cAADP2AAA0BAAANAkAADQdAAA0JAAANDoAADREAAA0UwAANFkAADRmAAA0bwAANHYAADSKAAA0nQAANK8AADS9AAA0yQAANRQAADU3AAA1VwAANXcAADV5AAA1ewAANX0AADV/AAA1gQAANYIAADWDAAA1hQAANYYAADWIAAA1iQAANYsAADWNAAA1jgAANY8AADWRAAA1kgAANZcAADWkAAA1qQAANasAADWtAAA1sgAANbQAADW2AAA1uAAANd0AADYBAAA2KAAANkwAADZOAAA2UAAANlIAADZUAAA2VgAANlgAADZZAAA2WwAANmgAADZ5AAA2ewAANn0AADZ/AAA2gQAANoMAADaFAAA2hwAANokAADaaAAA2nAAANp4AADagAAA2ogAANqQAADamAAA2qAAANqoAADasAAA26wAANu0AADbvAAA28QAANvMAADb0AAA29QAANvYAADb3AAA2+QAANvsAADb8AAA2/QAANv8AADcAAAA3PwAAN0EAADdDAAA3RQAAN0cAADdIAAA3SQAAN0oAADdLAAA3TQAAN08AADdQAAA3UQAAN1MAADdUAAA3kwAAN5UAADeXAAA3mQAAN5sAADecAAA3nQAAN54AADefAAA3oQAAN6MAADekAAA3pQAAN6cAADeoAAA3tQAAN7YAADe3AAA3uQAAN/gAADf6AAA3/AAAN/4AADgAAAA4AQAAOAIAADgDAAA4BAAAOAYAADgIAAA4CQAAOAoAADgMAAA4DQAAOEwAADhOAAA4UAAAOFIAADhUAAA4VQAAOFYAADhXAAA4WAAAOFoAADhcAAA4XQAAOF4AADhgAAA4YQAAOKAAADiiAAA4pAAAOKYAADioAAA4qQAAOKoAADirAAA4rAAAOK4AADiwAAA4sQAAOLIAADi0AAA4tQAAOPQAADj2AAA4+AAAOPoAADj8AAA4/QAAOP4AADj/AAA5AAAAOQIAADkEAAA5BQAAOQYAADkIAAA5CQAAOUgAADlKAAA5TAAAOU4AADlQAAA5UQAAOVIAADlTAAA5VAAAOVYAADlYAAA5WQAAOVoAADlcAAA5XQAAOYIAADmmAAA5zQAAOfEAADnzAAA59QAAOfcAADn5AAA5+wAAOf0AADn+AAA6AAAAOg0AADocAAA6HgAAOiAAADoiAAA6JAAAOiYAADooAAA6KgAAOjkAADo7AAA6PQAAOj8AADpBAAA6QwAAOkUAADpHAAA6SQAAOogAADqKAAA6jAAAOo4AADqQAAA6kQAAOpIAADqTAAA6lAAAOpYAADqYAAA6mQAAOpoAADqcAAA6nQAAOtwAADreAAA64AAAOuIAADrkAAA65QAAOuYAADrnAAA66AAAOuoAADrsAAA67QAAOu4AADrwAAA68QAAOzAAADsyAAA7NAAAOzYAADs4AAA7OQAAOzoAADs7AAA7PAAAOz4AADtAAAA7QQAAO0IAADtEAAA7RQAAO4QAADuGAAA7iAAAO4oAADuMAAA7jQAAO44AADuPAAA7kAAAO5IAADuUAAA7lQAAO5YAADuYAAA7mQAAO9gAADvaAAA73AAAO94AADvgAAA74QAAO+IAADvjAAA75AAAO+YAADvoAAA76QAAO+oAADvsAAA77QAAPCwAADwuAAA8MAAAPDIAADw0AAA8NQAAPDYAADw3AAA8OAAAPDoAADw8AAA8PQAAPD4AADxAAAA8QQAAPIAAADyCAAA8hAAAPIYAADyIAAA8iQAAPIoAADyLAAA8jAAAPI4AADyQAAA8kQAAPJIAADyUAAA8lQAAPJ4AADyxAAA8vgAAPNEAADzeAAA88QAAPQgAAD0aAAA9ZQAAPYgAAD2oAAA9yAAAPcoAAD3MAAA9zgAAPdAAAD3SAAA90wAAPdQAAD3WAAA91wAAPdkAAD3aAAA93AAAPd4AAD3fAAA94AAAPeIAAD3jAAA97AAAPfkAAD3+AAA+AAAAPgIAAD4HAAA+CQAAPgsAAD4NAAA+IgAAPkcAAD5rAAA+kgAAPrYAAD64AAA+ugAAPrwAAD6+AAA+wAAAPsIAAD7DAAA+xQAAPtIAAD7jAAA+5QAAPucAAD7pAAA+6wAAPu0AAD7vAAA+8QAAPvMAAD8EAAA/BgAAPwgAAD8KAAA/DAAAPw4AAD8QAAA/EgAAPxQAAD8WAAA/VQAAP1cAAD9ZAAA/WwAAP10AAD9eAAA/XwAAP2AAAD9hAAA/YwAAP2UAAD9mAAA/ZwAAP2kAAD9qAAA/qQAAP6sAAD+tAAA/rwAAP7EAAD+yAAA/swAAP7QAAD+1AAA/twAAP7kAAD+6AAA/uwAAP70AAD++AAA//QAAP/8AAEABAABAAwAAQAUAAEAGAABABwAAQAgAAEAJAABACwAAQA0AAEAOAABADwAAQBEAAEASAABAHwAAQCAAAEAhAABAIwAAQGIAAEBkAABAZgAAQGgAAEBqAABAawAAQGwAAEBtAABAbgAAQHAAAEByAABAcwAAQHQAAEB2AABAdwAAQLYAAEC4AABAugAAQLwAAEC+AABAvwAAQMAAAEDBAABAwgAAQMQAAEDGAABAxwAAQMgAAEDKAABAywAAQQoAAEEMAABBDgAAQRAAAEESAABBEwAAQRQAAEEVAABBFgAAQRgAAEEaAABBGwAAQRwAAEEeAABBHwAAQV4AAEFgAABBYgAAQWQAAEFmAABBZwAAQWgAAEFpAABBagAAQWwAAEFuAABBbwAAQXAAAEFyAABBcwAAQbIAAEG0AABBtgAAQbgAAEG6AABBuwAAQbwAAEG9AABBvgAAQcAAAEHCAABBwwAAQcQAAEHGAABBxwAAQewAAEIQAABCNwAAQlsAAEJdAABCXwAAQmEAAEJjAABCZQAAQmcAAEJoAABCagAAQncAAEKGAABCiAAAQooAAEKMAABCjgAAQpAAAEKSAABClAAAQqMAAEKlAABCpwAAQqkAAEKrAABCrQAAQq8AAEKxAABCswAAQtMAAEL+AABDGAAAQzEAAENLAABDawAAQ44AAEPNAABDzwAAQ9EAAEPTAABD1QAAQ9YAAEPXAABD2AAAQ9kAAEPbAABD3QAAQ94AAEPfAABD4QAAQ+IAAEPkAABEIwAARCUAAEQnAABEKQAARCsAAEQsAABELQAARC4AAEQvAABEMQAARDMAAEQ0AABENQAARDcAAEQ4AABEdwAARHkAAER7AABEfQAARH8AAESAAABEgQAARIIAAESDAABEhQAARIcAAESIAABEiQAARIsAAESMAABEywAARM0AAETPAABE0QAARNMAAETUAABE1QAARNYAAETXAABE2QAARNsAAETcAABE3QAARN8AAETgAABE4gAARSEAAEUjAABFJQAARScAAEUpAABFKgAARSsAAEUsAABFLQAARS8AAEUxAABFMgAARTMAAEU1AABFNgAARXUAAEV3AABFeQAARXsAAEV9AABFfgAARX8AAEWAAABFgQAARYMAAEWFAABFhgAARYcAAEWJAABFigAARckAAEXLAABFzQAARc8AAEXRAABF0gAARdMAAEXUAABF1QAARdcAAEXZAABF2gAARdsAAEXdAABF3gAARecAAEX1AABGAgAARhAAAEYdAABGMAAARkcAAEZZAABGpAAARscAAEbnAABHBwAARwkAAEcLAABHDQAARw8AAEcRAABHEgAARxMAAEcVAABHFgAARxgAAEcZAABHGwAARx0AAEceAABHHwAARyEAAEciAABHJwAARzQAAEc5AABHOwAARz0AAEdCAABHRAAAR0YAAEdIAABHbQAAR5EAAEe4AABH3AAAR94AAEfgAABH4gAAR+QAAEfmAABH6AAAR+kAAEfrAABH+AAASAkAAEgLAABIDQAASA8AAEgRAABIEwAASBUAAEgXAABIGQAASCoAAEgsAABILgAASDAAAEgyAABINAAASDYAAEg4AABIOgAASDwAAEh7AABIfQAASH8AAEiBAABIgwAASIQAAEiFAABIhgAASIcAAEiJAABIiwAASIwAAEiNAABIjwAASJAAAEjPAABI0QAASNMAAEjVAABI1wAASNgAAEjZAABI2gAASNsAAEjdAABI3wAASOAAAEjhAABI4wAASOQAAEkjAABJJQAASScAAEkpAABJKwAASSwAAEktAABJLgAASS8AAEkxAABJMwAASTQAAEk1AABJNwAASTgAAElFAABJRgAASUcAAElJAABJiAAASYoAAEmMAABJjgAASZAAAEmRAABJkgAASZMAAEmUAABJlgAASZgAAEmZAABJmgAASZwAAEmdAABJ3AAASd4AAEngAABJ4gAASeQAAEnlAABJ5gAASecAAEnoAABJ6gAASewAAEntAABJ7gAASfAAAEnxAABKMAAASjIAAEo0AABKNgAASjgAAEo5AABKOgAASjsAAEo8AABKPgAASkAAAEpBAABKQgAASkQAAEpFAABKhAAASoYAAEqIAABKigAASowAAEqNAABKjgAASo8AAEqQAABKkgAASpQAAEqVAABKlgAASpgAAEqZAABK2AAAStoAAErcAABK3gAASuAAAErhAABK4gAASuMAAErkAABK5gAASugAAErpAABK6gAASuwAAErtAABLEgAASzYAAEtdAABLgQAAS4MAAEuFAABLhwAAS4kAAEuLAABLjQAAS44AAEuQAABLnQAAS6wAAEuuAABLsAAAS7IAAEu0AABLtgAAS7gAAEu6AABLyQAAS8sAAEvNAABLzwAAS9EAAEvTAABL1QAAS9cAAEvZAABMGAAATBoAAEwcAABMHgAATCAAAEwhAABMIgAATCMAAEwkAABMJgAATCgAAEwpAABMKgAATCwAAEwtAABMbAAATG4AAExwAABMcgAATHQAAEx1AABMdgAATHcAAEx4AABMegAATHwAAEx9AABMfgAATIAAAEyBAABMwAAATMIAAEzEAABMxgAATMgAAEzJAABMygAATMsAAEzMAABMzgAATNAAAEzRAABM0gAATNQAAEzVAABNFAAATRYAAE0YAABNGgAATRwAAE0dAABNHgAATR8AAE0gAABNIgAATSQAAE0lAABNJgAATSgAAE0pAABNLAAATWsAAE1tAABNbwAATXEAAE1zAABNdAAATXUAAE12AABNdwAATXkAAE17AABNfAAATX0AAE1/AABNgAAATb8AAE3BAABNwwAATcUAAE3HAABNyAAATckAAE3KAABNywAATc0AAE3PAABN0AAATdEAAE3TAABN1AAAThMAAE4VAABOFwAAThkAAE4bAABOHAAATh0AAE4eAABOHwAATiEAAE4jAABOJAAATiUAAE4nAABOKAAATnMAAE6WAABOtgAATtYAAE7YAABO2gAATtwAAE7eAABO4AAATuEAAE7iAABO5AAATuUAAE7nAABO6AAATuoAAE7sAABO7QAATu4AAE7wAABO8QAATvYAAE8DAABPCAAATwoAAE8MAABPEQAATxMAAE8VAABPFwAATzwAAE9gAABPhwAAT6sAAE+tAABPrwAAT7EAAE+zAABPtQAAT7cAAE+4AABPugAAT8cAAE/YAABP2gAAT9wAAE/eAABP4AAAT+IAAE/kAABP5gAAT+gAAE/5AABP+wAAT/0AAE//AABQAQAAUAMAAFAFAABQBwAAUAkAAFALAABQSgAAUEwAAFBOAABQUAAAUFIAAFBTAABQVAAAUFUAAFBWAABQWAAAUFoAAFBbAABQXAAAUF4AAFBfAABQngAAUKAAAFCiAABQpAAAUKYAAFCnAABQqAAAUKkAAFCqAABQrAAAUK4AAFCvAABQsAAAULIAAFCzAABQ8gAAUPQAAFD2AABQ+AAAUPoAAFD7AABQ/AAAUP0AAFD+AABRAAAAUQIAAFEDAABRBAAAUQYAAFEHAABRFAAAURUAAFEWAABRGAAAUVcAAFFZAABRWwAAUV0AAFFfAABRYAAAUWEAAFFiAABRYwAAUWUAAFFnAABRaAAAUWkAAFFrAABRbAAAUasAAFGtAABRrwAAUbEAAFGzAABRtAAAUbUAAFG2AABRtwAAUbkAAFG7AABRvAAAUb0AAFG/AABRwAAAUf8AAFIBAABSAwAAUgUAAFIHAABSCAAAUgkAAFIKAABSCwAAUg0AAFIPAABSEAAAUhEAAFITAABSFAAAUlMAAFJVAABSVwAAUlkAAFJbAABSXAAAUl0AAFJeAABSXwAAUmEAAFJjAABSZAAAUmUAAFJnAABSaAAAUqcAAFKpAABSqwAAUq0AAFKvAABSsAAAUrEAAFKyAABSswAAUrUAAFK3AABSuAAAUrkAAFK7AABSvAAAUuEAAFMFAABTLAAAU1AAAFNSAABTVAAAU1YAAFNYAABTWgAAU1wAAFNdAABTXwAAU2wAAFN7AABTfQAAU38AAFOBAABTgwAAU4UAAFOHAABTiQAAU5gAAFOaAABTnAAAU54AAFOgAABTogAAU6QAAFOmAABTqAAAU+cAAFPpAABT6wAAU+0AAFPvAABT8AAAU/EAAFPyAABT8wAAU/UAAFP3AABT+AAAU/kAAFP7AABT/AAAVDsAAFQ9AABUPwAAVEEAAFRDAABURAAAVEUAAFRGAABURwAAVEkAAFRLAABUTAAAVE0AAFRPAABUUAAAVI8AAFSRAABUkwAAVJUAAFSXAABUmAAAVJkAAFSaAABUmwAAVJ0AAFSfAABUoAAAVKEAAFSjAABUpAAAVOMAAFTlAABU5wAAVOkAAFTrAABU7AAAVO0AAFTuAABU7wAAVPEAAFTzAABU9AAAVPUAAFT3AABU+AAAVPsAAFU6AABVPAAAVT4AAFVAAABVQgAAVUMAAFVEAABVRQAAVUYAAFVIAABVSgAAVUsAAFVMAABVTgAAVU8AAFWOAABVkAAAVZIAAFWUAABVlgAAVZcAAFWYAABVmQAAVZoAAFWcAABVngAAVZ8AAFWgAABVogAAVaMAAFXiAABV5AAAVeYAAFXoAABV6gAAVesAAFXsAABV7QAAVe4AAFXwAABV8gAAVfMAAFX0AABV9gAAVfcAAFZCAABWZQAAVoUAAFalAABWpwAAVqkAAFarAABWrQAAVq8AAFawAABWsQAAVrQAAFa1AABWtwAAVrgAAFa6AABWvAAAVr0AAFa+AABWwQAAVsIAAFbHAABW1AAAVtkAAFbbAABW3QAAVuIAAFblAABW6AAAVuoAAFcPAABXMwAAV1oAAFd+AABXgAAAV4IAAFeEAABXhgAAV4gAAFeKAABXiwAAV44AAFebAABXrAAAV64AAFewAABXsgAAV7QAAFe2AABXuAAAV7oAAFe8AABXzQAAV9AAAFfTAABX1gAAV9kAAFfcAABX3wAAV+IAAFflAABX5wAAWCYAAFgoAABYKgAAWCwAAFgvAABYMAAAWDEAAFgyAABYMwAAWDUAAFg3AABYOAAAWDkAAFg7AABYPAAAWHsAAFh9AABYfwAAWIEAAFiEAABYhQAAWIYAAFiHAABYiAAAWIoAAFiMAABYjQAAWI4AAFiQAABYkQAAWNAAAFjSAABY1QAAWNcAAFjaAABY2wAAWNwAAFjdAABY3gAAWOAAAFjiAABY4wAAWOQAAFjmAABY5wAAWPQAAFj1AABY9gAAWPgAAFk3AABZOQAAWTsAAFk9AABZQAAAWUEAAFlCAABZQwAAWUQAAFlGAABZSAAAWUkAAFlKAABZTAAAWU0AAFmMAABZjgAAWZAAAFmSAABZlQAAWZYAAFmXAABZmAAAWZkAAFmbAABZnQAAWZ4AAFmfAABZoQAAWaIAAFnhAABZ4wAAWeUAAFnnAABZ6gAAWesAAFnsAABZ7QAAWe4AAFnwAABZ8gAAWfMAAFn0AABZ9gAAWfcAAFo2AABaOAAAWjoAAFo8AABaPwAAWkAAAFpBAABaQgAAWkMAAFpFAABaRwAAWkgAAFpJAABaSwAAWkwAAFqLAABajQAAWo8AAFqRAABalAAAWpUAAFqWAABalwAAWpgAAFqaAABanAAAWp0AAFqeAABaoAAAWqEAAFrGAABa6gAAWxEAAFs1AABbNwAAWzkAAFs7AABbPQAAWz8AAFtBAABbQgAAW0UAAFtSAABbYQAAW2MAAFtlAABbZwAAW2kAAFtrAABbbQAAW28AAFt+AABbgQAAW4QAAFuHAABbigAAW40AAFuQAABbkwAAW5UAAFvUAABb1gAAW9gAAFvaAABb3QAAW94AAFvfAABb4AAAW+EAAFvjAABb5QAAW+YAAFvnAABb6QAAW+oAAFwpAABcKwAAXC0AAFwvAABcMgAAXDMAAFw0AABcNQAAXDYAAFw4AABcOgAAXDsAAFw8AABcPgAAXD8AAFx+AABcgAAAXIIAAFyEAABchwAAXIgAAFyJAABcigAAXIsAAFyNAABcjwAAXJAAAFyRAABckwAAXJQAAFzTAABc1QAAXNgAAFzaAABc3QAAXN4AAFzfAABc4AAAXOEAAFzjAABc5QAAXOYAAFznAABc6QAAXOoAAFztAABdLAAAXS4AAF0wAABdMgAAXTUAAF02AABdNwAAXTgAAF05AABdOwAAXT0AAF0+AABdPwAAXUEAAF1CAABdgQAAXYMAAF2GAABdiAAAXYsAAF2MAABdjQAAXY4AAF2PAABdkQAAXZMAAF2UAABdlQAAXZcAAF2YAABdvwAAXf4AAF4AAABeAgAAXgQAAF4HAABeCAAAXgkAAF4KAABeCwAAXg0AAF4PAABeEAAAXhEAAF4TAABeFAAAXl8AAF6CAABeogAAXsIAAF7EAABexgAAXsgAAF7KAABezAAAXs0AAF7OAABe0QAAXtIAAF7UAABe1QAAXtcAAF7ZAABe2gAAXtsAAF7eAABe3wAAXugAAF71AABe+gAAXvwAAF7+AABfAwAAXwYAAF8JAABfCwAAXzAAAF9UAABfewAAX58AAF+iAABfpAAAX6YAAF+oAABfqgAAX6wAAF+tAABfsAAAX70AAF/OAABf0AAAX9IAAF/UAABf1gAAX9gAAF/aAABf3AAAX94AAF/vAABf8gAAX/UAAF/4AABf+wAAX/4AAGABAABgBAAAYAcAAGAJAABgSAAAYEoAAGBMAABgTgAAYFEAAGBSAABgUwAAYFQAAGBVAABgVwAAYFkAAGBaAABgWwAAYF0AAGBeAABgnQAAYJ8AAGChAABgowAAYKYAAGCnAABgqAAAYKkAAGCqAABgrAAAYK4AAGCvAABgsAAAYLIAAGCzAABg8gAAYPQAAGD3AABg+QAAYPwAAGD9AABg/gAAYP8AAGEAAABhAgAAYQQAAGEFAABhBgAAYQgAAGEJAABhFgAAYRcAAGEYAABhGgAAYVkAAGFbAABhXQAAYV8AAGFiAABhYwAAYWQAAGFlAABhZgAAYWgAAGFqAABhawAAYWwAAGFuAABhbwAAYa4AAGGwAABhsgAAYbQAAGG3AABhuAAAYbkAAGG6AABhuwAAYb0AAGG/AABhwAAAYcEAAGHDAABhxAAAYgMAAGIFAABiBwAAYgkAAGIMAABiDQAAYg4AAGIPAABiEAAAYhIAAGIUAABiFQAAYhYAAGIYAABiGQAAYlgAAGJaAABiXAAAYl4AAGJhAABiYgAAYmMAAGJkAABiZQAAYmcAAGJpAABiagAAYmsAAGJtAABibgAAYq0AAGKvAABisQAAYrMAAGK2AABitwAAYrgAAGK5AABiugAAYrwAAGK+AABivwAAYsAAAGLCAABiwwAAYugAAGMMAABjMwAAY1cAAGNaAABjXAAAY14AAGNgAABjYgAAY2QAAGNlAABjaAAAY3UAAGOEAABjhgAAY4gAAGOKAABjjAAAY44AAGOQAABjkgAAY6EAAGOkAABjpwAAY6oAAGOtAABjsAAAY7MAAGO2AABjuAAAY/cAAGP5AABj/AAAY/4AAGQBAABkAgAAZAMAAGQEAABkBQAAZAcAAGQJAABkCgAAZAsAAGQNAABkDgAAZBEAAGRQAABkUgAAZFQAAGRWAABkWQAAZFoAAGRbAABkXAAAZF0AAGRfAABkYQAAZGIAAGRjAABkZQAAZGYAAGSlAABkpwAAZKkAAGSrAABkrgAAZK8AAGSwAABksQAAZLIAAGS0AABktgAAZLcAAGS4AABkugAAZLsAAGT6AABk/AAAZP8AAGUBAABlBAAAZQUAAGUGAABlBwAAZQgAAGUKAABlDAAAZQ0AAGUOAABlEAAAZREAAGUUAABlUwAAZVUAAGVXAABlWQAAZVwAAGVdAABlXgAAZV8AAGVgAABlYgAAZWQAAGVlAABlZgAAZWgAAGVpAABlqAAAZaoAAGWsAABlrgAAZbEAAGWyAABlswAAZbQAAGW1AABltwAAZbkAAGW6AABluwAAZb0AAGW+AABl/QAAZf8AAGYBAABmAwAAZgYAAGYHAABmCAAAZgkAAGYKAABmDAAAZg4AAGYPAABmEAAAZhIAAGYTAABmXgAAZoEAAGahAABmwQAAZsMAAGbFAABmxwAAZskAAGbLAABmzAAAZs0AAGbQAABm0QAAZtMAAGbUAABm1gAAZtgAAGbZAABm2gAAZt0AAGbeAABm4wAAZvAAAGb1AABm9wAAZvkAAGb+AABnAQAAZwQAAGcGAABnKwAAZ08AAGd2AABnmgAAZ50AAGefAABnoQAAZ6MAAGelAABnpwAAZ6gAAGerAABnuAAAZ8kAAGfLAABnzQAAZ88AAGfRAABn0wAAZ9UAAGfXAABn2QAAZ+oAAGftAABn8AAAZ/MAAGf2AABn+QAAZ/wAAGf/AABoAgAAaAQAAGhDAABoRQAAaEcAAGhJAABoTAAAaE0AAGhOAABoTwAAaFAAAGhSAABoVAAAaFUAAGhWAABoWAAAaFkAAGiYAABomgAAaJwAAGieAABooQAAaKIAAGijAABopAAAaKUAAGinAABoqQAAaKoAAGirAABorQAAaK4AAGjtAABo7wAAaPIAAGj0AABo9wAAaPgAAGj5AABo+gAAaPsAAGj9AABo/wAAaQAAAGkBAABpAwAAaQQAAGkRAABpEgAAaRMAAGkVAABpVAAAaVYAAGlYAABpWgAAaV0AAGleAABpXwAAaWAAAGlhAABpYwAAaWUAAGlmAABpZwAAaWkAAGlqAABpqQAAaasAAGmtAABprwAAabIAAGmzAABptAAAabUAAGm2AABpuAAAaboAAGm7AABpvAAAab4AAGm/AABp/gAAagAAAGoCAABqBAAAagcAAGoIAABqCQAAagoAAGoLAABqDQAAag8AAGoQAABqEQAAahMAAGoUAABqUwAAalUAAGpXAABqWQAAalwAAGpdAABqXgAAal8AAGpgAABqYgAAamQAAGplAABqZgAAamgAAGppAABqqAAAaqoAAGqsAABqrgAAarEAAGqyAABqswAAarQAAGq1AABqtwAAarkAAGq6AABquwAAar0AAGq+AABq4wAAawcAAGsuAABrUgAAa1UAAGtXAABrWQAAa1sAAGtdAABrXwAAa2AAAGtjAABrcAAAa38AAGuBAABrgwAAa4UAAGuHAABriQAAa4sAAGuNAABrnAAAa58AAGuiAABrpQAAa6gAAGurAABrrgAAa7EAAGuzAABr8gAAa/QAAGv2AABr+AAAa/sAAGv8AABr/QAAa/4AAGv/AABsAQAAbAMAAGwEAABsBQAAbAcAAGwIAABsRwAAbEkAAGxLAABsTQAAbFAAAGxRAABsUgAAbFMAAGxUAABsVgAAbFgAAGxZAABsWgAAbFwAAGxdAABsnAAAbJ4AAGygAABsogAAbKUAAGymAABspwAAbKgAAGypAABsqwAAbK0AAGyuAABsrwAAbLEAAGyyAABs8QAAbPMAAGz1AABs9wAAbPoAAGz7AABs/AAAbP0AAGz+AABtAAAAbQIAAG0DAABtBAAAbQYAAG0HAABtRgAAbUgAAG1KAABtTAAAbU8AAG1QAABtUQAAbVIAAG1TAABtVQAAbVcAAG1YAABtWQAAbVsAAG1cAABtmwAAbZ0AAG2fAABtoQAAbaQAAG2lAABtpgAAbacAAG2oAABtqgAAbawAAG2tAABtrgAAbbAAAG2xAABt8AAAbfIAAG30AABt9gAAbfkAAG36AABt+wAAbfwAAG39AABt/wAAbgEAAG4CAABuAwAAbgUAAG4GAABuUQAAbnQAAG6UAAButAAAbrYAAG64AABuugAAbrwAAG6+AABuvwAAbsAAAG7DAABuxAAAbsYAAG7HAABuyQAAbssAAG7MAABuzQAAbtAAAG7RAABu2gAAbucAAG7sAABu7gAAbvAAAG71AABu+AAAbvsAAG79AABvIgAAb0YAAG9tAABvkQAAb5QAAG+WAABvmAAAb5oAAG+cAABvngAAb58AAG+iAABvrwAAb8AAAG/CAABvxAAAb8YAAG/IAABvygAAb8wAAG/OAABv0AAAb+EAAG/kAABv5wAAb+oAAG/tAABv8AAAb/MAAG/2AABv+QAAb/sAAHA6AABwPAAAcD4AAHBAAABwQwAAcEQAAHBFAABwRgAAcEcAAHBJAABwSwAAcEwAAHBNAABwTwAAcFAAAHCPAABwkQAAcJMAAHCVAABwmAAAcJkAAHCaAABwmwAAcJwAAHCeAABwoAAAcKEAAHCiAABwpAAAcKUAAHDkAABw5gAAcOkAAHDrAABw7gAAcO8AAHDwAABw8QAAcPIAAHD0AABw9gAAcPcAAHD4AABw+gAAcPsAAHEIAABxCQAAcQoAAHEMAABxSwAAcU0AAHFPAABxUQAAcVQAAHFVAABxVgAAcVcAAHFYAABxWgAAcVwAAHFdAABxXgAAcWAAAHFhAABxoAAAcaIAAHGkAABxpgAAcakAAHGqAABxqwAAcawAAHGtAABxrwAAcbEAAHGyAABxswAAcbUAAHG2AABx9QAAcfcAAHH5AABx+wAAcf4AAHH/AAByAAAAcgEAAHICAAByBAAAcgYAAHIHAAByCAAAcgoAAHILAABySgAAckwAAHJOAAByUAAAclMAAHJUAAByVQAAclYAAHJXAAByWQAAclsAAHJcAAByXQA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AiNUAAIjiAACI4wAAiOQAAIjmAACJJQAAiScAAIkpAACJKwAAiS4AAIkvAACJMAAAiTEAAIkyAACJNAAAiTYAAIk3AACJOAAAiToAAIk7AACJegAAiXwAAIl+AACJgAAAiYMAAImEAACJhQAAiYYAAImHAACJiQAAiYsAAImMAACJjQAAiY8AAImQAACJzwAAidEAAInTAACJ1QAAidgAAInZAACJ2gAAidsAAIncAACJ3gAAieAAAInhAACJ4gAAieQAAInlAACKJAAAiiYAAIooAACKKgAAii0AAIouAACKLwAAijAAAIoxAACKMwAAijUAAIo2AACKNwAAijkAAIo6AACKeQAAinsAAIp9AACKfwAAioIAAIqDAACKhAAAioUAAIqGAACKiAAAiooAAIqLAACKjAAAio4AAIqPAACKtAAAitgAAIr/AACLIwAAiyYAAIsoAACLKgAAiywAAIsuAACLMAAAizEAAIs0AACLQQAAi1AAAItSAACLVAAAi1YAAItYAACLWgAAi1wAAIteAACLbQAAi3AAAItzAACLdgAAi3kAAIt8AACLfwAAi4IAAIuEAACLwwAAi8UAAIvHAACLyQAAi8wAAIvNAACLzgAAi88AAIvQAACL0gAAi9QAAIvVAACL1gAAi9gAAIvZAACMGAAAjBoAAIwcAACMHgAAjCEAAIwiAACMIwAAjCQAAIwlAACMJwAAjCkAAIwqAACMKwAAjC0AAIwuAACMbQAAjG8AAIxxAACMcwAAjHYAAIx3AACMeAAAjHkAAIx6AACMfAAAjH4AAIx/AACMgAAAjIIAAIyDAACMwgAAjMQAAIzGAACMyAAAjMsAAIzMAACMzQAAjM4AAIzPAACM0QAAjNMAAIzUAACM1QAAjNcAAIzYAACNFwAAjRkAAI0bAACNHQAAjSAAAI0hAACNIgAAjSMAAI0kAACNJgAAjSgAAI0pAACNKgAAjSwAAI0tAACNbAAAjW4AAI1wAACNcgAAjXUAAI12AACNdwAAjXgAAI15AACNewAAjX0AAI1+AACNfwAAjYEAAI2CAACNwQAAjcMAAI3FAACNxwAAjcoAAI3LAACNzAAAjc0AAI3OAACN0AAAjdIAAI3TAACN1AAAjdYAAI3XAACOIgAAjkUAAI5lAACOhQAAjocAAI6JAACOiwAAjo0AAI6PAACOkAAAjpEAAI6UAACOlQAAjpcAAI6YAACOmgAAjpwAAI6dAACOngAAjqEAAI6iAACOpwAAjrQAAI65AACOuwAAjr0AAI7CAACOxQAAjsgAAI7KAACO7wAAjxMAAI86AACPXgAAj2EAAI9jAACPZQAAj2cAAI9pAACPawAAj2wAAI9vAACPfAAAj40AAI+PAACPkQAAj5MAAI+VAACPlwAAj5kAAI+bAACPnQAAj64AAI+xAACPtAAAj7cAAI+6AACPvQAAj8AAAI/DAACPxgAAj8gAAJAHAACQCQAAkAsAAJANAACQEAAAkBEAAJASAACQEwAAkBQAAJAWAACQGAAAkBkAAJAaAACQHAAAkB0AAJBcAACQXgAAkGAAAJBiAACQZQAAkGYAAJBnAACQaAAAkGkAAJBrAACQbQAAkG4AAJBvAACQcQAAkHIAAJCxAACQswAAkLYAAJC4AACQuwAAkLwAAJC9AACQvgAAkL8AAJDBAACQwwAAkMQAAJDFAACQxwAAkMgAAJDVAACQ1gAAkNcAAJDZAACRGAAAkRoAAJEcAACRHgAAkSEAAJEiAACRIwAAkSQAAJElAACRJwAAkSkAAJEqAACRKwAAkS0AAJEuAACRbQAAkW8AAJFxAACRcwAAkXYAAJF3AACReAAAkXkAAJF6AACRfAAAkX4AAJF/AACRgAAAkYIAAJGDAACRwgAAkcQAAJHGAACRyAAAkcsAAJHMAACRzQAAkc4AAJHPAACR0QAAkdMAAJHUAACR1QAAkdcAAJHYAACSFwAAkhkAAJIbAACSHQAAkiAAAJIhAACSIgAAkiMAAJIkAACSJgAAkigAAJIpAACSKgAAkiwAAJItAACSbAAAkm4AAJJwAACScgAAknUAAJJ2AACSdwAAkngAAJJ5AACSewAAkn0AAJJ+AACSfwAAkoEAAJKCAACSpwAAkssAAJLyAACTFgAAkxkAAJMbAACTHQAAkx8AAJMhAACTIwAAkyQAAJMnAACTNAAAk0MAAJNFAACTRwAAk0kAAJNLAACTTQAAk08AAJNRAACTYAAAk2MAAJNmAACTaQAAk2wAAJNvAACTcgAAk3UAAJN3AACTtgAAk7gAAJO6AACTvAAAk78AAJPAAACTwQAAk8IAAJPDAACTxQAAk8cAAJPIAACTyQAAk8sAAJPMAACUCwAAlA0AAJQPAACUEQAAlBQAAJQVAACUFgAAlBcAAJQYAACUGgAAlBwAAJQdAACUHgAAlCAAAJQhAACUYAAAlGIAAJRkAACUZgAAlGkAAJRqAACUawAAlGwAAJRtAACUbwAAlHEAAJRyAACUcwAAlHUAAJR2AACUtQAAlLcAAJS6AACUvAAAlL8AAJTAAACUwQAAlMIAAJTDAACUxQAAlMcAAJTIAACUyQAAlMsAAJTMAACVDwAAlTMAAJVXAACVegAAlaEAAJXBAACV6AAAlg8AAJYvAACWUwAAlncAAJZ5AACWfAAAln4AAJaAAACWggAAloUAAJaIAACWigAAlowAAJaPAACWkQAAlpMAAJaWAACWmQAAlpoAAJafAACWrAAAlq8AAJaxAACWtAAAlrcAAJa5AACW3gAAlwIAAJcpAACXTQAAl1AAAJdSAACXVAAAl1YAAJdYAACXWgAAl1sAAJdeAACXawAAl34AAJeAAACXggAAl4QAAJeGAACXiAAAl4oAAJeMAACXjgAAl5AAAJejAACXpgAAl6kAAJesAACXrwAAl7IAAJe1AACXuAAAl7sAAJe+AACXwAAAl/8AAJgBAACYBAAAmAYAAJgJAACYCgAAmAsAAJgMAACYDQAAmA8AAJgRAACYEgAAmBMAAJgVAACYFgAAmB8AAJggAACYIgAAmGEAAJhjAACYZQAAmGcAAJhqAACYawAAmGwAAJhtAACYbgAAmHAAAJhyAACYcwAAmHQAAJh2AACYdwAAmLYAAJi4AACYuwAAmL0AAJjAAACYwQAAmMIAAJjDAACYxAAAmMYAAJjIAACYyQAAmMoAAJjMAACYzQAAmNYAAJjXAACY2QAAmRgAAJkaAACZHAAAmR4AAJkhAACZIgAAmSMAAJkkAACZJQAAmScAAJkpAACZKgAAmSsAAJktAACZLgAAmW0AAJlvAACZcgAAmXQAAJl3AACZeAAAmXkAAJl6AACZewAAmX0AAJl/AACZgAAAmYEAAJmDAACZhAAAmY0AAJmOAACZkAAAmc8AAJnRAACZ0wAAmdUAAJnYAACZ2QAAmdoAAJnbAACZ3AAAmd4AAJngAACZ4QAAmeIAAJnkAACZ5QAAmiQAAJomAACaKQAAmisAAJouAACaLwAAmjAAAJoxAACaMgAAmjQAAJo2AACaNwAAmjgAAJo6AACaOwAAmkgAAJpJAACaSgAAmkwAAJqLAACajQAAmo8AAJqRAACalAAAmpUAAJqWAACalwAAmpgAAJqaAACanAAAmp0AAJqeAACaoAAAmqEAAJrgAACa4gAAmuUAAJrnAACa6gAAmusAAJrsAACa7QAAmu4AAJrwAACa8gAAmvMAAJr0AACa9gAAmvcAAJsEAACbEQAAmyIAAJslAACbKAAAmysAAJstAACbMAAAmzIAAJs1AACbOAAAm0kAAJtMAACbTwAAm1IAAJtVAACbWAAAm1sAAJteAACbYQAAm2MAAJtrAACbcwAAm3wAAJuQAACblgAAm6AAAJvrAACcDgAAnC4AAJxOAACcUAAAnFIAAJxUAACcVgAAnFkAAJxaAACcWwAAnF4AAJxfAACcYQAAnGIAAJxkAACcZwAAnGgAAJxpAACcbAAAnG0AAJxyAACcfwAAnIQAAJyGAACciAAAnI0AAJyQAACckwAAnJUAAJy6AACc3gAAnQUAAJ0pAACdLAAAnS4AAJ0wAACdMgAAnTQAAJ02AACdNwAAnToAAJ1HAACdWAAAnVoAAJ1cAACdXgAAnWAAAJ1iAACdZAAAnWYAAJ1oAACdeQAAnXwAAJ1/AACdggAAnYUAAJ2IAACdiwAAnY4AAJ2RAACdkwAAndIAAJ3UAACd1gAAndgAAJ3bAACd3AAAnd0AAJ3eAACd3wAAneEAAJ3jAACd5AAAneUAAJ3nAACd6AAAnicAAJ4pAACeKwAAni0AAJ4wAACeMQAAnjIAAJ4zAACeNAAAnjYAAJ44AACeOQAAnjoAAJ48AACePQAAnnwAAJ5+AACegQAAnoMAAJ6GAACehwAAnogAAJ6JAACeigAAnowAAJ6OAACejwAAnpAAAJ6SAACekwAAnqAAAJ6hAACeogAAnqQAAJ7jAACe5QAAnucAAJ7pAACe7AAAnu0AAJ7uAACe7wAAnvAAAJ7yAACe9AAAnvUAAJ72AACe+AAAnvkAAJ84AACfOgAAnzwAAJ8+AACfQQAAn0IAAJ9DAACfRAAAn0UAAJ9HAACfSQAAn0oAAJ9LAACfTQAAn04AAJ+NAACfjwAAn5EAAJ+TAACflgAAn5cAAJ+YAACfmQAAn5oAAJ+cAACfngAAn58AAJ+gAACfogAAn6MAAJ/iAACf5AAAn+YAAJ/oAACf6wAAn+wAAJ/tAACf7gAAn+8AAJ/xAACf8wAAn/QAAJ/1AACf9wAAn/gAAKA3AACgOQAAoDsAAKA9AACgQAAAoEEAAKBCAACgQwAAoEQAAKBGAACgSAAAoEkAAKBKAACgTAAAoE0AAKByAACglgAAoL0AAKDhAACg5AAAoOYAAKDoAACg6gAAoOwAAKDuAACg7wAAoPIAAKD/AAChDgAAoRAAAKESAAChFAAAoRYAAKEYAAChGgAAoRwAAKErAAChLgAAoTEAAKE0AAChNwAAoToAAKE9AAChQAAAoUIAAKGBAAChgwAAoYUAAKGHAAChigAAoYsAAKGMAAChjQAAoY4AAKGQAAChkgAAoZMAAKGUAAChlgAAoZcAAKHWAACh2AAAodoAAKHcAACh3wAAoeAAAKHhAACh4gAAoeMAAKHlAACh5wAAoegAAKHpAACh6wAAoewAAKIrAACiLQAAoi8AAKIxAACiNAAAojUAAKI2AACiNwAAojgAAKI6AACiPAAAoj0AAKI+AACiQAAAokEAAKKAAACiggAAooQAAKKGAACiiQAAoooAAKKLAACijAAAoo0AAKKPAACikQAAopIAAKKTAACilQAAopYAAKLVAACi1wAAotkAAKLbAACi3gAAot8AAKLgAACi4QAAouIAAKLkAACi5gAAoucAAKLoAACi6gAAousAAKMqAACjLAAAoy4AAKMwAACjMwAAozQAAKM1AACjNgAAozcAAKM5AACjOwAAozwAAKM9AACjPwAAo0AAAKN/AACjgQAAo4MAAKOFAACjiAAAo4kAAKOKAACjiwAAo4wAAKOOAACjkAAAo5EAAKOSAACjlAAAo5UAAKPgAACkAwAApCMAAKRDAACkRQAApEcAAKRJAACkSwAApE4AAKRPAACkUAAApFMAAKRUAACkVgAApFcAAKRZAACkXAAApF0AAKReAACkYQAApGIAAKRnAACkdAAApHkAAKR7AACkfQAApIIAAKSFAACkiAAApIoAAKSvAACk0wAApPoAAKUeAAClIQAApSMAAKUlAAClJwAApSkAAKUrAAClLAAApS8AAKU8AAClTQAApU8AAKVRAAClUwAApVUAAKVXAAClWQAApVsAAKVdAAClbgAApXEAAKV0AACldwAApXoAAKV9AAClgAAApYMAAKWGAACliAAApccAAKXJAAClywAApc0AAKXQAACl0QAApdIAAKXTAACl1AAApdYAAKXYAACl2QAApdoAAKXcAACl3QAAphwAAKYeAACmIAAApiIAAKYlAACmJgAApicAAKYoAACmKQAApisAAKYtAACmLgAApi8AAKYxAACmMgAApnEAAKZzAACmdgAApngAAKZ7AACmfAAApn0AAKZ+AACmfwAApoEAAKaDAACmhAAApoUAAKaHAACmiAAAppUAAKaWAACmlwAAppkAAKbYAACm2gAAptwAAKbeAACm4QAApuIAAKbjAACm5AAApuUAAKbnAACm6QAApuoAAKbrAACm7QAApu4AAKctAACnLwAApzEAAKczAACnNgAApzcAAKc4AACnOQAApzoAAKc8AACnPgAApz8AAKdAAACnQgAAp0MAAKeCAACnhAAAp4YAAKeIAACniwAAp4wAAKeNAACnjgAAp48AAKeRAACnkwAAp5QAAKeVAACnlwAAp5gAAKfXAACn2QAAp9sAAKfdAACn4AAAp+EAAKfiAACn4wAAp+QAAKfmAACn6AAAp+kAAKfqAACn7AAAp+0AAKgsAACoLgAAqDAAAKgyAACoNQAAqDYAAKg3AACoOAAAqDkAAKg7AACoPQAAqD4AAKg/AACoQQAAqEIAAKhnAACoiwAAqLIAAKjWAACo2QAAqNsAAKjdAACo3wAAqOEAAKjjAACo5AAAqOcAAKj0AACpAwAAqQUAAKkHAACpCQAAqQsAAKkNAACpDwAAqREAAKkgAACpIwAAqSYAAKkpAACpLAAAqS8AAKkyAACpNQAAqTcAAKl2AACpeAAAqXoAAKl8AACpfwAAqYAAAKmBAACpggAAqYMAAKmFAACphwAAqYgAAKmJAACpiwAAqYwAAKnLAACpzQAAqc8AAKnRAACp1AAAqdUAAKnWAACp1wAAqdgAAKnaAACp3AAAqd0AAKneAACp4AAAqeEAAKogAACqIgAAqiQAAKomAACqKQAAqioAAKorAACqLAAAqi0AAKovAACqMQAAqjIAAKozAACqNQAAqjYAAKp1AACqdwAAqnkAAKp7AACqfgAAqn8AAKqAAACqgQAAqoIAAKqEAACqhgAAqocAAKqIAACqigAAqosAAKrKAACqzAAAqs4AAKrQAACq0wAAqtQAAKrVAACq1gAAqtcAAKrZAACq2wAAqtwAAKrdAACq3wAAquAAAKsfAACrIQAAqyMAAKslAACrKAAAqykAAKsqAACrKwAAqywAAKsuAACrMAAAqzEAAKsyAACrNAAAqzUAAKt0AACrdgAAq3gAAKt6AACrfQAAq34AAKt/AACrgAAAq4EAAKuDAACrhQAAq4YAAKuHAACriQAAq4oAAKvVAACr+AAArBgAAKw4AACsOgAArDwAAKw+AACsQAAArEMAAKxEAACsRQAArEgAAKxJAACsSwAArEwAAKxOAACsUQAArFIAAKxTAACsVgAArFcAAKxcAACsaQAArG4AAKxwAACscgAArHcAAKx6AACsfQAArH8AAKykAACsyAAArO8AAK0TAACtFgAArRgAAK0aAACtHAAArR4AAK0gAACtIQAArSQAAK0xAACtQgAArUQAAK1GAACtSAAArUoAAK1MAACtTgAArVAAAK1SAACtYwAArWYAAK1pAACtbAAArW8AAK1yAACtdQAArXgAAK17AACtfQAArbwAAK2+AACtwAAArcIAAK3FAACtxgAArccAAK3IAACtyQAArcsAAK3NAACtzgAArc8AAK3RAACt0gAArhEAAK4TAACuFQAArhcAAK4aAACuGwAArhwAAK4dAACuHgAAriAAAK4iAACuIwAAriQAAK4mAACuJwAArmYAAK5oAACuawAArm0AAK5wAACucQAArnIAAK5zAACudAAArnYAAK54AACueQAArnoAAK58AACufQAArooAAK6LAACujAAAro4AAK7NAACuzwAArtEAAK7TAACu1gAArtcAAK7YAACu2QAArtoAAK7cAACu3gAArt8AAK7gAACu4gAAruMAAK8iAACvJAAAryYAAK8oAACvKwAArywAAK8tAACvLgAAry8AAK8xAACvMwAArzQAAK81AACvNwAArzgAAK93AACveQAAr3sAAK99AACvgAAAr4EAAK+CAACvgwAAr4QAAK+GAACviAAAr4kAAK+KAACvjAAAr40AAK/MAACvzgAAr9AAAK/SAACv1QAAr9YAAK/XAACv2AAAr9kAAK/bAACv3QAAr94AAK/fAACv4QAAr+IAALAhAACwIwAAsCUAALAnAACwKgAAsCsAALAsAACwLQAAsC4AALAwAACwMgAAsDMAALA0AACwNgAAsDcAALBcAACwgAAAsKcAALDLAACwzgAAsNAAALDSAACw1AAAsNYAALDYAACw2QAAsNwAALDpAACw+AAAsPoAALD8AACw/gAAsQAAALECAACxBAAAsQYAALEVAACxGAAAsRsAALEeAACxIQAAsSQAALEnAACxKgAAsSwAALFrAACxbQAAsW8AALFxAACxdAAAsXUAALF2AACxdwAAsXgAALF6AACxfAAAsX0AALF+AACxgAAAsYEAALHAAACxwgAAscQAALHGAACxyQAAscoAALHLAACxzAAAsc0AALHPAACx0QAAsdIAALHTAACx1QAAsdYAALIVAACyFwAAshkAALIbAACyHgAAsh8AALIgAACyIQAAsiIAALIkAACyJgAAsicAALIoAACyKgAAsisAALJqAACybAAAsm8AALJxAACydAAAsnUAALJ2AACydwAAsngAALJ6AACyfAAAsn0AALJ+AACygAAAsoEAALLAAACywgAAssQAALLGAACyyQAAssoAALLLAACyzAAAss0AALLPAACy0QAAstIAALLTAACy1QAAstYAALMVAACzFwAAsxkAALMbAACzHgAAsx8AALMgAACzIQAAsyIAALMkAACzJgAAsycAALMoAACzKgAAsysAALNqAACzbAAAs24AALNwAACzcwAAs3QAALN1AACzdgAAs3cAALN5AACzewAAs3wAALN9AACzfwAAs4AAALPLAACz7gAAtA4AALQuAAC0MAAAtDIAALQ0AAC0NgAAtDkAALQ6AAC0OwAAtD4AALQ/AAC0QQAAtEIAALREAAC0RgAAtEcAALRIAAC0SwAAtEwAALRRAAC0XgAAtGMAALRlAAC0ZwAAtGwAALRvAAC0cgAAtHQAALSZAAC0vQAAtOQAALUIAAC1CwAAtQ0AALUPAAC1EQAAtRMAALUVAAC1FgAAtRkAALUmAAC1NwAAtTkAALU7AAC1PQAAtT8AALVBAAC1QwAAtUUAALVHAAC1WAAAtVsAALVeAAC1YQAAtWQAALVnAAC1agAAtW0AALVwAAC1cgAAtbEAALWzAAC1tQAAtbcAALW6AAC1uwAAtbwAALW9AAC1vgAAtcAAALXCAAC1wwAAtcQAALXGAAC1xwAAtgYAALYIAAC2CgAAtgwAALYPAAC2EAAAthEAALYSAAC2EwAAthUAALYXAAC2GAAAthkAALYbAAC2HAAAtlsAALZdAAC2YAAAtmIAALZlAAC2ZgAAtmcAALZoAAC2aQAAtmsAALZtAAC2bgAAtm8AALZxAAC2cgAAtn8AALaAAAC2gQAAtoMAALbCAAC2xAAAtsYAALbIAAC2ywAAtswAALbNAAC2zgAAts8AALbRAAC20wAAttQAALbVAAC21wAAttgAALcXAAC3GQAAtxsAALcdAAC3IAAAtyEAALciAAC3IwAAtyQAALcmAAC3KAAAtykAALcqAAC3LAAAty0AALdsAAC3bgAAt3AAALdyAAC3dQAAt3YAALd3AAC3eAAAt3kAALd7AAC3fQAAt34AALd/AAC3gQAAt4IAALfBAAC3wwAAt8UAALfHAAC3ygAAt8sAALfMAAC3zQAAt84AALfQAAC30gAAt9MAALfUAAC31gAAt9cAALgWAAC4GAAAuBoAALgcAAC4HwAAuCAAALghAAC4IgAAuCMAALglAAC4JwAAuCgAALgpAAC4KwAAuCwAALhRAAC4dQAAuJwAALjAAAC4wwAAuMUAALjHAAC4yQAAuMsAALjNAAC4zgAAuNEAALjeAAC47QAAuO8AALjxAAC48wAAuPUAALj3AAC4+QAAuPsAALkKAAC5DQAAuRAAALkTAAC5FgAAuRkAALkcAAC5HwAAuSEAALlgAAC5YgAAuWQAALlmAAC5aQAAuWoAALlrAAC5bAAAuW0AALlvAAC5cQAAuXIAALlzAAC5dQAAuXYAALm1AAC5twAAubkAALm7AAC5vgAAub8AALnAAAC5wQAAucIAALnEAAC5xgAAuccAALnIAAC5ygAAucsAALoKAAC6DAAAug4AALoQAAC6EwAAuhQAALoVAAC6FgAAuhcAALoZAAC6GwAAuhwAALodAAC6HwAAuiAAALpfAAC6YQAAumMAALplAAC6aAAAumkAALpqAAC6awAAumwAALpuAAC6cAAAunEAALpyAAC6dAAAunUAALq0AAC6tgAAurgAALq6AAC6vQAAur4AALq/AAC6wAAAusEAALrDAAC6xQAAusYAALrHAAC6yQAAusoAALsJAAC7CwAAuw0AALsPAAC7EgAAuxMAALsUAAC7FQAAuxYAALsYAAC7GgAAuxsAALscAAC7HgAAux8AALteAAC7YAAAu2MAALtlAAC7aAAAu2kAALtqAAC7awAAu2wAALtuAAC7cAAAu3EAALtyAAC7dAAAu3UAALvAAAC74wAAvAMAALwjAAC8JQAAvCcAALwpAAC8KwA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AzSIAAM0lAADNMgAAzUMAAM1FAADNRwAAzUkAAM1LAADNTQAAzU8AAM1RAADNUwAAzWQAAM1nAADNagAAzW0AAM1wAADNcwAAzXYAAM15AADNfAAAzX4AAM29AADNvwAAzcEAAM3DAADNxgAAzccAAM3IAADNyQAAzcoAAM3MAADNzgAAzc8AAM3QAADN0gAAzdMAAM4SAADOFAAAzhYAAM4YAADOGwAAzhwAAM4dAADOHgAAzh8AAM4hAADOIwAAziQAAM4lAADOJwAAzigAAM5nAADOaQAAzmwAAM5uAADOcQAAznIAAM5zAADOdAAAznUAAM53AADOeQAAznoAAM57AADOfQAAzn4AAM6LAADOjAAAzo0AAM6PAADOzgAAztAAAM7SAADO1AAAztcAAM7YAADO2QAAztoAAM7bAADO3QAAzt8AAM7gAADO4QAAzuMAAM7kAADPIwAAzyUAAM8nAADPKQAAzywAAM8tAADPLgAAzy8AAM8wAADPMgAAzzQAAM81AADPNgAAzzgAAM85AADPeAAAz3oAAM98AADPfgAAz4EAAM+CAADPgwAAz4QAAM+FAADPhwAAz4kAAM+KAADPiwAAz40AAM+OAADPzQAAz88AAM/RAADP0wAAz9YAAM/XAADP2AAAz9kAAM/aAADP3AAAz94AAM/fAADP4AAAz+IAAM/jAADQIgAA0CQAANAmAADQKAAA0CsAANAsAADQLQAA0C4AANAvAADQMQAA0DMAANA0AADQNQAA0DcAANA4AADQXQAA0IEAANCoAADQzAAA0M8AANDRAADQ0wAA0NUAANDXAADQ2QAA0NoAANDdAADQ6gAA0PcAAND5AADQ+wAA0P0AAND/AADRAQAA0QMAANEQAADREwAA0RYAANEZAADRHAAA0R8AANEiAADRJAAA0WMAANFlAADRaAAA0WoAANFtAADRbgAA0W8AANFwAADRcQAA0XMAANF1AADRdgAA0XcAANF5AADRegAA0b0AANHhAADSBQAA0igAANJPAADSbwAA0pYAANK9AADS3QAA0wEAANMlAADTJwAA0yoAANMsAADTLgAA0zAAANMzAADTNgAA0zgAANM6AADTPQAA0z8AANNBAADTRAAA00cAANNIAADTTQAA01oAANNdAADTXwAA02IAANNlAADTZwAA04wAANOwAADT1wAA0/sAANP+AADUAAAA1AIAANQEAADUBgAA1AgAANQJAADUDAAA1BkAANQsAADULgAA1DAAANQyAADUNAAA1DYAANQ4AADUOgAA1DwAANQ+AADUUQAA1FQAANRXAADUWgAA1F0AANRgAADUYwAA1GYAANRpAADUbAAA1G4AANStAADUrwAA1LIAANS0AADUtwAA1LgAANS5AADUugAA1LsAANS9AADUvwAA1MAAANTBAADUwwAA1MQAANTNAADUzgAA1NAAANUPAADVEQAA1RMAANUVAADVGAAA1RkAANUaAADVGwAA1RwAANUeAADVIAAA1SEAANUiAADVJAAA1SUAANVkAADVZgAA1WkAANVrAADVbgAA1W8AANVwAADVcQAA1XIAANV0AADVdgAA1XcAANV4AADVegAA1XsAANWEAADVhQAA1YcAANXGAADVyAAA1coAANXMAADVzwAA1dAAANXRAADV0gAA1dMAANXVAADV1wAA1dgAANXZAADV2wAA1dwAANYbAADWHQAA1iAAANYiAADWJQAA1iYAANYnAADWKAAA1ikAANYrAADWLQAA1i4AANYvAADWMQAA1jIAANY7AADWPAAA1j4AANZ9AADWfwAA1oEAANaDAADWhgAA1ocAANaIAADWiQAA1ooAANaMAADWjgAA1o8AANaQAADWkgAA1pMAANbSAADW1AAA1tcAANbZAADW3AAA1t0AANbeAADW3wAA1uAAANbiAADW5AAA1uUAANbmAADW6AAA1ukAANb2AADW9wAA1vgAANb6AADXOQAA1zsAANc9AADXPwAA10IAANdDAADXRAAA10UAANdGAADXSAAA10oAANdLAADXTAAA104AANdPAADXjgAA15AAANeSAADXlAAA15cAANeYAADXmQAA15oAANebAADXnQAA158AANegAADXoQAA16MAANekAADXsQAA18wAANfPAADX0gAA19QAANfXAADX2gAA190AANfgAADX4wAA1+YAANfoAADX6wAA1+4AANfxAADYDAAA2A8AANgSAADYFQAA2BgAANgbAADYHgAA2CEAANgkAADYJwAA2CoAANgtAADYMAAA2DMAANg1AADYOAAA2D8AANhNAADYUwAA2FkAANhhAADYbAAA2HYAANiLAADYngAA2KoAANj1AADZGAAA2TgAANlYAADZWgAA2VwAANleAADZYAAA2WMAANlkAADZZQAA2WgAANlpAADZawAA2WwAANluAADZcQAA2XIAANlzAADZdgAA2XcAANl8AADZiQAA2Y4AANmQAADZkgAA2ZcAANmaAADZnQAA2Z8AANnEAADZ6AAA2g8AANozAADaNgAA2jgAANo6AADaPAAA2j4AANpAAADaQQAA2kQAANpRAADaYgAA2mQAANpmAADaaAAA2moAANpsAADabgAA2nAAANpyAADagwAA2oYAANqJAADajAAA2o8AANqSAADalQAA2pgAANqbAADanQAA2twAANreAADa4AAA2uIAANrlAADa5gAA2ucAANroAADa6QAA2usAANrtAADa7gAA2u8AANrxAADa8gAA2zEAANszAADbNQAA2zcAANs6AADbOwAA2zwAANs9AADbPgAA20AAANtCAADbQwAA20QAANtGAADbRwAA24YAANuIAADbiwAA240AANuQAADbkQAA25IAANuTAADblAAA25YAANuYAADbmQAA25oAANucAADbnQAA26oAANurAADbrAAA264AANvtAADb7wAA2/EAANvzAADb9gAA2/cAANv4AADb+QAA2/oAANv8AADb/gAA2/8AANwAAADcAgAA3AMAANxCAADcRAAA3EYAANxIAADcSwAA3EwAANxNAADcTgAA3E8AANxRAADcUwAA3FQAANxVAADcVwAA3FgAANyXAADcmQAA3JsAANydAADcoAAA3KEAANyiAADcowAA3KQAANymAADcqAAA3KkAANyqAADcrAAA3K0AANzsAADc7gAA3PAAANzyAADc9QAA3PYAANz3AADc+AAA3PkAANz7AADc/QAA3P4AANz/AADdAQAA3QIAAN1BAADdQwAA3UUAAN1HAADdSgAA3UsAAN1MAADdTQAA3U4AAN1QAADdUgAA3VMAAN1UAADdVgAA3VcAAN18AADdoAAA3ccAAN3rAADd7gAA3fAAAN3yAADd9AAA3fYAAN34AADd+QAA3fwAAN4JAADeGAAA3hoAAN4cAADeHgAA3iAAAN4iAADeJAAA3iYAAN41AADeOAAA3jsAAN4+AADeQQAA3kQAAN5HAADeSgAA3kwAAN6LAADejQAA3o8AAN6RAADelAAA3pUAAN6WAADelwAA3pgAAN6aAADenAAA3p0AAN6eAADeoAAA3qEAAN7gAADe4gAA3uQAAN7mAADe6QAA3uoAAN7rAADe7AAA3u0AAN7vAADe8QAA3vIAAN7zAADe9QAA3vYAAN81AADfNwAA3zkAAN87AADfPgAA3z8AAN9AAADfQQAA30IAAN9EAADfRgAA30cAAN9IAADfSgAA30sAAN+KAADfjAAA344AAN+QAADfkwAA35QAAN+VAADflgAA35cAAN+ZAADfmwAA35wAAN+dAADfnwAA36AAAN/fAADf4QAA3+MAAN/lAADf6AAA3+kAAN/qAADf6wAA3+wAAN/uAADf8AAA3/EAAN/yAADf9AAA3/UAAOA0AADgNgAA4DgAAOA6AADgPQAA4D4AAOA/AADgQAAA4EEAAOBDAADgRQAA4EYAAOBHAADgSQAA4EoAAOCJAADgiwAA4I0AAOCPAADgkgAA4JMAAOCUAADglQAA4JYAAOCYAADgmgAA4JsAAOCcAADgngAA4J8AAODqAADhDQAA4S0AAOFNAADhTwAA4VEAAOFTAADhVQAA4VgAAOFZAADhWgAA4V0AAOFeAADhYAAA4WEAAOFjAADhZgAA4WcAAOFoAADhawAA4WwAAOFxAADhfgAA4YMAAOGFAADhhwAA4YwAAOGPAADhkgAA4ZQAAOG5AADh3QAA4gQAAOIoAADiKwAA4i0AAOIvAADiMQAA4jMAAOI1AADiNgAA4jkAAOJGAADiVwAA4lkAAOJbAADiXQAA4l8AAOJhAADiYwAA4mUAAOJnAADieAAA4nsAAOJ+AADigQAA4oQAAOKHAADiigAA4o0AAOKQAADikgAA4tEAAOLTAADi1QAA4tcAAOLaAADi2wAA4twAAOLdAADi3gAA4uAAAOLiAADi4wAA4uQAAOLmAADi5wAA4yYAAOMoAADjKgAA4ywAAOMvAADjMAAA4zEAAOMyAADjMwAA4zUAAOM3AADjOAAA4zkAAOM7AADjPAAA43sAAON9AADjgAAA44IAAOOFAADjhgAA44cAAOOIAADjiQAA44sAAOONAADjjgAA448AAOORAADjkgAA458AAOOgAADjoQAA46MAAOPiAADj5AAA4+YAAOPoAADj6wAA4+wAAOPtAADj7gAA4+8AAOPxAADj8wAA4/QAAOP1AADj9wAA4/gAAOQ3AADkOQAA5DsAAOQ9AADkQAAA5EEAAORCAADkQwAA5EQAAORGAADkSAAA5EkAAORKAADkTAAA5E0AAOSMAADkjgAA5JAAAOSSAADklQAA5JYAAOSXAADkmAAA5JkAAOSbAADknQAA5J4AAOSfAADkoQAA5KIAAOThAADk4wAA5OUAAOTnAADk6gAA5OsAAOTsAADk7QAA5O4AAOTwAADk8gAA5PMAAOT0AADk9gAA5PcAAOU2AADlOAAA5ToAAOU8AADlPwAA5UAAAOVBAADlQgAA5UMAAOVFAADlRwAA5UgAAOVJAADlSwAA5UwAAOVxAADllQAA5bwAAOXgAADl4wAA5eUAAOXnAADl6QAA5esAAOXtAADl7gAA5fEAAOX+AADmDQAA5g8AAOYRAADmEwAA5hUAAOYXAADmGQAA5hsAAOYqAADmLQAA5jAAAOYzAADmNgAA5jkAAOY8AADmPwAA5kEAAOaAAADmggAA5oQAAOaGAADmiQAA5ooAAOaLAADmjAAA5o0AAOaPAADmkQAA5pIAAOaTAADmlQAA5pYAAObVAADm1wAA5tkAAObbAADm3gAA5t8AAObgAADm4QAA5uIAAObkAADm5gAA5ucAAOboAADm6gAA5usAAOcqAADnLAAA5y4AAOcwAADnMwAA5zQAAOc1AADnNgAA5zcAAOc5AADnOwAA5zwAAOc9AADnPwAA50AAAOd/AADngQAA54MAAOeFAADniAAA54kAAOeKAADniwAA54wAAOeOAADnkAAA55EAAOeSAADnlAAA55UAAOfUAADn1gAA59gAAOfaAADn3QAA594AAOffAADn4AAA5+EAAOfjAADn5QAA5+YAAOfnAADn6QAA5+oAAOgpAADoKwAA6C0AAOgvAADoMgAA6DMAAOg0AADoNQAA6DYAAOg4AADoOgAA6DsAAOg8AADoPgAA6D8AAOh+AADogAAA6IIAAOiEAADohwAA6IgAAOiJAADoigAA6IsAAOiNAADojwAA6JAAAOiRAADokwAA6JQAAOjfAADpAgAA6SIAAOlCAADpRAAA6UYAAOlIAADpSgAA6U0AAOlOAADpTwAA6VIAAOlTAADpVQAA6VYAAOlYAADpWgAA6VsAAOlcAADpXwAA6WAAAOlpAADpdgAA6XsAAOl9AADpfwAA6YQAAOmHAADpigAA6YwAAOmxAADp1QAA6fwAAOogAADqIwAA6iUAAOonAADqKQAA6isAAOotAADqLgAA6jEAAOo+AADqTwAA6lEAAOpTAADqVQAA6lcAAOpZAADqWwAA6l0AAOpfAADqcAAA6nMAAOp2AADqeQAA6nwAAOp/AADqggAA6oUAAOqIAADqigAA6skAAOrLAADqzQAA6s8AAOrSAADq0wAA6tQAAOrVAADq1gAA6tgAAOraAADq2wAA6twAAOreAADq3wAA6x4AAOsgAADrIgAA6yQAAOsnAADrKAAA6ykAAOsqAADrKwAA6y0AAOsvAADrMAAA6zEAAOszAADrNAAA63MAAOt1AADreAAA63oAAOt9AADrfgAA638AAOuAAADrgQAA64MAAOuFAADrhgAA64cAAOuJAADrigAA65cAAOuYAADrmQAA65sAAOvaAADr3AAA694AAOvgAADr4wAA6+QAAOvlAADr5gAA6+cAAOvpAADr6wAA6+wAAOvtAADr7wAA6/AAAOwvAADsMQAA7DMAAOw1AADsOAAA7DkAAOw6AADsOwAA7DwAAOw+AADsQAAA7EEAAOxCAADsRAAA7EUAAOyEAADshgAA7IgAAOyKAADsjQAA7I4AAOyPAADskAAA7JEAAOyTAADslQAA7JYAAOyXAADsmQAA7JoAAOzZAADs2wAA7N0AAOzfAADs4gAA7OMAAOzkAADs5QAA7OYAAOzoAADs6gAA7OsAAOzsAADs7gAA7O8AAO0uAADtMAAA7TIAAO00AADtNwAA7TgAAO05AADtOgAA7TsAAO09AADtPwAA7UAAAO1BAADtQwAA7UQAAO1pAADtjQAA7bQAAO3YAADt2wAA7d0AAO3fAADt4QAA7eMAAO3lAADt5gAA7ekAAO32AADuBQAA7gcAAO4JAADuCwAA7g0AAO4PAADuEQAA7hMAAO4iAADuJQAA7igAAO4rAADuLgAA7jEAAO40AADuNwAA7jkAAO54AADuegAA7nwAAO5+AADugQAA7oIAAO6DAADuhAAA7oUAAO6HAADuiQAA7ooAAO6LAADujQAA7o4AAO7NAADuzwAA7tEAAO7TAADu1gAA7tcAAO7YAADu2QAA7toAAO7cAADu3gAA7t8AAO7gAADu4gAA7uMAAO8iAADvJAAA7yYAAO8oAADvKwAA7ywAAO8tAADvLgAA7y8AAO8xAADvMwAA7zQAAO81AADvNwAA7zgAAO93AADveQAA73sAAO99AADvgAAA74EAAO+CAADvgwAA74QAAO+GAADviAAA74kAAO+KAADvjAAA740AAO/MAADvzgAA79AAAO/SAADv1QAA79YAAO/XAADv2AAA79kAAO/bAADv3QAA794AAO/fAADv4QAA7+IAAPAhAADwIwAA8CUAAPAnAADwKgAA8CsAAPAsAADwLQAA8C4AAPAwAADwMgAA8DMAAPA0AADwNgAA8DcAAPB2AADweAAA8HoAAPB8AADwfwAA8IAAAPCBAADwggAA8IMAAPCFAADwhwAA8IgAAPCJAADwiwAA8IwAAPDXAADw+gAA8RoAAPE6AADxPAAA8T4AAPFAAADxQgAA8UUAAPFGAADxRwAA8UoAAPFLAADxTQAA8U4AAPFQAADxUwAA8VQAAPFVAADxWAAA8VkAAPFeAADxawAA8XAAAPFyAADxdAAA8XkAAPF8AADxfwAA8YEAAPGmAADxygAA8fEAAPIVAADyGAAA8hoAAPIcAADyHgAA8iAAAPIiAADyIwAA8iYAAPIzAADyRAAA8kYAAPJIAADySgAA8kwAAPJOAADyUAAA8lIAAPJUAADyZQAA8mgAAPJrAADybgAA8nEAAPJ0AADydwAA8noAAPJ9AADyfwAA8r4AAPLAAADywgAA8sQAAPLHAADyyAAA8skAAPLKAADyywAA8s0AAPLPAADy0AAA8tEAAPLTAADy1AAA8xMAAPMVAADzFwAA8xkAAPMcAADzHQAA8x4AAPMfAADzIAAA8yIAAPMkAADzJQAA8yYAAPMoAADzKQAA82gAAPNqAADzbQAA828AAPNyAADzcwAA83QAAPN1AADzdgAA83gAAPN6AADzewAA83wAAPN+AADzfwAA84wAAPONAADzjgAA85AAAPPPAADz0QAA89MAAPPVAADz2AAA89kAAPPaAADz2wAA89wAAPPeAADz4AAA8+EAAPPiAADz5AAA8+UAAPQkAAD0JgAA9CgAAPQqAAD0LQAA9C4AAPQvAAD0MAAA9DEAAPQzAAD0NQAA9DYAAPQ3AAD0OQAA9DoAAPR5AAD0ewAA9H0AAPR/AAD0ggAA9IMAAPSEAAD0hQAA9IYAAPSIAAD0igAA9IsAAPSMAAD0jgAA9I8AAPTOAAD00AAA9NIAAPTUAAD01wAA9NgAAPTZAAD02gAA9NsAAPTdAAD03wA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BESMAARElAAERKAABESkAAREqAAERLQABES4AAREwAAERMQABETMAARE2AAERNwABETgAARE7AAERPAABEUEAARFOAAERUwABEVUAARFXAAERXAABEV8AARFiAAERZAABEYkAARGtAAER1AABEfgAARH7AAER/QABEf8AARIBAAESAwABEgUAARIGAAESCQABEhYAARInAAESKQABEisAARItAAESLwABEjEAARIzAAESNQABEjcAARJIAAESSwABEk4AARJRAAESVAABElcAARJaAAESXQABEmAAARJiAAESoQABEqMAARKlAAESpwABEqoAARKrAAESrAABEq0AARKuAAESsAABErIAARKzAAEStAABErYAARK3AAES9gABEvgAARL6AAES/AABEv8AARMAAAETAQABEwIAARMDAAETBQABEwcAARMIAAETCQABEwsAARMMAAETSwABE00AARNQAAETUgABE1UAARNWAAETVwABE1gAARNZAAETWwABE10AARNeAAETXwABE2EAARNiAAETbwABE3AAARNxAAETcwABE7IAARO0AAETtgABE7gAARO7AAETvAABE70AARO+AAETvwABE8EAARPDAAETxAABE8UAARPHAAETyAABFAcAARQJAAEUCwABFA0AARQQAAEUEQABFBIAARQTAAEUFAABFBYAARQYAAEUGQABFBoAARQcAAEUHQABFFwAARReAAEUYAABFGIAARRlAAEUZgABFGcAARRoAAEUaQABFGsAARRtAAEUbgABFG8AARRxAAEUcgABFLEAARSzAAEUtQABFLcAARS6AAEUuwABFLwAARS9AAEUvgABFMAAARTCAAEUwwABFMQAARTGAAEUxwABFQYAARUIAAEVCgABFQwAARUPAAEVEAABFREAARUSAAEVEwABFRUAARUXAAEVGAABFRkAARUbAAEVHAABFUEAARVlAAEVjAABFbAAARWzAAEVtQABFbcAARW5AAEVuwABFb0AARW+AAEVwQABFc4AARXdAAEV3wABFeEAARXjAAEV5QABFecAARXpAAEV6wABFfoAARX9AAEWAAABFgMAARYGAAEWCQABFgwAARYPAAEWEQABFlAAARZSAAEWVAABFlYAARZZAAEWWgABFlsAARZcAAEWXQABFl8AARZhAAEWYgABFmMAARZlAAEWZgABFqUAARanAAEWqQABFqsAARauAAEWrwABFrAAARaxAAEWsgABFrQAARa2AAEWtwABFrgAARa6AAEWuwABFvoAARb8AAEW/gABFwAAARcDAAEXBAABFwUAARcGAAEXBwABFwkAARcLAAEXDAABFw0AARcPAAEXEAABF08AARdRAAEXUwABF1UAARdYAAEXWQABF1oAARdbAAEXXAABF14AARdgAAEXYQABF2IAARdkAAEXZQABF6QAARemAAEXqAABF6oAARetAAEXrgABF68AARewAAEXsQABF7MAARe1AAEXtgABF7cAARe5AAEXugABF/kAARf7AAEX/QABF/8AARgCAAEYAwABGAQAARgFAAEYBgABGAgAARgKAAEYCwABGAwAARgOAAEYDwABGE4AARhQAAEYUgABGFQAARhXAAEYWAABGFkAARhaAAEYWwABGF0AARhfAAEYYAABGGEAARhjAAEYZAABGK8AARjSAAEY8gABGRIAARkUAAEZFgABGRgAARkaAAEZHQABGR4AARkfAAEZIgABGSMAARklAAEZJgABGSgAARkrAAEZLAABGS0AARkwAAEZMQABGTYAARlDAAEZSAABGUoAARlMAAEZUQABGVQAARlXAAEZWQABGX4AARmiAAEZyQABGe0AARnwAAEZ8gABGfQAARn2AAEZ+AABGfoAARn7AAEZ/gABGgsAARocAAEaHgABGiAAARoiAAEaJAABGiYAARooAAEaKgABGiwAARo9AAEaQAABGkMAARpGAAEaSQABGkwAARpPAAEaUgABGlUAARpXAAEalgABGpgAARqaAAEanAABGp8AARqgAAEaoQABGqIAARqjAAEapQABGqcAARqoAAEaqQABGqsAARqsAAEa6wABGu0AARrvAAEa8QABGvQAARr1AAEa9gABGvcAARr4AAEa+gABGvwAARr9AAEa/gABGwAAARsBAAEbQAABG0IAARtFAAEbRwABG0oAARtLAAEbTAABG00AARtOAAEbUAABG1IAARtTAAEbVAABG1YAARtXAAEbZAABG2UAARtmAAEbaAABG6cAARupAAEbqwABG60AARuwAAEbsQABG7IAARuzAAEbtAABG7YAARu4AAEbuQABG7oAARu8AAEbvQABG/wAARv+AAEcAAABHAIAARwFAAEcBgABHAcAARwIAAEcCQABHAsAARwNAAEcDgABHA8AARwRAAEcEgABHFEAARxTAAEcVQABHFcAARxaAAEcWwABHFwAARxdAAEcXgABHGAAARxiAAEcYwABHGQAARxmAAEcZwABHKYAARyoAAEcqgABHKwAARyvAAEcsAABHLEAARyyAAEcswABHLUAARy3AAEcuAABHLkAARy7AAEcvAABHPsAARz9AAEc/wABHQEAAR0EAAEdBQABHQYAAR0HAAEdCAABHQoAAR0MAAEdDQABHQ4AAR0QAAEdEQABHTYAAR1aAAEdgQABHaUAAR2oAAEdqgABHawAAR2uAAEdsAABHbIAAR2zAAEdtgABHcMAAR3SAAEd1AABHdYAAR3YAAEd2gABHdwAAR3eAAEd4AABHe8AAR3yAAEd9QABHfgAAR37AAEd/gABHgEAAR4EAAEeBgABHkUAAR5HAAEeSQABHksAAR5OAAEeTwABHlAAAR5RAAEeUgABHlQAAR5WAAEeVwABHlgAAR5aAAEeWwABHpoAAR6cAAEengABHqAAAR6jAAEepAABHqUAAR6mAAEepwABHqkAAR6rAAEerAABHq0AAR6vAAEesAABHu8AAR7xAAEe8wABHvUAAR74AAEe+QABHvoAAR77AAEe/AABHv4AAR8AAAEfAQABHwIAAR8EAAEfBQABH0QAAR9GAAEfSAABH0oAAR9NAAEfTgABH08AAR9QAAEfUQABH1MAAR9VAAEfVgABH1cAAR9ZAAEfWgABH5kAAR+bAAEfnQABH58AAR+iAAEfowABH6QAAR+lAAEfpgABH6gAAR+qAAEfqwABH6wAAR+uAAEfrwABH+4AAR/wAAEf8gABH/QAAR/3AAEf+AABH/kAAR/6AAEf+wABH/0AAR//AAEgAAABIAEAASADAAEgBAABIEMAASBFAAEgRwABIEkAASBMAAEgTQABIE4AASBPAAEgUAABIFIAASBUAAEgVQABIFYAASBYAAEgWQABIKQAASDHAAEg5wABIQcAASEJAAEhCwABIQ0AASEPAAEhEgABIRMAASEUAAEhFwABIRgAASEaAAEhGwABIR0AASEfAAEhIAABISEAASEkAAEhJQABISoAASE3AAEhPAABIT4AASFAAAEhRQABIUgAASFLAAEhTQABIXIAASGWAAEhvQABIeEAASHkAAEh5gABIegAASHqAAEh7AABIe4AASHvAAEh8gABIf8AASIQAAEiEgABIhQAASIWAAEiGAABIhoAASIcAAEiHgABIiAAASIxAAEiNAABIjcAASI6AAEiPQABIkAAASJDAAEiRgABIkkAASJLAAEiigABIowAASKOAAEikAABIpMAASKUAAEilQABIpYAASKXAAEimQABIpsAASKcAAEinQABIp8AASKgAAEi3wABIuEAASLjAAEi5QABIugAASLpAAEi6gABIusAASLsAAEi7gABIvAAASLxAAEi8gABIvQAASL1AAEjNAABIzYAASM5AAEjOwABIz4AASM/AAEjQAABI0EAASNCAAEjRAABI0YAASNHAAEjSAABI0oAASNLAAEjWAABI1kAASNaAAEjXAABI5sAASOdAAEjnwABI6EAASOkAAEjpQABI6YAASOnAAEjqAABI6oAASOsAAEjrQABI64AASOwAAEjsQABI/AAASPyAAEj9AABI/YAASP5AAEj+gABI/sAASP8AAEj/QABI/8AASQBAAEkAgABJAMAASQFAAEkBgABJEUAASRHAAEkSQABJEsAASROAAEkTwABJFAAASRRAAEkUgABJFQAASRWAAEkVwABJFgAASRaAAEkWwABJJoAASScAAEkngABJKAAASSjAAEkpAABJKUAASSmAAEkpwABJKkAASSrAAEkrAABJK0AASSvAAEksAABJO8AASTxAAEk8wABJPUAAST4AAEk+QABJPoAAST7AAEk/AABJP4AASUAAAElAQABJQIAASUEAAElBQABJSoAASVOAAEldQABJZkAASWcAAElngABJaAAASWiAAElpAABJaYAASWnAAElqgABJbcAASXGAAElyAABJcoAASXMAAElzgABJdAAASXSAAEl1AABJeMAASXmAAEl6QABJewAASXvAAEl8gABJfUAASX4AAEl+gABJjkAASY7AAEmPQABJj8AASZCAAEmQwABJkQAASZFAAEmRgABJkgAASZKAAEmSwABJkwAASZOAAEmTwABJo4AASaQAAEmkgABJpQAASaXAAEmmAABJpkAASaaAAEmmwABJp0AASafAAEmoAABJqEAASajAAEmpAABJuMAASblAAEm5wABJukAASbsAAEm7QABJu4AASbvAAEm8AABJvIAASb0AAEm9QABJvYAASb4AAEm+QABJzgAASc6AAEnPAABJz4AASdBAAEnQgABJ0MAASdEAAEnRQABJ0cAASdJAAEnSgABJ0sAASdNAAEnTgABJ40AASePAAEnkQABJ5MAASeWAAEnlwABJ5gAASeZAAEnmgABJ5wAASeeAAEnnwABJ6AAASeiAAEnowABJ+IAASfkAAEn5gABJ+gAASfrAAEn7AABJ+0AASfuAAEn7wABJ/EAASfzAAEn9AABJ/UAASf3AAEn+AABKDcAASg5AAEoOwABKD0AAShAAAEoQQABKEIAAShDAAEoRAABKEYAAShIAAEoSQABKEoAAShMAAEoTQABKJgAASi7AAEo2wABKPsAASj9AAEo/wABKQEAASkDAAEpBgABKQcAASkIAAEpCwABKQwAASkOAAEpDwABKREAASkUAAEpFQABKRYAASkZAAEpGgABKR8AASksAAEpMQABKTMAASk1AAEpOgABKT0AASlAAAEpQgABKWcAASmLAAEpsgABKdYAASnZAAEp2wABKd0AASnfAAEp4QABKeMAASnkAAEp5wABKfQAASoFAAEqBwABKgkAASoLAAEqDQABKg8AASoRAAEqEwABKhUAASomAAEqKQABKiwAASovAAEqMgABKjUAASo4AAEqOwABKj4AASpAAAEqfwABKoEAASqDAAEqhQABKogAASqJAAEqigABKosAASqMAAEqjgABKpAAASqRAAEqkgABKpQAASqVAAEq1AABKtYAASrYAAEq2gABKt0AASreAAEq3wABKuAAASrhAAEq4wABKuUAASrmAAEq5wABKukAASrqAAErKQABKysAASsuAAErMAABKzMAASs0AAErNQABKzYAASs3AAErOQABKzsAASs8AAErPQABKz8AAStAAAErTQABK04AAStPAAErUQABK5AAASuSAAErlAABK5YAASuZAAErmgABK5sAASucAAErnQABK58AASuhAAErogABK6MAASulAAErpgABK+UAASvnAAEr6QABK+sAASvuAAEr7wABK/AAASvxAAEr8gABK/QAASv2AAEr9wABK/gAASv6AAEr+wABLDoAASw8AAEsPgABLEAAASxDAAEsRAABLEUAASxGAAEsRwABLEkAASxLAAEsTAABLE0AASxPAAEsUAABLI8AASyRAAEskwABLJUAASyYAAEsmQABLJoAASybAAEsnAABLJ4AASygAAEsoQABLKIAASykAAEspQABLOQAASzmAAEs6AABLOoAASztAAEs7gABLO8AASzwAAEs8QABLPMAASz1AAEs9gABLPcAASz5AAEs+gABLR8AAS1DAAEtagABLY4AAS2RAAEtkwABLZUAAS2XAAEtmQABLZsAAS2cAAEtnwABLawAAS27AAEtvQABLb8AAS3BAAEtwwABLcUAAS3HAAEtyQABLdgAAS3bAAEt3gABLeEAAS3kAAEt5wABLeoAAS3tAAEt7wABLi4AAS4wAAEuMgABLjQAAS43AAEuOAABLjkAAS46AAEuOwABLj0AAS4/AAEuQAABLkEAAS5DAAEuRAABLoMAAS6FAAEuhwABLokAAS6MAAEujQABLo4AAS6PAAEukAABLpIAAS6UAAEulQABLpYAAS6YAAEumQABLtgAAS7aAAEu3AABLt4AAS7hAAEu4gABLuMAAS7kAAEu5QABLucAAS7pAAEu6gABLusAAS7tAAEu7gABLy0AAS8vAAEvMQABLzMAAS82AAEvNwABLzgAAS85AAEvOgABLzwAAS8+AAEvPwABL0AAAS9CAAEvQwABL4IAAS+EAAEvhgABL4gAAS+LAAEvjAABL40AAS+OAAEvjwABL5EAAS+TAAEvlAABL5UAAS+XAAEvmAABL9cAAS/ZAAEv2wABL90AAS/gAAEv4QABL+IAAS/jAAEv5AABL+YAAS/oAAEv6QABL+oAAS/sAAEv7QABMCwAATAuAAEwMAABMDIAATA1AAEwNgABMDcAATA4AAEwOQABMDsAATA9AAEwPgABMD8AATBBAAEwQgABMI0AATCwAAEw0AABMPAAATDyAAEw9AABMPYAATD4AAEw+wABMPwAATD9AAExAAABMQEAATEDAAExBAABMQYAATEJAAExCgABMQsAATEOAAExDwABMRQAATEhAAExJgABMSgAATEqAAExLwABMTIAATE1AAExNwABMVwAATGAAAExpwABMcsAATHOAAEx0AABMdIAATHUAAEx1gABMdgAATHZAAEx3AABMekAATH6AAEx/AABMf4AATIAAAEyAgABMgQAATIGAAEyCAABMgoAATIbAAEyHgABMiEAATIkAAEyJwABMioAATItAAEyMAABMjMAATI1AAEydAABMnYAATJ4AAEyegABMn0AATJ+AAEyfwABMoAAATKBAAEygwABMoUAATKGAAEyhwABMokAATKKAAEyyQABMssAATLNAAEyzwABMtIAATLTAAEy1AABMtUAATLWAAEy2AABMtoAATLbAAEy3AABMt4AATLfAAEzHgABMyAAATMjAAEzJQABMygAATMpAAEzKgABMysAATMsAAEzLgABMzAAATMxAAEzMgABMzQAATM1AAEzQgABM0MAATNEAAEzRgABM4UAATOHAAEziQABM4sAATOOAAEzjwABM5AAATORAAEzkgABM5QAATOWAAEzlwABM5gAATOaAAEzmwABM9oAATPcAAEz3gABM+AAATPjAAEz5AABM+UAATPmAAEz5wABM+kAATPrAAEz7AABM+0AATPvAAEz8AABNC8AATQxAAE0MwABNDUAATQ4AAE0OQABNDoAATQ7AAE0PAABND4AATRAAAE0QQABNEIAATREAAE0RQABNIQAATSGAAE0iAABNIoAATSNAAE0jgABNI8AATSQAAE0kQABNJMAATSVAAE0lgABNJcAATSZAAE0mgABNNkAATTbAAE03QABNN8AATTiAAE04wABNOQAATTlAAE05gABNOgAATTqAAE06wABNOwAATTuAAE07wABNRQAATU4AAE1XwABNYMAATWGAAE1iAABNYoAATWMAAE1jgABNZAAATWRAAE1lAABNaEAATWwAAE1sgABNbQAATW2AAE1uAABNboAATW8AAE1vgABNc0AATXQAAE10wABNdYAATXZAAE13AABNd8AATXiAAE15AABNiMAATYlAAE2JwABNikAATYsAAE2LQABNi4AATYvAAE2MAABNjIAATY0AAE2NQABNjYAATY4AAE2OQABNngAATZ6AAE2fAABNn4AATaBAAE2ggABNoMAATaEAAE2hQABNocAATaJAAE2igABNosAATaNAAE2jgABNs0AATbPAAE20QABNtMAATbWAAE21wABNtgAATbZAAE22gABNtwAATbeAAE23wABNuAAATbiAAE24wABNyIAATckAAE3JwABNykAATcsAAE3LQABNy4AATcvAAE3MAABNzIAATc0AAE3NQABNzYAATc4AAE3OQABN3gAATd6AAE3fAABN34AATeBAAE3ggABN4MAATeEAAE3hQABN4cAATeJAAE3igABN4sAATeNAAE3jgABN80AATfPAAE30QABN9MAATfWAAE31wABN9gAATfZAAE32gABN9wAATfeAAE33wABN+AAATfiAAE34wABOCIAATgkAAE4JgABOCgAATgrAAE4LAABOC0AATguAAE4LwABODEAATgzAAE4NAABODUAATg3AAE4OAABOIMAATimAAE4xgABOOYAATjoAAE46gABOOwAATjuAAE48QABOPIAATjzAAE49gABOPcAATj5AAE4+gABOPwAATj/AAE5AAABOQEAATkEAAE5BQABOQ4AATkbAAE5IAABOSIAATkkAAE5KQABOSwAATkvAAE5MQABOVYAATl6AAE5oQABOcUAATnIAAE5ygABOcwAATnOAAE50AABOdIAATnTAAE51gABOeMAATn0AAE59gABOfgAATn6AAE5/AABOf4AAToAAAE6AgABOgQAAToVAAE6GAABOhsAAToeAAE6IQABOiQAATonAAE6KgABOi0AATovAAE6bgABOnAAATpyAAE6dAABOncAATp4AAE6eQABOnoAATp7AAE6fQABOn8AATqAAAE6gQABOoMAATqEAAE6wwABOsUAATrHAAE6yQABOswAATrNAAE6zgABOs8AATrQAAE60gABOtQAATrVAAE61gABOtgAATrZAAE7GAABOxoAATsdAAE7HwABOyIAATsjAAE7JAABOyUAATsmAAE7KAABOyoAATsrAAE7LAABOy4AATsvAAE7PAABOz0AATs+AAE7QAABO38AATuBAAE7gwABO4UAATuIAAE7iQABO4oAATuLAAE7jAABO44AATuQAAE7kQABO5IAATuUAAE7lQABO9QAATvWAAE72AABO9oAATvdAAE73gABO98AATvgAAE74QABO+MAATvlAAE75gABO+cAATvpAAE76gABPCkAATwrAAE8LQABPC8AATwyAAE8MwABPDQAATw1AAE8NgABPDgAATw6AAE8OwABPDwAATw+AAE8PwABPH4AATyAAAE8ggABPIQAATyHAAE8iAABPIkAATyKAAE8iwABPI0AATyPAAE8kAABPJEAATyTAAE8lAABPNMAATzVAAE81wABPNkAATzcAAE83QABPN4AATzfAAE84AABPOIAATzkAAE85QABPOYAATzoAAE86QABPQ4AAT0yAAE9WQABPX0AAT2AAAE9ggABPYQAAT2GAAE9iAABPYoAAT2LAAE9jgABPZsAAT2qAAE9rAA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BVAMAAVQjAAFUJQABVCcAAVQpAAFUKwABVC0AAVQuAAFULwABVDIAAVQzAAFUNQABVDYAAVQ4AAFUOgABVDsAAVQ8AAFUPwABVEAAAVRFAAFUUgABVFcAAVRZAAFUWwABVGAAAVRjAAFUZgABVGgAAVSNAAFUsQABVNgAAVT8AAFU/wABVQEAAVUDAAFVBQABVQcAAVUJAAFVCgABVQ0AAVUaAAFVKwABVS0AAVUvAAFVMQABVTMAAVU1AAFVNwABVTkAAVU7AAFVTAABVU8AAVVSAAFVVQABVVgAAVVbAAFVXgABVWEAAVVkAAFVZgABVaUAAVWnAAFVqQABVasAAVWuAAFVrwABVbAAAVWxAAFVsgABVbQAAVW2AAFVtwABVbgAAVW6AAFVuwABVfoAAVX8AAFV/gABVgAAAVYDAAFWBAABVgUAAVYGAAFWBwABVgkAAVYLAAFWDAABVg0AAVYPAAFWEAABVk8AAVZRAAFWVAABVlYAAVZZAAFWWgABVlsAAVZcAAFWXQABVl8AAVZhAAFWYgABVmMAAVZlAAFWZgABVnMAAVZ0AAFWdQABVncAAVa2AAFWuAABVroAAVa8AAFWvwABVsAAAVbBAAFWwgABVsMAAVbFAAFWxwABVsgAAVbJAAFWywABVswAAVcLAAFXDQABVw8AAVcRAAFXFAABVxUAAVcWAAFXFwABVxgAAVcaAAFXHAABVx0AAVceAAFXIAABVyEAAVdgAAFXYgABV2QAAVdmAAFXaQABV2oAAVdrAAFXbAABV20AAVdvAAFXcQABV3IAAVdzAAFXdQABV3YAAVe1AAFXtwABV7kAAVe7AAFXvgABV78AAVfAAAFXwQABV8IAAVfEAAFXxgABV8cAAVfIAAFXygABV8sAAVgKAAFYDAABWA4AAVgQAAFYEwABWBQAAVgVAAFYFgABWBcAAVgZAAFYGwABWBwAAVgdAAFYHwABWCAAAVhFAAFYaQABWJAAAVi0AAFYtwABWLkAAVi7AAFYvQABWL8AAVjBAAFYwgABWMUAAVjSAAFY4QABWOMAAVjlAAFY5wABWOkAAVjrAAFY7QABWO8AAVj+AAFZAQABWQQAAVkHAAFZCgABWQ0AAVkQAAFZEwABWRUAAVlUAAFZVgABWVgAAVlaAAFZXQABWV4AAVlfAAFZYAABWWEAAVljAAFZZQABWWYAAVlnAAFZaQABWWoAAVmpAAFZqwABWa0AAVmvAAFZsgABWbMAAVm0AAFZtQABWbYAAVm4AAFZugABWbsAAVm8AAFZvgABWb8AAVn+AAFaAAABWgIAAVoEAAFaBwABWggAAVoJAAFaCgABWgsAAVoNAAFaDwABWhAAAVoRAAFaEwABWhQAAVpTAAFaVQABWlcAAVpZAAFaXAABWl0AAVpeAAFaXwABWmAAAVpiAAFaZAABWmUAAVpmAAFaaAABWmkAAVqoAAFaqgABWqwAAVquAAFasQABWrIAAVqzAAFatAABWrUAAVq3AAFauQABWroAAVq7AAFavQABWr4AAVr9AAFa/wABWwEAAVsDAAFbBgABWwcAAVsIAAFbCQABWwoAAVsMAAFbDgABWw8AAVsQAAFbEgABWxMAAVtSAAFbVAABW1YAAVtYAAFbWwABW1wAAVtdAAFbXgABW18AAVthAAFbYwABW2QAAVtlAAFbZwABW2gAAVuzAAFb1gABW/YAAVwWAAFcGAABXBoAAVwcAAFcHgABXCAAAVwhAAFcIgABXCUAAVwmAAFcKAABXCkAAVwrAAFcLQABXC4AAVwvAAFcMgABXDMAAVw8AAFcSQABXE4AAVxQAAFcUgABXFcAAVxaAAFcXQABXF8AAVyEAAFcqAABXM8AAVzzAAFc9gABXPgAAVz6AAFc/AABXP4AAV0AAAFdAQABXQQAAV0RAAFdIgABXSQAAV0mAAFdKAABXSoAAV0sAAFdLgABXTAAAV0yAAFdQwABXUYAAV1JAAFdTAABXU8AAV1SAAFdVQABXVgAAV1bAAFdXQABXZwAAV2eAAFdoAABXaIAAV2lAAFdpgABXacAAV2oAAFdqQABXasAAV2tAAFdrgABXa8AAV2xAAFdsgABXfEAAV3zAAFd9QABXfcAAV36AAFd+wABXfwAAV39AAFd/gABXgAAAV4CAAFeAwABXgQAAV4GAAFeBwABXkYAAV5IAAFeSwABXk0AAV5QAAFeUQABXlIAAV5TAAFeVAABXlYAAV5YAAFeWQABXloAAV5cAAFeXQABXmoAAV5rAAFebAABXm4AAV6tAAFerwABXrEAAV6zAAFetgABXrcAAV64AAFeuQABXroAAV68AAFevgABXr8AAV7AAAFewgABXsMAAV8CAAFfBAABXwYAAV8IAAFfCwABXwwAAV8NAAFfDgABXw8AAV8RAAFfEwABXxQAAV8VAAFfFwABXxgAAV9XAAFfWQABX1sAAV9dAAFfYAABX2EAAV9iAAFfYwABX2QAAV9mAAFfaAABX2kAAV9qAAFfbAABX20AAV+sAAFfrgABX7AAAV+yAAFftQABX7YAAV+3AAFfuAABX7kAAV+7AAFfvQABX74AAV+/AAFfwQABX8IAAWABAAFgAwABYAUAAWAHAAFgCgABYAsAAWAMAAFgDQABYA4AAWAQAAFgEgABYBMAAWAUAAFgFgABYBcAAWA8AAFgYAABYIcAAWCrAAFgrgABYLAAAWCyAAFgtAABYLYAAWC4AAFguQABYLwAAWDJAAFg2AABYNoAAWDcAAFg3gABYOAAAWDiAAFg5AABYOYAAWD1AAFg+AABYPsAAWD+AAFhAQABYQQAAWEHAAFhCgABYQwAAWFLAAFhTQABYVAAAWFSAAFhVQABYVYAAWFXAAFhWAABYVkAAWFbAAFhXQABYV4AAWFfAAFhYQABYWIAAWGhAAFhowABYaUAAWGnAAFhqgABYasAAWGsAAFhrQABYa4AAWGwAAFhsgABYbMAAWG0AAFhtgABYbcAAWH2AAFh+AABYfoAAWH8AAFh/wABYgAAAWIBAAFiAgABYgMAAWIFAAFiBwABYggAAWIJAAFiCwABYgwAAWJLAAFiTQABYlAAAWJSAAFiVQABYlYAAWJXAAFiWAABYlkAAWJbAAFiXQABYl4AAWJfAAFiYQABYmIAAWKhAAFiowABYqUAAWKnAAFiqgABYqsAAWKsAAFirQABYq4AAWKwAAFisgABYrMAAWK0AAFitgABYrcAAWL2AAFi+AABYvoAAWL8AAFi/wABYwAAAWMBAAFjAgABYwMAAWMFAAFjBwABYwgAAWMJAAFjCwABYwwAAWNLAAFjTQABY08AAWNRAAFjVAABY1UAAWNWAAFjVwABY1gAAWNaAAFjXAABY10AAWNeAAFjYAABY2EAAWOsAAFjzwABY+8AAWQPAAFkEQABZBMAAWQVAAFkFwABZBkAAWQaAAFkGwABZB4AAWQfAAFkIQABZCIAAWQkAAFkJgABZCcAAWQoAAFkKwABZCwAAWQ1AAFkQgABZEcAAWRJAAFkSwABZFAAAWRTAAFkVgABZFgAAWR9AAFkoQABZMgAAWTsAAFk7wABZPEAAWTzAAFk9QABZPcAAWT5AAFk+gABZP0AAWUKAAFlGwABZR0AAWUfAAFlIQABZSMAAWUlAAFlJwABZSkAAWUrAAFlPAABZT8AAWVCAAFlRQABZUgAAWVLAAFlTgABZVEAAWVUAAFlVgABZZUAAWWXAAFlmQABZZsAAWWeAAFlnwABZaAAAWWhAAFlogABZaQAAWWmAAFlpwABZagAAWWqAAFlqwABZeoAAWXsAAFl7gABZfAAAWXzAAFl9AABZfUAAWX2AAFl9wABZfkAAWX7AAFl/AABZf0AAWX/AAFmAAABZj8AAWZBAAFmRAABZkYAAWZJAAFmSgABZksAAWZMAAFmTQABZk8AAWZRAAFmUgABZlMAAWZVAAFmVgABZmMAAWZkAAFmZQABZmcAAWamAAFmqAABZqoAAWasAAFmrwABZrAAAWaxAAFmsgABZrMAAWa1AAFmtwABZrgAAWa5AAFmuwABZrwAAWb7AAFm/QABZv8AAWcBAAFnBAABZwUAAWcGAAFnBwABZwgAAWcKAAFnDAABZw0AAWcOAAFnEAABZxEAAWdQAAFnUgABZ1QAAWdWAAFnWQABZ1oAAWdbAAFnXAABZ10AAWdfAAFnYQABZ2IAAWdjAAFnZQABZ2YAAWelAAFnpwABZ6kAAWerAAFnrgABZ68AAWewAAFnsQABZ7IAAWe0AAFntgABZ7cAAWe4AAFnugABZ7sAAWf6AAFn/AABZ/4AAWgAAAFoAwABaAQAAWgFAAFoBgABaAcAAWgJAAFoCwABaAwAAWgNAAFoDwABaBAAAWg1AAFoWQABaIAAAWikAAFopwABaKkAAWirAAForQABaK8AAWixAAFosgABaLUAAWjCAAFo0QABaNMAAWjVAAFo1wABaNkAAWjbAAFo3QABaN8AAWjuAAFo8QABaPQAAWj3AAFo+gABaP0AAWkAAAFpAwABaQUAAWlEAAFpRgABaUgAAWlKAAFpTQABaU4AAWlPAAFpUAABaVEAAWlTAAFpVQABaVYAAWlXAAFpWQABaVoAAWmZAAFpmwABaZ0AAWmfAAFpogABaaMAAWmkAAFppQABaaYAAWmoAAFpqgABaasAAWmsAAFprgABaa8AAWnuAAFp8AABafIAAWn0AAFp9wABafgAAWn5AAFp+gABafsAAWn9AAFp/wABagAAAWoBAAFqAwABagQAAWpDAAFqRQABakcAAWpJAAFqTAABak0AAWpOAAFqTwABalAAAWpSAAFqVAABalUAAWpWAAFqWAABalkAAWqYAAFqmgABapwAAWqeAAFqoQABaqIAAWqjAAFqpAABaqUAAWqnAAFqqQABaqoAAWqrAAFqrQABaq4AAWrtAAFq7wABavEAAWrzAAFq9gABavcAAWr4AAFq+QABavoAAWr8AAFq/gABav8AAWsAAAFrAgABawMAAWtCAAFrRAABa0YAAWtIAAFrSwABa0wAAWtNAAFrTgABa08AAWtRAAFrUwABa1QAAWtVAAFrVwABa1gAAWujAAFrxgABa+YAAWwGAAFsCAABbAoAAWwMAAFsDgABbBAAAWwRAAFsEgABbBUAAWwWAAFsGAABbBkAAWwbAAFsHQABbB4AAWwfAAFsIgABbCMAAWwoAAFsNQABbDoAAWw8AAFsPgABbEMAAWxGAAFsSQABbEsAAWxwAAFslAABbLsAAWzfAAFs4gABbOQAAWzmAAFs6AABbOoAAWzsAAFs7QABbPAAAWz9AAFtDgABbRAAAW0SAAFtFAABbRYAAW0YAAFtGgABbRwAAW0eAAFtLwABbTIAAW01AAFtOAABbTsAAW0+AAFtQQABbUQAAW1HAAFtSQABbYgAAW2KAAFtjAABbY4AAW2RAAFtkgABbZMAAW2UAAFtlQABbZcAAW2ZAAFtmgABbZsAAW2dAAFtngABbd0AAW3fAAFt4QABbeMAAW3mAAFt5wABbegAAW3pAAFt6gABbewAAW3uAAFt7wABbfAAAW3yAAFt8wABbjIAAW40AAFuNwABbjkAAW48AAFuPQABbj4AAW4/AAFuQAABbkIAAW5EAAFuRQABbkYAAW5IAAFuSQABblYAAW5XAAFuWAABbloAAW6ZAAFumwABbp0AAW6fAAFuogABbqMAAW6kAAFupQABbqYAAW6oAAFuqgABbqsAAW6sAAFurgABbq8AAW7uAAFu8AABbvIAAW70AAFu9wABbvgAAW75AAFu+gABbvsAAW79AAFu/wABbwAAAW8BAAFvAwABbwQAAW9DAAFvRQABb0cAAW9JAAFvTAABb00AAW9OAAFvTwABb1AAAW9SAAFvVAABb1UAAW9WAAFvWAABb1kAAW+YAAFvmgABb5wAAW+eAAFvoQABb6IAAW+jAAFvpAABb6UAAW+nAAFvqQABb6oAAW+rAAFvrQABb64AAW/tAAFv7wABb/EAAW/zAAFv9gABb/cAAW/4AAFv+QABb/oAAW/8AAFv/gABb/8AAXAAAAFwAgABcAMAAXAoAAFwTAABcHMAAXCXAAFwmgABcJwAAXCeAAFwoAABcKIAAXCkAAFwpQABcKgAAXC1AAFwxAABcMYAAXDIAAFwygABcMwAAXDOAAFw0AABcNIAAXDhAAFw5AABcOcAAXDqAAFw7QABcPAAAXDzAAFw9gABcPgAAXE3AAFxOQABcTsAAXE9AAFxQAABcUEAAXFCAAFxQwABcUQAAXFGAAFxSAABcUkAAXFKAAFxTAABcU0AAXGMAAFxjgABcZEAAXGTAAFxlgABcZcAAXGYAAFxmQABcZoAAXGcAAFxngABcZ8AAXGgAAFxogABcaMAAXGlAAFx5AABceYAAXHoAAFx6gABce0AAXHuAAFx7wABcfAAAXHxAAFx8wABcfUAAXH2AAFx9wABcfkAAXH6AAFyOQABcjsAAXI+AAFyQAABckMAAXJEAAFyRQABckYAAXJHAAFySQABcksAAXJMAAFyTQABck8AAXJQAAFykwABcrcAAXLbAAFy/gABcyUAAXNFAAFzbAABc5MAAXOzAAFz1wABc/sAAXP9AAF0AAABdAIAAXQEAAF0BgABdAkAAXQMAAF0DgABdBAAAXQTAAF0FQABdBcAAXQaAAF0HQABdB4AAXQnAAF0NAABdDcAAXQ5AAF0PAABdD8AAXRBAAF0ZgABdIoAAXSxAAF01QABdNgAAXTaAAF03AABdN4AAXTgAAF04gABdOMAAXTmAAF08wABdQYAAXUIAAF1CgABdQwAAXUOAAF1EAABdRIAAXUUAAF1FgABdRgAAXUrAAF1LgABdTEAAXU0AAF1NwABdToAAXU9AAF1QAABdUMAAXVGAAF1SAABdYcAAXWJAAF1jAABdY4AAXWRAAF1kgABdZMAAXWUAAF1lQABdZcAAXWZAAF1mgABdZsAAXWdAAF1ngABdacAAXWoAAF1qgABdekAAXXrAAF17QABde8AAXXyAAF18wABdfQAAXX1AAF19gABdfgAAXX6AAF1+wABdfwAAXX+AAF1/wABdj4AAXZAAAF2QwABdkUAAXZIAAF2SQABdkoAAXZLAAF2TAABdk4AAXZQAAF2UQABdlIAAXZUAAF2VQABdl4AAXZhAAF2ZAABdmYAAXZvAAF2cgABdnQAAXZ2AAF2tQABdrcAAXa5AAF2uwABdr4AAXa/AAF2wAABdsEAAXbCAAF2xAABdsYAAXbHAAF2yAABdsoAAXbLAAF3CgABdwwAAXcPAAF3EQABdxQAAXcVAAF3FgABdxcAAXcYAAF3GgABdxwAAXcdAAF3HgABdyAAAXchAAF3KgABdysAAXctAAF3bAABd24AAXdwAAF3cgABd3UAAXd2AAF3dwABd3gAAXd5AAF3ewABd30AAXd+AAF3fwABd4EAAXeCAAF3wQABd8MAAXfGAAF3yAABd8sAAXfMAAF3zQABd84AAXfPAAF30QABd9MAAXfUAAF31QABd9cAAXfYAAF35QABd+YAAXfnAAF36QABeCgAAXgqAAF4LAABeC4AAXgxAAF4MgABeDMAAXg0AAF4NQABeDcAAXg5AAF4OgABeDsAAXg9AAF4PgABeH0AAXh/AAF4ggABeIQAAXiHAAF4iAABeIkAAXiKAAF4iwABeI0AAXiPAAF4kAABeJEAAXiTAAF4lAABeKAAAXitAAF4uAABeLoAAXi8AAF4vgABeMEAAXjEAAF4zwABeNIAAXjVAAF42AABeNsAAXjeAAF44AABeOsAAXj4AAF5QwABeWYAAXmGAAF5pgABeagAAXmqAAF5rAABea4AAXmxAAF5sgABebMAAXm2AAF5twABebkAAXm6AAF5vAABeb4AAXm/AAF5wAABecMAAXnEAAF5zQABedoAAXnfAAF54QABeeMAAXnoAAF56wABee4AAXnwAAF6FQABejkAAXpgAAF6hAABeocAAXqJAAF6iwABeo0AAXqPAAF6kQABepIAAXqVAAF6ogABerMAAXq1AAF6twABerkAAXq7AAF6vQABer8AAXrBAAF6wwABetQAAXrXAAF62gABet0AAXrgAAF64wABeuYAAXrpAAF67AABeu4AAXstAAF7LwABezEAAXszAAF7NgABezcAAXs4AAF7OQABezoAAXs8AAF7PgABez8AAXtAAAF7QgABe0MAAXuCAAF7hAABe4YAAXuIAAF7iwABe4wAAXuNAAF7jgABe48AAXuRAAF7kwABe5QAAXuVAAF7lwABe5gAAXvXAAF72QABe9wAAXveAAF74QABe+IAAXvjAAF75AA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Bl78AAZfBAAGXwwABl8UAAZfIAAGXyQABl8oAAZfLAAGXzAABl84AAZfQAAGX0QABl9IAAZfUAAGX1QABmBQAAZgWAAGYGAABmBoAAZgdAAGYHgABmB8AAZggAAGYIQABmCMAAZglAAGYJgABmCcAAZgpAAGYKgABmGkAAZhrAAGYbQABmG8AAZhyAAGYcwABmHQAAZh1AAGYdgABmHgAAZh6AAGYewABmHwAAZh+AAGYfwABmL4AAZjAAAGYwgABmMQAAZjHAAGYyAABmMkAAZjKAAGYywABmM0AAZjPAAGY0AABmNEAAZjTAAGY1AABmR8AAZlCAAGZYgABmYIAAZmEAAGZhgABmYgAAZmKAAGZjQABmY4AAZmPAAGZkgABmZMAAZmVAAGZlgABmZgAAZmbAAGZnAABmZ0AAZmgAAGZoQABmaYAAZmzAAGZuAABmboAAZm8AAGZwQABmcQAAZnHAAGZyQABme4AAZoSAAGaOQABml0AAZpgAAGaYgABmmQAAZpmAAGaaAABmmoAAZprAAGabgABmnsAAZqMAAGajgABmpAAAZqSAAGalAABmpYAAZqYAAGamgABmpwAAZqtAAGasAABmrMAAZq2AAGauQABmrwAAZq/AAGawgABmsUAAZrHAAGbBgABmwgAAZsKAAGbDAABmw8AAZsQAAGbEQABmxIAAZsTAAGbFQABmxcAAZsYAAGbGQABmxsAAZscAAGbWwABm10AAZtfAAGbYQABm2QAAZtlAAGbZgABm2cAAZtoAAGbagABm2wAAZttAAGbbgABm3AAAZtxAAGbsAABm7IAAZu1AAGbtwABm7oAAZu7AAGbvAABm70AAZu+AAGbwAABm8IAAZvDAAGbxAABm8YAAZvHAAGb1AABm9UAAZvWAAGb2AABnBcAAZwZAAGcGwABnB0AAZwgAAGcIQABnCIAAZwjAAGcJAABnCYAAZwoAAGcKQABnCoAAZwsAAGcLQABnGwAAZxuAAGccAABnHIAAZx1AAGcdgABnHcAAZx4AAGceQABnHsAAZx9AAGcfgABnH8AAZyBAAGcggABnMEAAZzDAAGcxQABnMcAAZzKAAGcywABnMwAAZzNAAGczgABnNAAAZzSAAGc0wABnNQAAZzWAAGc1wABnRYAAZ0YAAGdGgABnRwAAZ0fAAGdIAABnSEAAZ0iAAGdIwABnSUAAZ0nAAGdKAABnSkAAZ0rAAGdLAABnWsAAZ1tAAGdbwABnXEAAZ10AAGddQABnXYAAZ13AAGdeAABnXoAAZ18AAGdfQABnX4AAZ2AAAGdgQABnaYAAZ3KAAGd8QABnhUAAZ4YAAGeGgABnhwAAZ4eAAGeIAABniIAAZ4jAAGeJgABnjMAAZ5CAAGeRAABnkYAAZ5IAAGeSgABnkwAAZ5OAAGeUAABnl8AAZ5iAAGeZQABnmgAAZ5rAAGebgABnnEAAZ50AAGedgABnrUAAZ63AAGeuQABnrsAAZ6+AAGevwABnsAAAZ7BAAGewgABnsQAAZ7GAAGexwABnsgAAZ7KAAGeywABnwoAAZ8MAAGfDgABnxAAAZ8TAAGfFAABnxUAAZ8WAAGfFwABnxkAAZ8bAAGfHAABnx0AAZ8fAAGfIAABn18AAZ9hAAGfYwABn2UAAZ9oAAGfaQABn2oAAZ9rAAGfbAABn24AAZ9wAAGfcQABn3IAAZ90AAGfdQABn7QAAZ+2AAGfuAABn7oAAZ+9AAGfvgABn78AAZ/AAAGfwQABn8MAAZ/FAAGfxgABn8cAAZ/JAAGfygABoAkAAaALAAGgDQABoA8AAaASAAGgEwABoBQAAaAVAAGgFgABoBgAAaAaAAGgGwABoBwAAaAeAAGgHwABoF4AAaBgAAGgYgABoGQAAaBnAAGgaAABoGkAAaBqAAGgawABoG0AAaBvAAGgcAABoHEAAaBzAAGgdAABoLMAAaC1AAGgtwABoLkAAaC8AAGgvQABoL4AAaC/AAGgwAABoMIAAaDEAAGgxQABoMYAAaDIAAGgyQABoNIAAaDTAAGg1QABoRQAAaEWAAGhGAABoRoAAaEdAAGhHgABoR8AAaEgAAGhIQABoSMAAaElAAGhJgABoScAAaEpAAGhKgABoWkAAaFrAAGhbQABoW8AAaFyAAGhcwABoXQAAaF1AAGhdgABoXgAAaF6AAGhewABoXwAAaF+AAGhfwABob4AAaHAAAGhwwABocUAAaHIAAGhyQABocoAAaHLAAGhzAABoc4AAaHQAAGh0QABodIAAaHUAAGh1QABoiAAAaJDAAGiYwABooMAAaKFAAGihwABookAAaKLAAGijQABoo4AAaKPAAGikgABopMAAaKVAAGilgABopgAAaKaAAGimwABopwAAaKfAAGioAABoqUAAaKyAAGitwABorkAAaK7AAGiwAABosMAAaLGAAGiyAABou0AAaMRAAGjOAABo1wAAaNfAAGjYQABo2MAAaNlAAGjZwABo2kAAaNqAAGjbQABo3oAAaOLAAGjjQABo48AAaORAAGjkwABo5UAAaOXAAGjmQABo5sAAaOsAAGjrwABo7IAAaO1AAGjuAABo7sAAaO+AAGjwQABo8QAAaPGAAGkBQABpAcAAaQJAAGkCwABpA4AAaQPAAGkEAABpBEAAaQSAAGkFAABpBYAAaQXAAGkGAABpBoAAaQbAAGkWgABpFwAAaReAAGkYAABpGMAAaRkAAGkZQABpGYAAaRnAAGkaQABpGsAAaRsAAGkbQABpG8AAaRwAAGkrwABpLEAAaS0AAGktgABpLkAAaS6AAGkuwABpLwAAaS9AAGkvwABpMEAAaTCAAGkwwABpMUAAaTGAAGk0wABpNQAAaTVAAGk1wABpRYAAaUYAAGlGgABpRwAAaUfAAGlIAABpSEAAaUiAAGlIwABpSUAAaUnAAGlKAABpSkAAaUrAAGlLAABpWsAAaVtAAGlbwABpXEAAaV0AAGldQABpXYAAaV3AAGleAABpXoAAaV8AAGlfQABpX4AAaWAAAGlgQABpcAAAaXCAAGlxAABpcYAAaXJAAGlygABpcsAAaXMAAGlzQABpc8AAaXRAAGl0gABpdMAAaXVAAGl1gABphUAAaYXAAGmGQABphsAAaYeAAGmHwABpiAAAaYhAAGmIgABpiQAAaYmAAGmJwABpigAAaYqAAGmKwABpmoAAaZsAAGmbgABpnAAAaZzAAGmdAABpnUAAaZ2AAGmdwABpnkAAaZ7AAGmfAABpn0AAaZ/AAGmgAABpqUAAabJAAGm8AABpxQAAacXAAGnGQABpxsAAacdAAGnHwABpyEAAaciAAGnJQABpzIAAac/AAGnQQABp0MAAadFAAGnRwABp0kAAadLAAGnWAABp1sAAadeAAGnYQABp2QAAadnAAGnagABp2wAAaerAAGnrQABp7AAAaeyAAGntQABp7YAAae3AAGnuAABp7kAAae7AAGnvQABp74AAae/AAGnwQABp8IAAagBAAGoAwABqAUAAagHAAGoCgABqAsAAagMAAGoDQABqA4AAagQAAGoEgABqBMAAagUAAGoFgABqBcAAahWAAGoWAABqFoAAahcAAGoXwABqGAAAahhAAGoYgABqGMAAahlAAGoZwABqGgAAahpAAGoawABqGwAAairAAGorQABqK8AAaixAAGotAABqLUAAai2AAGotwABqLgAAai6AAGovAABqL0AAai+AAGowAABqMEAAakAAAGpAgABqQQAAakGAAGpCQABqQoAAakLAAGpDAABqQ0AAakPAAGpEQABqRIAAakTAAGpFQABqRYAAalVAAGpVwABqVkAAalbAAGpXgABqV8AAalgAAGpYQABqWIAAalkAAGpZgABqWcAAaloAAGpagABqWsAAam2AAGp2QABqfkAAaoZAAGqGwABqh0AAaofAAGqIQABqiMAAaokAAGqJQABqigAAaopAAGqKwABqiwAAaouAAGqMAABqjEAAaoyAAGqNQABqjYAAao7AAGqSAABqk0AAapPAAGqUQABqlYAAapZAAGqXAABql4AAaqDAAGqpwABqs4AAaryAAGq9QABqvcAAar5AAGq+wABqv0AAar/AAGrAAABqwMAAasQAAGrIQABqyMAAaslAAGrJwABqykAAasrAAGrLQABqy8AAasxAAGrQgABq0UAAatIAAGrSwABq04AAatRAAGrVAABq1cAAataAAGrXAABq5sAAaudAAGrnwABq6EAAaukAAGrpQABq6YAAaunAAGrqAABq6oAAausAAGrrQABq64AAauwAAGrsQABq/AAAavyAAGr9AABq/YAAav5AAGr+gABq/sAAav8AAGr/QABq/8AAawBAAGsAgABrAMAAawFAAGsBgABrEUAAaxHAAGsSgABrEwAAaxPAAGsUAABrFEAAaxSAAGsUwABrFUAAaxXAAGsWAABrFkAAaxbAAGsXAABrGkAAaxqAAGsawABrG0AAaysAAGsrgABrLAAAayyAAGstQABrLYAAay3AAGsuAABrLkAAay7AAGsvQABrL4AAay/AAGswQABrMIAAa0BAAGtAwABrQUAAa0HAAGtCgABrQsAAa0MAAGtDQABrQ4AAa0QAAGtEgABrRMAAa0UAAGtFgABrRcAAa1WAAGtWAABrVoAAa1cAAGtXwABrWAAAa1hAAGtYgABrWMAAa1lAAGtZwABrWgAAa1pAAGtawABrWwAAa2rAAGtrQABra8AAa2xAAGttAABrbUAAa22AAGttwABrbgAAa26AAGtvAABrb0AAa2+AAGtwAABrcEAAa4AAAGuAgABrgQAAa4GAAGuCQABrgoAAa4LAAGuDAABrg0AAa4PAAGuEQABrhIAAa4TAAGuFQABrhYAAa47AAGuXwABroYAAa6qAAGurQABrq8AAa6xAAGuswABrrUAAa63AAGuuAABrrsAAa7IAAGu1wABrtkAAa7bAAGu3QABrt8AAa7hAAGu4wABruUAAa70AAGu9wABrvoAAa79AAGvAAABrwMAAa8GAAGvCQABrwsAAa9KAAGvTAABr04AAa9QAAGvUwABr1QAAa9VAAGvVgABr1cAAa9ZAAGvWwABr1wAAa9dAAGvXwABr2AAAa+fAAGvoQABr6MAAa+lAAGvqAABr6kAAa+qAAGvqwABr6wAAa+uAAGvsAABr7EAAa+yAAGvtAABr7UAAa/0AAGv9gABr/gAAa/6AAGv/QABr/4AAa//AAGwAAABsAEAAbADAAGwBQABsAYAAbAHAAGwCQABsAoAAbBJAAGwSwABsE0AAbBPAAGwUgABsFMAAbBUAAGwVQABsFYAAbBYAAGwWgABsFsAAbBcAAGwXgABsF8AAbCeAAGwoAABsKIAAbCkAAGwpwABsKgAAbCpAAGwqgABsKsAAbCtAAGwrwABsLAAAbCxAAGwswABsLQAAbDzAAGw9QABsPcAAbD5AAGw/AABsP0AAbD+AAGw/wABsQAAAbECAAGxBAABsQUAAbEGAAGxCAABsQkAAbFIAAGxSgABsUwAAbFOAAGxUQABsVIAAbFTAAGxVAABsVUAAbFXAAGxWQABsVoAAbFbAAGxXQABsV4AAbGpAAGxzAABsewAAbIMAAGyDgABshAAAbISAAGyFAABshYAAbIXAAGyGAABshsAAbIcAAGyHgABsh8AAbIhAAGyIwABsiQAAbIlAAGyKAABsikAAbIuAAGyOwABskAAAbJCAAGyRAABskkAAbJMAAGyTwABslEAAbJ2AAGymgABssEAAbLlAAGy6AABsuoAAbLsAAGy7gABsvAAAbLyAAGy8wABsvYAAbMDAAGzFAABsxYAAbMYAAGzGgABsxwAAbMeAAGzIAABsyIAAbMkAAGzNQABszgAAbM7AAGzPgABs0EAAbNEAAGzRwABs0oAAbNNAAGzTwABs44AAbOQAAGzkgABs5QAAbOXAAGzmAABs5kAAbOaAAGzmwABs50AAbOfAAGzoAABs6EAAbOjAAGzpAABs+MAAbPlAAGz5wABs+kAAbPsAAGz7QABs+4AAbPvAAGz8AABs/IAAbP0AAGz9QABs/YAAbP4AAGz+QABtDgAAbQ6AAG0PQABtD8AAbRCAAG0QwABtEQAAbRFAAG0RgABtEgAAbRKAAG0SwABtEwAAbROAAG0TwABtFwAAbRdAAG0XgABtGAAAbSfAAG0oQABtKMAAbSlAAG0qAABtKkAAbSqAAG0qwABtKwAAbSuAAG0sAABtLEAAbSyAAG0tAABtLUAAbT0AAG09gABtPgAAbT6AAG0/QABtP4AAbT/AAG1AAABtQEAAbUDAAG1BQABtQYAAbUHAAG1CQABtQoAAbVJAAG1SwABtU0AAbVPAAG1UgABtVMAAbVUAAG1VQABtVYAAbVYAAG1WgABtVsAAbVcAAG1XgABtV8AAbWeAAG1oAABtaIAAbWkAAG1pwABtagAAbWpAAG1qgABtasAAbWtAAG1rwABtbAAAbWxAAG1swABtbQAAbXzAAG19QABtfcAAbX5AAG1/AABtf0AAbX+AAG1/wABtgAAAbYCAAG2BAABtgUAAbYGAAG2CAABtgkAAbYuAAG2UgABtnkAAbadAAG2oAABtqIAAbakAAG2pgABtqgAAbaqAAG2qwABtq4AAba7AAG2ygABtswAAbbOAAG20AABttIAAbbUAAG21gABttgAAbbnAAG26gABtu0AAbbwAAG28wABtvYAAbb5AAG2/AABtv4AAbc9AAG3PwABt0IAAbdEAAG3RwABt0gAAbdJAAG3SgABt0sAAbdNAAG3TwABt1AAAbdRAAG3UwABt1QAAbeTAAG3lQABt5cAAbeZAAG3nAABt50AAbeeAAG3nwABt6AAAbeiAAG3pAABt6UAAbemAAG3qAABt6kAAbfoAAG36gABt+wAAbfuAAG38QABt/IAAbfzAAG39AABt/UAAbf3AAG3+QABt/oAAbf7AAG3/QABt/4AAbg9AAG4PwABuEIAAbhEAAG4RwABuEgAAbhJAAG4SgABuEsAAbhNAAG4TwABuFAAAbhRAAG4UwABuFQAAbiTAAG4lQABuJcAAbiZAAG4nAABuJ0AAbieAAG4nwABuKAAAbiiAAG4pAABuKUAAbimAAG4qAABuKkAAbjoAAG46gABuOwAAbjuAAG48QABuPIAAbjzAAG49AABuPUAAbj3AAG4+QABuPoAAbj7AAG4/QABuP4AAbk9AAG5PwABuUEAAblDAAG5RgABuUcAAblIAAG5SQABuUoAAblMAAG5TgABuU8AAblQAAG5UgABuVMAAbmeAAG5wQABueEAAboBAAG6AwABugUAAboHAAG6CQABugsAAboMAAG6DQABuhAAAboRAAG6EwABuhQAAboWAAG6GAABuhkAAboaAAG6HQABuh4AAbonAAG6NAABujkAAbo7AAG6PQABukIAAbpFAAG6SAABukoAAbpvAAG6kwABuroAAbreAAG64QABuuMAAbrlAAG65wABuukAAbrrAAG67AABuu8AAbr8AAG7DQABuw8AAbsRAAG7EwABuxUAAbsXAAG7GQABuxsAAbsdAAG7LgABuzEAAbs0AAG7NwABuzoAAbs9AAG7QAABu0MAAbtGAAG7SAABu4cAAbuJAAG7iwABu40AAbuQAAG7kQABu5IAAbuTAAG7lAABu5YAAbuYAAG7mQABu5oAAbucAAG7nQABu9wAAbveAAG74AABu+IAAbvlAAG75gABu+cAAbvoAAG76QABu+sAAbvtAAG77gABu+8AAbvxAAG78gABvDEAAbwzAAG8NgABvDgAAbw7AAG8PAABvD0AAbw+AAG8PwABvEEAAbxDAAG8RAABvEUAAbxHAAG8SAABvFUAAbxWAAG8VwABvFkAAbyYAAG8mgABvJwAAbyeAAG8oQABvKIAAbyjAAG8pAABvKUAAbynAAG8qQABvKoAAbyrAAG8rQABvK4AAbztAAG87wABvPEAAbzzAAG89gABvPcAAbz4AAG8+QABvPoAAbz8AAG8/gABvP8AAb0AAAG9AgABvQMAAb1CAAG9RAABvUYAAb1IAAG9SwABvUwAAb1NAAG9TgABvU8AAb1RAAG9UwABvVQAAb1VAAG9VwABvVgAAb2XAAG9mQABvZsAAb2dAAG9oAABvaEAAb2iAAG9owABvaQAAb2mAAG9qAABvakAAb2qAAG9rAABva0AAb3sAAG97gABvfAAAb3yAAG99QABvfYAAb33AAG9+AABvfkAAb37AAG9/QABvf4AAb3/AAG+AQABvgIAAb4nAAG+SwABvnIAAb6WAAG+mQABvpsAAb6dAAG+nwABvqEAAb6jAAG+pAABvqcAAb60AAG+wwA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B1NoAAdTbAAHU3QAB1N4AAdUdAAHVHwAB1SEAAdUjAAHVJgAB1ScAAdUoAAHVKQAB1SoAAdUsAAHVLgAB1S8AAdUwAAHVMgAB1TMAAdVyAAHVdAAB1XYAAdV4AAHVewAB1XwAAdV9AAHVfgAB1X8AAdWBAAHVgwAB1YQAAdWFAAHVhwAB1YgAAdXHAAHVyQAB1csAAdXNAAHV0AAB1dEAAdXSAAHV0wAB1dQAAdXWAAHV2AAB1dkAAdXaAAHV3AAB1d0AAdYCAAHWJgAB1k0AAdZxAAHWdAAB1nYAAdZ4AAHWegAB1nwAAdZ+AAHWfwAB1oIAAdaPAAHWngAB1qAAAdaiAAHWpAAB1qYAAdaoAAHWqgAB1qwAAda7AAHWvgAB1sEAAdbEAAHWxwAB1soAAdbNAAHW0AAB1tIAAdcRAAHXEwAB1xUAAdcXAAHXGgAB1xsAAdccAAHXHQAB1x4AAdcgAAHXIgAB1yMAAdckAAHXJgAB1ycAAddmAAHXaAAB12oAAddsAAHXbwAB13AAAddxAAHXcgAB13MAAdd1AAHXdwAB13gAAdd5AAHXewAB13wAAde7AAHXvQAB178AAdfBAAHXxAAB18UAAdfGAAHXxwAB18gAAdfKAAHXzAAB180AAdfOAAHX0AAB19EAAdgQAAHYEgAB2BQAAdgWAAHYGQAB2BoAAdgbAAHYHAAB2B0AAdgfAAHYIQAB2CIAAdgjAAHYJQAB2CYAAdhlAAHYZwAB2GkAAdhrAAHYbgAB2G8AAdhwAAHYcQAB2HIAAdh0AAHYdgAB2HcAAdh4AAHYegAB2HsAAdi6AAHYvAAB2L4AAdjAAAHYwwAB2MQAAdjFAAHYxgAB2McAAdjJAAHYywAB2MwAAdjNAAHYzwAB2NAAAdkPAAHZEQAB2RMAAdkVAAHZGAAB2RkAAdkaAAHZGwAB2RwAAdkeAAHZIAAB2SEAAdkiAAHZJAAB2SUAAdlwAAHZkwAB2bMAAdnTAAHZ1QAB2dcAAdnZAAHZ2wAB2d0AAdneAAHZ3wAB2eIAAdnjAAHZ5QAB2eYAAdnoAAHZ6gAB2esAAdnsAAHZ7wAB2fAAAdn1AAHaAgAB2gcAAdoJAAHaCwAB2hAAAdoTAAHaFgAB2hgAAdo9AAHaYQAB2ogAAdqsAAHarwAB2rEAAdqzAAHatQAB2rcAAdq5AAHaugAB2r0AAdrKAAHa2wAB2t0AAdrfAAHa4QAB2uMAAdrlAAHa5wAB2ukAAdrrAAHa/AAB2v8AAdsCAAHbBQAB2wgAAdsLAAHbDgAB2xEAAdsUAAHbFgAB21UAAdtXAAHbWQAB21sAAdteAAHbXwAB22AAAdthAAHbYgAB22QAAdtmAAHbZwAB22gAAdtqAAHbawAB26oAAdusAAHbrgAB27AAAduzAAHbtAAB27UAAdu2AAHbtwAB27kAAdu7AAHbvAAB270AAdu/AAHbwAAB2/8AAdwBAAHcBAAB3AYAAdwJAAHcCgAB3AsAAdwMAAHcDQAB3A8AAdwRAAHcEgAB3BMAAdwVAAHcFgAB3CMAAdwkAAHcJQAB3CcAAdxmAAHcaAAB3GoAAdxsAAHcbwAB3HAAAdxxAAHccgAB3HMAAdx1AAHcdwAB3HgAAdx5AAHcewAB3HwAAdy7AAHcvQAB3L8AAdzBAAHcxAAB3MUAAdzGAAHcxwAB3MgAAdzKAAHczAAB3M0AAdzOAAHc0AAB3NEAAd0QAAHdEgAB3RQAAd0WAAHdGQAB3RoAAd0bAAHdHAAB3R0AAd0fAAHdIQAB3SIAAd0jAAHdJQAB3SYAAd1lAAHdZwAB3WkAAd1rAAHdbgAB3W8AAd1wAAHdcQAB3XIAAd10AAHddgAB3XcAAd14AAHdegAB3XsAAd26AAHdvAAB3b4AAd3AAAHdwwAB3cQAAd3FAAHdxgAB3ccAAd3JAAHdywAB3cwAAd3NAAHdzwAB3dAAAd31AAHeGQAB3kAAAd5kAAHeZwAB3mkAAd5rAAHebQAB3m8AAd5xAAHecgAB3nUAAd6CAAHejwAB3pEAAd6TAAHelQAB3pcAAd6ZAAHemwAB3qgAAd6rAAHergAB3rEAAd60AAHetwAB3roAAd68AAHe+wAB3v0AAd8AAAHfAgAB3wUAAd8GAAHfBwAB3wgAAd8JAAHfCwAB3w0AAd8OAAHfDwAB3xEAAd8SAAHfUQAB31MAAd9VAAHfVwAB31oAAd9bAAHfXAAB310AAd9eAAHfYAAB32IAAd9jAAHfZAAB32YAAd9nAAHfpgAB36gAAd+qAAHfrAAB368AAd+wAAHfsQAB37IAAd+zAAHftQAB37cAAd+4AAHfuQAB37sAAd+8AAHf+wAB3/0AAeAAAAHgAgAB4AUAAeAGAAHgBwAB4AgAAeAJAAHgCwAB4A0AAeAOAAHgDwAB4BEAAeASAAHgUQAB4FMAAeBVAAHgVwAB4FoAAeBbAAHgXAAB4F0AAeBeAAHgYAAB4GIAAeBjAAHgZAAB4GYAAeBnAAHgpgAB4KgAAeCqAAHgrAAB4K8AAeCwAAHgsQAB4LIAAeCzAAHgtQAB4LcAAeC4AAHguQAB4LsAAeC8AAHgxQAB4MYAAeDIAAHhBwAB4QkAAeELAAHhDQAB4Q8AAeEQAAHhEQAB4RIAAeETAAHhFQAB4RcAAeEYAAHhGQAB4RsAAeEcAAHhWwAB4V0AAeFfAAHhYQAB4WMAAeFkAAHhZQAB4WYAAeFnAAHhaQAB4WsAAeFsAAHhbQAB4W8AAeFwAAHhrwAB4bEAAeGzAAHhtQAB4bcAAeG4AAHhuQAB4boAAeG7AAHhvQAB4b8AAeHAAAHhwQAB4cMAAeHEAAHiDwAB4jIAAeJSAAHicgAB4nQAAeJ2AAHieAAB4noAAeJ8AAHifQAB4n4AAeKBAAHiggAB4oQAAeKFAAHihwAB4okAAeKKAAHiiwAB4o4AAeKPAAHilAAB4qEAAeKmAAHiqAAB4qoAAeKvAAHisgAB4rUAAeK3AAHi3AAB4wAAAeMnAAHjSwAB404AAeNQAAHjUgAB41QAAeNWAAHjWAAB41kAAeNcAAHjaQAB43oAAeN8AAHjfgAB44AAAeOCAAHjhAAB44YAAeOIAAHjigAB45sAAeOeAAHjoQAB46QAAeOnAAHjqgAB460AAeOwAAHjswAB47UAAeP0AAHj9gAB4/gAAeP6AAHj/QAB4/4AAeP/AAHkAAAB5AEAAeQDAAHkBQAB5AYAAeQHAAHkCQAB5AoAAeRJAAHkSwAB5E0AAeRPAAHkUgAB5FMAAeRUAAHkVQAB5FYAAeRYAAHkWgAB5FsAAeRcAAHkXgAB5F8AAeSeAAHkoAAB5KMAAeSlAAHkqAAB5KkAAeSqAAHkqwAB5KwAAeSuAAHksAAB5LEAAeSyAAHktAAB5LUAAeTCAAHkwwAB5MQAAeTGAAHlBQAB5QcAAeUJAAHlCwAB5Q4AAeUPAAHlEAAB5REAAeUSAAHlFAAB5RYAAeUXAAHlGAAB5RoAAeUbAAHlWgAB5VwAAeVeAAHlYAAB5WMAAeVkAAHlZQAB5WYAAeVnAAHlaQAB5WsAAeVsAAHlbQAB5W8AAeVwAAHlrwAB5bEAAeWzAAHltQAB5bgAAeW5AAHlugAB5bsAAeW8AAHlvgAB5cAAAeXBAAHlwgAB5cQAAeXFAAHmBAAB5gYAAeYIAAHmCgAB5g0AAeYOAAHmDwAB5hAAAeYRAAHmEwAB5hUAAeYWAAHmFwAB5hkAAeYaAAHmWQAB5lsAAeZdAAHmXwAB5mIAAeZjAAHmZAAB5mUAAeZmAAHmaAAB5moAAeZrAAHmbAAB5m4AAeZvAAHmlAAB5rgAAebfAAHnAwAB5wYAAecIAAHnCgAB5wwAAecOAAHnEAAB5xEAAecUAAHnIQAB5zAAAecyAAHnNAAB5zYAAec4AAHnOgAB5zwAAec+AAHnTQAB51AAAedTAAHnVgAB51kAAedcAAHnXwAB52IAAedkAAHnowAB56UAAeenAAHnqQAB56wAAeetAAHnrgAB568AAeewAAHnsgAB57QAAee1AAHntgAB57gAAee5AAHn+AAB5/oAAef8AAHn/gAB6AEAAegCAAHoAwAB6AQAAegFAAHoBwAB6AkAAegKAAHoCwAB6A0AAegOAAHoTQAB6E8AAehRAAHoUwAB6FYAAehXAAHoWAAB6FkAAehaAAHoXAAB6F4AAehfAAHoYAAB6GIAAehjAAHoogAB6KQAAeinAAHoqQAB6KwAAeitAAHorgAB6K8AAeiwAAHosgAB6LQAAei1AAHotgAB6LgAAei5AAHo+AAB6PoAAej8AAHo/gAB6QEAAekCAAHpAwAB6QQAAekFAAHpBwAB6QkAAekKAAHpCwAB6Q0AAekOAAHpTQAB6U8AAelSAAHpVAAB6VcAAelYAAHpWQAB6VoAAelbAAHpXQAB6V8AAelgAAHpYQAB6WMAAelkAAHpgAAB6b8AAenBAAHpwwAB6cUAAenIAAHpyQAB6coAAenLAAHpzAAB6c4AAenQAAHp0QAB6dIAAenUAAHp1QAB6iAAAepDAAHqYwAB6oMAAeqFAAHqhwAB6okAAeqLAAHqjQAB6o4AAeqPAAHqkgAB6pMAAeqVAAHqlgAB6pgAAeqaAAHqmwAB6pwAAeqfAAHqoAAB6qUAAeqyAAHqtwAB6rkAAeq7AAHqwAAB6sMAAerGAAHqyAAB6u0AAesRAAHrOAAB61wAAetfAAHrYQAB62MAAetlAAHrZwAB62kAAetqAAHrbQAB63oAAeuLAAHrjQAB648AAeuRAAHrkwAB65UAAeuXAAHrmQAB65sAAeusAAHrrwAB67IAAeu1AAHruAAB67sAAeu+AAHrwQAB68QAAevGAAHsBQAB7AcAAewJAAHsCwAB7A4AAewPAAHsEAAB7BEAAewSAAHsFAAB7BYAAewXAAHsGAAB7BoAAewbAAHsWgAB7FwAAexeAAHsYAAB7GMAAexkAAHsZQAB7GYAAexnAAHsaQAB7GsAAexsAAHsbQAB7G8AAexwAAHsrwAB7LEAAey0AAHstgAB7LkAAey6AAHsuwAB7LwAAey9AAHsvwAB7MEAAezCAAHswwAB7MUAAezGAAHs0wAB7NQAAezVAAHs1wAB7RYAAe0YAAHtGgAB7RwAAe0fAAHtIAAB7SEAAe0iAAHtIwAB7SUAAe0nAAHtKAAB7SkAAe0rAAHtLAAB7WsAAe1tAAHtbwAB7XEAAe10AAHtdQAB7XYAAe13AAHteAAB7XoAAe18AAHtfQAB7X4AAe2AAAHtgQAB7cAAAe3CAAHtxAAB7cYAAe3JAAHtygAB7csAAe3MAAHtzQAB7c8AAe3RAAHt0gAB7dMAAe3VAAHt1gAB7hUAAe4XAAHuGQAB7hsAAe4eAAHuHwAB7iAAAe4hAAHuIgAB7iQAAe4mAAHuJwAB7igAAe4qAAHuKwAB7moAAe5sAAHubgAB7nAAAe5zAAHudAAB7nUAAe52AAHudwAB7nkAAe57AAHufAAB7n0AAe5/AAHugAAB7qUAAe7JAAHu8AAB7xQAAe8XAAHvGQAB7xsAAe8dAAHvHwAB7yEAAe8iAAHvJQAB7zIAAe9BAAHvQwAB70UAAe9HAAHvSQAB70sAAe9NAAHvTwAB714AAe9hAAHvZAAB72cAAe9qAAHvbQAB73AAAe9zAAHvdQAB77QAAe+2AAHvuAAB77oAAe+9AAHvvgAB778AAe/AAAHvwQAB78MAAe/FAAHvxgAB78cAAe/JAAHvygAB8AkAAfALAAHwDQAB8A8AAfASAAHwEwAB8BQAAfAVAAHwFgAB8BgAAfAaAAHwGwAB8BwAAfAeAAHwHwAB8F4AAfBgAAHwYgAB8GQAAfBnAAHwaAAB8GkAAfBqAAHwawAB8G0AAfBvAAHwcAAB8HEAAfBzAAHwdAAB8LMAAfC1AAHwtwAB8LkAAfC8AAHwvQAB8L4AAfC/AAHwwAAB8MIAAfDEAAHwxQAB8MYAAfDIAAHwyQAB8QgAAfEKAAHxDAAB8Q4AAfERAAHxEgAB8RMAAfEUAAHxFQAB8RcAAfEZAAHxGgAB8RsAAfEdAAHxHgAB8V0AAfFfAAHxYQAB8WMAAfFmAAHxZwAB8WgAAfFpAAHxagAB8WwAAfFuAAHxbwAB8XAAAfFyAAHxcwAB8bIAAfG0AAHxtgAB8bgAAfG7AAHxvAAB8b0AAfG+AAHxvwAB8cEAAfHDAAHxxAAB8cUAAfHHAAHxyAAB8hMAAfI2AAHyVgAB8nYAAfJ4AAHyegAB8nwAAfJ+AAHygAAB8oEAAfKCAAHyhQAB8oYAAfKIAAHyiQAB8osAAfKNAAHyjgAB8o8AAfKSAAHykwAB8pwAAfKpAAHyrgAB8rAAAfKyAAHytwAB8roAAfK9AAHyvwAB8uQAAfMIAAHzLwAB81MAAfNWAAHzWAAB81oAAfNcAAHzXgAB82AAAfNhAAHzZAAB83EAAfOCAAHzhAAB84YAAfOIAAHzigAB84wAAfOOAAHzkAAB85IAAfOjAAHzpgAB86kAAfOsAAHzrwAB87IAAfO1AAHzuAAB87sAAfO9AAHz/AAB8/4AAfQAAAH0AgAB9AUAAfQGAAH0BwAB9AgAAfQJAAH0CwAB9A0AAfQOAAH0DwAB9BEAAfQSAAH0UQAB9FMAAfRVAAH0VwAB9FoAAfRbAAH0XAAB9F0AAfReAAH0YAAB9GIAAfRjAAH0ZAAB9GYAAfRnAAH0pgAB9KgAAfSrAAH0rQAB9LAAAfSxAAH0sgAB9LMAAfS0AAH0tgAB9LgAAfS5AAH0ugAB9LwAAfS9AAH0ygAB9MsAAfTMAAH0zgAB9Q0AAfUPAAH1EQAB9RMAAfUWAAH1FwAB9RgAAfUZAAH1GgAB9RwAAfUeAAH1HwAB9SAAAfUiAAH1IwAB9WIAAfVkAAH1ZgAB9WgAAfVrAAH1bAAB9W0AAfVuAAH1bwAB9XEAAfVzAAH1dAAB9XUAAfV3AAH1eAAB9bcAAfW5AAH1uwAB9b0AAfXAAAH1wQAB9cIAAfXDAAH1xAAB9cYAAfXIAAH1yQAB9coAAfXMAAH1zQAB9gwAAfYOAAH2EAAB9hIAAfYVAAH2FgAB9hcAAfYYAAH2GQAB9hsAAfYdAAH2HgAB9h8AAfYhAAH2IgAB9mEAAfZjAAH2ZQAB9mcAAfZqAAH2awAB9mwAAfZtAAH2bgAB9nAAAfZyAAH2cwAB9nQAAfZ2AAH2dwAB9pwAAfbAAAH25wAB9wsAAfcOAAH3EAAB9xIAAfcUAAH3FgAB9xgAAfcZAAH3HAAB9ykAAfc4AAH3OgAB9zwAAfc+AAH3QAAB90IAAfdEAAH3RgAB91UAAfdYAAH3WwAB914AAfdhAAH3ZAAB92cAAfdqAAH3bAAB96sAAfetAAH3rwAB97EAAfe0AAH3tQAB97YAAfe3AAH3uAAB97oAAfe8AAH3vQAB974AAffAAAH3wQAB+AAAAfgCAAH4BAAB+AYAAfgJAAH4CgAB+AsAAfgMAAH4DQAB+A8AAfgRAAH4EgAB+BMAAfgVAAH4FgAB+FUAAfhXAAH4WQAB+FsAAfheAAH4XwAB+GAAAfhhAAH4YgAB+GQAAfhmAAH4ZwAB+GgAAfhqAAH4awAB+KoAAfisAAH4rgAB+LAAAfizAAH4tAAB+LUAAfi2AAH4twAB+LkAAfi7AAH4vAAB+L0AAfi/AAH4wAAB+P8AAfkBAAH5AwAB+QUAAfkIAAH5CQAB+QoAAfkLAAH5DAAB+Q4AAfkQAAH5EQAB+RIAAfkUAAH5FQAB+VQAAflWAAH5WAAB+VoAAfldAAH5XgAB+V8AAflgAAH5YQAB+WMAAfllAAH5ZgAB+WcAAflpAAH5agAB+akAAfmrAAH5rQAB+a8AAfmyAAH5swAB+bQAAfm1AAH5tgAB+bgAAfm6AAH5uwAB+bwAAfm+AAH5vwAB+cgAAfnJAAH5ywAB+g4AAfoyAAH6VgAB+nkAAfqgAAH6wAAB+ucAAfsOAAH7LgAB+1IAAft2AAH7eAAB+3sAAft9AAH7fwAB+4EAAfuEAAH7hwAB+4kAAfuLAAH7jgAB+5AAAfuSAAH7lQAB+5gAAfuZAAH7ngAB+6sAAfuuAAH7sAAB+7MAAfu2AAH7uAAB+90AAfwBAAH8KAAB/EwAAfxPAAH8UQAB/FMAAfxVAAH8VwAB/FkAAfxaAAH8XQAB/GoAAfx9AAH8fwAB/IEAAfyDAAH8hQAB/IcAAfyJAAH8iwAB/I0AAfyPAAH8ogAB/KUAAfyoAAH8qwAB/K4AAfyxAAH8tAAB/LcAAfy6AAH8vQAB/L8AAfz+AAH9AAAB/QMAAf0FAAH9CAA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CB8YAAgfHAAIHyQACB8oAAggJAAIICwACCA0AAggPAAIIEgACCBMAAggUAAIIFQACCBYAAggYAAIIGgACCBsAAggcAAIIHgACCB8AAgheAAIIYAACCGIAAghkAAIIZwACCGgAAghpAAIIagACCGsAAghtAAIIbwACCHAAAghxAAIIcwACCHQAAgi/AAII4gACCQIAAgkiAAIJJAACCSYAAgkoAAIJKgACCS0AAgkuAAIJLwACCTIAAgkzAAIJNQACCTYAAgk4AAIJOwACCTwAAgk9AAIJQAACCUEAAglGAAIJUwACCVgAAglaAAIJXAACCWEAAglkAAIJZwACCWkAAgmOAAIJsgACCdkAAgn9AAIKAAACCgIAAgoEAAIKBgACCggAAgoKAAIKCwACCg4AAgobAAIKLAACCi4AAgowAAIKMgACCjQAAgo2AAIKOAACCjoAAgo8AAIKTQACClAAAgpTAAIKVgACClkAAgpcAAIKXwACCmIAAgplAAIKZwACCqYAAgqoAAIKqgACCqwAAgqvAAIKsAACCrEAAgqyAAIKswACCrUAAgq3AAIKuAACCrkAAgq7AAIKvAACCvsAAgr9AAIK/wACCwEAAgsEAAILBQACCwYAAgsHAAILCAACCwoAAgsMAAILDQACCw4AAgsQAAILEQACC1AAAgtSAAILVQACC1cAAgtaAAILWwACC1wAAgtdAAILXgACC2AAAgtiAAILYwACC2QAAgtmAAILZwACC3QAAgt1AAILdgACC3gAAgu3AAILuQACC7sAAgu9AAILwAACC8EAAgvCAAILwwACC8QAAgvGAAILyAACC8kAAgvKAAILzAACC80AAgwMAAIMDgACDBAAAgwSAAIMFQACDBYAAgwXAAIMGAACDBkAAgwbAAIMHQACDB4AAgwfAAIMIQACDCIAAgxhAAIMYwACDGUAAgxnAAIMagACDGsAAgxsAAIMbQACDG4AAgxwAAIMcgACDHMAAgx0AAIMdgACDHcAAgy2AAIMuAACDLoAAgy8AAIMvwACDMAAAgzBAAIMwgACDMMAAgzFAAIMxwACDMgAAgzJAAIMywACDMwAAg0LAAINDQACDQ8AAg0RAAINFAACDRUAAg0WAAINFwACDRgAAg0aAAINHAACDR0AAg0eAAINIAACDSEAAg1GAAINagACDZEAAg21AAINuAACDboAAg28AAINvgACDcAAAg3CAAINwwACDcYAAg3TAAIN4gACDeQAAg3mAAIN6AACDeoAAg3sAAIN7gACDfAAAg3/AAIOAgACDgUAAg4IAAIOCwACDg4AAg4RAAIOFAACDhYAAg5VAAIOVwACDlkAAg5bAAIOXgACDl8AAg5gAAIOYQACDmIAAg5kAAIOZgACDmcAAg5oAAIOagACDmsAAg6qAAIOrAACDq4AAg6wAAIOswACDrQAAg61AAIOtgACDrcAAg65AAIOuwACDrwAAg69AAIOvwACDsAAAg7/AAIPAQACDwMAAg8FAAIPCAACDwkAAg8KAAIPCwACDwwAAg8OAAIPEAACDxEAAg8SAAIPFAACDxUAAg9UAAIPVgACD1gAAg9aAAIPXQACD14AAg9fAAIPYAACD2EAAg9jAAIPZQACD2YAAg9nAAIPaQACD2oAAg+pAAIPqwACD60AAg+vAAIPsgACD7MAAg+0AAIPtQACD7YAAg+4AAIPugACD7sAAg+8AAIPvgACD78AAg/+AAIQAAACEAIAAhAEAAIQBwACEAgAAhAJAAIQCgACEAsAAhANAAIQDwACEBAAAhARAAIQEwACEBQAAhBTAAIQVQACEFcAAhBZAAIQXAACEF0AAhBeAAIQXwACEGAAAhBiAAIQZAACEGUAAhBmAAIQaAACEGkAAhC0AAIQ1wACEPcAAhEXAAIRGQACERsAAhEdAAIRHwACESIAAhEjAAIRJAACEScAAhEoAAIRKgACESsAAhEtAAIRMAACETEAAhEyAAIRNQACETYAAhE7AAIRSAACEU0AAhFPAAIRUQACEVYAAhFZAAIRXAACEV4AAhGDAAIRpwACEc4AAhHyAAIR9QACEfcAAhH5AAIR+wACEf0AAhH/AAISAAACEgMAAhIQAAISIQACEiMAAhIlAAISJwACEikAAhIrAAISLQACEi8AAhIxAAISQgACEkUAAhJIAAISSwACEk4AAhJRAAISVAACElcAAhJaAAISXAACEpsAAhKdAAISnwACEqEAAhKkAAISpQACEqYAAhKnAAISqAACEqoAAhKsAAISrQACEq4AAhKwAAISsQACEvAAAhLyAAIS9AACEvYAAhL5AAIS+gACEvsAAhL8AAIS/QACEv8AAhMBAAITAgACEwMAAhMFAAITBgACE0UAAhNHAAITSgACE0wAAhNPAAITUAACE1EAAhNSAAITUwACE1UAAhNXAAITWAACE1kAAhNbAAITXAACE2kAAhNqAAITawACE20AAhOsAAITrgACE7AAAhOyAAITtQACE7YAAhO3AAITuAACE7kAAhO7AAITvQACE74AAhO/AAITwQACE8IAAhQBAAIUAwACFAUAAhQHAAIUCgACFAsAAhQMAAIUDQACFA4AAhQQAAIUEgACFBMAAhQUAAIUFgACFBcAAhRWAAIUWAACFFoAAhRcAAIUXwACFGAAAhRhAAIUYgACFGMAAhRlAAIUZwACFGgAAhRpAAIUawACFGwAAhSrAAIUrQACFK8AAhSxAAIUtAACFLUAAhS2AAIUtwACFLgAAhS6AAIUvAACFL0AAhS+AAIUwAACFMEAAhUAAAIVAgACFQQAAhUGAAIVCQACFQoAAhULAAIVDAACFQ0AAhUPAAIVEQACFRIAAhUTAAIVFQACFRYAAhU7AAIVXwACFYYAAhWqAAIVrQACFa8AAhWxAAIVswACFbUAAhW3AAIVuAACFbsAAhXIAAIV1wACFdkAAhXbAAIV3QACFd8AAhXhAAIV4wACFeUAAhX0AAIV9wACFfoAAhX9AAIWAAACFgMAAhYGAAIWCQACFgsAAhZKAAIWTAACFk4AAhZQAAIWUwACFlQAAhZVAAIWVgACFlcAAhZZAAIWWwACFlwAAhZdAAIWXwACFmAAAhafAAIWoQACFqMAAhalAAIWqAACFqkAAhaqAAIWqwACFqwAAhauAAIWsAACFrEAAhayAAIWtAACFrUAAhb0AAIW9gACFvgAAhb6AAIW/QACFv4AAhb/AAIXAAACFwEAAhcDAAIXBQACFwYAAhcHAAIXCQACFwoAAhdJAAIXSwACF04AAhdQAAIXUwACF1QAAhdVAAIXVgACF1cAAhdZAAIXWwACF1wAAhddAAIXXwACF2AAAhdjAAIXogACF6QAAhemAAIXqAACF6sAAhesAAIXrQACF64AAhevAAIXsQACF7MAAhe0AAIXtQACF7cAAhe4AAIX9wACF/kAAhf7AAIX/QACGAAAAhgBAAIYAgACGAMAAhgEAAIYBgACGAgAAhgJAAIYCgACGAwAAhgNAAIYTAACGE4AAhhQAAIYUgACGFUAAhhWAAIYVwACGFgAAhhZAAIYWwACGF0AAhheAAIYXwACGGEAAhhiAAIYrQACGNAAAhjwAAIZEAACGRIAAhkUAAIZFgACGRgAAhkbAAIZHAACGR0AAhkgAAIZIQACGSMAAhkkAAIZJgACGSkAAhkqAAIZKwACGS4AAhkvAAIZOAACGUUAAhlKAAIZTAACGU4AAhlTAAIZVgACGVkAAhlbAAIZgAACGaQAAhnLAAIZ7wACGfIAAhn0AAIZ9gACGfgAAhn6AAIZ/AACGf0AAhoAAAIaDQACGh4AAhogAAIaIgACGiQAAhomAAIaKAACGioAAhosAAIaLgACGj8AAhpCAAIaRQACGkgAAhpLAAIaTgACGlEAAhpUAAIaVwACGlkAAhqYAAIamgACGpwAAhqeAAIaoQACGqIAAhqjAAIapAACGqUAAhqnAAIaqQACGqoAAhqrAAIarQACGq4AAhrtAAIa7wACGvEAAhrzAAIa9gACGvcAAhr4AAIa+QACGvoAAhr8AAIa/gACGv8AAhsAAAIbAgACGwMAAhtCAAIbRAACG0cAAhtJAAIbTAACG00AAhtOAAIbTwACG1AAAhtSAAIbVAACG1UAAhtWAAIbWAACG1kAAhtmAAIbZwACG2gAAhtqAAIbqQACG6sAAhutAAIbrwACG7IAAhuzAAIbtAACG7UAAhu2AAIbuAACG7oAAhu7AAIbvAACG74AAhu/AAIb/gACHAAAAhwCAAIcBAACHAcAAhwIAAIcCQACHAoAAhwLAAIcDQACHA8AAhwQAAIcEQACHBMAAhwUAAIcUwACHFUAAhxXAAIcWQACHFwAAhxdAAIcXgACHF8AAhxgAAIcYgACHGQAAhxlAAIcZgACHGgAAhxpAAIcqAACHKoAAhysAAIcrgACHLEAAhyyAAIcswACHLQAAhy1AAIctwACHLkAAhy6AAIcuwACHL0AAhy+AAIc/QACHP8AAh0BAAIdAwACHQYAAh0HAAIdCAACHQkAAh0KAAIdDAACHQ4AAh0PAAIdEAACHRIAAh0TAAIdOAACHVwAAh2DAAIdpwACHaoAAh2sAAIdrgACHbAAAh2yAAIdtAACHbUAAh24AAIdxQACHdQAAh3WAAId2AACHdoAAh3cAAId3gACHeAAAh3iAAId8QACHfQAAh33AAId+gACHf0AAh4AAAIeAwACHgYAAh4IAAIeRwACHkkAAh5LAAIeTQACHlAAAh5RAAIeUgACHlMAAh5UAAIeVgACHlgAAh5ZAAIeWgACHlwAAh5dAAIenAACHp4AAh6gAAIeogACHqUAAh6mAAIepwACHqgAAh6pAAIeqwACHq0AAh6uAAIerwACHrEAAh6yAAIe8QACHvMAAh71AAIe9wACHvoAAh77AAIe/AACHv0AAh7+AAIfAAACHwIAAh8DAAIfBAACHwYAAh8HAAIfRgACH0gAAh9KAAIfTAACH08AAh9QAAIfUQACH1IAAh9TAAIfVQACH1cAAh9YAAIfWQACH1sAAh9cAAIfmwACH50AAh+fAAIfoQACH6QAAh+lAAIfpgACH6cAAh+oAAIfqgACH6wAAh+tAAIfrgACH7AAAh+xAAIf8AACH/IAAh/0AAIf9gACH/kAAh/6AAIf+wACH/wAAh/9AAIf/wACIAEAAiACAAIgAwACIAUAAiAGAAIgRQACIEcAAiBJAAIgSwACIE4AAiBPAAIgUAACIFEAAiBSAAIgVAACIFYAAiBXAAIgWAACIFoAAiBbAAIgpgACIMkAAiDpAAIhCQACIQsAAiENAAIhDwACIREAAiEUAAIhFQACIRYAAiEZAAIhGgACIRwAAiEdAAIhHwACISIAAiEjAAIhJAACIScAAiEoAAIhLQACIToAAiE/AAIhQQACIUMAAiFIAAIhSwACIU4AAiFQAAIhdQACIZkAAiHAAAIh5AACIecAAiHpAAIh6wACIe0AAiHvAAIh8QACIfIAAiH1AAIiAgACIhMAAiIVAAIiFwACIhkAAiIbAAIiHQACIh8AAiIhAAIiIwACIjQAAiI3AAIiOgACIj0AAiJAAAIiQwACIkYAAiJJAAIiTAACIk4AAiKNAAIijwACIpEAAiKTAAIilgACIpcAAiKYAAIimQACIpoAAiKcAAIingACIp8AAiKgAAIiogACIqMAAiLiAAIi5AACIuYAAiLoAAIi6wACIuwAAiLtAAIi7gACIu8AAiLxAAIi8wACIvQAAiL1AAIi9wACIvgAAiM3AAIjOQACIzwAAiM+AAIjQQACI0IAAiNDAAIjRAACI0UAAiNHAAIjSQACI0oAAiNLAAIjTQACI04AAiNbAAIjXAACI10AAiNfAAIjngACI6AAAiOiAAIjpAACI6cAAiOoAAIjqQACI6oAAiOrAAIjrQACI68AAiOwAAIjsQACI7MAAiO0AAIj8wACI/UAAiP3AAIj+QACI/wAAiP9AAIj/gACI/8AAiQAAAIkAgACJAQAAiQFAAIkBgACJAgAAiQJAAIkSAACJEoAAiRMAAIkTgACJFEAAiRSAAIkUwACJFQAAiRVAAIkVwACJFkAAiRaAAIkWwACJF0AAiReAAIknQACJJ8AAiShAAIkowACJKYAAiSnAAIkqAACJKkAAiSqAAIkrAACJK4AAiSvAAIksAACJLIAAiSzAAIk8gACJPQAAiT2AAIk+AACJPsAAiT8AAIk/QACJP4AAiT/AAIlAQACJQMAAiUEAAIlBQACJQcAAiUIAAIlLQACJVEAAiV4AAIlnAACJZ8AAiWhAAIlowACJaUAAiWnAAIlqQACJaoAAiWtAAIlugACJckAAiXLAAIlzQACJc8AAiXRAAIl0wACJdUAAiXXAAIl5gACJekAAiXsAAIl7wACJfIAAiX1AAIl+AACJfsAAiX9AAImPAACJj4AAiZAAAImQgACJkUAAiZGAAImRwACJkgAAiZJAAImSwACJk0AAiZOAAImTwACJlEAAiZSAAImkQACJpMAAiaVAAImlwACJpoAAiabAAImnAACJp0AAiaeAAImoAACJqIAAiajAAImpAACJqYAAianAAIm5gACJugAAibqAAIm7AACJu8AAibwAAIm8QACJvIAAibzAAIm9QACJvcAAib4AAIm+QACJvsAAib8AAInOwACJz0AAic/AAInQQACJ0QAAidFAAInRgACJ0cAAidIAAInSgACJ0wAAidNAAInTgACJ1AAAidRAAInkAACJ5IAAieUAAInlgACJ5kAAieaAAInmwACJ5wAAiedAAInnwACJ6EAAieiAAInowACJ6UAAiemAAIn5QACJ+cAAifpAAIn6wACJ+4AAifvAAIn8AACJ/EAAifyAAIn9AACJ/YAAif3AAIn+AACJ/oAAif7AAIoOgACKDwAAig+AAIoQAACKEMAAihEAAIoRQACKEYAAihHAAIoSQACKEsAAihMAAIoTQACKE8AAihQAAIoWQACKFoAAihcAAIonwACKMMAAijnAAIpCgACKTEAAilRAAIpeAACKZ8AAim/AAIp4wACKgcAAioJAAIqDAACKg4AAioQAAIqEgACKhUAAioYAAIqGgACKhwAAiofAAIqIQACKiMAAiomAAIqKQACKioAAiovAAIqPAACKj8AAipBAAIqRAACKkcAAipJAAIqbgACKpIAAiq5AAIq3QACKuAAAiriAAIq5AACKuYAAiroAAIq6gACKusAAiruAAIq+wACKw4AAisQAAIrEgACKxQAAisWAAIrGAACKxoAAiscAAIrHgACKyAAAiszAAIrNgACKzkAAis8AAIrPwACK0IAAitFAAIrSAACK0sAAitOAAIrUAACK48AAiuRAAIrlAACK5YAAiuZAAIrmgACK5sAAiucAAIrnQACK58AAiuhAAIrogACK6MAAiulAAIrpgACK68AAiuwAAIrsgACK/EAAivzAAIr9QACK/cAAiv6AAIr+wACK/wAAiv9AAIr/gACLAAAAiwCAAIsAwACLAQAAiwGAAIsBwACLEYAAixIAAIsSwACLE0AAixQAAIsUQACLFIAAixTAAIsVAACLFYAAixYAAIsWQACLFoAAixcAAIsXQACLGYAAixnAAIsaQACLKgAAiyqAAIsrAACLK4AAiyxAAIssgACLLMAAiy0AAIstQACLLcAAiy5AAIsugACLLsAAiy9AAIsvgACLP0AAiz/AAItAgACLQQAAi0HAAItCAACLQkAAi0KAAItCwACLQ0AAi0PAAItEAACLREAAi0TAAItFAACLR0AAi0eAAItIAACLV8AAi1hAAItYwACLWUAAi1oAAItaQACLWoAAi1rAAItbAACLW4AAi1wAAItcQACLXIAAi10AAItdQACLbQAAi22AAItuQACLbsAAi2+AAItvwACLcAAAi3BAAItwgACLcQAAi3GAAItxwACLcgAAi3KAAItywACLdgAAi3ZAAIt2gACLdwAAi4bAAIuHQACLh8AAi4hAAIuJAACLiUAAi4mAAIuJwACLigAAi4qAAIuLAACLi0AAi4uAAIuMAACLjEAAi5wAAIucgACLnUAAi53AAIuegACLnsAAi58AAIufQACLn4AAi6AAAIuggACLoMAAi6EAAIuhgACLocAAi6jAAIusAACLrsAAi6+AAIuwQACLsQAAi7HAAIuygACLtUAAi7YAAIu2wACLt4AAi7hAAIu5AACLuYAAi75AAIvBwACLxAAAi8iAAIvKgACL3UAAi+YAAIvuAACL9gAAi/aAAIv3AACL94AAi/gAAIv4wACL+QAAi/lAAIv6AACL+kAAi/rAAIv7AACL+4AAi/xAAIv8gACL/MAAi/2AAIv9wACL/wAAjAJAAIwDgACMBAAAjASAAIwFwACMBoAAjAdAAIwHwACMEQAAjBoAAIwjwACMLMAAjC2AAIwuAACMLoAAjC8AAIwvgACMMAAAjDBAAIwxAACMNEAAjDiAAIw5AACMOYAAjDoAAIw6gACMOwAAjDuAAIw8AACMPIAAjEDAAIxBgACMQkAAjEMAAIxDwACMRIAAjEVAAIxGAACMRsAAjEdAAIxXAACMV4AAjFgAAIxYgACMWUAAjFmAAIxZwACMWgAAjFpAAIxawACMW0AAjFuAAIxbwACMXEAAjFyAAIxsQACMbMAAjG1AAIxtwACMboAAjG7AAIxvAACMb0AAjG+AAIxwAACMcIAAjHDAAIxxAACMcYAAjHHAAIyBgACMggAAjILAAIyDQACMhAAAjIRAAIyEgACMhMAAjIUAAIyFgACMhgAAjIZAAIyGgACMhwAAjIdAAIyKgACMisAAjIsAAIyLgACMm0AAjJvAAIycQACMnMAAjJ2AAIydwACMngAAjJ5AAIyegACMnwAAjJ+AAIyfwACMoAAAjKCAAIygwACMsIAAjLEAAIyxgACMsgAAjLLAAIyzAACMs0AAjLOAAIyzwACMtEAAjLTAAIy1AACMtUAAjLXAAIy2AACMxcAAjMZAAIzGwACMx0AAjMgAAIzIQACMyIAAjMjAAIzJAACMyYAAjMoAAIzKQACMyoAAjMsAAIzLQACM2wAAjNuAAIzcAACM3IAAjN1AAIzdgACM3cAAjN4AAIzeQACM3sAAjN9AAIzfgACM38AAjOBAAIzggACM8EAAjPDAAIzxQACM8cAAjPKAAIzywACM8wAAjPNAAIzzgACM9AAAjPSAAIz0wACM9QAAjPWAAIz1wACM/wAAjQgAAI0RwACNGsAAjRuAAI0cAACNHIAAjR0AAI0dgACNHgAAjR5AAI0fAACNIkAAjSYAAI0mgACNJwAAjSeAAI0oAACNKIAAjSkAAI0pgACNLUAAjS4AAI0uwACNL4AAjTBAAI0xAACNMcAAjTKAAI0zAACNQsAAjUNAAI1DwACNREAAjUUAAI1FQACNRYAAjUXAAI1GAACNRoAAjUcAAI1HQACNR4AAjUgAAI1IQACNWAAAjViAAI1ZAACNWYAAjVpAAI1agACNWsAAjVsAAI1bQACNW8AAjVxAAI1cgA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CWFQAAlhWAAJYWAACWFsAAlhcAAJYXQACWF4AAlhfAAJYYQACWGMAAlhkAAJYZQACWGcAAlhoAAJYjQACWLEAAljYAAJY/AACWP8AAlkBAAJZAwACWQUAAlkHAAJZCQACWQoAAlkNAAJZGgACWSkAAlkrAAJZLQACWS8AAlkxAAJZMwACWTUAAlk3AAJZRgACWUkAAllMAAJZTwACWVIAAllVAAJZWAACWVsAAlldAAJZnAACWZ4AAlmgAAJZogACWaUAAlmmAAJZpwACWagAAlmpAAJZqwACWa0AAlmuAAJZrwACWbEAAlmyAAJZ8QACWfMAAln1AAJZ9wACWfoAAln7AAJZ/AACWf0AAln+AAJaAAACWgIAAloDAAJaBAACWgYAAloHAAJaRgACWkgAAlpKAAJaTAACWk8AAlpQAAJaUQACWlIAAlpTAAJaVQACWlcAAlpYAAJaWQACWlsAAlpcAAJamwACWp0AAlqfAAJaoQACWqQAAlqlAAJapgACWqcAAlqoAAJaqgACWqwAAlqtAAJargACWrAAAlqxAAJa8AACWvIAAlr0AAJa9gACWvkAAlr6AAJa+wACWvwAAlr9AAJa/wACWwEAAlsCAAJbAwACWwUAAlsGAAJbRQACW0cAAltJAAJbSwACW04AAltPAAJbUAACW1EAAltSAAJbVAACW1YAAltXAAJbWAACW1oAAltbAAJbmgACW5wAAlueAAJboAACW6MAAlukAAJbpQACW6YAAlunAAJbqQACW6sAAlusAAJbrQACW68AAluwAAJb+wACXB4AAlw+AAJcXgACXGAAAlxiAAJcZAACXGYAAlxpAAJcagACXGsAAlxuAAJcbwACXHEAAlxyAAJcdAACXHYAAlx3AAJceAACXHsAAlx8AAJcgQACXI4AAlyTAAJclQACXJcAAlycAAJcnwACXKIAAlykAAJcyQACXO0AAl0UAAJdOAACXTsAAl09AAJdPwACXUEAAl1DAAJdRQACXUYAAl1JAAJdVgACXWcAAl1pAAJdawACXW0AAl1vAAJdcQACXXMAAl11AAJddwACXYgAAl2LAAJdjgACXZEAAl2UAAJdlwACXZoAAl2dAAJdoAACXaIAAl3hAAJd4wACXeUAAl3nAAJd6gACXesAAl3sAAJd7QACXe4AAl3wAAJd8gACXfMAAl30AAJd9gACXfcAAl42AAJeOAACXjoAAl48AAJePwACXkAAAl5BAAJeQgACXkMAAl5FAAJeRwACXkgAAl5JAAJeSwACXkwAAl6LAAJejQACXpAAAl6SAAJelQACXpYAAl6XAAJemAACXpkAAl6bAAJenQACXp4AAl6fAAJeoQACXqIAAl6vAAJesAACXrEAAl6zAAJe8gACXvQAAl72AAJe+AACXvsAAl78AAJe/QACXv4AAl7/AAJfAQACXwMAAl8EAAJfBQACXwcAAl8IAAJfRwACX0kAAl9LAAJfTQACX1AAAl9RAAJfUgACX1MAAl9UAAJfVgACX1gAAl9ZAAJfWgACX1wAAl9dAAJfnAACX54AAl+gAAJfogACX6UAAl+mAAJfpwACX6gAAl+pAAJfqwACX60AAl+uAAJfrwACX7EAAl+yAAJf8QACX/MAAl/1AAJf9wACX/oAAl/7AAJf/AACX/0AAl/+AAJgAAACYAIAAmADAAJgBAACYAYAAmAHAAJgRgACYEgAAmBKAAJgTAACYE8AAmBQAAJgUQACYFIAAmBTAAJgVQACYFcAAmBYAAJgWQACYFsAAmBcAAJggQACYKUAAmDMAAJg8AACYPMAAmD1AAJg9wACYPkAAmD7AAJg/QACYP4AAmEBAAJhDgACYR0AAmEfAAJhIQACYSMAAmElAAJhJwACYSkAAmErAAJhOgACYT0AAmFAAAJhQwACYUYAAmFJAAJhTAACYU8AAmFRAAJhkAACYZIAAmGUAAJhlgACYZkAAmGaAAJhmwACYZwAAmGdAAJhnwACYaEAAmGiAAJhowACYaUAAmGmAAJh5QACYecAAmHpAAJh6wACYe4AAmHvAAJh8AACYfEAAmHyAAJh9AACYfYAAmH3AAJh+AACYfoAAmH7AAJiOgACYjwAAmI+AAJiQAACYkMAAmJEAAJiRQACYkYAAmJHAAJiSQACYksAAmJMAAJiTQACYk8AAmJQAAJijwACYpEAAmKTAAJilQACYpgAAmKZAAJimgACYpsAAmKcAAJingACYqAAAmKhAAJiogACYqQAAmKlAAJi5AACYuYAAmLoAAJi6gACYu0AAmLuAAJi7wACYvAAAmLxAAJi8wACYvUAAmL2AAJi9wACYvkAAmL6AAJjOQACYzsAAmM9AAJjPwACY0IAAmNDAAJjRAACY0UAAmNGAAJjSAA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Cbm8AAm6TAAJuugACbt4AAm7hAAJu4wACbuUAAm7nAAJu6QACbusAAm7sAAJu7wACbvwAAm8NAAJvDwACbxEAAm8TAAJvFQACbxcAAm8ZAAJvGwACbx0AAm8uAAJvMQACbzQAAm83AAJvOgACbz0AAm9AAAJvQwACb0YAAm9IAAJvhwACb4kAAm+LAAJvjQACb5AAAm+RAAJvkgACb5MAAm+UAAJvlgACb5gAAm+ZAAJvmgACb5wAAm+dAAJv3AACb94AAm/gAAJv4gACb+UAAm/mAAJv5wACb+gAAm/pAAJv6wACb+0AAm/uAAJv7wACb/EAAm/yAAJwMQACcDMAAnA2AAJwOAACcDsAAnA8AAJwPQACcD4AAnA/AAJwQQACcEMAAnBEAAJwRQACcEcAAnBIAAJwVQACcFYAAnBXAAJwWQACcJgAAnCaAAJwnAACcJ4AAnChAAJwogACcKMAAnCkAAJwpQACcKcAAnCpAAJwqgACcKsAAnCtAAJwrgACcO0AAnDvAAJw8QACcPMAAnD2AAJw9wACcPgAAnD5AAJw+gACcPwAAnD+AAJw/wACcQAAAnECAAJxAwACcUIAAnFEAAJxRgACcUgAAnFLAAJxTAACcU0AAnFOAAJxTwACcVEAAnFTAAJxVAACcVUAAnFXAAJxWAACcZcAAnGZAAJxmwACcZ0AAnGgAAJxoQACcaIAAnGjAAJxpAACcaYAAnGoAAJxqQACcaoAAnGsAAJxrQACcewAAnHuAAJx8AACcfIAAnH1AAJx9gACcfcAAnH4AAJx+QACcfsAAnH9AAJx/gACcf8AAnIBAAJyAgACcicAAnJLAAJycgACcpYAAnKZAAJymwACcp0AAnKfAAJyoQACcqMAAnKkAAJypwACcrQAAnLDAAJyxQACcscAAnLJAAJyywACcs0AAnLPAAJy0QACcuAAAnLjAAJy5gACcukAAnLsAAJy7wACcvIAAnL1AAJy9wACczYAAnM4AAJzOgACczwAAnM/AAJzQAACc0EAAnNCAAJzQwACc0UAAnNHAAJzSAACc0kAAnNLAAJzTAACc4sAAnONAAJzjwACc5EAAnOUAAJzlQACc5YAAnOXAAJzmAACc5oAAnOcAAJznQACc54AAnOgAAJzoQACc+AAAnPiAAJz5AACc+YAAnPpAAJz6gACc+sAAnPsAAJz7QA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ChaMAAoWmAAKFqAAChecAAoXpAAKF6wAChe0AAoXwAAKF8QAChfIAAoXzAAKF9AAChfYAAoX4AAKF+QAChfoAAoX8AAKF/QAChjwAAoY+AAKGQAAChkIAAoZFAAKGRgAChkcAAoZIAAKGSQAChksAAoZNAAKGTgAChk8AAoZRAAKGUgAChpEAAoaTAAKGlgAChpgAAoabAAKGnAAChp0AAoaeAAKGnwAChqEAAoajAAKGpAAChqUAAoanAAKGqAAChrUAAoa2AAKGtwAChrkAAob4AAKG+gAChvwAAob+AAKHAQAChwIAAocDAAKHBAAChwUAAocHAAKHCQAChwoAAocLAAKHDQAChw4AAodNAAKHTwACh1EAAodTAAKHVgACh1cAAodYAAKHWQACh1oAAodcAAKHXgACh18AAodgAAKHYgACh2MAAoeiAAKHpAACh6YAAoeoAAKHqwACh6wAAoetAAKHrgACh68AAoexAAKHswACh7QAAoe1AAKHtwACh7gAAof3AAKH+QACh/sAAof9AAKIAAACiAEAAogCAAKIAwACiAQAAogGAAKICAACiAkAAogKAAKIDAACiA0AAohMAAKITgACiFAAAohSAAKIVQACiFYAAohXAAKIWAACiFkAAohbAAKIXQACiF4AAohfAAKIYQACiGIAAoiHAAKIqwACiNIAAoj2AAKI+QACiPsAAoj9AAKI/wACiQEAAokDAAKJBAACiQcAAokUAAKJIwACiSUAAoknAAKJKQACiSsAAoktAAKJLwACiTEAAolAAAKJQwACiUYAAolJAAKJTAACiU8AAolSAAKJVQACiVcAAomWAAKJmAACiZoAAomcAAKJnwACiaAAAomhAAKJogACiaMAAomlAAKJpwACiagAAompAAKJqwACiawAAonrAAKJ7QACie8AAonxAAKJ9AACifUAAon2AAKJ9wACifgAAon6AAKJ/AACif0AAon+AAKKAAACigEAAopAAAKKQgACikQAAopGAAKKSQACikoAAopLAAKKTAACik0AAopPAAKKUQACilIAAopTAAKKVQACilYAAoqVAAKKlwACipkAAoqbAAKKngACip8AAoqgAAKKoQACiqIAAoqkAAKKpgACiqcAAoqoAAKKqgACiqsAAorqAAKK7AACiu4AAorwAAKK8wACivQAAor1AAKK9gACivcAAor5AAKK+wACivwAAor9AAKK/wACiwAAAos/AAKLQQACi0MAAotFAAKLSAACi0kAAotKAAKLSwACi0wAAotOAAKLUAACi1EAAotSAAKLVAACi1UAAouUAAKLlgACi5gAAouaAAKLnQACi54AAoufAAKLoAACi6EAAoujAAKLpQACi6YAAounAAKLqQACi6oAAouzAAKLtAACi7YAAov5AAKMHQACjEEAAoxkAAKMiwACjKsAAozSAAKM+QACjRkAAo09AAKNYQACjWMAAo1mAAKNaAACjWoAAo1sAAKNbwACjXIAAo10AAKNdgACjXkAAo17AAKNfQACjYAAAo2DAAKNhAACjYkAAo2WAAKNmQACjZsAAo2eAAKNoQACjaMAAo3IAAKN7AACjhMAAo43AAKOOgACjjwAAo4+AAKOQAACjkIAAo5EAAKORQACjkgAAo5VAAKOaAACjmoAAo5sAAKObgACjnAAAo5yAAKOdAACjnYAAo54AAKOegACjo0AAo6QAAKOkwACjpYAAo6ZAAKOnAACjp8AAo6iAAKOpQACjqgAAo6qAAKO6QACjusAAo7uAAKO8AACjvMAAo70AAKO9QACjvYAAo73AAKO+QACjvsAAo78AAKO/QACjv8AAo8AAAKPCQACjwoAAo8MAAKPSwACj00AAo9PAAKPUQACj1QAAo9VAAKPVgACj1cAAo9YAAKPWgACj1wAAo9dAAKPXgACj2AAAo9hAAKPoAACj6IAAo+lAAKPpwACj6oAAo+rAAKPrAACj60AAo+uAAKPsAACj7IAAo+zAAKPtAACj7YAAo+3AAKPwAACj8EAAo/DAAKQAgACkAQAApAGAAKQCAACkAsAApAMAAKQDQACkA4AApAPAAKQEQACkBMAApAUAAKQFQACkBcAApAYAAKQVwACkFkAApBcAAKQXgACkGEAApBiAAKQYwACkGQAApBlAAKQZwACkGkAApBqAAKQawACkG0AApBuAAKQdwACkHgAApB6AAKQuQACkLsAApC9AAKQvwACkMIAApDDAAKQxAACkMUAApDGAAKQyAACkMoAApDLAAKQzAACkM4AApDPAAKRDgACkRAAApETAAKRFQACkRgAApEZAAKRGgACkRsAApEcAAKRHgACkSAAApEhAAKRIgACkSQAApElAAKRMgACkTMAApE0AAKRNgACkXUAApF3AAKReQACkXsAApF+AAKRfwACkYAAApGBAAKRggACkYQAApGGAAKRhwACkYgAApGKAAKRiwACkcoAApHMAAKRzwACkdEAApHUAAKR1QACkdYAApHXAAKR2AACkdoAApHcAAKR3QACkd4AApHgAAKR4QACke0AApH6AAKR/wACkgIAApIFAAKSCgACkg0AApIQAAKSEgACkhgAApIjAAKSbgACkpEAApKxAAKS0QACktMAApLVAAKS1wACktkAApLcAAKS3QACkt4AApLhAAKS4gACkuQAApLlAAKS5wACkuoAApLrAAKS7AACku8AApLwAAKS9QACkwIAApMHAAKTCQACkwsAApMQAAKTEwACkxYAApMYAAKTPQACk2EAApOIAAKTrAACk68AApOxAAKTswACk7UAApO3AAKTuQACk7oAApO9AAKTygACk9sAApPdAAKT3wACk+EAApPjAAKT5QACk+cAApPpAAKT6wACk/wAApP/AAKUAgAClAUAApQIAAKUCwAClA4AApQRAAKUFAAClBYAApRVAAKUVwAClFkAApRbAAKUXgAClF8AApRgAAKUYQAClGIAApRkAAKUZgAClGcAApRoAAKUagAClGsAApSqAAKUrAAClK4AApSwAAKUswAClLQAApS1AAKUtgAClLcAApS5AAKUuwAClLwAApS9AAKUvwAClMAAApT/AAKVAQAClQQAApUGAAKVCQAClQoAApULAAKVDAAClQ0AApUPAAKVEQAClRIAApUTAAKVFQAClRYAApUjAAKVJAAClSUAApUnAAKVZgAClWgAApVqAAKVbAAClW8AApVwAAKVcQAClXIAApVzAAKVdQAClXcAApV4AAKVeQAClXsAApV8AAKVuwAClb0AApW/AAKVwQAClcQAApXFAAKVxgAClccAApXIAAKVygAClcwAApXNAAKVzgACldAAApXRAAKWEAAClhIAApYUAAKWFgAClhkAApYaAAKWGwAClhwAApYdAAKWHwACliEAApYiAAKWIwACliUAApYmAAKWZQAClmcAApZpAAKWawAClm4AApZvAAKWcAAClnEAApZyAAKWdAAClnYAApZ3AAKWeAAClnoAApZ7AAKWugAClrwAApa+AAKWwAAClsMAApbEAAKWxQAClsYAApbHAAKWyQAClssAApbMAAKWzQACls8AApbQAAKW9QAClxkAApdAAAKXZAACl2cAApdpAAKXawACl20AApdvAAKXcQACl3IAApd1AAKXggACl5EAApeTAAKXlQACl5cAApeZAAKXmwACl50AApefAAKXrgACl7EAApe0AAKXtwACl7oAApe9AAKXwAACl8MAApfFAAKYBAACmAYAApgIAAKYCgACmA0AApgOAAKYDwACmBAAApgRAAKYEwACmBUAApgWAAKYFwACmBkAApgaAAKYWQACmFsAAphdAAKYXwACmGIAAphjAAKYZAACmGUAAphmAAKYaAACmGoAAphrAAKYbAACmG4AAphvAAKYrgACmLAAApiyAAKYtAACmLcAApi4AAKYuQACmLoAApi7AAKYvQACmL8AApjAAAKYwQACmMMAApjEAAKZAwACmQUAApkHAAKZCQACmQwAApkNAAKZDgACmQ8AApkQAAKZEgACmRQAApkVAAKZFgACmRgAApkZAAKZWAACmVoAAplcAAKZXgACmWEAApliAAKZYwACmWQAApllAAKZZwACmWkAAplqAAKZawACmW0AApluAAKZrQACma8AApmxAAKZswACmbYAApm3AAKZuAACmbkAApm6AAKZvAACmb4AApm/AAKZwAACmcIAApnDAAKaAgACmgQAApoGAAKaCAACmgsAApoMAAKaDQACmg4AApoPAAKaEQACmhMAApoUAAKaFQACmhcAApoYAAKaYwACmoYAApqmAAKaxgACmsgAAprKAAKazAACms4AAprRAAKa0gACmtMAAprWAAKa1wACmtkAApraAAKa3AACmt8AAprgAAKa4QACmuQAAprlAAKa6gACmvcAApr8AAKa/gACmwAAApsFAAKbCAACmwsAApsNAAKbMgACm1YAApt9AAKboQACm6QAApumAAKbqAACm6oAApusAAKbrgACm68AApuyAAKbvwACm9AAApvSAAKb1AACm9YAApvYAAKb2gACm9wAApveAAKb4AACm/EAApv0AAKb9wACm/oAApv9AAKcAAACnAMAApwGAAKcCQACnAsAApxKAAKcTAACnE4AApxQAAKcUwACnFQAApxVAAKcVgACnFcAApxZAAKcWwACnFwAApxdAAKcXwACnGAAApyfAAKcoQACnKMAApylAAKcqAACnKkAApyqAAKcqwACnKwAApyuAAKcsAACnLEAApyyAAKctAACnLUAApz0AAKc9gACnPkAApz7AAKc/gACnP8AAp0AAAKdAQACnQIAAp0EAAKdBgACnQcAAp0IAAKdCgACnQsAAp0YAAKdGQACnRoAAp0cAAKdWwACnV0AAp1fAAKdYQACnWQAAp1lAAKdZgACnWcAAp1oAAKdagACnWwAAp1tAAKdbgACnXAAAp1xAAKdsAACnbIAAp20AAKdtgACnbkAAp26AAKduwACnbwAAp29AAKdvwACncEAAp3CAAKdwwACncUAAp3GAAKeBQACngcAAp4JAAKeCwACng4AAp4PAAKeEAACnhEAAp4SAAKeFAACnhYAAp4XAAKeGAACnhoAAp4bAAKeWgACnlwAAp5eAAKeYAACnmMAAp5kAAKeZQACnmYAAp5nAAKeaQACnmsAAp5sAAKebQACnm8AAp5wAAKerwACnrEAAp6zAAKetQACnrgAAp65AAKeugACnrsAAp68AAKevgACnsAAAp7BAAKewgACnsQAAp7FAAKe6gACnw4AAp81AAKfWQACn1wAAp9eAAKfYAACn2IAAp9kAAKfZgACn2cAAp9qAAKfdwACn4YAAp+IAAKfigACn4wAAp+OAAKfkAACn5IAAp+UAAKfowACn6YAAp+pAAKfrAACn68AAp+yAAKftQACn7gAAp+6AAKf+QACn/sAAp/9AAKf/wACoAIAAqADAAKgBAACoAUAAqAGAAKgCAACoAoAAqALAAKgDAACoA4AAqAPAAKgTgACoFAAAqBSAAKgVAACoFcAAqBYAAKgWQACoFoAAqBbAAKgXQACoF8AAqBgAAKgYQACoGMAAqBkAAKgowACoKUAAqCnAAKgqQACoKwAAqCtAAKgrgACoK8AAqCwAAKgsgACoLQAAqC1AAKgtgACoLgAAqC5AAKg+AACoPoAAqD8AAKg/gACoQEAAqECAAKhAwACoQQAAqEFAAKhBwACoQkAAqEKAAKhCwACoQ0AAqEOAAKhTQACoU8AAqFRAAKhUwACoVYAAqFXAAKhWAACoVkAAqFaAAKhXAACoV4AAqFfAAKhYAACoWIAAqFjAAKhogACoaQAAqGmAAKhqAACoasAAqGsAAKhrQACoa4AAqGvAAKhsQACobMAAqG0AAKhtQACobcAAqG4AAKh9wACofkAAqH7AAKh/QACogAAAqIBAAKiAgA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CrjcAAq5GAAKuSQACrkwAAq5PAAKuUgACrlUAAq5YAAKuWwACrl0AAq6cAAKungACrqAAAq6iAAKupQACrqYAAq6nAAKuqAACrqkAAq6rAAKurQACrq4AAq6vAAKusQACrrIAAq7xAAKu8wACrvUAAq73AAKu+gACrvsAAq78AAKu/QACrv4AAq8AAAKvAgACrwMAAq8EAAKvBgACrwcAAq9GAAKvSAACr0oAAq9MAAKvTwACr1AAAq9RAAKvUgACr1MAAq9VAAKvVwACr1gAAq9ZAAKvWwACr1wAAq+bAAKvnQACr6AAAq+iAAKvpQACr6YAAq+nAAKvqAACr6kAAq+rAAKvrQACr64AAq+vAAKvsQACr7IAAq/xAAKv8wACr/UAAq/3AAKv+gACr/sAAq/8AAKv/QACr/4AArAAAAKwAgACsAMAArAEAAKwBgACsAcAArBGAAKwSAACsEoAArBMAAKwTwACsFAAArBRAAKwUgACsFMAArBVAAKwVwACsFgAArBZAAKwWwACsFwAArCbAAKwnQACsJ8AArChAAKwpAACsKUAArCmAAKwpwACsKgAArCqAAKwrAACsK0AArCuAAKwsAACsLEAArD8AAKxHwACsT8AArFfAAKxYQACsWMAArFlAAKxZwACsWoAArFrAAKxbAACsW8AArFwAAKxcgACsXMAArF1AAKxeAACsXkAArF6AAKxfQACsX4AArGHAAKxlAACsZkAArGbAAKxnQACsaIAArGlAAKxqAACsaoAArHPAAKx8wACshoAArI+AAKyQQACskMAArJFAAKyRwACskkAArJLAAKyTAACsk8AArJcAAKybQACsm8AArJxAAKycwACsnUAArJ3AAKyeQACsnsAArJ9AAKyjgACspEAArKUAAKylwACspoAArKdAAKyoAACsqMAArKmAAKyqAACsucAArLpAAKy6wACsu0AArLwAAKy8QACsvIAArLzAAKy9AACsvYAArL4AAKy+QACsvoAArL8AAKy/QACszwAArM+AAKzQAACs0IAArNFAAKzRgACs0cAArNIAAKzSQACs0sAArNNAAKzTgACs08AArNRAAKzUgACs5EAArOTAAKzlgACs5gAArObAAKznAACs50AArOeAAKznwACs6EAArOjAAKzpAACs6UAArOnAAKzqAACs7UAArO2AAKztwACs7kAArP4AAKz+gACs/wAArP+AAK0AQACtAIAArQDAAK0BAACtAUAArQHAAK0CQACtAoAArQLAAK0DQACtA4AArRNAAK0TwACtFEAArRTAAK0VgACtFcAArRYAAK0WQACtFoAArRcAAK0XgACtF8AArRgAAK0YgACtGMAArSiAAK0pAACtKYAArSoAAK0qwACtKwAArStAAK0rgACtK8AArSxAAK0swACtLQAArS1AAK0twACtLgAArT3AAK0+QACtPsAArT9AAK1AAACtQEAArUCAAK1AwACtQQAArUGAAK1CAACtQkAArUKAAK1DAACtQ0AArVMAAK1TgACtVAAArVSAAK1VQACtVYAArVXAAK1WAACtVkAArVbAAK1XQACtV4AArVfAAK1YQACtWIAArWHAAK1qwACtdIAArX2AAK1+QACtfsAArX9AAK1/wACtgEAArYDAAK2BAACtgcAArYUAAK2IwACtiUAArYnAAK2KQACtisAArYtAAK2LwACtjEAArZAAAK2QwACtkYAArZJAAK2TAACtk8AArZSAAK2VQACtlcAAraWAAK2mAACtpoAAracAAK2nwACtqAAArahAAK2ogACtqMAAralAAK2pwACtqgAArapAAK2qwACtqwAArbrAAK27QACtu8AArbxAAK29AACtvUAArb2AAK29wACtvgAArb6AAK2/AACtv0AArb+AAK3AAACtwEAArdAAAK3QgACt0QAArdGAAK3SQACt0oAArdLAAK3TAACt00AArdPAAK3UQACt1IAArdTAAK3VQACt1YAAreVAAK3lwACt5oAArecAAK3nwACt6AAArehAAK3ogACt6MAArelAAK3pwACt6gAArepAAK3qwACt6wAArfrAAK37QACt+8AArfxAAK39AACt/UAArf2AAK39wACt/gAArf6AAK3/AACt/0AArf+AAK4AAACuAEAArhAAAK4QgACuEQAArhGAAK4SQACuEoAArhLAAK4TAACuE0AArhPAAK4UQACuFIAArhTAAK4VQACuFYAAriVAAK4lwACuJkAAribAAK4ngACuJ8AArigAAK4oQACuKIAArikAAK4pgACuKcAArioAAK4qgACuKsAArj2AAK5GQACuTkAArlZAAK5WwACuV0AArlfAAK5YQACuWQAArllAAK5ZgACuWkAArlqAAK5bAACuW0AArlvAAK5cgACuXMAArl0AAK5dwACuXgAArl9AAK5igACuY8AArmRAAK5kwACuZgAArmbAAK5ngACuaAAArnFAAK56QACuhAAAro0AAK6NwACujkAAro7AAK6PQACuj8AArpBAAK6QgACukUAArpSAAK6YwACumUAArpnAAK6aQACumsAArptAAK6bwACunEAArpzAAK6hAACuocAArqKAAK6jQACupAAArqTAAK6lgACupkAArqcAAK6ngACut0AArrfAAK64QACuuMAArrmAAK65wACuugAArrpAAK66gACuuwAArruAAK67wACuvAAArryAAK68wACuzIAArs0AAK7NgACuzgAArs7AAK7PAACuz0AArs+AAK7PwACu0EAArtDAAK7RAACu0UAArtHAAK7SAACu4cAAruJAAK7jAACu44AAruRAAK7kgACu5MAAruUAAK7lQACu5cAAruZAAK7mgACu5sAArudAAK7ngACu6sAArusAAK7rQACu68AArvuAAK78AACu/IAArv0AAK79wACu/gAArv5AAK7+gACu/sAArv9AAK7/wACvAAAArwBAAK8AwACvAQAArxDAAK8RQACvEcAArxJAAK8TAACvE0AArxOAAK8TwACvFAAArxSAAK8VAACvFUAArxWAAK8WAACvFkAAryYAAK8mgACvJwAAryeAAK8oQACvKIAAryjAAK8pAACvKUAArynAAK8qQACvKoAAryrAAK8rQACvK4AArztAAK87wACvPEAArzzAAK89gACvPcAArz4AAK8+QACvPoAArz8AAK8/gACvP8AAr0AAAK9AgACvQMAAr1CAAK9RAACvUYAAr1IAAK9SwACvUwAAr1NAAK9TgACvU8AAr1RAAK9UwACvVQAAr1VAAK9VwACvVgAAr19AAK9oQACvcgAAr3sAAK97wACvfEAAr3zAAK99QACvfcAAr35AAK9+gACvf0AAr4KAAK+GQACvhsAAr4dAAK+HwACviEAAr4jAAK+JQACvicAAr42AAK+OQACvjwAAr4/AAK+QgACvkUAAr5IAAK+SwACvk0AAr6MAAK+jgACvpAAAr6SAAK+lQACvpYAAr6XAAK+mAACvpkAAr6bAAK+nQACvp4AAr6fAAK+oQACvqIAAr7hAAK+4wACvuUAAr7nAAK+6gACvusAAr7sAAK+7QACvu4AAr7wAAK+8gACvvMAAr70AAK+9gACvvcAAr82AAK/OAACvzoAAr88AAK/PwACv0AAAr9BAAK/QgACv0MAAr9FAAK/RwACv0gAAr9JAAK/SwACv0wAAr+LAAK/jQACv48AAr+RAAK/lAACv5UAAr+WAAK/lwACv5gAAr+aAAK/nAACv50AAr+eAAK/oAACv6EAAr/gAAK/4gACv+QAAr/mAAK/6QACv+oAAr/rAAK/7AACv+0AAr/vAAK/8QACv/IAAr/zAAK/9QACv/YAAsA1AALANwACwDkAAsA7AALAPgACwD8AAsBAAALAQQACwEIAAsBEAALARgACwEcAAsBIAALASgACwEsAAsCKAALAjAACwI4AAsCQAALAkwACwJQAAsCVAALAlgACwJcAAsCZAALAmwACwJwAAsCdAALAnwACwKAAAsDrAALBDgACwS4AAsFOAALBUAACwVIAAsFUAALBVgACwVkAAsFaAALBWwACwV4AAsFfAALBYQACwWIAAsFkAALBZwACwWgAAsFpAALBbAACwW0AAsFyAALBfwACwYQAAsGGAALBiAACwY0AAsGQAALBkwACwZUAAsG6AALB3gACwgUAAsIpAALCLAACwi4AAsIwAALCMgACwjQAAsI2AALCNwACwjoAAsJHAALCWAACwloAAsJcAALCXgACwmAAAsJiAALCZAACwmYAAsJoAALCeQACwnwAAsJ/AALCggACwoUAAsKIAALCiwACwo4AAsKRAALCkwACwtIAAsLUAALC1gACwtgAAsLbAALC3AACwt0AAsLeAALC3wACwuEAAsLjAALC5AACwuUAAsLnAALC6AACwycAAsMpAALDKwACwy0AAsMwAALDMQACwzIAAsMzAALDNAACwzYAAsM4AALDOQACwzoAAsM8AALDPQACw3wAAsN+AALDgQACw4MAAsOGAALDhwACw4gAAsOJAALDigACw4wAAsOOAALDjwACw5AAAsOSAALDkwACw6AAAsOhAALDogACw6QAAsPjAALD5QACw+cAAsPpAALD7AACw+0AAsPuAALD7wACw/AAAsPyAALD9AACw/UAAsP2AALD+AACw/kAAsQ4AALEOgACxDwAAsQ+AALEQQACxEIAAsRDAALERAACxEUAAsRHAALESQACxEoAAsRLAALETQACxE4AAsSNAALEjwACxJEAAsSTAALElgACxJcAAsSYAALEmQACxJoAAsScAALEngACxJ8AAsSgAALEogACxKMAAsTiAALE5AACxOYAAsToAALE6wACxOwAAsTtAALE7gACxO8AAsTxAALE8wACxPQAAsT1AALE9wACxPgAAsU3AALFOQACxTsAAsU9AALFQAACxUEAAsVCAALFQwACxUQAAsVGAALFSAACxUkAAsVKAALFTAACxU0AAsVyAALFlgACxb0AAsXhAALF5AACxeYAAsXoAALF6gACxewAAsXuAALF7wACxfIAAsX/AALGDgACxhAAAsYSAALGFAACxhYAAsYYAALGGgACxhwAAsYrAALGLgACxjEAAsY0AALGNwACxjoAAsY9AALGQAACxkIAAsaBAALGgwACxoUAAsaHAALGigACxosAAsaMAALGjQACxo4AAsaQAALGkgACxpMAAsaUAALGlgACxpcAAsbWAALG2AACxtoAAsbcAALG3wACxuAAAsbhAALG4gACxuMAAsblAALG5wACxugAAsbpAALG6wACxuwAAscrAALHLQACxy8AAscxAALHNAACxzUAAsc2AALHNwACxzgAAsc6AALHPAACxz0AAsc+AALHQAACx0EAAseAAALHggACx4UAAseHAALHigACx4sAAseMAALHjQACx44AAseQAALHkgACx5MAAseUAALHlgACx5cAAsfWAALH2AACx9oAAsfcAALH3wACx+AAAsfhAALH4gACx+MAAsflAALH5wACx+gAAsfpAALH6wACx+wAAsgrAALILQACyC8AAsgxAALINAACyDUAAsg2AALINwACyDgAAsg6AALIPAACyD0AAsg+AALIQAACyEEAAsiAAALIggACyIQAAsiGAALIiQACyIoAAsiLAALIjAACyI0AAsiPAALIkQACyJIAAsiTAALIlQACyJYAAsjhAALJBAACySQAAslEAALJRgACyUgAAslKAALJTAACyU8AAslQAALJUQACyVQAAslVAALJVwACyVgAAslaAALJXQACyV4AAslfAALJYgACyWMAAsloAALJdQACyXoAAsl8AALJfgACyYMAAsmGAALJiQACyYsAAsmwAALJ1AACyfsAAsofAALKIgACyiQAAsomAALKKAACyioAAsosAALKLQACyjAAAso9AALKTgACylAAAspSAALKVAACylYAAspYAALKWgACylwAAspeAALKbwACynIAAsp1AALKeAACynsAAsp+AALKgQACyoQAAsqHAALKiQACysgAAsrKAALKzAACys4AAsrRAALK0gACytMAAsrUAALK1QACytcAAsrZAALK2gACytsAAsrdAALK3gACyx0AAssfAALLIQACyyMAAssmAALLJwACyygAAsspAALLKgACyywAAssuAALLLwACyzAAAssyAALLMwACy3IAAst0AALLdwACy3kAAst8AALLfQACy34AAst/AALLgAACy4IAAsuEAALLhQACy4YAAsuIAALLiQACy5YAAsuXAALLmAACy5oAAsvZAALL2wACy90AAsvfAALL4gACy+MAAsvkAALL5QACy+YAAsvoAALL6gACy+sAAsvsAALL7gACy+8AAswuAALMMAACzDIAAsw0AALMNwACzDgAAsw5AALMOgACzDsAAsw9AALMPwACzEAAAsxBAALMQwACzEQAAsyDAALMhQACzIcAAsyJAALMjAACzI0AAsyOAALMjwACzJAAAsySAALMlAACzJUAAsyWAALMmAACzJkAAszYAALM2gACzNwAAszeAALM4QACzOIAAszjAALM5AACzOUAAsznAALM6QACzOoAAszrAALM7QACzO4AAs0tAALNLwACzTEAAs0zAALNNgACzTcAAs04AALNOQACzToAAs08AALNPgACzT8AAs1AAALNQgACzUMAAs1oAALNjAACzbMAAs3XAALN2gACzdwAAs3eAALN4AACzeIAAs3kAALN5QACzegAAs31AALOBAACzgYAAs4IAALOCgACzgwAAs4OAALOEAACzhIAAs4hAALOJAACzicAAs4qAALOLQACzjAAAs4zAALONgACzjgAAs53AALOeQACznsAAs59AALOgAACzoEAAs6CAALOgwACzoQAAs6GAALOiAACzokAAs6KAALOjAACzo0AAs7MAALOzgACztAAAs7SAALO1QACztYAAs7XAALO2AACztkAAs7bAALO3QACzt4AAs7fAALO4QACzuIAAs8hAALPIwACzyUAAs8nAALPKgACzysAAs8sAALPLQACzy4AAs8wAALPMgACzzMAAs80AALPNgACzzcAAs92AALPeAACz3sAAs99AALPgAACz4EAAs+CAALPgwACz4QAAs+GAALPiAACz4kAAs+KAALPjAACz40AAs/MAALPzgACz9AAAs/SAALP1QACz9YAAs/XAALP2AACz9kAAs/bAALP3QACz94AAs/fAALP4QACz+IAAtAhAALQIwAC0CUAAtAnAALQKgAC0CsAAtAsAALQLQAC0C4AAtAwAALQMgAC0DMAAtA0AALQNgAC0DcAAtB2AALQeAAC0HoAAtB8AALQfwAC0IAAAtCBAALQggAC0IMAAtCFAALQhwAC0IgAAtCJAALQiwAC0IwAAtCVAALQlgAC0JgAAtDbAALQ/wAC0SMAAtFGAALRbQAC0Y0AAtG0AALR2wAC0fsAAtIfAALSQwAC0kUAAtJIAALSSgAC0kwAAtJOAALSUQAC0lQAAtJWAALSWAAC0lsAAtJdAALSXwAC0mIAAtJlAALSZgAC0m8AAtJ8AALSfwAC0oEAAtKEAALShwAC0okAAtKuAALS0gAC0vkAAtMdAALTIAAC0yIAAtMkAALTJgAC0ygAAtMqAALTKwAC0y4AAtM7AALTTgAC01AAAtNSAALTVAAC01YAAtNYAALTWgAC01wAAtNeAALTYAAC03MAAtN2AALTeQAC03wAAtN/AALTggAC04UAAtOIAALTiwAC044AAtOQAALTzwAC09EAAtPUAALT1gAC09kAAtPaAALT2wAC09wAAtPdAALT3wAC0+EAAtPiAALT4wAC0+UAAtPmAALT7wAC0/AAAtPyAALUMQAC1DMAAtQ1AALUNwAC1DoAAtQ7AALUPAAC1D0AAtQ+AALUQAAC1EIAAtRDAALURAAC1EYAAtRHAALUhgAC1IgAAtSLAALUjQAC1JAAAtSRAALUkgAC1JMAAtSUAALUlgAC1JgAAtSZAALUmgAC1JwAAtSdAALUpgAC1KcAAtSpAALU6AAC1OoAAtTsAALU7gAC1PEAAtTyAALU8wAC1PQAAtT1AALU9wAC1PkAAtT6AALU+wAC1P0AAtT+AALVPQAC1T8AAtVCAALVRAAC1UcAAtVIAALVSQAC1UoAAtVLAALVTQAC1U8AAtVQAALVUQAC1VMAAtVUAALVXQAC1V4AAtVgAALVnwAC1aEAAtWjAALVpQAC1agAAtWpAALVqgAC1asAAtWsAALVrgAC1bAAAtWxAALVsgAC1bQAAtW1AALV9AAC1fYAAtX5AALV+wAC1f4AAtX/AALWAAAC1gEAAtYCAALWBAAC1gYAAtYHAALWCAAC1goAAtYLAALWGAAC1hkAAtYaAALWHAAC1lsAAtZdAALWXwAC1mEAAtZkAALWZQAC1mYAAtZnAALWaAAC1moAAtZsAALWbQAC1m4AAtZwAALWcQAC1rAAAtayAALWtQAC1rcAAta6AALWuwAC1rwAAta9AALWvgAC1sAAAtbCAALWwwAC1sQAAtbGAALWxwAC1tIAAtbfAALW6AAC1uoAAtbsAALW7wAC1vIAAtb7AALW/gAC1wEAAtcEAALXBwAC1wkAAtcRAALXGQAC12QAAteHAALXpwAC18cAAtfJAALXywAC180AAtfPAALX0gAC19MAAtfUAALX1wAC19gAAtfaAALX2wAC190AAtffAALX4AAC1+EAAtfkAALX5QAC1+oAAtf3AALX/AAC1/4AAtgAAALYBQAC2AgAAtgLAALYDQAC2DIAAthWAALYfQAC2KEAAtikAALYpgAC2KgAAtiqAALYrAAC2K4AAtivAALYsgAC2L8AAtjQAALY0gAC2NQAAtjWAALY2AAC2NoAAtjcAALY3gAC2OAAAtjxAALY9AAC2PcAAtj6AALY/QAC2QAAAtkDAALZBgAC2QkAAtkLAALZSgAC2UwAAtlOAALZUAAC2VMAAtlUAALZVQAC2VYAAtlXAALZWQAC2VsAAtlcAALZXQAC2V8AAtlgAALZnwAC2aEAAtmjAALZpQAC2agAAtmpAALZqgAC2asAAtmsAALZrgAC2bAAAtmxAALZsgAC2bQAAtm1AALZ9AAC2fYAAtn5AALZ+wAC2f4AAtn/AALaAAAC2gEAAtoCAALaBAAC2gYAAtoHAALaCAAC2goAAtoLAALaGAAC2hkAAtoaAALaHAAC2lsAAtpdAALaXwAC2mEAAtpkAALaZQAC2mYAAtpnAALaaAAC2moAAtpsAALabQAC2m4AAtpwAALacQAC2rAAAtqyAALatAAC2rYAAtq5AALaugAC2rsAAtq8AALavQAC2r8AAtrBAALawgAC2sMAAtrFAALaxgAC2wUAAtsHAALbCQAC2wsAAtsOAALbDwAC2xAAAtsRAALbEgAC2xQAAtsWAALbFwAC2xgAAtsaAALbGwAC21oAAttcAALbXgAC22AAAttjAALbZAAC22UAAttmAALbZwAC22kAAttrAALbbAAC220AAttvAALbcAAC268AAtuxAALbswAC27UAAtu4AALbuQAC27oAAtu7AALbvAAC274AAtvAAALbwQAC28IAAtvEAALbxQAC2+oAAtwOAALcNQAC3FkAAtxcAALcXgAC3GAAAtxiAALcZAAC3GYAAtxnAALcagAC3HcAAtyGAALciAAC3IoAAtyMAALcjgAC3JAAAtySAALclAAC3KMAAtymAALcqQAC3KwAAtyvAALcsgAC3LUAAty4AALcugAC3PkAAtz7AALc/QAC3P8AAt0CAALdAwAC3QQAAt0FAALdBgAC3QgAAt0KAALdCwAC3QwAAt0OAALdDwAC3U4AAt1QAALdUgAC3VQAAt1XAALdWAAC3VkAAt1aAALdWwAC3V0AAt1fAALdYAAC3WEAAt1jAALdZAAC3aMAAt2lAALdpwAC3akAAt2sAALdrQAC3a4AAt2vAALdsAAC3bIAAt20AALdtQAC3bYAAt24AALduQAC3fgAAt36AALd/AAC3f4AAt4BAALeAgAC3gMAAt4EAALeBQAC3gcAAt4JAALeCgAC3gsAAt4NAALeDgAC3k0AAt5PAALeUQAC3lMAAt5WAALeVwAC3lgAAt5ZAALeWgAC3lwAAt5eAALeXwAC3mAAAt5iAALeYwAC3qIAAt6kAALepgAC3qgAAt6rAALerAAC3q0AAt6uAALerwAC3rEAAt6zAALetAAC3rUAAt63AALeuAAC3vcAAt75AALe+wAC3v0AAt8AAALfAQAC3wIAAt8DAALfBAAC3wYAAt8IAALfCQAC3woAAt8MAALfDQAC31gAAt97AALfmwAC37sAAt+9AALfvwAC38EAAt/DAALfxgAC38cAAt/IAALfywAC38wAAt/OAALfzwAC39EAAt/TAALf1AAC39UAAt/YAALf2QAC394AAt/rAALf8AAC3/IAAt/0AALf+QAC3/wAAt//AALgAQAC4CYAAuBKAALgcQAC4JUAAuCYAALgmgAC4JwAAuCeAALgoAAC4KIAAuCjAALgpgAC4LMAAuDEAALgxgAC4MgAAuDKAALgzAAC4M4AAuDQAALg0gAC4NQAAuDlAALg6AAC4OsAAuDuAALg8QAC4PQAAuD3AALg+gAC4P0AAuD/AALhPgAC4UAAAuFCAALhRAAC4UcAAuFIAALhSQAC4UoAAuFLAALhTQAC4U8AAuFQAALhUQAC4VMAAuFUAALhkwAC4ZUAAuGXAALhmQAC4ZwAAuGdAALhngAC4Z8AAuGgAALhogAC4aQAAuGlAALhpgAC4agAAuGpAALh6AAC4eoAAuHtAALh7wAC4fIAAuHzAALh9AAC4fUAAuH2AALh+AAC4foAAuH7AALh/AAC4f4AAuH/AALiDAAC4g0AAuIOAALiEAAC4k8AAuJRAALiUwAC4lUAAuJYAALiWQAC4loAAuJbAALiXAAC4l4AAuJgAALiYQAC4mIAAuJkAALiZQAC4qQAAuKmAALiqAAC4qoAAuKtAALirgAC4q8AAuKwAALisQAC4rMAAuK1AALitgAC4rcAAuK5AALiugAC4vkAAuL7AALi/QAC4v8AAuMCAALjAwAC4wQAAuMFAALjBgAC4wgAAuMKAALjCwAC4wwAAuMOAALjDwAC404AAuNQAALjUgAC41QAAuNXAALjWAAC41kAAuNaAALjWwAC410AAuNfAALjYAAC42EAAuNjAALjZAAC46MAAuOlAALjpwAC46kAAuOsAALjrQAC464AAuOvAALjsAAC47IAAuO0AALjtQAC47YAAuO4AALjuQAC494AAuQCAALkKQAC5E0AAuRQAALkUgAC5FQAAuRWAALkWAAC5FoAAuRbAALkXgAC5GsAAuR6AALkfAAC5H4AAuSAAALkggAC5IQAAuSGAALkiAAC5JcAAuSaAALknQAC5KAAAuSjAALkpgAC5KkAAuSsAALkrgAC5O0AAuTvAALk8QAC5PMAAuT2AALk9wAC5PgAAuT5AALk+gAC5PwAAuT+AALk/wAC5QAAAuUCAALlAwAC5UIAAuVEAALlRgAC5UgAAuVLAALlTAAC5U0AAuVOAALlTwAC5VEAAuVTAALlVAAC5VUAAuVXAALlWAAC5ZcAAuWZAALlmwAC5Z0AAuWgAALloQAC5aIAAuWjAALlpAAC5aYAAuWoAALlqQAC5aoAAuWsAALlrQAC5ewAAuXuAALl8AAC5fIAAuX1AALl9gAC5fcAAuX4AALl+QAC5fsAAuX9AALl/gAC5f8AAuYBAALmAgAC5kEAAuZDAALmRQAC5kcAAuZKAALmSwAC5kwAAuZNAALmTgAC5lAAAuZSAALmUwAC5lQAAuZWAALmVwAC5pYAAuaYAALmmgAC5pwAAuafAALmoAAC5qEAAuaiAALmowAC5qUAAuanAALmqAAC5qkAAuarAALmrAAC5usAAubtAALm7wAC5vEAAub0AALm9QAC5vYAAub3AALm+AAC5voAAub8AALm/QAC5v4AAucAAALnAQAC50wAAudvAALnjwAC568AAuexAALnswAC57UAAue3AALnugAC57sAAue8AALnvwAC58AAAufCAALnwwAC58UAAufIAALnyQAC58oAAufNAALnzgAC59cAAufkAALn6QAC5+sAAuftAALn8gAC5/UAAuf4AALn+gAC6B8AAuhDAALoagAC6I4AAuiRAALokwAC6JUAAuiXAALomQAC6JsAAuicAALonwAC6KwAAui9AALovwAC6MEAAujDAALoxQAC6McAAujJAALoywAC6M0AAujeAALo4QAC6OQAAujnAALo6gAC6O0AAujwAALo8wAC6PYAAuj4AALpNwAC6TkAAuk7AALpPQAC6UAAAulBAALpQgAC6UMAAulEAALpRgAC6UgAAulJAALpSgAC6UwAAulNAALpjAAC6Y4AAumQAALpkgAC6ZUAAumWAALplwAC6ZgAAumZAALpmwAC6Z0AAumeAALpnwAC6aEAAumiAALp4QAC6eMAAunmAALp6AAC6esAAunsAALp7QAC6e4AAunvAALp8QAC6fMAAun0AALp9QAC6fcAAun4AALqBQAC6gYAAuoHAALqCQAC6kgAAupKAALqTAAC6k4AAupRAALqUgAC6lMAAupUAALqVQAC6lcAAupZAALqWgAC6lsAAupdAALqXgAC6p0AAuqfAALqoQAC6qMAAuqmAALqpwAC6qgAAuqpAALqqgAC6qwAAuquAALqrwAC6rAAAuqyAALqswAC6vIAAur0AALq9gAC6vgAAur7AALq/AAC6v0AAur+AALq/wAC6wEAAusDAALrBAAC6wUAAusHAALrCAAC60cAAutJAALrSwAC600AAutQAALrUQAC61IAAutTAALrVAAC61YAAutYAALrWQAC61oAAutcAALrXQAC65wAAuueAALroAAC66IAAuulAALrpgAC66cAAuuoAALrqQAC66sAAuutAALrrgAC668AAuuxAALrsgAC69cAAuv7AALsIgAC7EYAAuxJAALsSwAC7E0AAuxPAALsUQAC7FMAAuxUAALsVwAC7GQAAuxzAALsdQAC7HcAAux5AALsewAC7H0AAux/AALsgQAC7JAAAuyTAALslgAC7JkAAuycAALsnwAC7KIAAuylAALspwAC7OYAAuzoAALs6gAC7OwAAuzvAALs8AAC7PEAAuzyAALs8wAC7PUAAuz3AALs+AAC7PkAAuz7AALs/AAC7TsAAu09AALtPwAC7UEAAu1EAALtRQAC7UYAAu1HAALtSAAC7UoAAu1MAALtTQAC7U4AAu1QAALtUQAC7ZAAAu2SAALtlAAC7ZYAAu2ZAALtmgAC7ZsAAu2cAALtnQAC7Z8AAu2hAALtogAC7aMAAu2lAALtpgAC7eUAAu3nAALt6QAC7esAAu3uAALt7wAC7fAAAu3xAALt8gAC7fQAAu32AALt9wAC7fgAAu36AALt+wAC7joAAu48AALuPgAC7kAAAu5DAALuRAAC7kUAAu5GAALuRwAC7kkAAu5LAALuTAAC7k0AAu5PAALuUAAC7o8AAu6RAALukwAC7pUAAu6YAALumQAC7poAAu6bAALunAAC7p4AAu6gAALuoQAC7qIAAu6kAALupQAC7uQAAu7mAALu6AAC7uoAAu7tAALu7gAC7u8AAu7wAALu8QAC7vMAAu71AALu9gAC7vcAAu75AALu+gAC70UAAu9oAALviAAC76gAAu+qAALvrAAC764AAu+wAALvswAC77QAAu+1AALvuAAC77kAAu+7AALvvAAC774AAu/BAALvwgAC78MAAu/GAALvxwAC78wAAu/ZAALv3gAC7+AAAu/iAALv5wAC7+oAAu/tAALv7wAC8BQAAvA4AALwXwAC8IMAAvCGAALwiAAC8IoAAvCMAALwjgAC8JAAAvCRAALwlAAC8KEAAvCyAALwtAAC8LYAAvC4AALwugAC8LwAAvC+AALwwAAC8MIAAvDTAALw1gAC8NkAAvDcAALw3wAC8OIAAvDlAALw6AAC8OsAAvDtAALxLAAC8S4AAvEwAALxMgAC8TUAAvE2AALxNwAC8TgAAvE5AALxOwAC8T0AAvE+AALxPwAC8UEAAvFCAALxgQAC8YMAAvGFAALxhwAC8YoAAvGLAALxjAAC8Y0AAvGOAALxkAAC8ZIAAvGTAALxlAAC8ZYAAvGXAALx1gAC8dgAAvHbAALx3QAC8eAAAvHhAALx4gAC8eMAAvHkAALx5gAC8egAAvHpAALx6gA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DFD0AAxQ+AAMUPwADFEEAAxRDAAMURAADFEUAAxRHAAMUSAADFIcAAxSJAAMUiwADFI0AAxSQAAMUkQADFJIAAxSTAAMUlAADFJYAAxSYAAMUmQADFJoAAxScAAMUnQADFNwAAxTeAAMU4AADFOIAAxTlAAMU5gADFOcAAxToAAMU6QADFOsAAxTtAAMU7gADFO8AAxTxAAMU8gADFTEAAxUzAAMVNQADFTcAAxU6AAMVOwADFTwAAxU9AAMVPgADFUAAAxVCAAMVQwADFUQAAxVGAAMVRwADFYYAAxWIAAMVigADFYwAAxWPAAMVkAADFZEAAxWSAAMVkwADFZUAAxWXAAMVmAADFZkAAxWbAAMVnAADFdsAAxXdAAMV3wADFeEAAxXkAAMV5QADFeYAAxXnAAMV6AADFeoAAxXsAAMV7QADFe4AAxXwAAMV8QADFjwAAxZfAAMWfwADFp8AAxahAAMWowADFqUAAxanAAMWqgADFqsAAxasAAMWrwADFrAAAxayAAMWswADFrUAAxa4AAMWuQADFroAAxa9AAMWvgADFsMAAxbQAAMW1QADFtcAAxbZAAMW3gADFuEAAxbkAAMW5gADFwsAAxcvAAMXVgADF3oAAxd9AAMXfwADF4EAAxeDAAMXhQADF4cAAxeIAAMXiwADF5gAAxepAAMXqwADF60AAxevAAMXsQADF7MAAxe1AAMXtwADF7kAAxfKAAMXzQADF9AAAxfTAAMX1gADF9kAAxfcAAMX3wADF+IAAxfkAAMYIwADGCUAAxgnAAMYKQADGCwAAxgtAAMYLgADGC8AAxgwAAMYMgADGDQAAxg1AAMYNgADGDgAAxg5AAMYeAADGHoAAxh8AAMYfgADGIEAAxiCAAMYgwADGIQAAxiFAAMYhwADGIkAAxiKAAMYiwADGI0AAxiOAAMYzQADGM8AAxjSAAMY1AADGNcAAxjYAAMY2QADGNoAAxjbAAMY3QADGN8AAxjgAAMY4QADGOMAAxjkAAMY8QADGPIAAxjzAAMY9QADGTQAAxk2AAMZOAADGToAAxk9AAMZPgADGT8AAxlAAAMZQQADGUMAAxlFAAMZRgADGUcAAxlJAAMZSgADGYkAAxmLAAMZjQADGY8AAxmSAAMZkwADGZQAAxmVAAMZlgADGZgAAxmaAAMZmwADGZwAAxmeAAMZnwADGd4AAxngAAMZ4gADGeQAAxnnAAMZ6AADGekAAxnqAAMZ6wADGe0AAxnvAAMZ8AADGfEAAxnzAAMZ9AADGjMAAxo1AAMaNwADGjkAAxo8AAMaPQADGj4AAxo/AAMaQAADGkIAAxpEAAMaRQADGkYAAxpIAAMaSQADGogAAxqKAAMajAADGo4AAxqRAAMakgADGpMAAxqUAAMalQADGpcAAxqZAAMamgADGpsAAxqdAAMangADGsMAAxrnAAMbDgADGzIAAxs1AAMbNwADGzkAAxs7AAMbPQADGz8AAxtAAAMbQwADG1AAAxtfAAMbYQADG2MAAxtlAAMbZwADG2kAAxtrAAMbbQADG3wAAxt/AAMbggADG4UAAxuIAAMbiwADG44AAxuRAAMbkwADG9IAAxvUAAMb1gADG9gAAxvbAAMb3AADG90AAxveAAMb3wADG+EAAxvjAAMb5AADG+UAAxvnAAMb6AADHCcAAxwpAAMcKwADHC0AAxwwAAMcMQADHDIAAxwzAAMcNAADHDYAAxw4AAMcOQADHDoAAxw8AAMcPQADHHwAAxx+AAMcgAADHIIAAxyFAAMchgADHIcAAxyIAAMciQADHIsAAxyNAAMcjgADHI8AAxyRAAMckgADHNEAAxzTAAMc1gADHNgAAxzbAAMc3AADHN0AAxzeAAMc3wADHOEAAxzjAAMc5AADHOUAAxznAAMc6AADHScAAx0pAAMdKwADHS0AAx0wAAMdMQADHTIAAx0zAAMdNAADHTYAAx04AAMdOQADHToAAx08AAMdPQADHXwAAx1+AAMdgAADHYIAAx2FAAMdhgADHYcAAx2IAAMdiQADHYsAAx2NAAMdjgADHY8AAx2RAAMdkgADHdEAAx3TAAMd1QADHdcAAx3aAAMd2wADHdwAAx3dAAMd3gADHeAAAx3iAAMd4wADHeQAAx3mAAMd5wADHjIAAx5VAAMedQADHpUAAx6XAAMemQADHpsAAx6dAAMeoAADHqEAAx6iAAMepQADHqYAAx6oAAMeqQADHqsAAx6uAAMerwADHrAAAx6zAAMetAADHr0AAx7KAAMezwADHtEAAx7TAAMe2AADHtsAAx7eAAMe4AADHwUAAx8pAAMfUAADH3QAAx93AAMfeQADH3sAAx99AAMffwADH4EAAx+CAAMfhQADH5IAAx+jAAMfpQADH6cAAx+pAAMfqwADH60AAx+vAAMfsQADH7MAAx/EAAMfxwADH8oAAx/NAAMf0AADH9MAAx/WAAMf2QADH9wAAx/eAAMgHQADIB8AAyAhAAMgIwADICYAAyAnAAMgKAADICkAAyAqAAMgLAADIC4AAyAvAAMgMAADIDIAAyAzAAMgcgADIHQAAyB2AAMgeAADIHsAAyB8AAMgfQADIH4AAyB/AAMggQADIIMAAyCEAAMghQADIIcAAyCIAAMgxwADIMkAAyDMAAMgzgADINEAAyDSAAMg0wADINQAAyDVAAMg1wADINkAAyDaAAMg2wADIN0AAyDeAAMg6wADIOwAAyDtAAMg7wADIS4AAyEwAAMhMgADITQAAyE3AAMhOAADITkAAyE6AAMhOwADIT0AAyE/AAMhQAADIUEAAyFDAAMhRAADIYMAAyGFAAMhhwADIYkAAyGMAAMhjQADIY4AAyGPAAMhkAADIZIAAyGUAAMhlQADIZYAAyGYAAMhmQADIdgAAyHaAAMh3AADId4AAyHhAAMh4gADIeMAAyHkAAMh5QADIecAAyHpAAMh6gADIesAAyHtAAMh7gADIi0AAyIvAAMiMQADIjMAAyI2AAMiNwADIjgAAyI5AAMiOgADIjwAAyI+AAMiPwADIkAAAyJCAAMiQwADIoIAAyKEAAMihgADIogAAyKLAAMijAADIo0AAyKOAAMijwADIpEAAyKTAAMilAADIpUAAyKXAAMimAADIr0AAyLhAAMjCAADIywAAyMvAAMjMQADIzMAAyM1AAMjNwADIzkAAyM6AAMjPQADI0oAAyNZAAMjWwADI10AAyNfAAMjYQADI2MAAyNlAAMjZwADI3YAAyN5AAMjfAADI38AAyOCAAMjhQADI4gAAyOLAAMjjQADI8wAAyPOAAMj0AADI9IAAyPVAAMj1gADI9cAAyPYAAMj2QADI9sAAyPdAAMj3gADI98AAyPhAAMj4gADJCEAAyQjAAMkJQADJCcAAyQqAAMkKwADJCwAAyQtAAMkLgADJDAAAyQyAAMkMwADJDQAAyQ2AAMkNwADJHYAAyR4AAMkegADJHwAAyR/AAMkgAADJIEAAySCAAMkgwADJIUAAySHAAMkiAADJIkAAySLAAMkjAADJMsAAyTNAAMkzwADJNEAAyTUAAMk1QADJNYAAyTXAAMk2AADJNoAAyTcAAMk3QADJN4AAyTgAAMk4QADJSAAAyUiAAMlJAADJSYAAyUpAAMlKgADJSsAAyUsAAMlLQADJS8AAyUxAAMlMgADJTMAAyU1AAMlNgADJXUAAyV3AAMleQADJXsAAyV+AAMlfwADJYAAAyWBAAMlggADJYQAAyWGAAMlhwADJYgAAyWKAAMliwADJcoAAyXMAAMlzgADJdAAAyXTAAMl1AADJdUAAyXWAAMl1wADJdkAAyXbAAMl3AADJd0AAyXfAAMl4AADJisAAyZOAAMmbgADJo4AAyaQAAMmkgADJpQAAyaWAAMmmQADJpoAAyabAAMmngADJp8AAyahAAMmogADJqQAAyanAAMmqAADJqkAAyasAAMmrQADJrYAAybDAAMmyAADJsoAAybMAAMm0QADJtQAAybXAAMm2QADJv4AAyciAAMnSQADJ20AAydwAAMncgADJ3QAAyd2AAMneAADJ3oAAyd7AAMnfgADJ4sAAyecAAMnngADJ6AAAyeiAAMnpAADJ6YAAyeoAAMnqgADJ6wAAye9AAMnwAADJ8MAAyfGAAMnyQADJ8wAAyfPAAMn0gADJ9UAAyfXAAMoFgADKBgAAygaAAMoHAADKB8AAyggAAMoIQADKCIAAygjAAMoJQADKCcAAygoAAMoKQADKCsAAygsAAMoawADKG0AAyhvAAMocQADKHQAAyh1AAModgADKHcAAyh4AAMoegADKHwAAyh9AAMofgADKIAAAyiBAAMowAADKMIAAyjFAAMoxwADKMoAAyjLAAMozAADKM0AAyjOAAMo0AADKNIAAyjTAAMo1AADKNYAAyjXAAMo5AADKOUAAyjmAAMo6AADKScAAykpAAMpKwADKS0AAykwAAMpMQADKTIAAykzAAMpNAADKTYAAyk4AAMpOQADKToAAyk8AAMpPQADKXwAAyl+AAMpgAADKYIAAymFAAMphgADKYcAAymIAAMpiQADKYsAAymNAAMpjgADKY8AAymRAAMpkgADKdEAAynTAAMp1QADKdcAAynaAAMp2wADKdwAAyndAAMp3gADKeAAAyniAAMp4wADKeQAAynmAAMp5wADKiYAAyooAAMqKgADKiwAAyovAAMqMAADKjEAAyoyAAMqMwADKjUAAyo3AAMqOAADKjkAAyo7AAMqPAADKnsAAyp9AAMqfwADKoEAAyqEAAMqhQADKoYAAyqHAAMqiAADKooAAyqMAAMqjQADKo4AAyqQAAMqkQADKrYAAyraAAMrAQADKyUAAysoAAMrKgADKywAAysuAAMrMAADKzIAAyszAAMrNgADK0MAAytSAAMrVAADK1YAAytYAAMrWgADK1wAAyteAAMrYAADK28AAytyAAMrdQADK3gAAyt7AAMrfgADK4EAAyuEAAMrhgADK8UAAyvHAAMryQADK8sAAyvOAAMrzwADK9AAAyvRAAMr0gADK9QAAyvWAAMr1wADK9gAAyvaAAMr2wADLBoAAywcAAMsHgADLCAAAywjAAMsJAADLCUAAywmAAMsJwADLCkAAywrAAMsLAADLC0AAywvAAMsMAADLG8AAyxxAAMscwADLHUAAyx4AAMseQADLHoAAyx7AAMsfAADLH4AAyyAAAMsgQADLIIAAyyEAAMshQADLMQAAyzGAAMsyQADLMsAAyzOAAMszwADLNAAAyzRAAMs0gADLNQAAyzWAAMs1wADLNgAAyzaAAMs2wADLRoAAy0cAAMtHgADLSAAAy0jAAMtJAADLSUAAy0mAAMtJwADLSkAAy0rAAMtLAADLS0AAy0vAAMtMAADLW8AAy1xAAMtcwADLXUAAy14AAMteQADLXoAAy17AAMtfAADLX4AAy2AAAMtgQADLYIAAy2EAAMthQADLcQAAy3GAAMtyAADLcoAAy3NAAMtzgADLc8AAy3QAAMt0QADLdMAAy3VAAMt1gADLdcAAy3ZAAMt2gADLiUAAy5IAAMuaAADLogAAy6KAAMujAADLo4AAy6QAAMukwADLpQAAy6VAAMumAADLpkAAy6bAAMunAADLp4AAy6hAAMuogADLqMAAy6mAAMupwADLqwAAy65AAMuvgADLsAAAy7CAAMuxwADLsoAAy7NAAMuzwADLvQAAy8YAAMvPwADL2MAAy9mAAMvaAADL2oAAy9sAAMvbgADL3AAAy9xAAMvdAADL4EAAy+SAAMvlAADL5YAAy+YAAMvmgADL5wAAy+eAAMvoAADL6IAAy+zAAMvtgADL7kAAy+8AAMvvwADL8IAAy/FAAMvyAADL8sAAy/NAAMwDAADMA4AAzAQAAMwEgADMBUAAzAWAAMwFwADMBgAAzAZAAMwGwADMB0AAzAeAAMwHwADMCEAAzAiAAMwYQADMGMAAzBlAAMwZwADMGoAAzBrAAMwbAADMG0AAzBuAAMwcAADMHIAAzBzAAMwdAADMHYAAzB3AAMwtgADMLgAAzC7AAMwvQADMMAAAzDBAAMwwgADMMMAAzDEAAMwxgADMMgAAzDJAAMwygADMMwAAzDNAAMw2gADMNsAAzDcAAMw3gADMR0AAzEfAAMxIQADMSMAAzEmAAMxJwADMSgAAzEpAAMxKgADMSwAAzEuAAMxLwADMTAAAzEyAAMxMwADMXIAAzF0AAMxdgADMXgAAzF7AAMxfAADMX0AAzF+AAMxfwADMYEAAzGDAAMxhAADMYUAAzGHAAMxiAADMccAAzHJAAMxywADMc0AAzHQAAMx0QADMdIAAzHTAAMx1AADMdYAAzHYAAMx2QADMdoAAzHcAAMx3QADMhwAAzIeAAMyIAADMiIAAzIlAAMyJgADMicAAzIoAAMyKQADMisAAzItAAMyLgADMi8AAzIxAAMyMgADMnEAAzJzAAMydQADMncAAzJ6AAMyewADMnwAAzJ9AAMyfgADMoAAAzKCAAMygwADMoQAAzKGAAMyhwADMqwAAzLQAAMy9wADMxsAAzMeAAMzIAADMyIAAzMkAAMzJgADMygAAzMpAAMzLAADMzkAAzNIAAMzSgADM0wAAzNOAAMzUAADM1IAAzNUAAMzVgADM2UAAzNoAAMzawADM24AAzNxAAMzdAADM3cAAzN6AAMzfAADM7sAAzO9AAMzvwADM8EAAzPEAAMzxQADM8YAAzPHAAMzyAADM8oAAzPMAAMzzQADM84AAzPQAAMz0QADNBAAAzQSAAM0FAADNBYAAzQZAAM0GgADNBsAAzQcAAM0HQADNB8AAzQhAAM0IgADNCMAAzQlAAM0JgADNGUAAzRnAAM0aQADNGsAAzRuAAM0bwADNHAAAzRxAAM0cgADNHQAAzR2AAM0dwADNHgAAzR6AAM0ewADNLoAAzS8AAM0vgADNMAAAzTDAAM0xAADNMUAAzTGAAM0xwADNMkAAzTLAAM0zAADNM0AAzTPAAM00AADNQ8AAzURAAM1EwADNRUAAzUYAAM1GQADNRoAAzUbAAM1HAADNR4AAzUgAAM1IQADNSIAAzUkAAM1JQADNWQAAzVmAAM1aAADNWoAAzVtAAM1bgADNW8AAzVwAAM1cQADNXMAAzV1AAM1dgADNXcAAzV5AAM1egADNbkAAzW7AAM1vQADNb8AAzXCAAM1wwADNcQAAzXFAAM1xgADNcgAAzXKAAM1ywADNcwAAzXOAAM1zwADNhoAAzY9AAM2XQADNn0AAzZ/AAM2gQADNoMAAzaFAAM2iAADNokAAzaKAAM2jQADNo4AAzaQAAM2kQADNpMAAzaWAAM2lwADNpgAAzabAAM2nAADNqEAAzauAAM2swADNrUAAza3AAM2vAADNr8AAzbCAAM2xAADNukAAzcNAAM3NAADN1gAAzdbAAM3XQADN18AAzdhAAM3YwADN2UAAzdmAAM3aQADN3YAAzeHAAM3iQADN4sAAzeNAAM3jwADN5EAAzeTAAM3lQADN5cAAzeoAAM3qwADN64AAzexAAM3tAADN7cAAze6AAM3vQADN8AAAzfCAAM4AQADOAMAAzgFAAM4BwADOAoAAzgLAAM4DAADOA0AAzgOAAM4EAADOBIAAzgTAAM4FAADOBYAAzgXAAM4VgADOFgAAzhaAAM4XAADOF8AAzhgAAM4YQADOGIAAzhjAAM4ZQADOGcAAzhoAAM4aQADOGsAAzhsAAM4qwADOK0AAziwAAM4sgADOLUAAzi2AAM4twADOLgAAzi5AAM4uwADOL0AAzi+AAM4vwADOMEAAzjCAAM4zwADONAAAzjRAAM40wADORIAAzkUAAM5FgADORgAAzkbAAM5HAADOR0AAzkeAAM5HwADOSEAAzkjAAM5JAADOSUAAzknAAM5KAADOWcAAzlpAAM5awADOW0AAzlwAAM5cQADOXIAAzlzAAM5dAADOXYAAzl4AAM5eQADOXoAAzl8AAM5fQADObwAAzm+AAM5wAADOcIAAznFAAM5xgADOccAAznIAAM5yQADOcsAAznNAAM5zgADOc8AAznRAAM50gADOhEAAzoTAAM6FQADOhcAAzoaAAM6GwADOhwAAzodAAM6HgADOiAAAzoiAAM6IwADOiQAAzomAAM6JwADOmYAAzpoAAM6agADOmwAAzpvAAM6cAADOnEAAzpyAAM6cwADOnUAAzp3AAM6eAADOnkAAzp7AAM6fAADOqEAAzrFAAM67AADOxAAAzsTAAM7FQADOxcAAzsZAAM7GwADOx0AAzseAAM7IQADOy4AAzs9AAM7PwADO0EAAztDAAM7RQADO0cAAztJAAM7SwADO1oAAztdAAM7YAADO2MAAztmAAM7aQADO2wAAztvAAM7cQADO7AAAzuyAAM7tAADO7YAAzu5AAM7ugADO7sAAzu8AAM7vQADO78AAzvBAAM7wgADO8MAAzvFAAM7xgADPAUAAzwHAAM8CQADPAsAAzwOAAM8DwADPBAAAzwRAAM8EgADPBQAAzwWAAM8FwADPBgAAzwaAAM8GwADPFoAAzxcAAM8XgADPGAAAzxjAAM8ZAADPGUAAzxmAAM8ZwADPGkAAzxrAAM8bAADPG0AAzxvAAM8cAADPK8AAzyxAAM8swADPLUAAzy4AAM8uQADPLoAAzy7AAM8vAADPL4AAzzAAAM8wQADPMIAAzzEAAM8xQADPQQAAz0GAAM9CAADPQoAAz0NAAM9DgADPQ8AAz0QAAM9EQADPRMAAz0VAAM9FgADPRcAAz0ZAAM9GgADPVkAAz1bAAM9XQADPV8AAz1iAAM9YwADPWQAAz1lAAM9ZgADPWgAAz1qAAM9awADPWwAAz1uAAM9bwADPa4AAz2wAAM9sgADPbQAAz23AAM9uAADPbkAAz26AAM9uwADPb0AAz2/AAM9wAADPcEAAz3DAAM9xAADPg8AAz4yAAM+UgADPnIAAz50AAM+dgADPngAAz56AAM+fQADPn4AAz5/AAM+ggADPoMAAz6FAAM+hgADPogAAz6LAAM+jAADPo0AAz6QAAM+kQADPpYAAz6jAAM+qAADPqoAAz6sAAM+sQADPrQAAz63AAM+uQADPt4AAz8CAAM/KQADP00AAz9QAAM/UgADP1QAAz9WAAM/WAADP1oAAz9bAAM/XgADP2sAAz98AAM/fgADP4AAAz+CAAM/hAADP4YAAz+IAAM/igADP4wAAz+dAAM/oAADP6MAAz+mAAM/qQADP6wAAz+vAAM/sgADP7UAAz+3AAM/9gADP/gAAz/6AAM//AADP/8AA0AAAANAAQADQAIAA0ADAANABQADQAcAA0AIAANACQADQAsAA0AMAANASwADQE0AA0BPAANAUQADQFQAA0BVAANAVgADQFcAA0BYAANAWgADQFwAA0BdAANAXgADQGAAA0BhAANAoAADQKIAA0ClAANApwADQKoAA0CrAANArAADQK0AA0CuAANAsAADQLIAA0CzAANAtAADQLYAA0C3AANAxAADQMUAA0DGAANAyAADQQcAA0EJAANBCwADQQ0AA0EQAANBEQADQRIAA0ETAANBFAADQRYAA0EYAANBGQADQRoAA0EcAANBHQADQVwAA0FeAANBYAADQWIAA0FlAANBZgADQWcAA0FoAANBaQADQWsAA0FtAANBbgADQW8AA0FxAANBcgADQbEAA0GzAANBtQADQbcAA0G6AANBuwADQbwAA0G9AANBvgADQcAAA0HCAANBwwADQcQAA0HGAANBxwADQgYAA0IIAANCCgADQgwAA0IPAANCEAADQhEAA0ISAANCEwADQhUAA0IXAANCGAADQhkAA0IbAANCHAADQlsAA0JdAANCXwADQmEAA0JkAANCZQADQmYAA0JnAANCaAADQmoAA0JsAANCbQADQm4AA0JwAANCcQADQpYAA0K6AANC4QADQwUAA0MIAANDCgADQwwAA0MOAANDEAADQxIAA0MTAANDFgADQyMAA0MyAANDNAADQzYAA0M4AANDOgADQzwAA0M+AANDQAADQ08AA0NSAANDVQADQ1gAA0NbAANDXgADQ2EAA0NkAANDZgADQ6UAA0OnAANDqQADQ6sAA0OuAANDrwADQ7AAA0OxAANDsgADQ7QAA0O2AANDtwADQ7gAA0O6AANDuwADQ/oAA0P8AAND/gADRAAAA0QDAANEBAADRAUAA0QGAANEBwADRAkAA0QLAANEDAADRA0AA0QPAANEEAADRE8AA0RRAANEUwADRFUAA0RYAANEWQADRFoAA0RbAANEXAADRF4AA0RgAANEYQADRGIAA0RkAANEZQADRKQAA0SmAANEqAADRKoAA0StAANErgADRK8AA0SwAANEsQADRLMAA0S1AANEtgADRLcAA0S5AANEugADRPkAA0T7AANE/QADRP8AA0UCAANFAwADRQQAA0UFAANFBgADRQgAA0UKAANFCwADRQwAA0UOAANFDwADRU4AA0VQAANFUgADRVQAA0VXAANFWAADRVkAA0VaAANFWwADRV0AA0VfAANFYAADRWEAA0VjAANFZAADRaMAA0WlAANFpwADRakAA0WsAANFrQADRa4AA0WvAANFsAADRbIAA0W0AANFtQADRbYAA0W4AANFuQADRgQAA0YnAANGRwADRmcAA0ZpAANGawADRm0AA0ZvAANGcgADRnMAA0Z0AANGdwADRngAA0Z6AANGewADRn0AA0aAAANGgQADRoIAA0aFAANGhgADRosAA0aYAANGnQADRp8AA0ahAANGpgADRqkAA0asAANGrgADRtMAA0b3AANHHgADR0IAA0dFAANHRwADR0kAA0dLAANHTQADR08AA0dQAANHUwADR2AAA0dxAANHcwADR3UAA0d3AANHeQADR3sAA0d9AANHfwADR4EAA0eSAANHlQADR5gAA0ebAANHngADR6EAA0ekAANHpwADR6oAA0esAANH6wADR+0AA0fvAANH8QADR/QAA0f1AANH9gADR/cAA0f4AANH+gADR/wAA0f9AANH/gADSAAAA0gBAANIQAADSEIAA0hEAANIRgADSEkAA0hKAANISwADSEwAA0hNAANITwADSFEAA0hSAANIUwADSFUAA0hWAANIlQADSJcAA0iaAANInAADSJ8AA0igAANIoQADSKIAA0ijAANIpQADSKcAA0ioAANIqQADSKsAA0isAANIuQADSLoAA0i7AANIvQADSPwAA0j+AANJAAADSQIAA0kFAANJBgADSQcAA0kIAANJCQADSQsAA0kNAANJDgADSQ8AA0kRAANJEgADSVEAA0lTAANJVQADSVcAA0laAANJWwADSVwAA0ldAANJXgADSWAAA0liAANJYwADSWQAA0lmAANJZwADSaYAA0moAANJqgADSawAA0mvAANJsAADSbEAA0myAANJswADSbUAA0m3AANJuAADSbkAA0m7AANJvAADSfsAA0n9AANJ/wADSgEAA0oEAANKBQADSgYAA0oHAANKCAADSgoAA0oMAANKDQADSg4AA0oQAANKEQADSlAAA0pSAANKVAADSlYAA0pZAANKWgADSlsAA0pcAANKXQADSl8AA0phAANKYgADSmMAA0plAANKZgADSosAA0qvAANK1gADSvoAA0r9AANK/wADSwEAA0sDAANLBQADSwcAA0sIAANLCwADSxgAA0snAANLKQADSysAA0stAANLLwADSzEAA0szAANLNQADS0QAA0tHAANLSgADS00AA0tQAANLUwADS1YAA0tZAANLWwADS5oAA0ucAANLngADS6AAA0ujAANLpAADS6UAA0umAANLpwADS6kAA0urAANLrAADS60AA0uvAANLsAADS+8AA0vxAANL8wADS/UAA0v4AANL+QADS/oAA0v7AANL/AADS/4AA0wAAANMAQADTAIAA0wEAANMBQADTEQAA0xGAANMSAADTEoAA0xNAANMTgADTE8AA0xQAANMUQADTFMAA0xVAANMVgADTFcAA0xZAANMWgADTJkAA0ybAANMngADTKAAA0yjAANMpAADTKUAA0ymAANMpwADTKkAA0yrAANMrAADTK0AA0yvAANMsAADTO8AA0zxAANM8wADTPUAA0z4AANM+QADTPoAA0z7AANM/AADTP4AA00AAANNAQADTQIAA00EAANNBQADTUQAA01GAANNSAADTUoAA01NAANNTgADTU8AA01QAANNUQADTVMAA01VAANNVgADTVcAA01ZAANNWgADTZkAA02bAANNnQADTZ8AA02iAANNowADTaQAA02lAANNpgADTagAA02qAANNqwADTawAA02uAANNrwADTfoAA04dAANOPQADTl0AA05fAANOYQADTmMAA05lAANOaAADTmkAA05qAANObQADTm4AA05wAANOcQADTnMAA052AANOdwADTngAA057AANOfAADToUAA06SAANOlwADTpkAA06bAANOoAADTqMAA06mAANOqAADTs0AA07xAANPGAADTzwAA08/AANPQQADT0MAA09FAANPRwADT0kAA09KAANPTQADT1oAA09rAANPbQADT28AA09xAANPcwADT3UAA093AANPeQADT3sAA0+MAANPjwADT5IAA0+VAANPmAADT5sAA0+eAANPoQADT6QAA0+mAANP5QADT+cAA0/pAANP6wADT+4AA0/vAANP8AADT/EAA0/yAANP9AADT/YAA0/3AANP+AADT/oAA0/7AANQOgADUDwAA1A+AANQQAADUEMAA1BEAANQRQADUEYAA1BHAANQSQADUEsAA1BMAANQTQADUE8AA1BQAANQjwADUJEAA1CUAANQlgADUJkAA1CaAANQmwADUJwAA1CdAANQnwADUKEAA1CiAANQowADUKUAA1CmAANQswADULQAA1C1AANQtwADUPYAA1D4AANQ+gADUPwAA1D/AANRAAADUQEAA1ECAANRAwADUQUAA1EHAANRCAADUQkAA1ELAANRDAADUUsAA1FNAANRTwADUVEAA1FUAANRVQADUVYAA1FXAANRWAADUVoAA1FcAANRXQADUV4AA1FgAANRYQADUaAAA1GiAANRpAADUaYAA1GpAANRqgADUasAA1GsAANRrQADUa8AA1GxAANRsgADUbMAA1G1AANRtgADUfUAA1H3AANR+QADUfsAA1H+AANR/wADUgAAA1IBAANSAgADUgQAA1IGAANSBwADUggAA1IKAANSCwADUkoAA1JMAANSTgADUlAAA1JTAANSVAADUlUAA1JWAANSVwADUlkAA1JbAANSXAADUl0AA1JfAANSYAADUoUAA1KpAANS0AADUvQAA1L3AANS+QADUvsAA1L9AANS/wADUwEAA1MCAANTBQADUxIAA1MhAANTIwADUyUAA1MnAANTKQADUysAA1MtAANTLwADUz4AA1NBAANTRAADU0cAA1NKAANTTQADU1AAA1NTAANTVQADU5QAA1OWAANTmAADU5oAA1OdAANTngADU58AA1OgAANToQADU6MAA1OlAANTpgADU6cAA1OpAANTqgADU+kAA1PrAANT7QADU+8AA1PyAANT8wADU/QAA1P1AANT9gADU/gAA1P6AANT+wADU/wAA1P+AANT/wADVD4AA1RAAANUQgADVEQAA1RHAANUSAADVEkAA1RKAANUSwADVE0AA1RPAANUUAADVFEAA1RTAANUVAADVJMAA1SVAANUlwADVJkAA1ScAANUnQADVJ4AA1SfAANUoAADVKIAA1SkAANUpQADVKYAA1SoAANUqQADVOgAA1TqAANU7AADVO4AA1TxAANU8gADVPMAA1T0AANU9QADVPcAA1T5AANU+gADVPsAA1T9AANU/gADVT0AA1U/AANVQQADVUMAA1VGAANVRwADVUgAA1VJAANVSgADVUwAA1VOAANVTwADVVAAA1VSAANVUwADVZIAA1WUAANVlgADVZgAA1WbAANVnAADVZ0AA1WeAANVnwADVaEAA1WjAANVpAADVaUAA1WnAANVqAADVbEAA1WyAANVtAADVfcAA1YbAANWPwADVmIAA1aJAANWqQADVtAAA1b3AANXFwADVzsAA1dfAANXYQADV2QAA1dmAANXaAADV2oAA1dtAANXcAADV3IAA1d0AANXdwADV3kAA1d7AANXfgADV4EAA1eCAANXiwADV5gAA1ebAANXnQADV6AAA1ejAANXpQADV8oAA1fuAANYFQADWDkAA1g8AANYPgADWEAAA1hCAANYRAADWEYAA1hHAANYSgADWFcAA1hqAANYbAADWG4AA1hwAANYcgADWHQAA1h2AANYeAADWHoAA1h8AANYjwADWJIAA1iVAANYmAADWJsAA1ieAANYoQADWKQAA1inAANYqgADWKwAA1jrAANY7QADWPAAA1jyAANY9QADWPYAA1j3AANY+AADWPkAA1j7AANY/QADWP4AA1j/AANZAQADWQIAA1kLAANZDAADWQ4AA1lNAANZTwADWVEAA1lTAANZVgADWVcAA1lYAANZWQADWVoAA1lcAANZXgADWV8AA1lgAANZYgADWWMAA1miAANZpAADWacAA1mpAANZrAADWa0AA1muAANZrwADWbAAA1myAANZtAADWbUAA1m2AANZuAADWbkAA1nCAANZwwADWcUAA1oEAANaBgADWggAA1oKAANaDQADWg4AA1oPAANaEAADWhEAA1oTAANaFQADWhYAA1oXAANaGQADWhoAA1pZAANaWwADWl4AA1pgAANaYwADWmQAA1plAANaZgADWmcAA1ppAANaawADWmwAA1ptAANabwADWnAAA1p5AANaegADWnwAA1q7AANavQADWr8AA1rBAANaxAADWsUAA1rGAANaxwADWsgAA1rKAANazAADWs0AA1rOAANa0AADWtEAA1sQAANbEgADWxUAA1sXAANbGgADWxsAA1scAANbHQADWx4AA1sgAANbIgADWyMAA1skAANbJgADWycAA1s0AANbNQADWzYAA1s4AANbdwADW3kAA1t7AANbfQADW4AAA1uBAANbggADW4MAA1uEAANbhgADW4gAA1uJAANbigADW4wAA1uNAANbzAADW84AA1vQAANb0gADW9UAA1vWAANb1wADW9gAA1vZAANb2wADW90AA1veAANb3wADW+EAA1viAANb7wADW/YAA1v5AANb+wADW/0AA1wEAANcBwADXAoAA1wNAANcDwADXFoAA1x9AANcnQADXL0AA1y/AANcwQADXMMAA1zFAANcyAADXMkAA1zKAANczQADXM4AA1zQAANc0QADXNMAA1zWAANc1wADXNgAA1zbAANc3AADXOEAA1zuAANc8wADXPUAA1z3AANc/AADXP8AA10CAANdBAADXSkAA11NAANddAADXZgAA12bAANdnQADXZ8AA12hAANdowADXaUAA12mAANdqQADXbYAA13HAANdyQADXcsAA13NAANdzwADXdEAA13TAANd1QADXdcAA13oAANd6wADXe4AA13xAANd9AADXfcAA136AANd/QADXgAAA14CAANeQQADXkMAA15FAANeRwADXkoAA15LAANeTAADXk0AA15OAANeUAADXlIAA15TAANeVAADXlYAA15XAANelgADXpgAA16aAANenAADXp8AA16gAANeoQADXqIAA16jAANepQADXqcAA16oAANeqQADXqsAA16sAANe6wADXu0AA17wAANe8gADXvUAA172AANe9wADXvgAA175AANe+wADXv0AA17+AANe/wADXwEAA18CAANfDwADXxAAA18RAANfEwADX1IAA19UAANfVgADX1gAA19bAANfXAADX10AA19eAANfXwADX2EAA19jAANfZAADX2UAA19nAANfaAADX6cAA1+pAANfqwADX60AA1+wAANfsQADX7IAA1+zAANftAADX7YAA1+4AANfuQADX7oAA1+8AANfvQADX/wAA1/+AANgAAADYAIAA2AFAANgBgADYAcAA2AIAANgCQADYAsAA2ANAANgDgADYA8AA2ARAANgEgADYFEAA2BTAANgVQADYFcAA2BaAANgWwADYFwAA2BdAANgXgADYGAAA2BiAANgYwADYGQAA2BmAANgZwADYKYAA2CoAANgqgADYKwAA2CvAANgsAADYLEAA2CyAANgswADYLUAA2C3AANguAADYLkAA2C7AANgvAADYOEAA2EFAANhLAADYVAAA2FTAANhVQADYVcAA2FZAANhWwADYV0AA2FeAANhYQADYW4AA2F9AANhfwADYYEAA2GDAANhhQADYYcAA2GJAANhiwADYZoAA2GdAANhoAADYaMAA2GmAANhqQADYawAA2GvAANhsQADYfAAA2HyAANh9AADYfYAA2H5AANh+gADYfsAA2H8AANh/QADYf8AA2IBAANiAgADYgMAA2IFAANiBgADYkUAA2JHAANiSQADYksAA2JOAANiTwADYlAAA2JRAANiUgADYlQAA2JWAANiVwADYlgAA2JaAANiWwADYpoAA2KcAANingADYqAAA2KjAANipAADYqUAA2KmAANipwADYqkAA2KrAANirAADYq0AA2KvAANisAADYu8AA2LxAANi8wADYvUAA2L4AANi+QADYvoAA2L7AANi/AADYv4AA2MAAANjAQADYwIAA2MEAANjBQADY0QAA2NGAANjSAADY0oAA2NNAANjTgADY08AA2NQAANjUQADY1MAA2NVAANjVgADY1cAA2NZAANjWgADY5kAA2ObAANjnQADY58AA2OiAANjowADY6QAA2OlAANjpgADY6gAA2OqAANjqwADY6wAA2OuAANjrwADY+4AA2PwAANj8gADY/QAA2P3AANj+AADY/kAA2P6AANj+wADY/0AA2P/AANkAAADZAEAA2QDAANkBAADZE8AA2RyAANkkgADZLIAA2S0AANktgADZLgAA2S6AANkvQADZL4AA2S/AANkwgADZMMAA2TFAANkxgADZMgAA2TKAANkywADZMwAA2TPAANk0AADZNUAA2TiAANk5wADZOkAA2TrAANk8AADZPMAA2T2AANk+AADZR0AA2VBAANlaAADZYwAA2WPAANlkQADZZMAA2WVAANllwADZZkAA2WaAANlnQADZaoAA2W7AANlvQADZb8AA2XBAANlwwADZcUAA2XHAANlyQADZcsAA2XcAANl3wADZeIAA2XlAANl6AADZesAA2XuAANl8QADZfQAA2X2AANmNQADZjcAA2Y5AANmOwADZj4AA2Y/AANmQAADZkEAA2ZCAANmRAADZkYAA2ZHAANmSAADZkoAA2ZLAANmigADZowAA2aOAANmkAADZpMAA2aUAANmlQADZpYAA2aXAANmmQADZpsAA2acAANmnQADZp8AA2agAANm3wADZuEAA2bkAANm5gADZukAA2bqAANm6wADZuwAA2btAANm7wADZvEAA2byAANm8wADZvUAA2b2AANnAwADZwQAA2cFAANnBwADZ0YAA2dIAANnSgADZ0wAA2dPAANnUAADZ1EAA2dSAANnUwADZ1UAA2dXAANnWAADZ1kAA2dbAANnXAADZ5sAA2edAANnnwADZ6EAA2ekAANnpQADZ6YAA2enAANnqAADZ6oAA2esAANnrQADZ64AA2ewAANnsQADZ/AAA2fyAANn9AADZ/YAA2f5AANn+gADZ/sAA2f8AANn/QADZ/8AA2gBAANoAgADaAMAA2gFAANoBgADaEUAA2hHAANoSQADaEsAA2hOAANoTwADaFAAA2hRAANoUgADaFQAA2hWAANoVwADaFgAA2haAANoWwADaJoAA2icAANongADaKAAA2ijAANopAADaKUAA2imAANopwADaKkAA2irAANorAADaK0AA2ivAANosAADaNUAA2j5AANpIAADaUQAA2lHAANpSQADaUsAA2lNAANpTwADaVEAA2lSAANpVQADaWIAA2lxAANpcwADaXUAA2l3AANpeQADaXsAA2l9AANpfwADaY4AA2mRAANplAADaZcAA2maAANpnQADaaAAA2mjAANppQADaeQAA2nmAANp6AADaeoAA2ntAANp7gADae8AA2nwAANp8QADafMAA2n1AANp9gADafcAA2n5AANp+gADajkAA2o7AANqPQADaj8AA2pCAANqQwADakQAA2pFAANqRgADakgAA2pKAANqSwADakwAA2pOAANqTwADao4AA2qQAANqkgADapQAA2qXAANqmAADapkAA2qaAANqmwADap0AA2qfAANqoAADaqEAA2qjAANqpAADauMAA2rlAANq5wADaukAA2rsAANq7QADau4AA2rvAANq8AADavIAA2r0AANq9QADavYAA2r4AANq+QADazgAA2s6AANrPAADaz4AA2tBAANrQgADa0MAA2tEAANrRQADa0cAA2tJAANrSgADa0sAA2tNAANrTgADa40AA2uPAANrkQADa5MAA2uWAANrlwADa5gAA2uZAANrmgADa5wAA2ueAANrnwADa6AAA2uiAANrowADa+IAA2vkAANr5gADa+gAA2vrAANr7AADa+0AA2vuAANr7wADa/EAA2vzAANr9AADa/UAA2v3AANr+AADbEMAA2xmAANshgADbKYAA2yoAANsqgADbKwAA2yuAANssQADbLIAA2yzAANstgADbLcAA2y5AANsugADbLwAA2y+AANsvwADbMAAA2zDAANsxAADbMkAA2zWAANs2wADbN0AA2zfAANs5AADbOcAA2zqAANs7AADbREAA201AANtXAADbYAAA22DAANthQADbYcAA22JAANtiwADbY0AA22OAANtkQADbZ4AA22vAANtsQADbbMAA221AANttwADbbkAA227AANtvQADbb8AA23QAANt0wADbdYAA23ZAANt3AADbd8AA23iAANt5QADbegAA23qAANuKQADbisAA24tAANuLwADbjIAA24zAANuNAADbjUAA242AANuOAADbjoAA247AANuPAADbj4AA24/AANufgADboAAA26CAANuhAADbocAA26IAANuiQADbooAA26LAANujQADbo8AA26QAANukQADbpMAA26UAANu0wADbtUAA27YAANu2gADbt0AA27eAANu3wADbuAAA27hAANu4wADbuUAA27mAANu5wADbukAA27qAANu9wADbvgAA275AANu+wADbzoAA288AANvPgADb0AAA29DAANvRAADb0UAA29GAANvRwADb0kAA29LAANvTAADb00AA29PAANvUAADb48AA2+RAANvkwADb5UAA2+YAANvmQADb5oAA2+bAANvnAADb54AA2+gAANvoQADb6IAA2+kAANvpQADb+QAA2/mAANv6AADb+oAA2/tAANv7gADb+8AA2/wAANv8QADb/MAA2/1AANv9gADb/cAA2/5AANv+gADcDkAA3A7AANwPQADcD8AA3BCAANwQwADcEQAA3BFAANwRgADcEgAA3BKAANwSwADcEwAA3BOAANwTwADcI4AA3CQAANwkgADcJQAA3CXAANwmAADcJkAA3CaAANwmwADcJ0AA3CfAANwoAADcKEAA3CjAANwpAADcMkAA3DtAANxFAADcTgAA3E7AANxPQADcT8AA3FBAANxQwADcUUAA3FGAANxSQADcVYAA3FlAANxZwADcWkAA3FrAANxbQADcW8AA3FxAANxcwADcYIAA3GFAANxiAADcYsAA3GOAANxkQADcZQAA3GXAANxmQADcdgAA3HaAANx3AADcd4AA3HhAANx4gADceMAA3HkAANx5QADcecAA3HpAANx6gADcesAA3HtAANx7gADci0AA3IvAANyMQADcjMAA3I2AANyNwADcjgAA3I5AANyOgADcjwAA3I+AANyPwADckAAA3JCAANyQwADcoIAA3KEAANyhgADcogAA3KLAANyjAADco0AA3KOAANyjwADcpEAA3KTAANylAADcpUAA3KXAANymAADctcAA3LZAANy2wADct0AA3LgAANy4QADcuIAA3LjAANy5AADcuYAA3LoAANy6QADcuoAA3LsAANy7QADcywAA3MuAANzMAADczIAA3M1AANzNgADczcAA3M4AANzOQADczsAA3M9AANzPgADcz8AA3NBAANzQgADc4EAA3ODAANzhQADc4cAA3OKAANziwADc4wAA3ONAANzjgADc5AAA3OSAANzkwADc5QAA3OWAANzlwADc9YAA3PYAANz2gADc9wAA3PfAANz4AADc+EAA3PiAANz4wADc+UAA3PnAANz6AADc+kAA3PrAANz7AADc/UAA3P2AANz+AADdDsAA3RfAAN0gwADdKYAA3TNAAN07QADdRQAA3U7AAN1WwADdX8AA3WjAAN1pQADdagAA3WqAAN1rAADda4AA3WxAAN1tAADdbYAA3W4AAN1uwADdb0AA3W/AAN1wgADdcUAA3XGAAN1ywADddgAA3XbAAN13QADdeAAA3XjAAN15QADdgoAA3YuAAN2VQADdnkAA3Z8AAN2fgADdoAAA3aCAAN2hAADdoYAA3aHAAN2igADdpcAA3aqAAN2rAADdq4AA3awAAN2sgADdrQAA3a2AAN2uAADdroAA3a8AAN2zwADdtIAA3bVAAN22AADdtsAA3beAAN24QADduQAA3bnAAN26gADduwAA3crAAN3LQADdzAAA3cyAAN3NQADdzYAA3c3AAN3OAADdzkAA3c7AAN3PQADdz4AA3c/AAN3QQADd0IAA3dLAAN3TAADd04AA3eNAAN3jwADd5EAA3eTAAN3lgADd5cAA3eYAAN3mQADd5oAA3ecAAN3ngADd58AA3egAAN3ogADd6MAA3fiAAN35AADd+cAA3fpAAN37AADd+0AA3fuAAN37wADd/AAA3fyAAN39AADd/UAA3f2AAN3+AADd/kAA3gCAAN4AwADeAUAA3hEAAN4RgADeEgAA3hKAAN4TQADeE4AA3hPAAN4UAADeFEAA3hTAAN4VQADeFYAA3hXAAN4WQADeFoAA3iZAAN4mwADeJ4AA3igAAN4owADeKQAA3ilAAN4pgADeKcAA3ipAAN4qwADeKwAA3itAAN4rwADeLAAA3i5AAN4ugADeLwAA3j7AAN4/QADeP8AA3kBAAN5BAADeQUAA3kGAAN5BwADeQgAA3kKAAN5DAADeQ0AA3kOAAN5EAADeREAA3lQAAN5UgADeVUAA3lXAAN5WgADeVsAA3lcAAN5XQADeV4AA3lgAAN5YgADeWMAA3lkAAN5ZgADeWcAA3l0AAN5dQADeXYAA3l4AAN5twADebkAA3m7AAN5vQADecAAA3nBAAN5wgADecMAA3nEAAN5xgADecgAA3nJAAN5ygADecwAA3nNAAN6DAADeg4AA3oRAAN6EwADehYAA3oXAAN6GAADehkAA3oaAAN6HAADeh4AA3ofAAN6IAADeiIAA3ojAAN6MgADej8AA3pGAAN6SQADekwAA3pPAAN6VgADelkAA3pcAAN6XwADemEAA3poAAN6cgADer0AA3rgAAN7AAADeyAAA3siAAN7JAADeyYAA3soAAN7KwADeywAA3stAAN7MAADezEAA3szAAN7NAADezYAA3s5AAN7OgADezsAA3s+AAN7PwADe0QAA3tRAAN7VgADe1gAA3taAAN7XwADe2IAA3tlAAN7ZwADe4wAA3uwAAN71wADe/sAA3v+AAN8AAADfAIAA3wEAAN8BgADfAgAA3wJAAN8DAADfBkAA3wqAAN8LAADfC4AA3wwAAN8MgADfDQAA3w2AAN8OAADfDoAA3xLAAN8TgADfFEAA3xUAAN8VwADfFoAA3xdAAN8YAADfGMAA3xlAAN8pAADfKYAA3yoAAN8qgADfK0AA3yuAAN8rwADfLAAA3yxAAN8swADfLUAA3y2AAN8twADfLkAA3y6AAN8+QADfPsAA3z9AAN8/wADfQIAA30DAAN9BAADfQUAA30GAAN9CAADfQoAA30LAAN9DAADfQ4AA30PAAN9TgADfVAAA31TAAN9VQADfVgAA31ZAAN9WgADfVsAA31cAAN9XgADfWAAA31hAAN9YgADfWQAA31lAAN9cgADfXMAA310AAN9dgADfbUAA323AAN9uQADfbsAA32+AAN9vwADfcAAA33BAAN9wgADfcQAA33GAAN9xwADfcgAA33KAAN9ywADfgoAA34MAAN+DgADfhAAA34TAAN+FAADfhUAA34WAAN+FwADfhkAA34bAAN+HAADfh0AA34fAAN+IAADfl8AA35hAAN+YwADfmUAA35oAAN+aQADfmoAA35rAAN+bAADfm4AA35wAAN+cQADfnIAA350AAN+dQADfrQAA362AAN+uAADfroAA369AAN+vgADfr8AA37AAAN+wQADfsMAA37FAAN+xgADfscAA37JAAN+ygADfwkAA38LAAN/DQADfw8AA38SAAN/EwADfxQAA38VAAN/FgADfxgAA38aAAN/GwADfxwAA38eAAN/HwADf0QAA39oAAN/jwADf7MAA3+2AAN/uAADf7oAA3+8AAN/vgADf8AAA3/BAAN/xAADf9EAA3/gAAN/4gA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DixYAA4sXAAOLGgADixsAA4sdAAOLHgADiyAAA4sjAAOLJAADiyUAA4soAAOLKQADiy4AA4s7AAOLQAADi0IAA4tEAAOLSQADi0wAA4tPAAOLUQADi3YAA4uaAAOLwQADi+UAA4voAAOL6gADi+wAA4vuAAOL8AADi/IAA4vzAAOL9gADjAMAA4wUAAOMFgADjBgAA4waAAOMHAADjB4AA4wgAAOMIgADjCQAA4w1AAOMOAADjDsAA4w+AAOMQQADjEQAA4xHAAOMSgADjE0AA4xPAAOMjgADjJAAA4ySAAOMlAADjJcAA4yYAAOMmQADjJoAA4ybAAOMnQADjJ8AA4ygAAOMoQADjKMAA4ykAAOM4wADjOUAA4znAAOM6QADjOwAA4ztAAOM7gADjO8AA4zwAAOM8gADjPQAA4z1AAOM9gADjPgAA4z5AAONOAADjToAA409AAONPwADjUIAA41DAAONRAADjUUAA41GAAONSAADjUoAA41LAAONTAADjU4AA41PAAONXAADjV0AA41eAAONYAADjZ8AA42hAAONowADjaUAA42oAAONqQADjaoAA42rAAONrAADja4AA42wAAONsQADjbIAA420AAONtQADjfQAA432AAON+AADjfoAA439AAON/gADjf8AA44AAAOOAQADjgMAA44FAAOOBgADjgcAA44JAAOOCgADjkkAA45LAAOOTQADjk8AA45SAAOOUwADjlQAA45VAAOOVgADjlgAA45aAAOOWwADjlwAA45eAAOOXwADjp4AA46gAAOOogADjqQAA46nAAOOqAADjqkAA46qAAOOqwADjq0AA46vAAOOsAADjrEAA46zAAOOtAADjvMAA471AAOO9wADjvkAA478AAOO/QADjv4AA47/AAOPAAADjwIAA48EAAOPBQADjwYAA48IAAOPCQADjy4AA49SAAOPeQADj50AA4+gAAOPogADj6QAA4+mAAOPqAADj6oAA4+rAAOPrgADj7sAA4/KAAOPzAADj84AA4/QAAOP0gADj9QAA4/WAAOP2AADj+cAA4/qAAOP7QADj/AAA4/zAAOP9gADj/kAA4/8AAOP/gADkD0AA5A/AAOQQQADkEMAA5BGAAOQRwADkEgAA5BJAAOQSgADkEwAA5BOAAOQTwADkFAAA5BSAAOQUwADkJIAA5CUAAOQlgADkJgAA5CbAAOQnAADkJ0AA5CeAAOQnwADkKEAA5CjAAOQpAADkKUAA5CnAAOQqAADkOcAA5DpAAOQ6wADkO0AA5DwAAOQ8QADkPIAA5DzAAOQ9AADkPYAA5D4AAOQ+QADkPoAA5D8AAOQ/QADkTwAA5E+AAORQAADkUIAA5FFAAORRgADkUcAA5FIAAORSQADkUsAA5FNAAORTgADkU8AA5FRAAORUgADkZEAA5GTAAORlQADkZcAA5GaAAORmwADkZwAA5GdAAORngADkaAAA5GiAAORowADkaQAA5GmAAORpwADkeYAA5HoAAOR6gADkewAA5HvAAOR8AADkfEAA5HyAAOR8wADkfUAA5H3AAOR+AADkfkAA5H7AAOR/AADkjsAA5I9AAOSPwADkkEAA5JEAAOSRQADkkYAA5JHAAOSSAADkkoAA5JMAAOSTQADkk4AA5JQAAOSUQADkloAA5JbAAOSXQADkqAAA5LEAAOS6AADkwsAA5MyAAOTUgADk3kAA5OgAAOTwAADk+QAA5QIAAOUCgADlA0AA5QPAAOUEQADlBMAA5QWAAOUGQADlBsAA5QdAAOUIAADlCIAA5QkAAOUJwADlCoAA5QrAAOUNAADlEEAA5REAAOURgADlEkAA5RMAAOUTgADlHMAA5SXAAOUvgADlOIAA5TlAAOU5wADlOkAA5TrAAOU7QADlO8AA5TwAAOU8wADlQAAA5UTAAOVFQADlRcAA5UZAAOVGwADlR0AA5UfAAOVIQADlSMAA5UlAAOVOAADlTsAA5U+AAOVQQADlUQAA5VHAAOVSgADlU0AA5VQAAOVUwADlVUAA5WUAAOVlgADlZkAA5WbAAOVngADlZ8AA5WgAAOVoQADlaIAA5WkAAOVpgADlacAA5WoAAOVqgADlasAA5W0AAOVtQADlbcAA5X2AAOV+AADlfoAA5X8AAOV/wADlgAAA5YBAAOWAgADlgMAA5YFAAOWBwADlggAA5YJAAOWCwADlgwAA5ZLAAOWTQADllAAA5ZSAAOWVQADllYAA5ZXAAOWWAADllkAA5ZbAAOWXQADll4AA5ZfAAOWYQADlmIAA5ZrAAOWbAADlm4AA5atAAOWrwADlrEAA5azAAOWtgADlrcAA5a4AAOWuQADlroAA5a8AAOWvgADlr8AA5bAAAOWwgADlsMAA5cCAAOXBAADlwcAA5cJAAOXDAADlw0AA5cOAAOXDwADlxAAA5cSAAOXFAADlxUAA5cWAAOXGAADlxkAA5ciAAOXIwADlyUAA5dkAAOXZgADl2gAA5dqAAOXbQADl24AA5dvAAOXcAADl3EAA5dzAAOXdQADl3YAA5d3AAOXeQADl3oAA5e5AAOXuwADl74AA5fAAAOXwwADl8QAA5fFAAOXxgADl8cAA5fJAAOXywADl8wAA5fNAAOXzwADl9AAA5fdAAOX3gADl98AA5fhAAOYIAADmCIAA5gkAAOYJgADmCkAA5gqAAOYKwADmCwAA5gtAAOYLwADmDEAA5gyAAOYMwADmDUAA5g2AAOYdQADmHcAA5h6AAOYfAADmH8AA5iAAAOYgQADmIIAA5iDAAOYhQADmIcAA5iIAAOYiQADmIsAA5iMAAOYoQADmK4AA5izAAOYtgADmLkAA5i+AAOYwQADmMQAA5jGAAOYywADmRYAA5k5AAOZWQADmXkAA5l7AAOZfQADmX8AA5mBAAOZhAADmYUAA5mGAAOZiQADmYoAA5mMAAOZjQADmY8AA5mSAAOZkwADmZQAA5mXAAOZmAADmaEAA5muAAOZswADmbUAA5m3AAOZvAADmb8AA5nCAAOZxAADmekAA5oNAAOaNAADmlgAA5pbAAOaXQADml8AA5phAAOaYwADmmUAA5pmAAOaaQADmnYAA5qHAAOaiQADmosAA5qNAAOajwADmpEAA5qTAAOalQADmpcAA5qoAAOaqwADmq4AA5qxAAOatAADmrcAA5q6AAOavQADmsAAA5rCAAObAQADmwMAA5sFAAObBwADmwoAA5sLAAObDAADmw0AA5sOAAObEAADmxIAA5sTAAObFAADmxYAA5sXAAObVgADm1gAA5taAAObXAADm18AA5tgAAObYQADm2IAA5tjAAObZQADm2cAA5toAAObaQADm2sAA5tsAAObqwADm60AA5uwAAObsgADm7UAA5u2AAObtwADm7gAA5u5AAObuwADm70AA5u+AAObvwADm8EAA5vCAAObzwADm9AAA5vRAAOb0wADnBIAA5wUAAOcFgADnBgAA5wbAAOcHAADnB0AA5weAAOcHwADnCEAA5wjAAOcJAADnCUAA5wnAAOcKAADnGcAA5xpAAOcawADnG0AA5xwAAOccQADnHIAA5xzAAOcdAADnHYAA5x4AAOceQADnHoAA5x8AAOcfQADnLwAA5y+AAOcwAADnMIAA5zFAAOcxgADnMcAA5zIAAOcyQADnMsAA5zNAAOczgADnM8AA5zRAAOc0gADnREAA50TAAOdFQADnRcAA50aAAOdGwADnRwAA50dAAOdHgADnSAAA50iAAOdIwADnSQAA50mAAOdJwADnWYAA51oAAOdagADnWwAA51vAAOdcAADnXEAA51yAAOdcwADnXUAA513AAOdeAADnXkAA517AAOdfAADnaEAA53FAAOd7AADnhAAA54TAAOeFQADnhcAA54ZAAOeGwADnh0AA54eAAOeIQADni4AA549AAOePwADnkEAA55DAAOeRQADnkcAA55JAAOeSwADnloAA55dAAOeYAADnmMAA55mAAOeaQADnmwAA55vAAOecQADnrAAA56yAAOetAADnrYAA565AAOeugADnrsAA568AAOevQADnr8AA57BAAOewgADnsMAA57FAAOexgADnwUAA58HAAOfCQADnwsAA58OAAOfDwADnxAAA58RAAOfEgADnxQAA58WAAOfFwADnxgAA58aAAOfGwADn1oAA59cAAOfXgADn2AAA59jAAOfZAADn2UAA59mAAOfZwADn2kAA59rAAOfbAADn20AA59vAAOfcAADn68AA5+xAAOftAADn7YAA5+5AAOfugADn7sAA5+8AAOfvQADn78AA5/BAAOfwgADn8MAA5/FAAOfxgADoAUAA6AHAAOgCQADoAsAA6AOAAOgDwADoBAAA6ARAAOgEgADoBQAA6AWAAOgFwADoBgAA6AaAAOgGwADoFoAA6BcAAOgXgADoGAAA6BjAAOgZAADoGUAA6BmAAOgZwADoGkAA6BrAAOgbAADoG0AA6BvAAOgcAADoK8AA6CxAAOgswADoLUAA6C4AAOguQADoLoAA6C7AAOgvAADoL4AA6DAAAOgwQADoMIAA6DEAAOgxQADoRAAA6EzAAOhUwADoXMAA6F1AAOhdwADoXkAA6F7AAOhfgADoX8AA6GAAAOhgwADoYQAA6GGAAOhhwADoYkAA6GMAAOhjQADoY4AA6GRAAOhkgADoZcAA6GkAAOhqQADoasAA6GtAAOhsgADobUAA6G4AAOhugADod8AA6IDAAOiKgADok4AA6JRAAOiUwADolUAA6JXAAOiWQADolsAA6JcAAOiXwADomwAA6J9AAOifwADooEAA6KDAAOihQADoocAA6KJAAOiiwADoo0AA6KeAAOioQADoqQAA6KnAAOiqgADoq0AA6KwAAOiswADorYAA6K4AAOi9wADovkAA6L7AAOi/QADowAAA6MBAAOjAgADowMAA6MEAAOjBgADowgAA6MJAAOjCgADowwAA6MNAAOjTAADo04AA6NQAAOjUgADo1UAA6NWAAOjVwADo1gAA6NZAAOjWwADo10AA6NeAAOjXwADo2EAA6NiAAOjoQADo6MAA6OmAAOjqAADo6sAA6OsAAOjrQADo64AA6OvAAOjsQADo7MAA6O0AAOjtQADo7cAA6O4AAOjxQADo8YAA6PHAAOjyQADpAgAA6QKAAOkDAADpA4AA6QRAAOkEgADpBMAA6QUAAOkFQADpBcAA6QZAAOkGgADpBsAA6QdAAOkHgADpF0AA6RfAAOkYQADpGMAA6RmAAOkZwADpGgAA6RpAAOkagADpGwAA6RuAAOkbwADpHAAA6RyAAOkcwADpLIAA6S0AAOktgADpLgAA6S7AAOkvAADpL0AA6S+AAOkvwADpMEAA6TDAAOkxAADpMUAA6THAAOkyAADpQcAA6UJAAOlCwADpQ0AA6UQAAOlEQADpRIAA6UTAAOlFAADpRYAA6UYAAOlGQADpRoAA6UcAAOlHQADpVwAA6VeAAOlYAADpWIAA6VlAAOlZgADpWcAA6VoAAOlaQADpWsAA6VtAAOlbgADpW8AA6VxAAOlcgADpZcAA6W7AAOl4gADpgYAA6YJAAOmCwADpg0AA6YPAAOmEQADphMAA6YUAAOmFwADpiQAA6YzAAOmNQADpjcAA6Y5AAOmOwADpj0AA6Y/AAOmQQADplAAA6ZTAAOmVgADplkAA6ZcAAOmXwADpmIAA6ZlAAOmZwADpqYAA6aoAAOmqgADpqwAA6avAAOmsAADprEAA6ayAAOmswADprUAA6a3AAOmuAADprkAA6a7AAOmvAADpvsAA6b9AAOm/wADpwEAA6cEAAOnBQADpwYAA6cHAAOnCAADpwoAA6cMAAOnDQADpw4AA6cQAAOnEQADp1AAA6dSAAOnVAADp1YAA6dZAAOnWgADp1sAA6dcAAOnXQADp18AA6dhAAOnYgADp2MAA6dlAAOnZgADp6UAA6enAAOnqQADp6sAA6euAAOnrwADp7AAA6exAAOnsgADp7QAA6e2AAOntwADp7gAA6e6AAOnuwADp/oAA6f8AAOn/gADqAAAA6gDAAOoBAADqAUAA6gGAAOoBwADqAkAA6gLAAOoDAADqA0AA6gPAAOoEAADqE8AA6hRAAOoUwADqFUAA6hYAAOoWQADqFoAA6hbAAOoXAADqF4AA6hgAAOoYQADqGIAA6hkAAOoZQADqKQAA6imAAOoqAADqKoAA6itAAOorgADqK8AA6iwAAOosQADqLMAA6i1AAOotgADqLcAA6i5AAOougADqMMAA6jEAAOoxgADqNMAA6jUAAOo1QADqNcAA6jkAAOo5QADqOYAA6joAAOo9QADqPYAA6j3AAOo+QADqQIAA6kRAAOpHgADqS0AA6k/AAOpUwADqWoAA6l8AAOphQADqYYAA6mIAAOplQADqZYAA6mXAAOpmQADqaIAA6msAAOpswAAAAAAAAQCAAAAAAAAjUQAAAAAAAAAAAAAAAAAA6m7 - + url - \ No newline at end of file + diff --git a/fearless/Common/Storage/MigrationMappings/SubstrateV3toV4.xcmappingmodel/xcmapping.xml b/fearless/Common/Storage/MigrationMappings/SubstrateV3toV4.xcmappingmodel/xcmapping.xml index 201ab37810..7f4bf53aa4 100644 --- a/fearless/Common/Storage/MigrationMappings/SubstrateV3toV4.xcmappingmodel/xcmapping.xml +++ b/fearless/Common/Storage/MigrationMappings/SubstrateV3toV4.xcmappingmodel/xcmapping.xml @@ -108,7 +108,7 @@ cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxEL+wALAAwAGwA3ADgAOQBjAGQAZQBm fearless/Common/Storage/SubstrateDataModel.xcdatamodeld/SubstrateDataModel_v4.xcdatamodel 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WJFYoFivWL5Y01jUWNxY6Fj8WQtZGlkpWS1ZPFlLWVpZaVl4WYRZllmlWbRZw1nSWeFZ8Fn/WhRaFVodWilaPVpMWltaalpuWn1ajFqbWqpauVrFWtda5lr1WwRbE1siWzFbQFtDW11bXltkW3BbhluVW5hbp1u2W7lbyFvXW9pb6Vv4W/xcC1waXBtcKVwqXCtcLFwtXC5cQ1xEXExcWFxsXHtcilyZXJ1crFy7XMpc2VzoXPRdBl0VXSRdM11CXVFdYF1hXXBdhV2GXY5dml2uXb1dzF3bXd9d7l39XgxeG14qXjZeSF5XXmZedV6EXpNeol6jXrJex17IXtBe3F7wXv9fDl8dXyFfMF8/X05fXV9sX3hfil+ZX6hft1/GX9Vf5F/zYAhgCWARYB1gMWBAYE9gXmBiYHFggGCPYJ5grWC5YMlg2GDyYPNg+WEFYRthKmEtYTxhS2FOYV1hbGFvYX5hjWGRYaBhr2GwYbphu2G8YdFh0mHaYeZh+mIJYhhiJ2IrYjpiSWJYYmdidmKCYpRio2KyYsFi0GLfYu5i/WMSYxNjG2MnYztjSmNZY2hjbGN7Y4pjmWOoY7djw2PVY+Rj82QCZBFkIGQvZD5kU2RUZFxkaGR8ZItkmmSpZK1kvGTLZNpk6WT4ZQRlFmUlZTRlQ2VSZVNlYmVxZYBlg2WSZaFlsGW/Zc5l42XkZexl+GYMZhtmKmY5Zj1mTGZbZmpmeWaIZpRmpma1ZsRm02biZvFnAGcPZxJnLGctZzNnP2dVZ2RnZ2d2Z4VniGeXZ6ZnqWe4Z8dny2faZ+ln6mfyZ/Nn9GgJaApoEmgeaDJoQWhQaF9oY2hyaIFokGifaK5oumjMaNto6mj5aQhpF2kmaTVpSmlLaVNpX2lzaYJpkWmgaaRps2nCadFp4GnvaftqDWocaitqOmpJalhqZ2p2anlqk2qUappqpmq8astqzmrdauxq72r+aw1rEGsfay5rMmtBa1BrUWtfa2BrYWtia3dreGuAa4xroGuva75rzWvRa+Br72v+bA1sHGwobDpsSWxYbGdsdmyFbJRso2y4bLlswWzNbOFs8Gz/bQ5tEm0hbTBtP21ObV1taW17bYptmW2obbdtxm3VbeRt+W36bgJuDm4ibjFuQG5PblNuYm5xboBuj26ebqpuvG7Lbtpu6W74bwdvFm8lbzpvO29Db09vY29yb4FvkG+Ub6Nvsm/Bb9Bv32/rb/1wDHAbcCpwOXBIcFdwZnB7cHxwhHCQcKRws3DCcNFw1XDkcPNxAnERcSBxLHE+cU1xXHFrcXpxiXGYcadxqnHEccVxy3HXce1x/HH/cg5yHXIgci9yPnJBclByX3JjcnJygXKCco5yj3KQcqVypnKucrpyznLdcuxy+3L/cw5zHXMscztzSnNWc2hzd3OGc5VzpHOzc8Jz0XPmc+dz73P7dA90HnQtdDx0QHRPdF50bXR8dIt0l3SpdLh0x3TWdOV09HUDdRJ1J3UodTB1PHVQdV91bnV9dYF1kHWfda51vXXMddh16nX5dgh2F3YmdjV2RHZTdmh2aXZxdn12kXagdq92vnbCdtF24Hbvdv53DXcZdyt3OndJd1h3Z3d2d4V3lHeXd7F3sne4d8R32nfpd+x3+3gKeA14HHgreC54PXhMeFB4X3hueG94iXiKeIt4jHiNeI54j3iQeJF4kniTeKh4qXixeL140XjgeO94/nkCeRF5IHkveT55TXlZeWt5enmJeZh5p3m2ecV51Hnpeep58nn+ehJ6IXowej96Q3pSemF6cHp/eo56mnqsert6ynrZeuh693sGexV7KnsrezN7P3tTe2J7cXuAe4R7k3uie7F7wHvPe9t77Xv8fAt8GnwpfDh8R3xWfGt8bHx0fIB8lHyjfLJ8wXzFfNR843zyfQF9EH0cfS59PX1MfVt9an15fYh9l32sfa19tX3BfdV95H3zfgJ+Bn4VfiR+M35CflF+XX5vfn5+jX6cfqt+un7Jfth+7X7ufvZ/An8WfyV/NH9Df0d/Vn9lf3R/g3+Sf55/sH+/f85/3X/sf/uACoAZgC6AL4A3gEOAV4BmgHWAhICIgJeApoC1gMSA04DfgPGBAIEPgR6BLYE8gUuBWoFvgXCBeIGEgZiBp4G2gcWByYHYgeeB9oIFghSCIIIygkGCUIJfgm6CfYKMgpuCsIKxgrmCxYLZguiC94MGgwqDGYMogzeDRoNVg2GDc4OCg5GDoIOvg76DzYPcg/GD8oP6hAaEGoQphDiER4RLhFqEaYR4hIeEloSihLSEw4TShOGE8IT/hQ6FHYUyhTOFO4VHhVuFaoV5hYiFjIWbhaqFuYXIhdeF44X1hgSGE4YihjGGQIZPhl6GYYZ7hnyGgoaOhqSGs4a2hsWG1IbXhuaG9Yb4hweHFocahymHOIdCh1eHWIdgh2yHgIePh56HrYexh8CHz4feh+2H/IgIiBqIKYg4iEeIVohliHSIg4iYiJmIoYitiMGI0IjfiO6I8okBiRCJH4kuiT2JSYlbiWqJeYmIiZeJpom1icSJ2YnaieKJ7ooCihGKIIovijOKQopRimCKb4p+ioqKnIqrirqKyYrYiueK9osFiwiLIosjiymLNYtLi1qLXYtsi3uLfouNi5yLn4uui72LwYvQi9+L4Ivqi+uL7IwBjAKMCowWjCqMOYxIjFeMW4xqjHmMiIyXjKaMsozEjNOM4ozxjQCND40ejS2NQo1DjUuNV41rjXqNiY2YjZyNq426jcmN2I3njfOOBY4UjiOOMo5BjlCOX45ujoOOhI6MjpiOrI67jsqO2Y7djuyO+48KjxmPKI80j0aPVY9kj3OPgo+Rj6CPr4+yj8yPzY/Tj9+P9ZAEkAeQFpAlkCiQN5BGkEmQWJBnkGuQepCJkIqQkpCTkKiQqZCxkL2Q0ZDgkO+Q/pECkRGRIJEvkT6RTZFZkWuRepGJkZiRp5G2kcWR1JHpkeqR8pH+khKSIZIwkj+SQ5JSkmGScJJ/ko6SmpKskruSypLZkuiS95MGkxWTGJMckyCTJJMsky+TM1UkbnVsbNcADQAOAA8AEAARABIAEwAUABUAFgAXABgAFwAaXxAPX3hkX3Jvb3RQYWNrYWdlViRjbGFzc1xfeGRfY29tbWVudHNfEBBfeGRfbW9kZWxNYW5hZ2VyXxAVX2NvbmZpZ3VyYXRpb25zQnlOYW1lXV94ZF9tb2RlbE5hbWVfEBdfbW9kZWxWZXJzaW9uSWRlbnRpZmllcoACgQtvgQttgACBC26AAIEEGt4AHAAdAB4AHwAgACEAIgAOACMAJAAlACYAJwAoACkAKgArAAkAKQAXAC8AMAAxADIAMwApACkAF18QHFhEQnVja2V0Rm9yQ2xhc3Nlc3dhc0VuY29kZWRfEBpYREJ1Y2tldEZvclBhY2thZ2Vzc3RvcmFnZV8QHFhEQnVja2V0Rm9ySW50ZXJmYWNlc3N0b3JhZ2VfEA9feGRfb3duaW5nTW9kZWxfEB1YREJ1Y2tldEZvclBhY2thZ2Vzd2FzRW5jb2RlZFZfb3duZXJfEBtYREJ1Y2tldEZvckRhdGFUeXBlc3N0b3JhZ2VbX3Zpc2liaWxpdHlfEBlYREJ1Y2tldEZvckNsYXNzZXNzdG9yYWdlVV9uYW1lXxAfWERCdWNrZXRGb3JJbnRlcmZhY2Vzd2FzRW5jb2RlZF8QHlhEQnVja2V0Rm9yRGF0YVR5cGVzd2FzRW5jb2RlZF8QEF91bmlxdWVFbGVtZW50SUSABIELa4ELaYABgASAAIELaoELbBAAgAWAA4AEgASAAFBTWUVT0wA6ADsADgA8AE4AYFdOUy5rZXlzWk5TLm9iamVjdHOvEBEAPQA+AD8AQABBAEIAQwBEAEUARgBHAEgASQBKAEsATABNgAaAB4AIgAmACoALgAyADYAOgA+AEIARgBKAE4AUgBWAFq8QEQBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF+AF4BqgQZTgQG4gQaZgQcmgQTwgQgRgQhWgQeXgQjhgQPEgQlUgQVhgQpwgQrJgQslgDVdQ0RFeHRlcm5hbEFwaVdDRENoYWluXUNEU2luZ2xlVmFsdWVXQ0RBc3NldF1DRENvbnRhY3RJdGVtXxAZQ0RQb2xrYXN3YXBSZW1vdGVTZXR0aW5nc18QEENEQ2hhaW5YY21Db25maWdbQ0RTdGFzaEl0ZW1fEBVDRFJ1bnRpbWVNZXRhZGF0YUl0ZW1eQ0RQb2xrYXN3YXBEZXhaQ0RTY2FtSW5mb1tDRENoYWluTm9kZV8QGENEVHJhbnNhY3Rpb25IaXN0b3J5SXRlbV8QGUNEWGNtQXZhaWxhYmxlRGVzdGluYXRpb25ZQ0RDb250YWN0XkNEUGhpc2hpbmdJdGVtXxASQ0RDaGFpblN0b3JhZ2VJdGVt3xAQAHMAdAB1AHYAIQB3AHgAIwB5AHoADgAlAHsAfAAoAH0AfgB/ACkAKQAUAIMAhAAxACkAfgCHAD0AfgCKAIsAjF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZVtfaXNBYnN0cmFjdIAZgD2ABIAEgAKAGoEDS4AEgBmBA02ABoAZgQZSgBgIEmGLcH1Xb3JkZXJlZNMAOgA7AA4AkACSAGChAJGAG6EAk4AcgDVeWERfUFN0ZXJlb3R5cGXZACEAJQCXAA4AKACYACMAfQCZAE8AkQB+AJ0AFwApADEAjAChXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgBeAG4AZgDyAAIAECIAd0wA6ADsADgCjAK0AYKkApAClAKYApwCoAKkAqgCrAKyAHoAfgCCAIYAigCOAJIAlgCapAK4ArwCwALEAsgCzALQAtQC2gCeAK4AsgC6AL4AxgDOANoA6gDVfEBNYRFBNQ29tcG91bmRJbmRleGVzXxAQWERfUFNLX2VsZW1lbnRJRF8QGVhEUE1VbmlxdWVuZXNzQ29uc3RyYWludHNfEBpYRF9QU0tfdmVyc2lvbkhhc2hNb2RpZmllcl8QGVhEX1BTS19mZXRjaFJlcXVlc3RzQXJyYXlfEBFYRF9QU0tfaXNBYnN0cmFjdF8QD1hEX1BTS191c2VySW5mb18QE1hEX1BTS19jbGFzc01hcHBpbmdfEBZYRF9QU0tfZW50aXR5Q2xhc3NOYW1l3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAzQAXAJMAjACMAIwAMQCMANQApACMAIwAFwCMVV90eXBlWF9kZWZhdWx0XF9hc3NvY2lhdGlvbltfaXNSZWFkT25seVlfaXNTdGF0aWNZX2lzVW5pcXVlWl9pc0Rlcml2ZWRaX2lzT3JkZXJlZFxfaXNDb21wb3NpdGVXX2lzTGVhZoAAgCiAAIAcCAgICIAqgB4ICIAACNIAOwAOANsA3KCAKdIA3gDfAOAA4VokY2xhc3NuYW1lWCRjbGFzc2VzXk5TTXV0YWJsZUFycmF5owDgAOIA41dOU0FycmF5WE5TT2JqZWN00gDeAN8A5QDmXxAQWERVTUxQcm9wZXJ0eUltcKQA5wDoAOkA418QEFhEVU1MUHJvcGVydHlJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFwCTAIwAjACMADEAjADUAKUAjACMABcAjIAAgACAAIAcCAgICIAqgB8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAPsAFwCTAIwAjACMADEAjADUAKYAjACMABcAjIAAgC2AAIAcCAgICIAqgCAICIAACNIAOwAOAQkA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFwCTAIwAjACMADEAjADUAKcAjACMABcAjIAAgACAAIAcCAgICIAqgCEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXARwAFwCTAIwAjACMADEAjADUAKgAjACMABcAjIAAgDCAAIAcCAgICIAqgCIICIAACNIAOwAOASoA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFwCTAIwAjACMADEAjADUAKkAjACMABcAjIAAgDKAAIAcCAgICIAqgCMICIAACAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwE+ABcAkwCMAIwAjAAxAIwA1ACqAIwAjAAXAIyAAIA0gACAHAgICAiAKoAkCAiAAAjTADoAOwAOAUwBTQBgoKCANdIA3gDfAVABUV8QE05TTXV0YWJsZURpY3Rpb25hcnmjAVABUgDjXE5TRGljdGlvbmFyed8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAVUAFwCTAIwAjACMADEAjADUAKsAjACMABcAjIAAgDeAAIAcCAgICIAqgCUICIAACNYAJQAOACgAfQAhACMBYwFkABcAjAAXADGAOIA5gAAIgABfEBRYREdlbmVyaWNSZWNvcmRDbGFzc9IA3gDfAWoBa11YRFVNTENsYXNzSW1wpgFsAW0BbgFvAXAA411YRFVNTENsYXNzSW1wXxASWERVTUxDbGFzc2lmaWVySW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAXMAFwCTAIwAjACMADEAjADUAKwAjACMABcAjIAAgDuAAIAcCAgICIAqgCYICIAACF1DREV4dGVybmFsQXBp0gDeAN8BggGDXxASWERVTUxTdGVyZW90eXBlSW1wpwGEAYUBhgGHAYgBiQDjXxASWERVTUxTdGVyZW90eXBlSW1wXVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w0wA6ADsADgGLAZAAYKQBjAGNAY4Bj4A+gD+AQIBBpAGRAZIBkwGUgEKBBgyBBiSBBjuANVVjaGFpblV0eXBlc1R0eXBlU3VybN8QEgDCAMMAxAGbACEAxgDHAZwAIwDFAZ0AyAAOACUAyQDKACgAywAXABcAFwApAE8AjACMAaUAMQCMAH4AjAGpAYwAjACMAa0AjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgBcICIBECIAZCICvgD4ICIBDCBL4hOVq0wA6ADsADgGxAbQAYKIBsgGzgEWARqIBtQG2gEeAW4A1XxASWERfUFByb3BTdGVyZW90eXBlXxAQWERfUFJfU3RlcmVvdHlwZdkAIQAlAbsADgAoAbwAIwB9Ab0BkQGyAH4AnQAXACkAMQCMAcVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tl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Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAaeARoAZgDyAAIAECIEBttMAOgA7AA4SoxKqAGCmAnACcgJtAm4CbwJxgGCAYoBdgF6AX4BhphKrEqwSrRKuEq8SsIEBt4EDToEDT4EDUIEDUYEDUoA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAUgAXEfgAjACMAIwAMQCMANQCcACMAIwAFwCMgACBAbiAAIEBtQgICAiAKoBgCAiAAAjfEBASwhLDEsQSxQAhEsYSxwAjEsgSyQAOACUSyhLLACgAfQB+Es0AKQApABQS0QCEADEAKQB+AIcAQAB+EtgS2QCMXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgBmBAcqABIAEgAKBAbqBA0uABIAZgQNNgAmAGYEDTIEBuQgSSbQAydMAOgA7AA4S3RLfAGChAJGAG6ES4IEBu4A12QAhACUS4wAOACgS5AAjAH0S5QBSAJEAfgCdABcAKQAxAIwS7V8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3du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ADEAjADUAnAAjACMABcAjIAAgQVhgACBBVsICAgIgCqAYAgIgAAI3xAQQ/lD+kP7Q/wAIUP9Q/4AI0P/RAAADgAlRAFEAgAoAH0AfkQEACkAKQAURAgAhAAxACkAfgCHAEoAfkQPRBAAjF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZYAZgQV0gASABIACgQVjgQNLgASAGYEDTYATgBmBBbyBBWIIEjaNuqbTADoAOwAORBREFgBgoQCRgBuhRBeBBWSANdkAIQAlRBoADgAoRBsAIwB9RBwAXACRAH4AnQAXACkAMQCMRCRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBWGAG4AZgDyAAIAECIEFZdMAOgA7AA5EJkQwAGCpAKQApQCmAKcAqACpAKoAqwCsgB6AH4AggCGAIoAjgCSAJYAmqUQxRDJEM0Q0RDVENkQ3RDhEOYEFZoEFaIEFaYEFa4EFbIEFboEFb4EFcYEFcoA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdEPQAXRBcAjACMAIwAMQCMANQApACMAIwAFwCMgACBBWeAAIEFZAgICAiAKoAeCAiAAAjSADsADkRLANyggCnfEA8AwgDD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cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBB4aARoAZgDyAAIAECIEHldMAOgA7AA5gumDBAGCmAnACcgJtAm4CbwJxgGCAYoBdgF6AX4BhpmDCYMNgxGDFYMZgx4EHloEH9IEH9YEH9oEH94EH+IA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAWAAXYA8AjACMAIwAMQCMANQCcACMAIwAFwCMgACBB5eAAIEHlAgICAiAKoBgCAiAAAjfEBBg2WDaYNtg3AAhYN1g3gAjYN9g4AAOACVg4WDiACgAfQB+YOQAKQApABRg6ACEADEAKQB+AIcARgB+YO9g8ACMXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgBmBB6qABIAEgAKBB5mBA0uABIAZgQNNgA+AGYEH84EHmAgSRteJf9MAOgA7AA5g9GD2AGChAJGAG6Fg94EHmoA12QAhACVg+gAOAChg+wAjAH1g/ABYAJEAfgCdABcAKQAxAIxhBF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEHl4AbgBmAPIAAgAQIgQeb0wA6ADsADmEGYRAAYKkA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AAAnDAAAJw4AACcbAAAnLAAAJy4AACcwAAAnMgAAJzQAACc2AAAnOAAAJzoAACc8AAAnTQAAJ08AACdRAAAnUwAAJ1UAACdXAAAnWQAAJ1sAACddAAAnXwAAJ30AACebAAAnrgAAJ8IAACfXAAAn9AAAKAgAACgeAAAoXQAAKF8AAChhAAAoYwAAKGUAAChmAAAoZwAAKGgAAChpAAAoawAAKG0AAChuAAAobwAAKHEAAChyAAAosQAAKLMAACi1AAAotwAAKLkAACi6AAAouwAAKLwAACi9AAAovwAAKMEAACjCAAAowwAAKMUAACjGAAApBQAAKQcAACkJAAApCwAAKQ0AACkOAAApDwAAKRAAACkRAAApEwAAKRUAACkWAAApFwAAKRkAACkaAAApJwAAKSgAACkpAAApKwAAKWoAAClsAAApbgAAKXAAAClyAAApcwAAKXQAACl1AAApdgAAKXgAACl6AAApewAAKXwAACl+AAApfwAAKb4AACnAAAApwgAAKcQAACnGAAApxwAAKcgAACnJAAApygAAKcwAACnOAAApzwAAKdAAACnSAAAp0wAAKdQAACoTAAAqFQAAKhcAACoZAAAqGwAAKhwAACodAAAqHgAAKh8AACohAAAqIwAAKiQAAColAAAqJwAAKigAACpnAAAqaQAAKmsAACptAAAqbwAAKnAAACpxAAAqcgAAKnMAACp1AAAqdwAAKngAACp5AAAqewAAKnwAACq7AAAqvQAAKr8AACrBAAAqwwAAKsQAACrFAAAqxgAAKscAACrJAAAqywAAKswAACrNAAAqzwAAKtAAACr1AAArGQAAK0AAACtkAAArZgAAK2gAACtqAAArbAAAK24AACtwAAArcQAAK3MAACuAAAArjwAAK5EAACuTAAArlQAAK5cAACuZAAArmwAAK50AACusAAArrgAAK7AAACuyAAArtAAAK7cAACu6AAArvQAAK78AACvRAAAr5QAAK/cAACwMAAAsHgAALC0AACxKAAAsiQAALIsAACyNAAAsjwAALJEAACySAAAskwAALJQAACyVAAAslwAALJkAACyaAAAsmwAALJ0AACyeAAAs3QAALN8AACzhAAAs4wAALOUAACzmAAAs5wAALOgAACzpAAAs6wAALO0AACzuAAAs7wAALPEAACzyAAAs9AAALTMAAC01AAAtNwAALTkAAC07AAAtPAAALT0AAC0+AAAtPwAALUEAAC1DAAAtRAAALUUAAC1HAAAtSAAALYcAAC2JAAAtiwAALY0AAC2PAAAtkAAALZEAAC2SAAAtkwAALZUAAC2XAAAtmAAALZkAAC2bAAAtnAAALd8AAC4DAAAuJwAALkoAAC5xAAAukQAALrgAAC7fAAAu/wAALyMAAC9HAAAvSQAAL0sAAC9NAAAvTwAAL1EAAC9TAAAvVgAAL1gAAC9aAAAvXQAAL18AAC9hAAAvZAAAL2YAAC9nAAAvbAAAL3kAAC98AAAvfgAAL4EAAC+DAAAvhQAAL6oAAC/OAAAv9QAAMBkAADAbAAAwHQAAMB8AADAhAAAwIwAAMCUAADAmAAAwKAAAMDUAADBIAAAwSgAAMEwAADBOAAAwUAAAMFIAADBUAAAwVgAAMFgAADBaAAAwbQAAMG8AADBxAAAwcwAAMHUAADB3AAAweQAAMHsAADB9AAAwfwAAMIEAADDAAAAwwgAAMMQAADDGAAAwyAAAMMkAADDKAAAwywAAMMwAADDOAAAw0AAAMNEAADDSAAAw1AAAMNUAADDeAAAw3wAAMOEAADEgAAAxIgAAMSQAADEmAAAxKAAAMSkAADEqAAAxKwAAMSwAADEuAAAxMAAAMTEAADEyAAAxNAAAMTUAADF0AAAxdgAAMXgAADF6AAAxfAAAMX0AADF+AAAxfwAAMYAAADGCAAAxhAAAMYUAADGGAAAxiAAAMYkAADGSAAAxlQAAMZcAADGZAAAxogAAMaUAADGnAAAxqQAAMbEAADHwAAAx8gAAMfQAADH2AAAx+AAAMfkAADH6AAAx+wAAMfwAADH+AAAyAAAAMgEAADICAAAyBAAAMgUAADJEAAAyRgAAMkgAADJKAAAyTAAAMk0AADJOAAAyTwAAMlAAADJSAAAyVAAAMlUAADJWAAAyWAAAMlkAADJiAAAyYwAAMmUAADKkAAAypgAAMqgAADKqAAAyrAAAMq0AADKuAAAyrwAAMrAAADKyAAAytAAAMrUAADK2AAAyuAAAMrkAADL4AAAy+gAAMvwAADL+AAAzAAAAMwEAADMCAAAzAwAAMwQAADMGAAAzCAAAMwkAADMKAAAzDAAAMw0AADMaAAAzGwAAMxwAADMeAAAzXQAAM18AADNhAAAzYwAAM2UAADNmAAAzZwAAM2gAADNpAAAzawAAM20AADNuAAAzbwAAM3EAADNyAAAzsQAAM7MAADO1AAAztwAAM7kAADO6AAAzuwAAM7wAADO9AAAzvwAAM8EAADPCAAAzwwAAM8UAADPGAAAz0wAANAwAADQOAAA0EAAANBIAADQUAAA0FgAANBgAADQaAAA0HAAANB4AADQgAAA0IgAANCQAADQmAAA0KAAANCoAADQsAAA0LgAANDAAADQyAAA0NAAANDYAADQ4AAA0OgAANDwAADQ+AAA0QAAANEIAADR7AAA0fQAANH8AADSBAAA0gwAANIYAADSJAAA0jAAANI8AADSSAAA0lQAANJgAADSbAAA0ngAANKEAADSkAAA0pwAANKoAADStAAA0sAAANLMAADS2AAA0uQAANLwAADS/AAA0wgAANMUAADTIAAA0ygAANNQAADTiAAA08AAANPgAADUGAAA1CwAANRoAADUoAAA1LQAANUEAADVIAAA1XgAANWgAADV3AAA1fQAANYoAADWTAAA1mgAANaMAADW3AAA1ygAANdQAADXmAAA19AAANgAAADZLAAA2bgAANo4AADauAAA2sAAANrIAADa0AAA2tgAANrgAADa5AAA2ugAANrwAADa9AAA2vwAANsAAADbCAAA2xAAANsUAADbGAAA2yAAANskAADbOAAA22wAANuAAADbiAAA25AAANukAADbrAAA27QAANu8AADcUAAA3OAAAN18AADeDAAA3hQAAN4cAADeJAAA3iwAAN40AADePAAA3kAAAN5IAADefAAA3sAAAN7IAADe0AAA3tgAAN7gAADe6AAA3vAAAN74AADfAAAA30QAAN9MAADfVAAA31wAAN9kAADfbAAA33QAAN98AADfhAAA34wAAOCIAADgkAAA4JgAAOCgAADgqAAA4KwAAOCwAADgtAAA4LgAAODAAADgyAAA4MwAAODQAADg2AAA4NwAAOHYAADh4AAA4egAAOHwAADh+AAA4fwAAOIAAADiBAAA4ggAAOIQAADiGAAA4hwAAOIgAADiKAAA4iwAAOMoAADjMAAA4zgAAONAAADjSAAA40wAAONQAADjVAAA41gAAONgAADjaAAA42wAAONwAADjeAAA43wAAOOwAADjtAAA47gAAOPAAADkvAAA5MQAAOTMAADk1AAA5NwAAOTgAADk5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AABFFwAARVYAAEVYAABFWgAARVwAAEVeAABFXwAARWAAAEVhAABFYgAARWQAAEVmAABFZwAARWgAAEVqAABFawAARaoAAEWsAABFrgAARbAAAEWyAABFswAARbQAAEW1AABFtgAARbgAAEW6AABFuwAARbwAAEW+AABFvwAARf4AAEYAAABGAgAARgQAAEYGAABGBwAARggAAEYJAABGCgAARgwAAEYOAABGDwAARhAAAEYSAABGEwAARhUAAEZUAABGVgAARlgAAEZaAABGXAAARl0AAEZeAABGXwAARmAAAEZiAABGZAAARmUAAEZmAABGaAAARmkAAEaoAABGqgAARqwAAEauAABGsAAARrEAAEayAABGswAARrQAAEa2AABGuAAARrkAAEa6AABGvAAARr0AAEb8AABG/gAARwAAAEcCAABHBAAARwUAAEcGAABHBwAARwgAAEcKAABHDAAARw0AAEcOAABHEAAARxEAAEcaAABHKAAARzUAAEdDAABHUAAAR2MAAEd6AABHjAAAR9cAAEf6AABIGgAASDoAAEg8AABIPgAASEAAAEhCAABIRAAASEUAAEhGAABISAAASEkAAEhLAABITAAASE4AAEhQAABIUQAASFIAAEhUAABIVQAASFoAAEhnAABIbAAASG4AAEhwAABIdQAASHcAAEh5AABIewAASKAAAEjEAABI6wAASQ8AAEkRAABJEwAASRUAAEkXAABJGQAASRsAAEkcAABJHgAASSsAAEk8AABJPgAASUAAAElCAABJRAAASUYAAElIAABJSgAASUwAAEldAABJXwAASWEAAEljAABJZQAASWcAAElpAABJawAASW0AAElvAABJrgAASbAAAEmyAABJtAAASbYAAEm3AABJuAAASbkAAEm6AABJvAAASb4AAEm/AABJwAAAScIAAEnDAABKAgAASgQAAEoGAABKCAAASgoAAEoLAABKDAAASg0AAEoOAABKEAAAShIAAEoTAABKFAAAShYAAEoXAABKVgAASlgAAEpaAABKXAAASl4AAEpfAABKYAAASmEAAEpiAABKZAAASmYAAEpnAABKaAAASmoAAEprAABKeAAASnkAAEp6AABKfAAASrsAAEq9AABKvwAASsEAAErDAABKxAAASsUAAErGAABKxwAASskAAErLAABKzAAASs0AAErPAABK0AAASw8AAEsRAABLEwAASxUAAEsXAABLGAAASxkAAEsaAABLGwAASx0AAEsfAABLIAAASyEAAEsjAABLJAAAS2MAAEtlAABLZwAAS2kAAEtrAABLbAAAS20AAEtuAABLbwAAS3EAAEtzAABLdAAAS3UAAEt3AABLeAAAS7cAAEu5AABLuwAAS70AAEu/AABLwAAAS8EAAEvCAABLwwAAS8UAAEvHAABLyAAAS8kAAEvLAABLzAAATAsAAEwNAABMDwAATBEAAEwTAABMFAAATBUAAEwWAABMFwAATBkAAEwbAABMHAAATB0AAEwfAABMIAAATEUAAExpAABMkAAATLQAAEy2AABMuAAATLoAAEy8AABMvgAATMAAAEzBAABMwwAATNAAAEzfAABM4QAATOMAAEzlAABM5wAATOkAAEzrAABM7QAATPwAAEz+AABNAAAATQIAAE0EAABNBgAATQgAAE0KAABNDAAATUsAAE1NAABNTwAATVEAAE1TAABNVAAATVUAAE1WAABNVwAATVkAAE1bAABNXAAATV0AAE1fAABNYAAATZ8AAE2hAABNowAATaUAAE2nAABNqAAATakAAE2qAABNqwAATa0AAE2vAABNsAAATbEAAE2zAABNtAAATfMAAE31AABN9wAATfkAAE37AABN/AAATf0AAE3+AABN/wAATgEAAE4DAABOBAAATgUAAE4HAABOCAAATkcAAE5JAABOSwAATk0AAE5PAABOUAAATlEAAE5SAABOUwAATlUAAE5XAABOWAAATlkAAE5bAABOXAAATl8AAE6eAABOoAAATqIAAE6kAABOpgAATqcAAE6oAABOqQAATqoAAE6sAABOrgAATq8AAE6wAABOsgAATrMAAE7yAABO9AAATvYAAE74AABO+gAATvsAAE78AABO/QAATv4AAE8AAABPAgAATwMAAE8EAABPBgAATwcAAE9GAABPSAAAT0oAAE9MAABPTgAAT08AAE9QAABPUQAAT1IAAE9UAABPVgAAT1cAAE9YAABPWgAAT1sAAE+mAABPyQAAT+kAAFAJAABQCwAAUA0AAFAPAABQEQAAUBMAAFAUAABQFQAAUBcAAFAYAABQGgAAUBsAAFAdAABQHwAAUCAAAFAhAABQIwAAUCQAAFAtAABQOgAAUD8AAFBBAABQQwAAUEgAAFBK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AACIAgAAiAUAAIgIAACICgAAiC8AAIhTAACIegAAiJ4AAIihAACIowAAiKUAAIinAACIqQAAiKsAAIisAACIrwAAiLwAAIjNAACIzwAAiNEAAIjTAACI1QAAiNcAAIjZAACI2wAAiN0AAIjuAACI8QAAiPQAAIj3AACI+gAAiP0AAIkAAACJAwAAiQYAAIkIAACJRwAAiUkAAIlLAACJTQAAiVAAAIlRAACJUgAAiVMAAIlUAACJVgAAiVgAAIlZAACJWgAAiVwAAIldAACJnAAAiZ4AAImgAACJogAAiaUAAImmAACJpwAAiagAAImpAACJqwAAia0AAImuAACJrwAAibEAAImyAACJ8QAAifMAAIn2AACJ+AAAifsAAIn8AACJ/QAAif4AAIn/AACKAQAAigMAAIoEAACKBQAAigcAAIoIAACKFQAAihYAAIoXAACKGQAAilgAAIpaAACKXAAAil4AAIphAACKYgAAimMAAIpkAACKZQAAimcAAIppAACKagAAimsAAIptAACKbgAAiq0AAIqvAACKsQAAirMAAIq2AACKtwAAirgAAIq5AACKugAAirwAAIq+AACKvwAAisAAAIrCAACKwwAAiwIAAIsEAACLBgAAiwgAAIsLAACLDAAAiw0AAIsOAACLDwAAixEAAIsTAACLFAAAixUAAIsXAACLGAAAi1cAAItZAACLWwAAi10AAItgAACLYQAAi2IAAItjAACLZAAAi2YAAItoAACLaQAAi2oAAItsAACLbQAAi6wAAIuuAACLsAAAi7IAAIu1AACLtgAAi7cAAIu4AACLuQAAi7sAAIu9AACLvgAAi78AAIvBAACLwgAAi+cAAIwLAACMMgAAjFYAAIxZAACMWwAAjF0AAIxfAACMYQAAjGMAAIxkAACMZwAAjHQAAIyDAACMhQAAjIcAAIyJAACMiwAAjI0AAIyPAACMkQAAjKAAAIyjAACMpgAAjKkAAIysAACMrwAAjLIAAIy1AACMtwAAjPYAAIz4AACM+gAAjPwAAIz/AACNAAAAjQEAAI0CAACNAwAAjQUAAI0HAACNCAAAjQkAAI0LAACNDAAAjUsAAI1NAACNTwAAjVEAAI1UAACNVQAAjVYAAI1XAACNWAAAjVoAAI1cAACNXQAAjV4AAI1gAACNYQAAjaAAAI2iAACNpAAAjaYAAI2pAACNqgAAjasAAI2sAACNrQAAja8AAI2xAACNsgAAjbMAAI21AACNtgAAjfUAAI33AACN+QAAjfsAAI3+AACN/wAAjgAAAI4BAACOAgAAjgQAAI4GAACOBwAAjggAAI4KAACOCwAAjkoAAI5MAACOTgAAjlAAAI5TAACOVAAAjlUAAI5WAACOVwAAjlkAAI5bAACOXAAAjl0AAI5fAACOYAAAjp8AAI6hAACOowAAjqUAAI6oAACOqQAAjqoAAI6rAACOrAAAjq4AAI6wAACOsQAAjrIAAI60AACOtQAAjvQAAI72AACO+AAAjvoAAI79AACO/gAAjv8AAI8AAACPAQAAjwMAAI8FAACPBgAAjwcAAI8JAACPCgAAj1UAAI94AACPmAAAj7gAAI+6AACPvAAAj74AAI/AAACPwgAAj8MAAI/EAACPxwAAj8gAAI/KAACPywAAj80AAI/PAACP0AAAj9EAAI/UAACP1QAAj9oAAI/nAACP7AAAj+4AAI/wAACP9QAAj/gAAI/7AACP/QAAkCIAAJBGAACQbQAAkJEAAJCUAACQlgAAkJgAAJCaAACQnAAAkJ4AAJCfAACQogAAkK8AAJDAAACQwgAAkMQAAJDGAACQyAAAkMoAAJDMAACQzgAAkNAAAJDhAACQ5AAAkOcAAJDqAACQ7QAAkPAAAJDzAACQ9gAAkPkAAJD7AACROgAAkTwAAJE+AACRQAAAkUMAAJFEAACRRQAAkUYAAJFHAACRSQAAkUsAAJFMAACRTQAAkU8AAJFQAACRjwAAkZEAAJGTAACRlQAAkZgAAJGZAACRmgAAkZsAAJGcAACRngAAkaAAAJGhAACRogAAkaQAAJGlAACR5AAAkeYAAJHpAACR6wAAke4AAJHvAACR8AAAkfEAAJHyAACR9AAAkfYAAJH3AACR+AAAkfoAAJH7AACSCAAAkgkAAJIKAACSDAAAkksAAJJNAACSTwAAklEAAJJUAACSVQAAklYAAJJXAACSWAAAkloAAJJcAACSXQAAkl4AAJJgAACSYQAAkqAAAJKiAACSpAAAkqYAAJKpAACSqgAAkqsAAJKsAACSrQAAkq8AAJKxAACSsgAAkrMAAJK1AACStgAAkvUAAJL3AACS+QAAkvsAAJL+AACS/wAAkwAAAJMBAACTAgAAkwQAAJMGAACTBwAAkwgAAJMKAACTCwAAk0oAAJNMAACTTgAAk1AAAJNTAACTVAAAk1UAAJNWAACTVwAAk1kAAJNbAACTXAAAk10AAJNfAACTYAAAk58AAJOhAACTowAAk6UAAJOoAACTqQAAk6oAAJOrAACTrAAAk64AAJOwAACTsQAAk7IAAJO0AACTtQAAk9oAAJP+AACUJQAAlEkAAJRMAACUTgAAlFAAAJRSAACUVAAAlFYAAJRXAACUWgAAlGcAAJR0AACUdgAAlHgAAJR6AACUfAAAlH4AAJSAAACUjQAAlJAAAJSTAACUlgAAlJkAAJScAACUnwAAlKEAAJTgAACU4gAAlOUAAJTnAACU6gAAlOsAAJTsAACU7QAAlO4AAJTwAACU8gAAlPMAAJT0AACU9gAAlPcAAJU6AACVXgAAlYIAAJWlAACVzAAAlewAAJYTAACWOgAAlloAAJZ+AACWogAAlqQAAJanAACWqQAAlqsAAJatAACWsAAAlrMAAJa1AACWtwAAlroAAJa8AACWvgAAlsEAAJbEAACWxQAAlsoAAJbXAACW2gAAltwAAJbfAACW4gAAluQAAJcJAACXLQAAl1QAAJd4AACXewAAl30AAJd/AACXgQAAl4MAAJeFAACXhgAAl4kAAJeWAACXqQAAl6sAAJetAACXrwAAl7EAAJezAACXtQAAl7cAAJe5AACXuwAAl84AAJfRAACX1AAAl9cAAJfaAACX3QAAl+AAAJfjAACX5gAAl+kAAJfrAACYKgAAmCwAAJgvAACYMQAAmDQAAJg1AACYNgAAmDcAAJg4AACYOgAAmDwAAJg9AACYPgAAmEAAAJhBAACYSgAAmEsAAJhNAACYjAAAmI4AAJiQAACYkgAAmJUAAJiWAACYlwAAmJgAAJiZAACYmwAAmJ0AAJieAACYnwAAmKEAAJiiAACY4QAAmOMAAJjmAACY6AAAmOsAAJjsAACY7QAAmO4AAJjvAACY8QAAmPMAAJj0AACY9QAAmPcAAJj4AACZAQAAmQIAAJkEAACZQwAAmUUAAJlHAACZSQAAmUwAAJlNAACZTgAAmU8AAJlQAACZUgAAmVQAAJlVAACZVgAAmVgAAJlZAACZmAAAmZoAAJmdAACZnwAAmaIAAJmjAACZpAAAmaUAAJmmAACZqAAAmaoAAJmrAACZrAAAma4AAJmvAACZuAAAmbkAAJm7AACZ+gAAmfwAAJn+AACaAAAAmgMAAJoEAACaBQAAmgYAAJoHAACaCQAAmgsAAJoMAACaDQAAmg8AAJoQAACaTwAAmlEAAJpUAACaVgAAmlkAAJpaAACaWwAAmlwAAJpdAACaXwAAmmEAAJpiAACaYwAAmmUAAJpmAACacwAAmnQAAJp1AACadwAAmrYAAJq4AACaugAAmrwAAJq/AACawAAAmsEAAJrCAACawwAAmsUAAJrHAACayAAAmskAAJrLAACazAAAmwsAAJsNAACbDwAAmxEAAJsUAACbFQAAmxYAAJsXAACbGAAAmxoAAJscAACbHQAAmx4AAJsgAACbIQAAmy4AAJtRAACbVAAAm1YAAJtZAACbXAAAm18AAJtiAACbZQAAm2gAAJtrAACbbgAAm3AAAJtzAACbdgAAm3kAAJt7AACbfgAAm6EAAJukAACbpwAAm6oAAJutAACbsAAAm7MAAJu2AACbuQAAm7wAAJu/AACbwgAAm8UAAJvIAACbywAAm84AAJvRAACb0wAAm9YAAJvdAACb6wAAm/EAAJv3AACb/wAAnAoAAJwUAACcHQAAnCcAAJw8AACcUAAAnFgAAJyjAACcxgAAnOYAAJ0GAACdCAAAnQoAAJ0MAACdDgAAnREAAJ0SAACdEwAAnRYAAJ0XAACdGQAAnRoAAJ0cAACdHwAAnSAAAJ0hAACdJAAAnSUAAJ0qAACdNwAAnTwAAJ0+AACdQAAAnUUAAJ1IAACdSwAAnU0AAJ1yAACdlgAAnb0AAJ3hAACd5AAAneYAAJ3oAACd6gAAnewAAJ3uAACd7wAAnfIAAJ3/AACeEAAAnhIAAJ4UAACeFgAAnhgAAJ4aAACeHAAAnh4AAJ4gAACeMQAAnjQAAJ43AACeOgAAnj0AAJ5AAACeQwAAnkYAAJ5JAACeSwAAnooAAJ6MAACejgAAnpAAAJ6TAACelAAAnpUAAJ6WAACelwAAnpkAAJ6bAACenAAAnp0AAJ6fAACeoAAAnt8AAJ7hAACe4wAAnuUAAJ7oAACe6QAAnuoAAJ7rAACe7AAAnu4AAJ7wAACe8QAAnvIAAJ70AACe9QAAnzQAAJ82AACfOQAAnzsAAJ8+AACfPwAAn0AAAJ9BAACfQgAAn0QAAJ9GAACfRwAAn0gAAJ9KAACfSwAAn1gAAJ9ZAACfWgAAn1wAAJ+bAACfnQAAn58AAJ+hAACfpAAAn6UAAJ+mAACfpwAAn6gAAJ+qAACfrAAAn60AAJ+uAACfsAAAn7EAAJ/wAACf8gAAn/QAAJ/2AACf+QAAn/oAAJ/7AACf/AAAn/0AAJ//AACgAQAAoAIAAKADAACgBQAAoAYAAKBFAACgRwAAoEkAAKBLAACgTgAAoE8AAKBQAACgUQAAoFIAAKBUAACgVgAAoFcAAKBYAACgWgAAoFsAAKCaAACgnAAAoJ4AAKCgAACgowAAoKQAAKClAACgpgAAoKcAAKCpAACgqwAAoKwAAKCtAACgrwAAoLAAAKDvAACg8QAAoPMAAKD1AACg+AAAoPkAAKD6AACg+wAAoPwAAKD+AAChAAAAoQEAAKECAAChBAAAoQUAAKEqAAChTgAAoXUAAKGZAAChnAAAoZ4AAKGgAAChogAAoaQAAKGmAAChpwAAoaoAAKG3AAChxgAAocgAAKHKAAChzAAAoc4AAKHQAACh0gAAodQAAKHjAACh5gAAoekAAKHsAACh7wAAofIAAKH1AACh+AAAofoAAKI5AACiOwAAoj0AAKI/AACiQgAAokMAAKJEAACiRQAAokYAAKJIAACiSgAAoksAAKJMAACiTgAAok8AAKKOAACikAAAopIAAKKUAACilwAAopgAAKKZAACimgAAopsAAKKdAACinwAAoqAAAKKhAACiowAAoqQAAKLjAACi5QAAoucAAKLpAACi7AAAou0AAKLuAACi7wAAovAAAKLyAACi9AAAovUAAKL2AACi+AAAovkAAKM4AACjOgAAozwAAKM+AACjQQAAo0IAAKNDAACjRAAAo0UAAKNHAACjSQAAo0oAAKNLAACjTQAAo04AAKONAACjjwAAo5EAAKOTAACjlgAAo5cAAKOYAACjmQAAo5oAAKOcAACjngAAo58AAKOgAACjogAAo6MAAKPiAACj5AAAo+YAAKPoAACj6wAAo+wAAKPtAACj7gAAo+8AAKPxAACj8wAAo/QAAKP1AACj9wAAo/gAAKQ3AACkOQAApDsAAKQ9AACkQAAApEEAAKRCAACkQwAApEQAAKRGAACkSAAApEkAAKRKAACkTAAApE0AAKSYAACkuwAApNsAAKT7AACk/QAApP8AAKUBAAClAwAApQYAAKUHAAClCAAApQsAAKUMAAClDgAApQ8AAKURAAClEwAApRQAAKUVAAClGAAApRkAAKUeAAClKwAApTAAAKUyAAClNAAApTkAAKU8AAClPwAApUEAAKVmAACligAApbEAAKXVAACl2AAApdoAAKXcAACl3gAApeAAAKXiAACl4wAApeYAAKXzAACmBAAApgYAAKYIAACmCgAApgwAAKYOAACmEAAAphIAAKYUAACmJQAApigAAKYrAACmLgAApjEAAKY0AACmNwAApjoAAKY9AACmPwAApn4AAKaAAACmggAApoQAAKaHAACmiAAApokAAKaKAACmiwAApo0AAKaPAACmkAAAppEAAKaTAACmlAAAptMAAKbVAACm1wAAptkAAKbcAACm3QAApt4AAKbfAACm4AAApuIAAKbkAACm5QAApuYAAKboAACm6QAApygAAKcqAACnLQAApy8AAKcyAACnMwAApzQAAKc1AACnNgAApzgAAKc6AACnOwAApzwAAKc+AACnPwAAp0wAAKdNAACnTgAAp1AAAKePAACnkQAAp5MAAKeVAACnmAAAp5kAAKeaAACnmwAAp5wAAKeeAACnoAAAp6EAAKeiAACnpAAAp6UAAKfkAACn5gAAp+gAAKfqAACn7QAAp+4AAKfvAACn8AAAp/EAAKfzAACn9QAAp/YAAKf3AACn+QAAp/oAAKg5AACoOwAAqD0AAKg/AACoQgAAqEMAAKhEAACoRQAAqEYAAKhIAACoSgAAqEsAAKhMAACoTgAAqE8AAKiOAACokAAAqJIAAKiUAAColwAAqJgAAKiZAAComgAAqJsAAKidAAConwAAqKAAAKihAACoowAAqKQAAKjjAACo5QAAqOcAAKjpAACo7AAAqO0AAKjuAACo7wAAqPAAAKjyAACo9AAAqPUAAKj2AACo+AAAqPkAAKkeAACpQgAAqWkAAKmNAACpkAAAqZIAAKmUAACplgAAqZgAAKmaAACpmwAAqZ4AAKmrAACpugAAqbwAAKm+AACpwAAAqcIAAKnEAACpxgAAqcgAAKnXAACp2gAAqd0AAKngAACp4wAAqeYAAKnpAACp7AAAqe4AAKotAACqLwAAqjEAAKozAACqNgAAqjcAAKo4AACqOQAAqjoAAKo8AACqPgAAqj8AAKpAAACqQgAAqkMAAKqCAACqhAAAqoYAAKqIAACqiwAAqowAAKqNAACqjgAAqo8AAKqRAACqkwAAqpQAAKqVAACqlwAAqpgAAKrXAACq2QAAqtsAAKrdAACq4AAAquEAAKriAACq4wAAquQAAKrmAACq6AAAqukAAKrqAACq7AAAqu0AAKssAACrLgAAqzAAAKsyAACrNQAAqzYAAKs3AACrOAAAqzkAAKs7AACrPQAAqz4AAKs/AACrQQAAq0IAAKuBAACrgwAAq4UAAKuHAACrigAAq4sAAKuMAACrjQAAq44AAKuQAACrkgAAq5MAAKuUAACrlgAAq5cAAKvWAACr2AAAq9oAAKvcAACr3wAAq+AAAKvhAACr4gAAq+MAAKvlAACr5wAAq+gAAKvpAACr6wAAq+wAAKwrAACsLQAArC8AAKwxAACsNAAArDUAAKw2AACsNwAArDgAAKw6AACsPAAArD0AAKw+AACsQAAArEEAAKyMAACsrwAArM8AAKzvAACs8QAArPMAAKz1AACs9wAArPoAAKz7AACs/AAArP8AAK0AAACtAgAArQMAAK0FAACtCAAArQkAAK0KAACtDQAArQ4AAK0TAACtIAAArSUAAK0nAACtKQAArS4AAK0xAACtNAAArTYAAK1bAACtfwAAraYAAK3KAACtzQAArc8AAK3RAACt0wAArdUAAK3XAACt2AAArdsAAK3oAACt+QAArfsAAK39AACt/wAArgEAAK4DAACuBQAArgcAAK4JAACuGgAArh0AAK4gAACuIwAAriYAAK4pAACuLAAAri8AAK4yAACuNAAArnMAAK51AACudwAArnkAAK58AACufQAArn4AAK5/AACugAAAroIAAK6EAACuhQAAroYAAK6IAACuiQAArsgAAK7KAACuzAAArs4AAK7RAACu0gAArtMAAK7UAACu1QAArtcAAK7ZAACu2gAArtsAAK7dAACu3gAArx0AAK8fAACvIgAAryQAAK8nAACvKAAArykAAK8qAACvKwAAry0AAK8vAACvMAAArzEAAK8zAACvNAAAr0EAAK9CAACvQwAAr0UAAK+EAACvhgAAr4gAAK+KAACvjQAAr44AAK+PAACvkAAAr5EAAK+TAACvlQAAr5YAAK+XAACvmQAAr5oAAK/ZAACv2wAAr90AAK/fAACv4gAAr+MAAK/kAACv5QAAr+YAAK/oAACv6gAAr+sAAK/sAACv7gAAr+8AALAuAACwMAAAsDIAALA0AACwNwAAsDgAALA5AACwOgAAsDsAALA9AACwPwAAsEAAALBBAACwQwAAsEQAALCDAACwhQAAsIcAALCJAACwjAAAsI0AALCOAACwjwAAsJAAALCSAACwlAAAsJUAALCWAACwmAAAsJkAALDYAACw2gAAsNwAALDeAACw4QAAsOIAALDjAACw5AAAsOUAALDnAACw6QAAsOoAALDrAACw7QAAsO4AALETAACxNwAAsV4AALGCAACxhQAAsYcAALGJAACxiwAAsY0AALGPAACxkAAAsZMAALGgAACxrwAAsbEAALGzAACxtQAAsbcAALG5AACxuwAAsb0AALHMAACxzwAAsdIAALHVAACx2AAAsdsAALHeAACx4QAAseMAALIiAACyJAAAsiYAALIoAACyKwAAsiwAALItAACyLgAAsi8AALIxAACyMwAAsjQAALI1AACyNwAAsjgAALJ3AACyeQAAsnsAALJ9AACygAAAsoEAALKCAACygwAAsoQAALKGAACyiAAAsokAALKKAACyjAAAso0AALLMAACyzgAAstAAALLSAACy1QAAstYAALLXAACy2AAAstkAALLbAACy3QAAst4AALLfAACy4QAAsuIAALMhAACzIwAAsyUAALMnAACzKgAAsysAALMsAACzLQAAsy4AALMwAACzMgAAszMAALM0AACzNgAAszcAALN2AACzeAAAs3oAALN8AACzfwAAs4AAALOBAACzggAAs4MAALOFAACzhwAAs4gAALOJAACziwAAs4wAALPLAACzzQAAs88AALPRAACz1AAAs9UAALPWAACz1wAAs9gAALPaAACz3AAAs90AALPeAACz4AAAs+EAALQgAAC0IgAAtCQAALQmAAC0KQAAtCoAALQrAAC0LAAAtC0AALQvAAC0MQAAtDIAALQzAAC0NQAAtDYAALSBAAC0pAAAtMQAALTkAAC05gAAtOgAALTqAAC07AAAtO8AALTwAAC08QAAtPQAALT1AAC09wAAtPgAALT6AAC0/QAAtP4AALT/AAC1AgAAtQMAALUIAAC1FQAAtRoAALUcAAC1HgAAtSMAALUmAAC1KQAAtSsAALVQAAC1dAAAtZsAALW/AAC1wgAAtcQAALXGAAC1yAAAtcoAALXMAAC1zQAAtdAAALXdAAC17gAAtfAAALXyAAC19AAAtfYAALX4AAC1+gAAtfwAALX+AAC2DwAAthIAALYVAAC2GAAAthsAALYeAAC2IQAAtiQAALYnAAC2KQAAtmgAALZqAAC2bAAAtm4AALZxAAC2cgAAtnMAALZ0AAC2dQAAtncAALZ5AAC2egAAtnsAALZ9AAC2fgAAtr0AALa/AAC2wQAAtsMAALbGAAC2xwAAtsgAALbJAAC2ygAAtswAALbOAAC2zwAAttAAALbSAAC20wAAtxIAALcUAAC3FwAAtxkAALccAAC3HQAAtx4AALcfAAC3IAAAtyIAALckAAC3JQAAtyYAALcoAAC3KQAAtzYAALc3AAC3OAAAtzoAALd5AAC3ewAAt30AALd/AAC3ggAAt4MAALeEAAC3hQAAt4YAALeIAAC3igAAt4sAALeMAAC3jgAAt48AALfOAAC30AAAt9IAALfUAAC31wAAt9gAALfZAAC32gAAt9sAALfdAAC33wAAt+AAALfhAAC34wAAt+QAALgjAAC4JQAAuCcAALgpAAC4LAAAuC0AALguAAC4LwAAuDAAALgyAAC4NAAAuDUAALg2AAC4OAAAuDkAALh4AAC4egAAuHwAALh+AAC4gQAAuIIAALiDAAC4hAAAuIUAALiHAAC4iQAAuIoAALiLAAC4jQAAuI4AALjNAAC4zwAAuNEAALjTAAC41gAAuNcAALjYAAC42QAAuNoAALjcAAC43gAAuN8AALjgAAC44gAAuOMAALkIAAC5LAAAuVMAALl3AAC5egAAuXwAALl+AAC5gAAAuYIAALmEAAC5hQAAuYgAALmVAAC5pAAAuaYAALmoAAC5qgAAuawAALmuAAC5sAAAubIAALnBAAC5xAAAuccAALnKAAC5zQAAudAAALnTAAC51gAAudgAALoXAAC6GQAAuhwAALoeAAC6IQAAuiIAALojAAC6JAAAuiUAALonAAC6KQAAuioAALorAAC6LQAAui4AALoyAAC6cQAAunMAALp1AAC6dwAAunoAALp7AAC6fAAAun0AALp+AAC6gAAAuoIAALqDAAC6hAAAuoYAALqHAAC6xgAAusgAALrKAAC6zAAAus8AALrQAAC60QAAutIAALrTAAC61QAAutcAALrYAAC62QAAutsAALrcAAC7GwAAux0AALsgAAC7IgAAuyUAALsmAAC7JwAAuygAALspAAC7KwAAuy0AALsu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AADLywAAzAoAAMwMAADMDgAAzBAAAMwTAADMFAAAzBUAAMwWAADMFwAAzBkAAMwbAADMHAAAzB0AAMwfAADMIAAAzGsAAMyOAADMrgAAzM4AAMzQAADM0gAAzNQAAMzWAADM2QAAzNoAAMzbAADM3gAAzN8AAMzhAADM4gAAzOQAAMznAADM6AAAzOkAAMzsAADM7QAAzPIAAMz/AADNBAAAzQYAAM0IAADNDQAAzRAAAM0TAADNFQAAzToAAM1eAADNhQAAzakAAM2sAADNrgAAzbAAAM2yAADNtAAAzbYAAM23AADNugAAzccAAM3YAADN2gAAzdwAAM3eAADN4AAAzeIAAM3kAADN5gAAzegAAM35AADN/AAAzf8AAM4CAADOBQAAzggAAM4LAADODgAAzhEAAM4TAADOUgAAzlQAAM5WAADOWAAAzlsAAM5cAADOXQAAzl4AAM5fAADOYQAAzmMAAM5kAADOZQAAzmcAAM5oAADOpwAAzqkAAM6rAADOrQAAzrAAAM6xAADOsgAAzrMAAM60AADOtgAAzrgAAM65AADOugAAzrwAAM69AADO/AAAzv4AAM8BAADPAwAAzwYAAM8HAADPCAAAzwkAAM8KAADPDAAAzw4AAM8PAADPEAAAzxIAAM8TAADPIAAAzyEAAM8iAADPJAAAz2MAAM9lAADPZwAAz2kAAM9sAADPbQAAz24AAM9vAADPcAAAz3IAAM90AADPdQAAz3YAAM94AADPeQAAz7gAAM+6AADPvAAAz74AAM/BAADPwgAAz8MAAM/EAADPxQAAz8cAAM/JAADPygAAz8sAAM/NAADPzgAA0A0AANAPAADQEQAA0BMAANAWAADQFwAA0BgAANAZAADQGgAA0BwAANAeAADQHwAA0CAAANAiAADQIwAA0GIAANBkAADQZgAA0GgAANBrAADQbAAA0G0AANBuAADQbwAA0HEAANBzAADQdAAA0HUAANB3AADQeAAA0LcAANC5AADQuwAA0L0AANDAAADQwQAA0MIAANDDAADQxAAA0MYAANDIAADQyQAA0MoAANDMAADQzQAA0PIAANEWAADRPQAA0WEAANFkAADRZgAA0WgAANFqAADRbAAA0W4AANFvAADRcgAA0X8AANGOAADRkAAA0ZIAANGUAADRlgAA0ZgAANGaAADRnAAA0asAANGuAADRsQAA0bQAANG3AADRugAA0b0AANHAAADRwgAA0gEAANIDAADSBQAA0gcAANIKAADSCwAA0gwAANINAADSDgAA0hAAANISAADSEwAA0hQAANIWAADSFwAA0lYAANJYAADSWgAA0lwAANJfAADSYAAA0mEAANJiAADSYwAA0mUAANJnAADSaAAA0mkAANJrAADSbAAA0qsAANKtAADSrwAA0rEAANK0AADStQAA0rYAANK3AADSuAAA0roAANK8AADSvQAA0r4AANLAAADSwQAA0wAAANMCAADTBAAA0wYAANMJAADTCgAA0wsAANMMAADTDQAA0w8AANMRAADTEgAA0xMAANMVAADTFgAA01UAANNXAADTWQAA01sAANNeAADTXwAA02AAANNhAADTYgAA02QAANNmAADTZwAA02gAANNqAADTawAA06oAANOsAADTrgAA07AAANOzAADTtAAA07UAANO2AADTtwAA07kAANO7AADTvAAA070AANO/AADTwAAA0/8AANQBAADUAwAA1AUAANQIAADUCQAA1AoAANQLAADUDAAA1A4AANQQAADUEQAA1BIAANQUAADUFQAA1GAAANSDAADUowAA1MMAANTFAADUxwAA1MkAANTLAADUzgAA1M8AANTQAADU0wAA1NQAANTWAADU1wAA1NkAANTcAADU3QAA1N4AANThAADU4gAA1OcAANT0AADU+QAA1PsAANT9AADVAgAA1QUAANUIAADVCgAA1S8AANVTAADVegAA1Z4AANWhAADVowAA1aUAANWnAADVqQAA1asAANWsAADVrwAA1bwAANXNAADVzwAA1dEAANXTAADV1QAA1dcAANXZAADV2wAA1d0AANXuAADV8QAA1fQAANX3AADV+gAA1f0AANYAAADWAwAA1gYAANYIAADWRwAA1kkAANZLAADWTQAA1lAAANZRAADWUgAA1lMAANZUAADWVgAA1lgAANZZAADWWgAA1lwAANZdAADWnAAA1p4AANagAADWogAA1qUAANamAADWpwAA1qgAANapAADWqwAA1q0AANauAADWrwAA1rEAANayAADW8QAA1vMAANb2AADW+AAA1vsAANb8AADW/QAA1v4AANb/AADXAQAA1wMAANcEAADXBQAA1wcAANcIAADXFQAA1xYAANcXAADXGQAA11gAANdaAADXXAAA114AANdhAADXYgAA12MAANdkAADXZQAA12cAANdpAADXagAA12sAANdtAADXbgAA160AANevAADXsQAA17MAANe2AADXtwAA17gAANe5AADXugAA17wAANe+AADXvwAA18AAANfCAADXwwAA2AIAANgEAADYBgAA2AgAANgLAADYDAAA2A0AANgOAADYDwAA2BEAANgTAADYFAAA2BUAANgXAADYGAAA2FcAANhZAADYWwAA2F0AANhgAADYYQAA2GIAANhjAADYZAAA2GYAANhoAADYaQAA2GoAANhsAADYbQAA2KwAANiuAADYsAAA2LIAANi1AADYtgAA2LcAANi4AADYuQAA2LsAANi9AADYvgAA2L8AANjBAADYwgAA2OcAANkLAADZMgAA2VYAANlZAADZWwAA2V0AANlfAADZYQAA2WMAANlkAADZZwAA2XQAANmDAADZhQAA2YcAANmJAADZiwAA2Y0AANmPAADZkQAA2aAAANmjAADZpgAA2akAANmsAADZrwAA2bIAANm1AADZtwAA2fYAANn4AADZ+gAA2fwAANn/AADaAAAA2gEAANoCAADaAwAA2gUAANoHAADaCAAA2gkAANoLAADaDAAA2ksAANpNAADaTwAA2lEAANpUAADaVQAA2lYAANpXAADaWAAA2loAANpcAADaXQAA2l4AANpgAADaYQAA2qAAANqiAADapAAA2qYAANqpAADaqgAA2qsAANqsAADarQAA2q8AANqxAADasgAA2rMAANq1AADatgAA2vUAANr3AADa+QAA2vsAANr+AADa/wAA2wAAANsBAADbAgAA2wQAANsGAADbBwAA2wgAANsKAADbCwAA20oAANtMAADbTgAA21AAANtTAADbVAAA21UAANtWAADbVwAA21kAANtbAADbXAAA210AANtfAADbYAAA258AANuhAADbowAA26UAANuoAADbqQAA26oAANurAADbrAAA264AANuwAADbsQAA27IAANu0AADbtQAA2/QAANv2AADb+AAA2/oAANv9AADb/gAA2/8AANwAAADcAQAA3AMAANwFAADcBgAA3AcAANwJAADcCgAA3FUAANx4AADcmAAA3LgAANy6AADcvAAA3L4AANzAAADcwwAA3MQAANzFAADcyAAA3MkAANzLAADczAAA3M4AANzRAADc0gAA3NMAANzWAADc1wAA3NwAANzpAADc7gAA3PAAANzyAADc9wAA3PoAANz9AADc/wAA3SQAAN1IAADdbwAA3ZMAAN2WAADdmAAA3ZoAAN2cAADdngAA3aAAAN2hAADdpAAA3bEAAN3CAADdxAAA3cYAAN3IAADdygAA3cwAAN3OAADd0AAA3dIAAN3jAADd5gAA3ekAAN3sAADd7wAA3fIAAN31AADd+AAA3fsAAN39AADePAAA3j4AAN5AAADeQgAA3kUAAN5GAADeRwAA3kgAAN5JAADeSwAA3k0AAN5OAADeTwAA3lEAAN5SAADekQAA3pMAAN6VAADelwAA3poAAN6bAADenAAA3p0AAN6eAADeoAAA3qIAAN6jAADepAAA3qYAAN6nAADe5gAA3ugAAN7rAADe7QAA3vAAAN7xAADe8gAA3vMAAN70AADe9gAA3vgAAN75AADe+gAA3vwAAN79AADfCgAA3wsAAN8MAADfDgAA300AAN9PAADfUQAA31MAAN9WAADfVwAA31gAAN9ZAADfWgAA31wAAN9eAADfXwAA32AAAN9iAADfYwAA36IAAN+kAADfpgAA36gAAN+rAADfrAAA360AAN+uAADfrwAA37EAAN+zAADftAAA37UAAN+3AADfuAAA3/cAAN/5AADf+wAA3/0AAOAAAADgAQAA4AIAAOADAADgBAAA4AYAAOAIAADgCQAA4AoAAOAMAADgDQAA4EwAAOBOAADgUAAA4FIAAOBVAADgVgAA4FcAAOBYAADgWQAA4FsAAOBdAADgXgAA4F8AAOBhAADgYgAA4KEAAOCjAADgpQAA4KcAAOCqAADgqwAA4KwAAOCtAADgrgAA4LAAAOCyAADgswAA4LQAAOC2AADgtwAA4NwAAOEAAADhJwAA4UsAAOFOAADhUAAA4VIAAOFUAADhVgAA4VgAAOFZAADhXAAA4WkAAOF4AADhegAA4XwAAOF+AADhgAAA4YIAAOGEAADhhgAA4ZUAAOGYAADhmwAA4Z4AAOGhAADhpAAA4acAAOGqAADhrAAA4esAAOHtAADh7wAA4fEAAOH0AADh9QAA4fYAAOH3AADh+AAA4foAAOH8AADh/QAA4f4AAOIAAADiAQAA4kAAAOJCAADiRAAA4kYAAOJJAADiSgAA4ksAAOJMAADiTQAA4k8AAOJRAADiUgAA4lMAAOJVAADiVgAA4pUAAOKXAADimQAA4psAAOKeAADinwAA4qAAAOKhAADiogAA4qQAAOKmAADipwAA4qgAAOKqAADiqwAA4uoAAOLsAADi7gAA4vAAAOLzAADi9AAA4vUAAOL2AADi9wAA4vkAAOL7AADi/AAA4v0AAOL/AADjAAAA4z8AAONBAADjQwAA40UAAONIAADjSQAA40oAAONLAADjTAAA404AAONQAADjUQAA41IAAONUAADjVQAA45QAAOOWAADjmAAA45oAAOOdAADjngAA458AAOOgAADjoQAA46MAAOOlAADjpgAA46cAAOOpAADjqgAA4+kAAOPrAADj7QAA4+8AAOPyAADj8wAA4/QAAOP1AADj9gAA4/gAAOP6AADj+wAA4/wAAOP+AADj/wAA5EoAAORtAADkjQAA5K0AAOSvAADksQAA5LMAAOS1AADkuAAA5LkAAOS6AADkvQAA5L4AAOTAAADkwQAA5MMAAOTGAADkxwAA5MgAAOTLAADkzAAA5NEAAOTeAADk4wAA5OUAAOTnAADk7AAA5O8AAOTyAADk9AAA5RkAAOU9AADlZAAA5YgAAOWLAADljQAA5Y8AAOWRAADlkwAA5ZUAAOWWAADlmQAA5aYAAOW3AADluQAA5bsAAOW9AADlvwAA5cEAAOXDAADlxQAA5ccAAOXYAADl2wAA5d4AAOXhAADl5AAA5ecAAOXqAADl7QAA5fAAAOXyAADmMQAA5jMAAOY1AADmNwAA5joAAOY7AADmPAAA5j0AAOY+AADmQAAA5kIAAOZDAADmRAAA5kYAAOZHAADmhgAA5ogAAOaKAADmjAAA5o8AAOaQAADmkQAA5pIAAOaTAADmlQAA5pcAAOaYAADmmQAA5psAAOacAADm2wAA5t0AAObgAADm4gAA5uUAAObmAADm5wAA5ugAAObpAADm6wAA5u0AAObuAADm7wAA5vEAAObyAADm/wAA5wAAAOcBAADnAwAA50IAAOdEAADnRgAA50gAAOdLAADnTAAA500AAOdOAADnTwAA51EAAOdTAADnVAAA51UAAOdXAADnWAAA55cAAOeZAADnmwAA550AAOegAADnoQAA56IAAOejAADnpAAA56YAAOeoAADnqQAA56oAAOesAADnrQAA5+wAAOfuAADn8AAA5/IAAOf1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AAEPQQABD0IAAQ9DAAEPRAABD0UAAQ9HAAEPSQABD0oAAQ9LAAEPTQABD04AAQ+NAAEPjwABD5EAAQ+TAAEPlgABD5cAAQ+YAAEPmQABD5oAAQ+cAAEPngABD58AAQ+gAAEPogABD6MAAQ/iAAEP5AABD+YAAQ/oAAEP6wABD+wAAQ/tAAEP7gABD+8AAQ/xAAEP8wABD/QAAQ/1AAEP9wABD/gAARA3AAEQOQABEDsAARA9AAEQQAABEEEAARBCAAEQQwABEEQAARBGAAEQSAABEEkAARBKAAEQTAABEE0AARCMAAEQjgABEJAAARCSAAEQlQABEJYAARCXAAEQmAABEJkAARCbAAEQnQABEJ4AARCfAAEQoQABEKIAARDHAAEQ6wABERIAARE2AAEROQABETsAARE9AAERPwABEUEAARFDAAERRAABEUcAARFUAAERYwABEWUAARFnAAERaQABEWsAARFtAAERbwABEXEAARGAAAERgwABEYYAARGJAAERjAABEY8AARGSAAERlQABEZcAARHWAAER2AABEdoAARHcAAER3wABEeAAARHhAAER4gABEeMAARHlAAER5wABEegAARHpAAER6wABEewAARIrAAESLQABEi8AARIxAAESNAABEjUAARI2AAESNwABEjgAARI6AAESPAABEj0AARI+AAESQAABEkEAARKAAAESggABEoQAARKGAAESiQABEooAARKLAAESjAABEo0AARKPAAESkQABEpIAARKTAAESlQABEpYAARLVAAES1wABEtkAARLbAAES3gABEt8AARLgAAES4QABEuIAARLkAAES5gABEucAARLoAAES6gABEusAARMqAAETLAABEy4AARMwAAETMwABEzQAARM1AAETNgABEzcAARM5AAETOwABEzwAARM9AAETPwABE0AAARN/AAETgQABE4MAAROFAAETiAABE4kAAROKAAETiwABE4wAAROOAAETkAABE5EAAROSAAETlAABE5UAARPUAAET1gABE9gAARPaAAET3QABE94AARPfAAET4AABE+EAARPjAAET5QABE+YAARPnAAET6QABE+oAARQ1AAEUWAABFHgAARSYAAEUmgABFJwAARSeAAEUoAABFKMAARSkAAEUpQABFKgAARSpAAEUqwABFKwAARSuAAEUsQABFLIAARSzAAEUtgABFLcAARS8AAEUyQABFM4AARTQAAEU0gABFNcAARTaAAEU3QABFN8AARUEAAEVKAABFU8AARVzAAEVdgABFXgAARV6AAEVfAABFX4AARWAAAEVgQABFYQAARWRAAEVogABFaQAARWmAAEVqAABFaoAARWsAAEVrgABFbAAARWyAAEVwwABFcYAARXJAAEVzAABFc8AARXSAAEV1QABFdgAARXbAAEV3QABFhwAARYeAAEWIAABFiIAARYlAAEWJgABFicAARYoAAEWKQABFisAARYtAAEWLgABFi8AARYxAAEWMgABFnEAARZzAAEWdQABFncAARZ6AAEWewABFnwAARZ9AAEWfgABFoAAARaCAAEWgwABFoQAARaGAAEWhwABFsYAARbIAAEWywABFs0AARbQAAEW0QABFtIAARbTAAEW1AABFtYAARbYAAEW2QABFtoAARbcAAEW3QABFuoAARbrAAEW7AABFu4AARctAAEXLwABFzEAARczAAEXNgABFzcAARc4AAEXOQABFzoAARc8AAEXPgABFz8AARdAAAEXQgABF0MAAReCAAEXhAABF4YAAReIAAEXiwABF4wAAReNAAEXjgABF48AAReRAAEXkwABF5QAAReVAAEXlwABF5gAARfXAAEX2QABF9sAARfdAAEX4AABF+EAARfiAAEX4wABF+QAARfmAAEX6AABF+kAARfqAAEX7AABF+0AARgsAAEYLgABGDAAARgyAAEYNQABGDYAARg3AAEYOAABGDkAARg7AAEYPQABGD4AARg/AAEYQQABGEIAARiBAAEYgwABGIUAARiHAAEYigABGIsAARiMAAEYjQABGI4AARiQAAEYkgABGJMAARiUAAEYlgABGJcAARi8AAEY4AABGQcAARkrAAEZLgABGTAAARkyAAEZNAABGTYAARk4AAEZOQABGTwAARlJAAEZWAABGVoAARlcAAEZXgABGWAAARliAAEZZAABGWYAARl1AAEZeAABGXsAARl+AAEZgQABGYQAARmHAAEZigABGYwAARnLAAEZzQABGc8AARnRAAEZ1AABGdUAARnWAAEZ1wABGdgAARnaAAEZ3AABGd0AARneAAEZ4AABGeEAARogAAEaIgABGiQAARomAAEaKQABGioAARorAAEaLAABGi0AARovAAEaMQABGjIAARozAAEaNQABGjYAARp1AAEadwABGnkAARp7AAEafgABGn8AARqAAAEagQABGoIAARqEAAEahgABGocAARqIAAEaigABGosAARrKAAEazAABGs4AARrQAAEa0wABGtQAARrVAAEa1gABGtcAARrZAAEa2wABGtwAARrdAAEa3wABGuAAARsfAAEbIQABGyMAARslAAEbKAABGykAARsqAAEbKwABGywAARsuAAEbMAABGzEAARsyAAEbNAABGzUAARt0AAEbdgABG3gAARt6AAEbfQABG34AARt/AAEbgAABG4EAARuDAAEbhQABG4YAARuHAAEbiQABG4oAARvJAAEbywABG80AARvPAAEb0gABG9MAARvUAAEb1QABG9YAARvYAAEb2gABG9sAARvcAAEb3gABG98AARvqAAEb8wABG/QAARv2AAEb/wABHAoAARwZAAEcJAABHDIAARxHAAEcWwABHHIAARyEAAEcwwABHMUAARzHAAEcyQABHMwAARzNAAEczgABHM8AARzQAAEc0gABHNQAARzVAAEc1gABHNgAARzZAAEdGAABHRoAAR0cAAEdHgABHSEAAR0iAAEdIwABHSQAAR0lAAEdJwABHSkAAR0qAAEdKwABHS0AAR0uAAEdbQABHW8AAR1xAAEdcwABHXYAAR13AAEdeAABHXkAAR16AAEdfAABHX4AAR1/AAEdgAABHYIAAR2DAAEdwgABHcQAAR3GAAEdyAABHcsAAR3MAAEdzQABHc4AAR3PAAEd0QABHdMAAR3UAAEd1QABHdcAAR3YAAEeFwABHhkAAR4bAAEeHQABHiAAAR4hAAEeIgABHiMAAR4kAAEeJgABHigAAR4pAAEeKgABHiwAAR4tAAEeeAABHpsAAR67AAEe2wABHt0AAR7fAAEe4QABHuMAAR7lAAEe5gABHucAAR7qAAEe6wABHu0AAR7uAAEe8AABHvIAAR7zAAEe9AABHvcAAR74AAEe/QABHwoAAR8PAAEfEQABHxMAAR8YAAEfGwABHx4AAR8gAAEfRQABH2kAAR+QAAEftAABH7cAAR+5AAEfuwABH70AAR+/AAEfwQABH8IAAR/FAAEf0gABH+MAAR/lAAEf5wABH+kAAR/rAAEf7QABH+8AAR/xAAEf8wABIAQAASAHAAEgCgABIA0AASAQAAEgEwABIBYAASAZAAEgHAABIB4AASBdAAEgXwABIGEAASBjAAEgZgABIGcAASBoAAEgaQABIGoAASBsAAEgbgABIG8AASBwAAEgcgABIHMAASCyAAEgtAABILYAASC4AAEguwABILwAASC9AAEgvgABIL8AASDBAAEgwwABIMQAASDFAAEgxwABIMgAASEHAAEhCQABIQwAASEOAAEhEQABIRIAASETAAEhFAABIRUAASEXAAEhGQABIRoAASEbAAEhHQABIR4AASErAAEhLAABIS0AASEvAAEhbgABIXAAASFyAAEhdAABIXcAASF4AAEheQABIXoAASF7AAEhfQABIX8AASGAAAEhgQABIYMAASGEAAEhwwABIcUAASHHAAEhyQABIcwAASHNAAEhzgABIc8AASHQAAEh0gABIdQAASHVAAEh1gABIdgAASHZAAEiGAABIhoAASIcAAEiHgABIiEAASIiAAEiIwABIiQAASIlAAEiJwABIikAASIqAAEiKwABIi0AASIuAAEibQABIm8AASJxAAEicwABInYAASJ3AAEieAABInkAASJ6AAEifAABIn4AASJ/AAEigAABIoIAASKDAAEiwgABIsQAASLGAAEiyAABIssAASLMAAEizQABIs4AASLPAAEi0QABItMAASLUAAEi1QABItcAASLYAAEi/QABIyEAASNIAAEjbAABI28AASNxAAEjcwABI3UAASN3AAEjeQABI3oAASN9AAEjigABI5kAASObAAEjnQABI58AASOhAAEjowABI6UAASOnAAEjtgABI7kAASO8AAEjvwABI8IAASPFAAEjyAABI8sAASPNAAEkDAABJA4AASQQAAEkEgABJBUAASQWAAEkFwABJBgAASQZAAEkGwABJB0AASQeAAEkHwABJCEAASQiAAEkYQABJGMAASRlAAEkZwABJGoAASRrAAEkbAABJG0AASRuAAEkcAABJHIAASRzAAEkdAABJHYAASR3AAEktgABJLgAASS6AAEkvAABJL8AASTAAAEkwQABJMIAASTDAAEkxQABJMcAASTIAAEkyQABJMsAASTMAAElCwABJQ0AASUPAAElEQABJRQAASUVAAElFgABJRcAASUYAAElGgABJRwAASUdAAElHgABJSAAASUhAAElYAABJWIAASVkAAElZgABJWkAASVqAAElawABJWwAASVtAAElbwABJXEAASVyAAElcwABJXUAASV2AAEltQABJbcAASW5AAEluwABJb4AASW/AAElwAABJcEAASXCAAElxAABJcYAASXHAAElyAABJcoAASXLAAEmCgABJgwAASYOAAEmEAABJhMAASYUAAEmFQABJhYAASYXAAEmGQABJhsAASYcAAEmHQABJh8AASYgAAEmawABJo4AASauAAEmzgABJtAAASbSAAEm1AABJtYAASbYAAEm2QABJtoAASbdAAEm3gABJuAAASbhAAEm4wABJuUAASbmAAEm5wABJuoAASbrAAEm9AABJwEAAScGAAEnCAABJwoAAScPAAEnEgABJxUAAScXAAEnPAABJ2AAASeHAAEnqwABJ64AASewAAEnsgABJ7QAASe2AAEnuAABJ7kAASe8AAEnyQABJ9oAASfcAAEn3gABJ+AAASfiAAEn5AABJ+YAASfoAAEn6gABJ/sAASf+AAEoAQABKAQAASgHAAEoCgABKA0AASgQAAEoEwABKBUAAShUAAEoVgABKFgAAShaAAEoXQABKF4AAShfAAEoYAABKGEAAShjAAEoZQABKGYAAShnAAEoaQABKGoAASipAAEoqwABKK0AASivAAEosgABKLMAASi0AAEotQABKLYAASi4AAEougABKLsAASi8AAEovgABKL8AASj+AAEpAAABKQMAASkFAAEpCAABKQkAASkKAAEpCwABKQwAASkOAAEpEAABKREAASkSAAEpFAABKRUAASkiAAEpIwABKSQAASkmAAEpZQABKWcAASlpAAEpawABKW4AASlvAAEpcAABKXEAASlyAAEpdAABKXYAASl3AAEpeAABKXoAASl7AAEpugABKbwAASm+AAEpwAABKcMAASnEAAEpxQABKcYAASnHAAEpyQABKcsAASnMAAEpzQABKc8AASnQAAEqDwABKhEAASoTAAEqFQABKhgAASoZAAEqGgABKhsAASocAAEqHgABKiAAASohAAEqIgABKiQAASolAAEqZAABKmYAASpoAAEqagABKm0AASpuAAEqbwABKnAAASpxAAEqcwABKnUAASp2AAEqdwABKnkAASp6AAEquQABKrsAASq9AAEqvwABKsIAASrDAAEqxAABKsUAASrGAAEqyAABKsoAASrLAAEqzAABKs4AASrPAAEq9AABKxgAASs/AAErYwABK2YAAStoAAEragABK2wAAStuAAErcAABK3EAASt0AAErgQABK5AAASuSAAErlAABK5YAASuYAAErmgABK5wAASueAAErrQABK7AAASuzAAErtgABK7kAASu8AAErvwABK8IAASvEAAEsAwABLAUAASwHAAEsCQABLAwAASwNAAEsDgABLA8AASwQAAEsEgABLBQAASwVAAEsFgABLBgAASwZAAEsWAABLFoAASxcAAEsXgABLGEAASxiAAEsYwABLGQAASxlAAEsZwABLGkAASxqAAEsawABLG0AASxuAAEsrQABLK8AASyxAAEsswABLLYAASy3AAEsuAABLLkAASy6AAEsvAABLL4AASy/AAEswAABLMIAASzDAAEtAgABLQQAAS0HAAEtCQABLQwAAS0NAAEtDgABLQ8AAS0QAAEtEgABLRQAAS0VAAEtFgABLRgAAS0ZAAEtWAABLVoAAS1cAAEtXgABLWEAAS1iAAEtYwABLWQAAS1lAAEtZwABLWkAAS1qAAEtawABLW0AAS1uAAEtrQABLa8AAS2xAAEtswABLbYAAS23AAEtuAABLbkAAS26AAEtvAABLb4AAS2/AAEtwAABLcIAAS3DAAEuAgABLgQAAS4GAAEuCAABLgsAAS4MAAEuDQABLg4AAS4PAAEuEQABLhMAAS4UAAEuFQABLhcAAS4YAAEuYwABLoYAAS6mAAEuxgABLsgAAS7KAAEuzAABLs4AAS7QAAEu0QABLtIAAS7VAAEu1gABLtgAAS7ZAAEu2wABLt0AAS7eAAEu3wABLuIAAS7jAAEu6AABLvUAAS76AAEu/AABLv4AAS8DAAEvBgABLwkAAS8LAAEvMAABL1QAAS97AAEvnwABL6IAAS+kAAEvpgABL6gAAS+qAAEvrAABL60AAS+wAAEvvQABL84AAS/QAAEv0gABL9QAAS/WAAEv2AABL9oAAS/cAAEv3gABL+8AAS/yAAEv9QABL/gAAS/7AAEv/gABMAEAATAEAAEwBwABMAkAATBIAAEwSgABMEwAATBOAAEwUQABMFIAATBTAAEwVAABMFUAATBXAAEwWQABMFoAATBbAAEwXQABMF4AATCdAAEwnwABMKEAATCjAAEwpgABMKcAATCoAAEwqQABMKoAATCsAAEwrgABMK8AATCwAAEwsgABMLMAATDyAAEw9AABMPcAATD5AAEw/AABMP0AATD+AAEw/wABMQAAATECAAExBAABMQUAATEGAAExCAABMQkAATEWAAExFwABMRgAATEaAAExWQABMVsAATFdAAExXwABMWIAATFjAAExZAABMWUAATFmAAExaAABMWoAATFrAAExbAABMW4AATFvAAExrgABMbAAATGyAAExtAABMbcAATG4AAExuQABMboAATG7AAExvQABMb8AATHAAAExwQABMcMAATHEAAEyAwABMgUAATIHAAEyCQABMgwAATINAAEyDgABMg8AATIQAAEyEgABMhQAATIVAAEyFgABMhgAATIZAAEyWAABMloAATJcAAEyXgABMmEAATJiAAEyYwABMmQAATJlAAEyZwABMmkAATJqAAEyawABMm0AATJuAAEyrQABMq8AATKxAAEyswABMrYAATK3AAEyuAABMrkAATK6AAEyvAABMr4AATK/AAEywAABMsIAATLDAAEy6AABMwwAATMzAAEzVwABM1oAATNcAAEzXgABM2AAATNiAAEzZAABM2UAATNoAAEzdQABM4QAATOGAAEziAABM4oAATOMAAEzjgABM5AAATOSAAEzoQABM6QAATOnAAEzqgABM60AATOwAAEzswABM7YAATO4AAEz9wABM/kAATP8AAEz/gABNAEAATQCAAE0AwABNAQAATQFAAE0BwABNAkAATQKAAE0CwABNA0AATQOAAE0TQABNE8AATRRAAE0UwABNFYAATRXAAE0WAABNFkAATRaAAE0XAABNF4AATRfAAE0YAABNGIAATRjAAE0ogABNKQAATSmAAE0qAABNKsAATSsAAE0rQABNK4AATSvAAE0sQABNLMAATS0AAE0tQABNLcAATS4AAE09wABNPkAATT8AAE0/gABNQEAATUCAAE1AwABNQQAATUFAAE1BwABNQkAATUKAAE1CwABNQ0AATUOAAE1TQABNU8AATVRAAE1UwABNVYAATVXAAE1WAABNVkAATVaAAE1XAABNV4AATVfAAE1YAABNWIAATVjAAE1ogABNaQAATWmAAE1qAABNasAATWsAAE1rQABNa4AATWvAAE1sQABNbMAATW0AAE1tQABNbcAATW4AAE19wABNfkAATX7AAE1/QABNgAAATYBAAE2AgABNgMAATYEAAE2BgABNggAATYJAAE2CgABNgwAATYNAAE2WAABNnsAATabAAE2uwABNr0AATa/AAE2wQABNsMAATbFAAE2xgABNscAATbKAAE2ywABNs0AATbOAAE20AABNtIAATbTAAE21AABNtcAATbYAAE23QABNuoAATbvAAE28QABNvMAATb4AAE2+wABNv4AATcAAAE3JQABN0kAATdwAAE3lAABN5cAATeZAAE3mwABN50AATefAAE3oQABN6IAATelAAE3sgABN8MAATfFAAE3xwABN8kAATfLAAE3zQABN88AATfRAAE30wABN+QAATfnAAE36gABN+0AATfwAAE38wABN/YAATf5AAE3/AABN/4AATg9AAE4PwABOEEAAThDAAE4RgABOEcAAThIAAE4SQABOEoAAThMAAE4TgABOE8AAThQAAE4UgABOFMAATiSAAE4lAABOJYAATiYAAE4mwABOJwAATidAAE4ngABOJ8AATihAAE4owABOKQAATilAAE4pwABOKgAATjnAAE46QABOOwAATjuAAE48QABOPIAATjzAAE49AABOPUAATj3AAE4+QABOPoAATj7AAE4/QABOP4AATkLAAE5DAABOQ0AATkPAAE5TgABOVAAATlSAAE5VAABOVcAATlYAAE5WQABOVoAATlbAAE5XQABOV8AATlgAAE5YQABOWMAATlkAAE5owABOaUAATmnAAE5qQABOawAATmtAAE5rgABOa8AATmwAAE5sgABObQAATm1AAE5tgABObgAATm5AAE5+AABOfoAATn8AAE5/gABOgEAAToCAAE6AwABOgQAAToFAAE6BwABOgkAAToKAAE6CwABOg0AAToOAAE6TQABOk8AATpRAAE6UwABOlYAATpXAAE6WAABOlkAATpaAAE6XAABOl4AATpfAAE6YAABOmIAATpjAAE6ogABOqQAATqmAAE6qAABOqsAATqsAAE6rQABOq4AATqvAAE6sQABOrMAATq0AAE6tQABOrcAATq4AAE63QABOwEAATsoAAE7TAABO08AATtRAAE7UwABO1UAATtXAAE7WQABO1oAATtdAAE7agABO3kAATt7AAE7fQABO38AATuBAAE7gwABO4UAATuHAAE7lgABO5kAATucAAE7nwABO6IAATulAAE7qAABO6sAATutAAE77AABO+4AATvwAAE78gABO/UAATv2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AAFpaAABaWkAAWlrAAFpbQABaW4AAWlvAAFpcQABaXIAAWmxAAFpswABabUAAWm3AAFpugABabsAAWm8AAFpvQABab4AAWnAAAFpwgABacMAAWnEAAFpxgABaccAAWoGAAFqCAABagoAAWoMAAFqDwABahAAAWoRAAFqEgABahMAAWoVAAFqFwABahgAAWoZAAFqGwABahwAAWpbAAFqXQABal8AAWphAAFqZAABamUAAWpmAAFqZwABamgAAWpqAAFqbAABam0AAWpuAAFqcAABanEAAWqwAAFqsgABarQAAWq2AAFquQABaroAAWq7AAFqvAABar0AAWq/AAFqwQABasIAAWrDAAFqxQABasYAAWsFAAFrBwABawkAAWsLAAFrDgABaw8AAWsQAAFrEQABaxIAAWsUAAFrFgABaxcAAWsYAAFrGgABaxsAAWtaAAFrXAABa14AAWtgAAFrYwABa2QAAWtlAAFrZgABa2cAAWtpAAFrawABa2wAAWttAAFrbwABa3AAAWu7AAFr3gABa/4AAWweAAFsIAABbCIAAWwkAAFsJgABbCkAAWwqAAFsKwABbC4AAWwvAAFsMQABbDIAAWw0AAFsNwABbDgAAWw5AAFsPAABbD0AAWxCAAFsTwABbFQAAWxWAAFsWAABbF0AAWxgAAFsYwABbGUAAWyKAAFsrgABbNUAAWz5AAFs/AABbP4AAW0AAAFtAgABbQQAAW0GAAFtBwABbQoAAW0XAAFtKAABbSoAAW0sAAFtLgABbTAAAW0yAAFtNAABbTYAAW04AAFtSQABbUwAAW1PAAFtUgABbVUAAW1YAAFtWwABbV4AAW1hAAFtYwABbaIAAW2kAAFtpgABbagAAW2rAAFtrAABba0AAW2uAAFtrwABbbEAAW2zAAFttAABbbUAAW23AAFtuAABbfcAAW35AAFt+wABbf0AAW4AAAFuAQABbgIAAW4DAAFuBAABbgYAAW4IAAFuCQABbgoAAW4MAAFuDQABbkwAAW5OAAFuUQABblMAAW5WAAFuVwABblgAAW5ZAAFuWgABblwAAW5eAAFuXwABbmAAAW5iAAFuYwABbnAAAW5xAAFucgABbnQAAW6zAAFutQABbrcAAW65AAFuvAABbr0AAW6+AAFuvwABbsAAAW7CAAFuxAABbsUAAW7GAAFuyAABbskAAW8I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AAF5+gABef0AAXoAAAF6AwABegYAAXoIAAF6RwABekkAAXpMAAF6TgABelEAAXpSAAF6UwABelQAAXpVAAF6VwABelkAAXpaAAF6WwABel0AAXpeAAF6nQABep8AAXqhAAF6owABeqYAAXqnAAF6qAABeqkAAXqqAAF6rAABeq4AAXqvAAF6sAABerIAAXqzAAF68gABevQAAXr2AAF6+AABevsAAXr8AAF6/QABev4AAXr/AAF7AQABewMAAXsEAAF7BQABewcAAXsIAAF7RwABe0kAAXtLAAF7TQABe1AAAXtRAAF7UgABe1MAAXtUAAF7VgABe1gAAXtZAAF7WgABe1wAAXtdAAF7nAABe54AAXugAAF7ogABe6UAAXumAAF7pwABe6gAAXupAAF7qwABe60AAXuuAAF7rwABe7EAAXuyAAF78QABe/MAAXv1AAF79wABe/oAAXv7AAF7/AABe/0AAXv+AAF8AAABfAIAAXwDAAF8BAABfAYAAXwHAAF8UgABfHUAAXyVAAF8tQABfLcAAXy5AAF8uwABfL0AAXy/AAF8wAABfMEAAXzEAAF8xQABfMcAAXzIAAF8ygABfMwAAXzNAAF8zgABfNEAAXzSAAF82wABfOgAAXztAAF87wABfPEAAXz2AAF8+QABfPwAAXz+AAF9IwABfUcAAX1uAAF9kgABfZUAAX2XAAF9mQABfZsAAX2dAAF9nwABfaAAAX2jAAF9sAABfcEAAX3DAAF9xQABfccAAX3JAAF9ywABfc0AAX3PAAF90QABfeIAAX3lAAF96AABfesAAX3uAAF98QABffQAAX33AAF9+gABffwAAX47AAF+PQABfj8AAX5BAAF+RAABfkUAAX5GAAF+RwABfkgAAX5KAAF+TAABfk0AAX5OAAF+UAABflEAAX6QAAF+kgABfpQAAX6WAAF+mQABfpoAAX6bAAF+nAABfp0AAX6fAAF+oQABfqIAAX6jAAF+pQABfqYAAX7lAAF+5wABfuoAAX7sAAF+7wABfvAAAX7xAAF+8gABfvMAAX71AAF+9wABfvgAAX75AAF++wABfvwAAX8JAAF/CgABfwsAAX8NAAF/TAABf04AAX9QAAF/UgABf1UAAX9WAAF/VwABf1gAAX9ZAAF/WwABf10AAX9eAAF/XwABf2EAAX9iAAF/oQABf6MAAX+l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AAGhKgABoSsAAaEuAAGhOwABoUoAAaFMAAGhTgABoVAAAaFSAAGhVAABoVYAAaFYAAGhZwABoWoAAaFtAAGhcAABoXMAAaF2AAGheQABoXwAAaF+AAGhvQABob8AAaHBAAGhwwABocYAAaHHAAGhyAABockAAaHKAAGhzAABoc4AAaHPAAGh0AABodIAAaHTAAGiEgABohQAAaIWAAGiGAABohsAAaIcAAGiHQABoh4AAaIfAAGiIQABoiMAAaIkAAGiJQABoicAAaIoAAGiZwABomkAAaJrAAGibQABonAAAaJxAAGicgABonMAAaJ0AAGidgABongAAaJ5AAGiegABonwAAaJ9AAGivAABor4AAaLAAAGiwgABosUAAaLGAAGixwABosgAAaLJAAGiywABos0AAaLOAAGizwABotEAAaLSAAGjEQABoxMAAaMVAAGjFwABoxoAAaMbAAGjHAABox0AAaMeAAGjIAABoyIAAaMjAAGjJAABoyYAAaMnAAGjZgABo2gAAaNqAAGjbAABo28AAaNwAAGjcQABo3IAAaNzAAGjdQABo3cAAaN4AAGjeQABo3sAAaN8AAGjuwABo70AAaO/AAGjwQABo8QAAaPFAAGjxgABo8cAAaPIAAGjygABo8wAAaPNAAGjzgABo9AAAaPRAAGkHAABpD8AAaRfAAGkfwABpIEAAaSDAAGkhQABpIcAAaSJAAGkigABpIsAAaSOAAGkjwABpJEAAaSSAAGklAABpJYAAaSXAAGkmAABpJsAAaScAAGkoQABpK4AAaSzAAGktQABpLcAAaS8AAGkvwABpMIAAaTEAAGk6QABpQ0AAaU0AAGlWAABpVsAAaVdAAGlXwABpWEAAaVjAAGlZQABpWYAAaVpAAGldgABpYcAAaWJAAGliwABpY0AAaWPAAGlkQABpZMAAaWVAAGllwABpagAAaWrAAGlrgABpbEAAaW0AAGltwABpboAAaW9AAGlwAABpcIAAaYBAAGmAwABpgUAAaYHAAGmCgABpgsAAaYMAAGmDQABpg4AAaYQAAGmEgABphMAAaYUAAGmFgABphcAAaZWAAGmWAABploAAaZcAAGmXwABpmAAAaZhAAGmYgABpmMAAaZlAAGmZwABpmgAAaZpAAGmawABpmwAAaarAAGmrQABprAAAaayAAGmtQABprYAAaa3AAGmuAABprkAAaa7AAGmvQABpr4AAaa/AAGmwQABpsIAAabPAAGm0AABptEAAabTAAGnEgABpxQAAacWAAGnGAABpxsAAaccAAGnHQABpx4AAacfAAGnIQABpyMAAackAAGnJQABpycAAacoAAGnZwABp2kAAadrAAGnbQABp3AAAadxAAGncgABp3MAAad0AAGndgABp3gAAad5AAGnegABp3wAAad9AAGnvAABp74AAafAAAGnwgABp8UAAafGAAGnxwABp8gAAafJAAGnywABp80AAafOAAGnzwABp9EAAafSAAGoEQABqBMAAagVAAGoFwABqBoAAagbAAGoHAABqB0AAageAAGoIAABqCIAAagjAAGoJAABqCYAAagnAAGoZgABqGgAAahqAAGobAABqG8AAahwAAGocQABqHIAAahzAAGodQABqHcAAah4AAGoeQABqHsAAah8AAGooQABqMUAAajsAAGpEAABqRMAAakVAAGpFwABqRkAAakbAAGpHQABqR4AAakhAAGpLgABqT0AAak/AAGpQQABqUMAAalFAAGpRwABqUkAAalLAAGpWgABqV0AAalgAAGpYwABqWYAAalpAAGpbAABqW8AAalxAAGpsAABqbIAAam0AAGptgABqbkAAam6AAGpuwABqbwAAam9AAGpvwABqcEAAanCAAGpwwABqcUAAanGAAGqBQABqgcAAaoJAAGqCwABqg4AAaoPAAGqEAABqhEAAaoSAAGqFAABqhYAAaoXAAGqGAABqhoAAaobAAGqWgABqlwAAapeAAGqYAABqmMAAapkAAGqZQABqmYAAapnAAGqaQABqmsAAapsAAGqbQABqm8AAapwAAGqrwABqrEAAaq0AAGqtgABqrkAAaq6AAGquwABqrwAAaq9AAGqvwABqsEAAarCAAGqwwABqsUAAarGAAGrCQABqy0AAatRAAGrdAABq5sAAau7AAGr4gABrAkAAawpAAGsTQABrHEAAaxzAAGsdgABrHgAAax6AAGsfAABrH8AAayCAAGshAABrIYAAayJAAGsiwABrI0AAayQAAGskwABrJQAAayZAAGspgABrKkAAayrAAGsrgABrLEAAayzAAGs2AABrPwAAa0jAAGtRwABrUoAAa1MAAGtTgABrVAAAa1SAAGtVAABrVUAAa1YAAGtZQABrXgAAa16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AAG4WwABuFwAAbhdAAG4XwABuGEAAbhiAAG4YwABuGUAAbhmAAG4pQABuKcAAbipAAG4qwABuK4AAbivAAG4sAABuLEAAbiyAAG4tAABuLYAAbi3AAG4uAABuLoAAbi7AAG4+gABuPwAAbj+AAG5AAABuQMAAbkEAAG5BQABuQYAAbkHAAG5CQABuQsAAbkMAAG5DQABuQ8AAbkQAAG5TwABuVEAAblUAAG5VgABuVkAAblaAAG5WwABuVwAAbldAAG5XwABuWEAAbliAAG5YwABuWUAAblmAAG5sQABudQAAbn0AAG6FAABuhYAAboYAAG6GgABuhwAAbofAAG6IAABuiEAAbokAAG6JQABuicAAbooAAG6KgABui0AAbouAAG6LwABujIAAbozAAG6OAABukUAAbpKAAG6TAABuk4AAbpTAAG6VgABulkAAbpbAAG6gAABuqQAAbrLAAG67wABuvIAAbr0AAG69gABuvgAAbr6AAG6/AABuv0AAbsAAAG7DQABux4AAbsgAAG7IgABuyQAAbsmAAG7KAABuyoAAbssAAG7LgABuz8AAbtCAAG7RQABu0gAAbtLAAG7TgABu1EAAbtUAAG7VwABu1kAAbuYAAG7mgABu5wAAbueAAG7oQABu6IAAbujAAG7pAABu6UAAbunAAG7qQABu6oAAburAAG7rQABu64AAbvtAAG77wABu/EAAbvzAAG79gABu/cAAbv4AAG7+QABu/oAAbv8AAG7/gABu/8AAbwAAAG8AgABvAMAAbxCAAG8RAABvEcAAbxJAAG8TAABvE0AAbxOAAG8TwABvFAAAbxSAAG8VAABvFUAAbxWAAG8WAABvFkAAbxmAAG8ZwABvGgAAbxqAAG8qQABvKsAAbytAAG8rwABvLIAAbyzAAG8tAABvLUAAby2AAG8uAABvLoAAby7AAG8vAABvL4AAby/AAG8/gABvQAAAb0CAAG9BAABvQcAAb0IAAG9CQABvQoAAb0LAAG9DQABvQ8AAb0QAAG9EQABvRMAAb0UAAG9UwABvVUAAb1XAAG9WQABvVwAAb1dAAG9XgABvV8AAb1gAAG9YgABvWQAAb1lAAG9ZgABvWgAAb1pAAG9qAABvaoAAb2sAAG9rgABvbEAAb2yAAG9swABvbQAAb21AAG9twABvbkAAb26AAG9uwABvb0AAb2+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AAHJGwAByR0AAckfAAHJIAABySEAAckjAAHJJAAByWMAAcllAAHJZwAByWkAAclsAAHJbQAByW4AAclvAAHJcAAByXIAAcl0AAHJdQAByXYAAcl4AAHJeQABycQAAcnnAAHKBwAByicAAcopAAHKKwAByi0AAcovAAHKMgAByjMAAco0AAHKNwAByjgAAco6AAHKOwAByj0AAcpAAAHKQQABykIAAcpFAAHKRgAByksAAcpYAAHKXQAByl8AAcphAAHKZgABymkAAcpsAAHKbgABypMAAcq3AAHK3gABywIAAcsFAAHLBwABywkAAcsLAAHLDQAByw8AAcsQAAHLEwAByyAAAcsxAAHLMwAByzUAAcs3AAHLOQAByzsAAcs9AAHLPwABy0EAActSAAHLVQABy1gAActbAAHLXgABy2EAActkAAHLZwABy2oAActsAAHLqwABy60AAcuvAAHLsQABy7QAAcu1AAHLtgABy7cAAcu4AAHLugABy7wAAcu9AAHLvgABy8AAAcvBAAHMAAABzAIAAcwEAAHMBgABzAkAAcwKAAHMCwABzAwAAcwNAAHMDwABzBEAAcwSAAHMEwABzBUAAcwWAAHMVQABzFcAAcxaAAHMXAABzF8AAcxgAAHMYQABzGIAAcxjAAHMZQABzGcAAcxoAAHMaQABzGsAAcxsAAHMeQABzHoAAcx7AAHMfQABzLwAAcy+AAHMwAABzMIAAczFAAHMxgABzMcAAczIAAHMyQABzMsAAczNAAHMzgABzM8AAczRAAHM0gABzREAAc0TAAHNFQABzRcAAc0aAAHNGwABzRwAAc0dAAHNHgABzSAAAc0iAAHNIwABzSQAAc0mAAHNJwABzWYAAc1oAAHNagABzWwAAc1vAAHNcAABzXEAAc1yAAHNcwABzXUAAc13AAHNeAABzXkAAc17AAHNfAABzbsAAc29AAHNvwABzcEAAc3EAAHNxQABzcYAAc3HAAHNyAABzcoAAc3MAAHNzQABzc4AAc3QAAHN0QABzhAAAc4SAAHOFAABzhYAAc4ZAAHOGgABzhsAAc4cAAHOHQABzh8AAc4hAAHOIgABziMAAc4lAAHOJgABzksAAc5vAAHOlgABzroAAc69AAHOvwABzsEAAc7DAAHOxQABzscAAc7IAAHOywABztgAAc7nAAHO6QABzusAAc7t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AAH2swAB9vIAAfb0AAH29wAB9vkAAfb8AAH2/QAB9v4AAfb/AAH3AAAB9wIAAfcEAAH3BQAB9wYAAfcIAAH3CQAB90gAAfdKAAH3TAAB904AAfdRAAH3UgAB91MAAfdUAAH3VQAB91cAAfdZAAH3WgAB91sAAfddAAH3XgAB950AAfefAAH3oQAB96MAAfemAAH3pwAB96gAAfepAAH3qgAB96wAAfeuAAH3rwAB97AAAfeyAAH3swAB9/IAAff0AAH39wAB9/kAAff8AAH3/QAB9/4AAff/AAH4AAAB+AIAAfgEAAH4BQAB+AYAAfgIAAH4CQAB+EgAAfhKAAH4TAAB+E4AAfhRAAH4UgAB+FMAAfhUAAH4VQAB+FcAAfhZAAH4WgAB+FsAAfhdAAH4XgAB+J0AAfifAAH4oQAB+KMAAfimAAH4pwAB+KgAAfipAAH4qgAB+KwAAfiuAAH4rwAB+LAAAfiyAAH4swAB+PIAAfj0AAH49gAB+PgAAfj7AAH4/AAB+P0AAfj+AAH4/wAB+QEAAfkDAAH5BAAB+QUAAfkHAAH5CAAB+VMAAfl2AAH5lgAB+bYAAfm4AAH5ugAB+bwAAfm+AAH5wAAB+cEAAfnCAAH5xQAB+cYAAfnIAAH5yQAB+csAAfnNAAH5zgAB+c8AAfnSAAH50wAB+dgAAfnlAAH56gAB+ewAAfnuAAH58wAB+fYAAfn5AAH5+wAB+iAAAfpEAAH6awAB+o8AAfqSAAH6lAAB+pYAAfqYAAH6mgAB+pwAAfqdAAH6oAAB+q0AAfq+AAH6wAAB+sIAAfrEAAH6xgAB+sgAAfrKAAH6zAAB+s4AAfrfAAH64gAB+uUAAfroAAH66wAB+u4AAfrxAAH69AAB+vcAAfr5AAH7OAAB+zoAAfs8AAH7PgAB+0EAAftCAAH7QwAB+0QAAftFAAH7RwAB+0kAAftKAAH7SwAB+00AAftOAAH7jQAB+48AAfuRAAH7kwAB+5YAAfuXAAH7mAAB+5kAAfuaAAH7nAAB+54AAfufAAH7oAAB+6IAAfujAAH74gAB++QAAfvnAAH76QAB++wAAfvtAAH77gAB++8AAfvwAAH78gAB+/QAAfv1AAH79gAB+/gAAfv5AAH8BgAB/AcAAfwIAAH8CgAB/EkAAfxLAAH8TQAB/E8AAfxSAAH8UwAB/FQAAfxV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AAIHhQACB4YAAgeHAAIHiAACB4kAAgeLAAIHjQACB44AAgePAAIHkQACB5IAAgfRAAIH0wACB9YAAgfYAAIH2wACB9wAAgfdAAIH3gACB98AAgfhAAIH4wACB+QAAgflAAIH5wACB+gAAggnAAIIKQACCCsAAggtAAIIMAACCDEAAggyAAIIMwACCDQAAgg2AAIIOAACCDkAAgg6AAIIPAACCD0AAgh8AAIIfgACCIAAAgiCAAIIhQACCIYAAgiHAAIIiAACCIkAAgiLAAIIjQACCI4AAgiPAAIIkQACCJIAAgibAAIInAACCJ4AAgjdAAII3wACCOEAAgjjAAII5QACCOYAAgjnAAII6AACCOkAAgjrAAII7QACCO4AAgjvAAII8QACCPIAAgkxAAIJMwACCTUAAgk3AAIJOQACCToAAgk7AAIJPAACCT0AAgk/AAIJQQACCUIAAglDAAIJRQACCUYAAgmFAAIJhwACCYkAAgmLAAIJjQACCY4AAgmPAAIJkAACCZEAAgmTAAIJlQACCZYAAgmXAAIJmQACCZoAAgnlAAIKCAACCigAAgpIAAIKSgACCkwAAgpOAAIKUAACClIAAgpTAAIKVAACClcAAgpYAAIKWgACClsAAgpdAAIKXwACCmAAAgphAAIKZAACCmUAAgpuAAIKewACCoAAAgqCAAIKhAACCokAAgqMAAIKjwACCpEAAgq2AAIK2gACCwEAAgslAAILKAACCyoAAgssAAILLgACCzAAAgsyAAILMwACCzYAAgtDAAILVAACC1YAAgtYAAILWgACC1wAAgteAAILYAACC2IAAgtkAAILdQACC3gAAgt7AAILfgACC4EAAguEAAILhwACC4oAAguNAAILjwACC84AAgvQAAIL0gACC9QAAgvXAAIL2AACC9kAAgvaAAIL2wACC90AAgvfAAIL4AACC+EAAgvjAAIL5AACDCMAAgwlAAIMJwACDCkAAgwsAAIMLQACDC4AAgwvAAIMMAACDDIAAgw0AAIMNQACDDYAAgw4AAIMOQACDHgAAgx6AAIMfQACDH8AAgyCAAIMgwACDIQAAgyFAAIMhgACDIgAAgyKAAIMiwACDIwAAgyOAAIMjwACDJwAAgydAAIMngACDKAAAgzfAAIM4QACDOMAAgzlAAIM6AACDOkAAgzqAAIM6wACDOwAAgzu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AAIkYwACJGUAAiR4AAIkewACJH4AAiSBAAIkhAACJIcAAiSKAAIkjQACJJAAAiSTAAIklQACJNQAAiTWAAIk2QACJNsAAiTeAAIk3wACJOAAAiThAAIk4gACJOQAAiTmAAIk5wACJOgAAiTqAAIk6wACJPQAAiT1AAIk9wACJTYAAiU4AAIlOgACJTwAAiU/AAIlQAACJUEAAiVCAAIlQwACJUUAAiVHAAIlSAACJUkAAiVLAAIlTAACJYsAAiWNAAIlkAACJZIAAiWVAAIllgACJZcAAiWYAAIlmQACJZsAAiWdAAIlngACJZ8AAiWhAAIlogACJasAAiWsAAIlrgACJe0AAiXvAAIl8QACJfMAAiX2AAIl9wACJfgAAiX5AAIl+gACJfwAAiX+AAIl/wACJgAAAiYCAAImAwACJkIAAiZEAAImRwACJkkAAiZMAAImTQACJk4AAiZPAAImUAACJlIAAiZUAAImVQACJlYAAiZYAAImWQACJmIAAiZjAAImZQACJqQAAiamAAImqAACJqoAAiatAAImrgACJq8AAiawAAImsQACJrMAAia1AAImtgACJrcAAia5AAImugACJvkAAib7AAIm/gACJwAAAicDAAInBAACJwUAAicGAAInBwACJwkAAicLAAInDAACJw0AAicPAAInEAACJx0AAiceAAInHwACJyEAAidgAAInYgACJ2QAAidmAAInaQACJ2oAAidrAAInbAACJ20AAidvAAIncQACJ3IAAidzAAIndQACJ3YAAie1AAIntwACJ7oAAie8AAInvwACJ8AAAifBAAInwgACJ8MAAifFAAInxwACJ8gAAifJAAInywACJ8wAAifaAAIn5wACJ+wAAifvAAIn8gACJ/cAAif6AAIn/QACJ/8AAigHAAIoEgACKF0AAiiAAAIooAACKMAAAijCAAIoxAACKMYAAijIAAIoywACKMwAAijNAAIo0AACKNEAAijTAAIo1AACKNYAAijZAAIo2gACKNsAAijeAAIo3wACKOQAAijxAAIo9gACKPgAAij6AAIo/wACKQIAAikFAAIpBwACKSwAAilQAAIpdwACKZsAAimeAAIpoAACKaIAAimkAAIppgACKagAAimpAAIprAACKbkAAinKAAIpzAACKc4AAinQAAIp0gACKdQAAinWAAIp2AACKdoAAinrAAIp7gACKfEAAin0AAIp9wACKfoAAin9AAIqAAACKgMAAioFAAIqRAACKkYAAipIAAIqSgACKk0AAipOAAIqTwACKlAAAipRAAIqUwACKlUAAipWAAIqVwACKlkAAipaAAIqmQACKpsAAiqdAAIqnwACKqIAAiqjAAIqpAACKqUAAiqmAAIqqAACKqoAAiqrAAIqrAACKq4AAiqvAAIq7gACKvAAAirzAAIq9QACKvgAAir5AAIq+gACKvsAAir8AAIq/gACKwAAAisBAAIrAgACKwQAAisFAAIrEgACKxMAAisUAAIrFgACK1UAAitXAAIrWQACK1sAAiteAAIrXwACK2AAAithAAIrYgACK2QAAitmAAIrZwACK2gAAitqAAIrawACK6oAAiusAAIrrgACK7AAAiuzAAIrtAACK7UAAiu2AAIrtwACK7kAAiu7AAIrvAACK70AAiu/AAIrwAACK/8AAiwBAAIsAwACLAUAAiwIAAIsCQACLAoAAiwLAAIsDAACLA4AAiwQAAIsEQACLBIAAiwUAAIsFQACLFQAAixWAAIsWAACLFoAAixdAAIsXgACLF8AAixgAAIsYQACLGMAAixlAAIsZgACLGcAAixpAAIsagACLKkAAiyrAAIsrQACLK8AAiyyAAIsswACLLQAAiy1AAIstgACLLgAAiy6AAIsuwACLLwAAiy+AAIsvwACLOQAAi0IAAItLwACLVMAAi1WAAItWAACLVoAAi1cAAItXgACLWAAAi1hAAItZAACLXEAAi2AAAItggACLYQAAi2GAAItiAACLYoAAi2MAAItjgACLZ0AAi2gAAItowACLaYAAi2pAAItrAACLa8AAi2yAAIttAACLfMAAi31AAIt9wACLfkAAi38AAIt/QACLf4AAi3/AAIuAAACLgIAAi4EAAIuBQACLgYAAi4IAAIuCQACLkgAAi5KAAIuTAACLk4AAi5RAAIuUgACLlMAAi5UAAIuVQACLlcAAi5ZAAIuWgACLlsAAi5dAAIuXgACLp0AAi6fAAIuoQACLqMAAi6mAAIupwACLqgAAi6pAAIuqgACLqwAAi6uAAIurwACLrAAAi6yAAIuswACLvIAAi70AAIu9wACLvkAAi78AAIu/QACLv4AAi7/AAIvAAACLwIAAi8EAAIvBQACLwYAAi8IAAIvCQACLwwAAi9LAAIvTQACL08AAi9RAAIvVAACL1UAAi9WAAIvVwACL1gAAi9aAAIvXAACL10AAi9eAAIvYAACL2EAAi+gAAIvogACL6QAAi+mAAIvqQACL6oAAi+rAAIvrAACL60AAi+vAAIvsQACL7IAAi+zAAIvtQACL7YAAi/1AAIv9wACL/kAAi/7AAIv/gACL/8AAjAAAAIwAQACMAIAAjAEAAIwBgACMAcAAjAIAAIwCgACMAsAAjBWAAIweQACMJkAAjC5AAIwuwACML0AAjC/AAIwwQACMMQAAjDFAAIwxgACMMkAAjDKAAIwzAACMM0AAjDPAAIw0gACMNMAAjDUAAIw1wACMNgAAjDdAAIw6gACMO8AAjDxAAIw8wACMPgAAjD7AAIw/gACMQAAAjElAAIxSQACMXAAAjGUAAIxlwACMZkAAjGbAAIxnQACMZ8AAjGhAAIxogACMaUAAjGyAAIxwwACMcUAAjHHAAIxyQACMcsAAjHNAAIxzwACMdEAAjHTAAIx5AACMecAAjHqAAIx7QACMfAAAjHzAAIx9gACMfkAAjH8AAIx/gACMj0AAjI/AAIyQQACMkMAAjJGAAIyRwACMkgAAjJJAAIySgACMkwAAjJOAAIyTwACMlAAAjJSAAIyUwACMpIAAjKUAAIylgACMpgAAjKbAAIynAACMp0AAjKeAAIynwACMqEAAjKjAAIypAACMqUAAjKnAAIyqAACMucAAjLpAAIy7AACMu4AAjLxAAIy8gACMvMAAjL0AAIy9QACMvcAAjL5AAIy+gACMvsAAjL9AAIy/gACMwsAAjMMAAIzDQACMw8AAjNOAAIzUAACM1IAAjNUAAIzVwACM1gAAjNZAAIzWgACM1sAAjNdAAIzXwACM2AAAjNhAAIzYwACM2QAAjOjAAIzpQACM6cAAjOpAAIzrAACM60AAjOuAAIzrwACM7AAAjOyAAIztAACM7UAAjO2AAIzuAACM7kAAjP4AAIz+gACM/wAAjP+AAI0AQACNAIAAjQDAAI0BAACNAUAAjQHAAI0CQACNAoAAjQLAAI0DQACNA4AAjRNAAI0TwACNFEAAjRTAAI0VgACNFcAAjRYAAI0WQACNFoAAjRcAAI0XgACNF8AAjRgAAI0YgACNGMAAjSiAAI0pAACNKYAAjSoAAI0qwACNKwAAjStAAI0rgACNK8AAjSxAAI0swACNLQAAjS1AAI0twACNLgAAjTdAAI1AQACNSgAAjVMAAI1TwACNVEAAjVTAAI1VQACNVcAAjVZAAI1WgACNV0AAjVqAAI1eQACNXsAAjV9AAI1fwACNYEAAjWDAAI1hQACNYcAAjWWAAI1mQACNZwAAjWfAAI1ogACNaUAAjWoAAI1qwACNa0AAjXsAAI17gACNfAAAjXyAAI19QACNfYAAjX3AAI1+AACNfkAAjX7AAI1/QACNf4AAjX/AAI2AQACNgIAAjZBAAI2QwACNkUAAjZHAAI2SgACNksAAjZMAAI2TQACNk4AAjZQAAI2UgACNlMAAjZUAAI2VgACNlcAAjaWAAI2mAACNpoAAjacAAI2nwACNqAAAjahAAI2ogACNqMAAjalAAI2pwACNqgAAjapAAI2qwACNqwAAjbrAAI27QACNu8AAjbxAAI29AACNvUAAjb2AAI29wACNvgAAjb6AAI2/AACNv0AAjb+AAI3AAACNwEAAjdAAAI3QgACN0QAAjdGAAI3SQACN0oAAjdLAAI3TAACN00AAjdPAAI3UQACN1IAAjdTAAI3VQACN1YAAjeVAAI3lwACN5kAAjebAAI3ngACN58AAjegAAI3oQACN6IAAjekAAI3pgACN6cAAjeoAAI3qgACN6sAAjfqAAI37AACN+4AAjfwAAI38wACN/QAAjf1AAI39gACN/cAAjf5AAI3+wACN/wAAjf9AAI3/wACOAAAAjgJAAI4CgACOAwAAjhPAAI4cwACOJcAAji6AAI44QACOQEAAjkoAAI5TwACOW8AAjmTAAI5twACObkAAjm8AAI5vgACOcAAAjnCAAI5xQACOcgAAjnKAAI5zAACOc8AAjnRAAI50wACOdYAAjnZAAI52gACOd8AAjnsAAI57wACOfEAAjn0AAI59wACOfkAAjoeAAI6QgACOmkAAjqNAAI6kAACOpIAAjqUAAI6lgACOpgAAjqaAAI6mwACOp4AAjqrAAI6vgACOsAAAjrCAAI6xAACOsYAAjrIAAI6ygACOswAAjrOAAI60AACOuMAAjrmAAI66QACOuwAAjrvAAI68gACOvUAAjr4AAI6+wACOv4AAjsAAAI7PwACO0EAAjtEAAI7RgACO0kAAjtKAAI7SwACO0wAAjtNAAI7TwACO1EAAjtSAAI7UwACO1UAAjtWAAI7XwACO2AAAjtiAAI7oQACO6MAAjulAAI7pwACO6oAAjurAAI7rAACO60AAjuuAAI7sAACO7IAAjuzAAI7tAACO7YAAju3AAI79gACO/gAAjv7AAI7/QACPAAAAjwBAAI8AgACPAMAAjwEAAI8BgACPAgAAjwJAAI8CgACPAwAAjwNAAI8FgACPBcAAjwZAAI8WAACPFoAAjxcAAI8XgACPGEAAjxiAAI8YwACPGQAAjxlAAI8ZwACPGkAAjxqAAI8awACPG0AAjxuAAI8rQACPK8AAjyyAAI8tAACPLcAAjy4AAI8uQACPLoAAjy7AAI8vQACPL8AAjzAAAI8wQACPMMAAjzEAAI8zQACPM4AAjzQAAI9DwACPREAAj0TAAI9FQACPRgAAj0ZAAI9GgACPRsAAj0cAAI9HgACPSAAAj0hAAI9IgACPSQAAj0lAAI9ZAACPWYAAj1pAAI9awACPW4AAj1vAAI9cAACPXEAAj1yAAI9dAACPXYAAj13AAI9eAACPXoAAj17AAI9iAACPYkAAj2KAAI9jAACPcsAAj3NAAI9zwACPdEAAj3UAAI91QACPdYAAj3XAAI92AACPdoAAj3cAAI93QACPd4AAj3gAAI94QACPiAAAj4iAAI+JQACPicAAj4qAAI+KwACPiwAAj4tAAI+LgACPjAAAj4yAAI+MwACPjQAAj42AAI+NwACPkUAAj5SAAI+XQACPmAAAj5jAAI+ZgACPmkAAj5sAAI+dwACPnoAAj59AAI+gAACPoMAAj6GAAI+iAACPpQAAj6iAAI+rAACPrUAAj8AAAI/IwACP0MAAj9jAAI/ZQACP2cAAj9pAAI/awACP24AAj9vAAI/cAACP3MAAj90AAI/dgACP3cAAj95AAI/fAACP30AAj9+AAI/gQACP4IAAj+HAAI/lAACP5kAAj+bAAI/nQACP6IAAj+lAAI/qAACP6oAAj/PAAI/8wACQBoAAkA+AAJAQQACQEMAAkBFAAJARwACQEkAAkBLAAJATAACQE8AAkBcAAJAbQACQG8AAkBxAAJAcwACQHUAAkB3AAJAeQACQHsAAkB9AAJAjgACQJEAAkCUAAJAlwACQJoAAkCdAAJAoAACQKMAAkCmAAJAqAACQOcAAkDpAAJA6wACQO0AAkDwAAJA8QACQPIAAkDzAAJA9AACQPYAAkD4AAJA+QACQPoAAkD8AAJA/QACQTwAAkE+AAJBQAACQUIAAkFFAAJBRgACQUcAAkFIAAJBSQACQUsAAkFNAAJBTgACQU8AAkFRAAJBUgACQZEAAkGTAAJBlgACQZgAAkGbAAJBnAACQZ0AAkGeAAJBnwACQaEAAkGjAAJBpAACQaUAAkGnAAJBqAACQbUAAkG2AAJBtwACQbkAAkH4AAJB+gACQfwAAkH+AAJCAQACQgIAAkIDAAJCBAACQgUAAkIHAAJCCQACQgoAAkILAAJCDQACQg4AAkJNAAJCTwACQlEAAkJTAAJCVgACQlcAAkJYAAJCWQACQloAAkJcAAJCXgACQl8AAkJgAAJCYgACQmMAAkKiAAJCpAACQqYAAkKoAAJCqwACQqwAAkKtAAJCrgACQq8AAkKxAAJCswACQrQAAkK1AAJCtwACQrgAAkL3AAJC+QACQvsAAkL9AAJDAAACQwEAAkMCAAJDAwACQwQAAkMGAAJDCAACQwkAAkMKAAJDDAACQw0AAkNMAAJDTgACQ1AAAkNSAAJDVQACQ1YAAkNXAAJDWAACQ1kAAkNbAAJDXQACQ14AAkNfAAJDYQACQ2IAAkOHAAJDqwACQ9IAAkP2AAJD+QACQ/sAAkP9AAJD/wACRAEAAkQDAAJEBAACRAcAAkQUAAJEIwACRCUAAkQnAAJEKQACRCsAAkQtAAJELwACRDEAAkRAAAJEQwACREYAAkRJAAJETAACRE8AAkRSAAJEVQACRFcAAkSWAAJEmAACRJoAAkScAAJEnwACRKAAAkShAAJEogACRKMAAkSlAAJEpwACRKgAAkSpAAJEqwACRKwAAkTrAAJE7QACRO8AAkTxAAJE9AACRPUAAkT2AAJE9wACRPgAAkT6AAJE/AACRP0AAkT+AAJFAAACRQEAAkVAAAJFQgACRUQAAkVGAAJFSQACRUoAAkVLAAJFTAACRU0AAkVPAAJFUQACRVIAAkVTAAJFVQACRVYAAkWVAAJFlwACRZkAAkWbAAJFngACRZ8AAkWgAAJFoQACRaIAAkWkAAJFpgACRacAAkWoAAJFqgACRasAAkXqAAJF7AACRe4AAkXwAAJF8wACRfQAAkX1AAJF9gACRfcAAkX5AAJF+wACRfwAAkX9AAJF/wACRgAAAkY/AAJGQQACRkMAAkZFAAJGSAACRkkAAkZKAAJGSwACRkwAAkZOAAJGUAACRlEAAkZSAAJGVAACRlUAAkaUAAJGlgACRpgAAkaaAAJGnQACRp4AAkafAAJGoAACRqEAAkajAAJGpQACRqYAAkanAAJGqQACRqoAAkb1AAJHGAACRzgAAkdYAAJHWgACR1wAAkdeAAJHYAACR2MAAkdkAAJHZQACR2gAAkdpAAJHawACR2wAAkduAAJHcQACR3IAAkdzAAJHdgACR3cAAkd8AAJHiQACR44AAkeQAAJHkgACR5cAAkeaAAJHnQACR58AAkfEAAJH6AACSA8AAkgzAAJINgACSDgAAkg6AAJIPAACSD4AAkhAAAJIQQACSEQAAkhRAAJIYgACSGQAAkhmAAJIaAACSGoAAkhsAAJIbgACSHAAAkhyAAJIgwACSIYAAkiJAAJIjAACSI8AAkiSAAJIlQACSJgAAkibAAJInQACSNwAAkjeAAJI4AACSOIAAkjlAAJI5gACSOcAAkjoAAJI6QACSOsAAkjtAAJI7gACSO8AAkjxAAJI8gACSTEAAkkzAAJJNQACSTcAAkk6AAJJOwACSTwAAkk9AAJJPgACSUAAAklCAAJJQwACSUQAAklGAAJJRwACSYYAAkmIAAJJiwACSY0AAkmQAAJJkQACSZIAAkmTAAJJlAACSZYAAkmYAAJJmQACSZoAAkmcAAJJnQACSaoAAkmrAAJJrAACSa4AAkntAAJJ7wACSfEAAknzAAJJ9gACSfcAAkn4AAJJ+QACSfoAAkn8AAJJ/gACSf8AAkoAAAJKAgACSgMAAkpCAAJKRAACSkYAAkpIAAJKSwACSkwAAkpNAAJKTgACSk8AAkpRAAJKUwACSlQAAkpVAAJKVwACSlgAAkqXAAJKmQACSpsAAkqdAAJKoAACSqEAAkqiAAJKowACSqQAAkqmAAJKqAACSqkAAkqqAAJKrAACSq0AAkrsAAJK7gACSvAAAkryAAJK9QACSvYAAkr3AAJK+AACSvkAAkr7AAJK/QACSv4AAkr/AAJLAQACSwIAAktBAAJLQwACS0UAAktHAAJLSgACS0sAAktMAAJLTQACS04AAktQAAJLUgACS1MAAktUAAJLVgACS1cAAkt8AAJLoAACS8cAAkvrAAJL7gACS/AAAkvyAAJL9AACS/YAAkv4AAJL+QACS/wAAkwJAAJMGAACTBoAAkwcAAJMHgACTCAAAkwiAAJMJAACTCYAAkw1AAJMOAACTDsAAkw+AAJMQQACTEQAAkxHAAJMSgACTEwAAkyLAAJMjQACTI8AAkyRAAJMlAACTJUAAkyWAAJMlwACTJgAAkyaAAJMnAACTJ0AAkyeAAJMoAACTKEAAkzgAAJM4gACTOQAAkzmAAJM6QACTOoAAkzrAAJM7AACTO0AAkzvAAJM8QACTPIAAkzzAAJM9QACTPYAAk01AAJNNwACTTkAAk07AAJNPgACTT8AAk1AAAJNQQACTUIAAk1EAAJNRgACTUcAAk1IAAJNSgACTUsAAk2KAAJNjAACTY4AAk2QAAJNkwACTZQAAk2VAAJNlgACTZcAAk2ZAAJNmwACTZwAAk2dAAJNnwACTaAAAk3fAAJN4QACTeMAAk3lAAJN6AACTekAAk3qAAJN6wACTewAAk3uAAJN8AACTfEAAk3yAAJN9AACTfUAAk40AAJONgACTjgAAk46AAJOPQACTj4AAk4/AAJOQAACTkEAAk5DAAJORQACTkYAAk5HAAJOSQACTkoAAk6JAAJOiwACTo0AAk6PAAJOkgACTpMAAk6UAAJOlQACTpYAAk6YAAJOmgACTpsAAk6cAAJOngACTp8AAk7qAAJPDQACTy0AAk9NAAJPTwACT1EAAk9TAAJPVQACT1gAAk9ZAAJPWgACT10AAk9eAAJPYAACT2EAAk9jAAJPZgACT2cAAk9oAAJPawACT2wAAk91AAJPggACT4cAAk+JAAJPiwACT5AAAk+TAAJPlgACT5gAAk+9AAJP4QACUAgAAlAsAAJQLwACUDEAAlAzAAJQNQACUDcAAlA5AAJQOgACUD0AAlBKAAJQWwACUF0AAlBfAAJQYQACUGMAAlBlAAJQZwACUGkAAlBrAAJQfAACUH8AAlCCAAJQhQACUIgAAlCLAAJQjgACUJEAAlCUAAJQlgACUNUAAlDXAAJQ2QACUNsAAlDeAAJQ3wACUOAAAlDhAAJQ4gACUOQAAlDmAAJQ5wACUOgAAlDqAAJQ6wACUSoAAlEsAAJRLgACUTAAAlEzAAJRNAACUTUAAlE2AAJRNwACUTkAAlE7AAJRPAACUT0AAlE/AAJRQAACUX8AAlGBAAJRhAACUYYAAlGJAAJRigACUYsAAlGMAAJRjQACUY8AAlGRAAJRkgACUZMAAlGVAAJRlgACUaMAAlGkAAJRpQACUacAAlHmAAJR6AACUeoAAlHsAAJR7wACUfAAAlHxAAJR8gACUfMAAlH1AAJR9wACUfgAAlH5AAJR+wACUfwAAlI7AAJSPQACUj8AAlJBAAJSRAACUkUAAlJGAAJSRwACUkgAAlJKAAJSTAACUk0AAlJOAAJSUAACUlEAAlKQAAJSkgACUpQAAlKWAAJSmQACUpoAAlKbAAJSnAACUp0AAlKfAAJSoQACUqIAAlKjAAJSpQACUqYAAlLlAAJS5wACUukAAlLrAAJS7gACUu8AAlLwAAJS8QACUvIAAlL0AAJS9gACUvcAAlL4AAJS+gACUvsAAlM6AAJTPAACUz4AAlNAAAJTQwACU0QAAlNFAAJTRgACU0cAAlNJAAJTSwACU0wAAlNNAAJTTwACU1AAAlN1AAJTmQACU8AAAlPkAAJT5wACU+kAAlPrAAJT7QACU+8AAlPxAAJT8gACU/UAAlQCAAJUEQACVBMAAlQVAAJUFwACVBkAAlQbAAJUHQACVB8AAlQuAAJUMQACVDQAAlQ3AAJUOgACVD0AAlRAAAJUQwACVEUAAlSEAAJUhgACVIgAAlSKAAJUjQACVI4AAlSPAAJUkAACVJEAAlSTAAJUlQACVJYAAlSXAAJUmQACVJoAAlTZAAJU2wACVN0AAlTfAAJU4gACVOMAAlTkAAJU5QACVOYAAlToAAJU6gACVOsAAlTsAAJU7gACVO8AAlUuAAJVMAACVTIAAlU0AAJVNwACVTgAAlU5AAJVOgACVTsAAlU9AAJVPwACVUAAAlVBAAJVQwACVUQAAlWDAAJVhQACVYgAAlWKAAJVjQACVY4AAlWPAAJVkAACVZEAAlWTAAJVlQACVZYAAlWXAAJVmQACVZoAAlWdAAJV3AACVd4AAlXgAAJV4gACVeUAAlXmAAJV5wACVegAAlXpAAJV6wACVe0AAlXuAAJV7wACVfEAAlXyAAJWMQACVjMAAlY1AAJWNwACVjoAAlY7AAJWPAACVj0AAlY+AAJWQAACVkIAAlZDAAJWRAACVkYAAlZHAAJWhgACVogAAlaKAAJWjAACVo8AAlaQAAJWkQACVpIAAlaTAAJWlQACVpcAAlaYAAJWmQACVpsAAlacAAJW5wACVwoAAlcqAAJXSgACV0wAAldOAAJXUAACV1IAAldVAAJXVgACV1cAAldaAAJXWwACV10AAldeAAJXYAACV2MAAldkAAJXZQACV2gAAldpAAJXbgACV3sAAleAAAJXggACV4QAAleJAAJXjAACV48AAleRAAJXtgACV9oAAlgBAAJYJQACWCgAAlgqAAJYLAACWC4AAlgwAAJYMgACWDMAAlg2AAJYQwACWFQAAlhWAAJYWAACWFoAAlhcAAJYXgACWGAAAlhiAAJYZAACWHUAAlh4AAJYewACWH4AAliBAAJYhAACWIcAAliKAAJYjQACWI8AAljOAAJY0AACWNIAAljUAAJY1wACWNgAAljZAAJY2gACWNsAAljdAAJY3wACWOAAAljhAAJY4wACWOQAAlkjAAJZJQACWScAAlkpAAJZLAACWS0AAlkuAAJZLwACWTAAAlkyAAJZNAACWTUAAlk2AAJZOAACWTkAAll4AAJZegACWX0AAll/AAJZggACWYMAAlmEAAJZhQACWYYAAlmIAAJZigACWYsAAlmMAAJZjgACWY8AAlmcAAJZnQACWZ4AAlmgAAJZ3wACWeEAAlnjAAJZ5QACWegAAlnpAAJZ6gACWesAAlnsAAJZ7gACWfAAAlnxAAJZ8gACWfQAAln1AAJaNAACWjYAAlo4AAJaOgACWj0AAlo+AAJaPwACWkAAAlpBAAJaQwACWkUAAlpGAAJaRwACWkkAAlpKAAJaiQACWosAAlqNAAJajwACWpIAAlqTAAJalAACWpUAAlqWAAJamAACWpoAAlqbAAJanAACWp4AAlqfAAJa3gACWuAAAlriAAJa5AACWucAAlroAAJa6QACWuoAAlrrAAJa7QACWu8AAlrwAAJa8QACWvMAAlr0AAJbMwACWzUAAls3AAJbOQACWzwAAls9AAJbPgACWz8AAltAAAJbQgACW0QAAltFAAJbRgACW0gAAltJAAJbbgACW5IAAlu5AAJb3QACW+AAAlviAAJb5AACW+YAAlvoAAJb6gACW+sAAlvuAAJb+wACXAoAAlwMAAJcDgACXBAAAlwSAAJcFAACXBYAAlwYAAJcJwACXCoAAlwtAAJcMAACXDMAAlw2AAJcOQACXDwAAlw+AAJcfQACXH8AAlyBAAJcgwACXIYAAlyHAAJciAACXIkAAlyKAAJcjAACXI4AAlyPAAJckAACXJIAAlyTAAJc0gACXNQAAlzWAAJc2AACXNsAAlzcAAJc3QACXN4AAlzfAAJc4QACXOMAAlzkAAJc5QACXOcAAlzoAAJdJwACXSkAAl0rAAJdLQACXTAAAl0xAAJdMgACXTMAAl00AAJdNgACXTgAAl05AAJdOgACXTwAAl09AAJdfAACXX4AAl2AAAJdggACXYUAAl2GAAJdhwACXYgAAl2JAAJdiwACXY0AAl2OAAJdjwACXZEAAl2SAAJd0QACXdMAAl3VAAJd1wACXdoAAl3bAAJd3AACXd0AAl3eAAJd4AACXeIAAl3jAAJd5AACXeYAAl3nAAJeJgACXigAAl4qAAJeLAACXi8AAl4wAAJeMQACXjIAAl4zAAJeNQACXjcAAl44AAJeOQACXjsAAl48AAJeewACXn0AAl5/AAJegQACXoQAAl6FAAJehgACXocAAl6IAAJeigACXowAAl6NAAJejgACXpAAAl6RAAJe3AACXv8AAl8fAAJfPwACX0EAAl9DAAJfRQACX0cAAl9KAAJfSwACX0wAAl9PAAJfUAACX1IAAl9TAAJfVQACX1gAAl9ZAAJfWgACX10AAl9eAAJfYwACX3AAAl91AAJfdwACX3kAAl9+AAJfgQACX4QAAl+GAAJfqwACX88AAl/2AAJgGgACYB0AAmAfAAJgIQACYCMAAmAlAAJgJwACYCgAAmArAAJgOAACYEkAAmBLAAJgTQACYE8AAmBRAAJgUwACYFUAAmBXAAJgWQACYGoAAmBtAAJgcAACYHMAAmB2AAJgeQACYHwAAmB/AAJgggACYIQAAmDDAAJgxQACYMcAAmDJAAJgzAACYM0AAmDOAAJgzwACYNAAAmDSAAJg1AACYNUAAmDWAAJg2AACYNkAAmEYAAJhGgACYRwAAmEeAAJhIQACYSIAAmEjAAJhJAACYSUAAmEnAAJhKQACYSoAAmErAAJhLQACYS4AAmFtAAJhbwACYXIAAmF0AAJhdwACYXgAAmF5AAJhegACYXsAAmF9AAJhfwACYYAAAmGBAAJhgwACYYQAAmGRAAJhkgACYZMAAmGVAAJh1AACYdYAAmHYAAJh2gACYd0AAmHeAAJh3wACYeAAAmHhAAJh4wACYeUAAmHmAAJh5wACYekAAmHqAAJiKQACYisAAmItAAJiLwACYjIAAmIzAAJiNAACYjUAAmI2AAJiOAACYjoAAmI7AAJiPAACYj4AAmI/AAJifgACYoAAAmKCAAJihAACYocAAmKIAAJiiQACYooAAmKLAAJijQACYo8AAmKQAAJikQACYpMAAmKUAAJi0wACYtUAAmLXAAJi2QACYtwAAmLdAAJi3gACYt8AAmLgAAJi4gACYuQAAmLlAAJi5gACYugAAmLpAAJjKAACYyoAAmMsAAJjLgACYzEAAmMyAAJjMwACYzQAAmM1AAJjNwACYzkAAmM6AAJjOwACYz0AAmM+AAJjYwACY4cAAmOuAAJj0gACY9UAAmPXAAJj2QACY9sAAmPdAAJj3wACY+AAAmPjAAJj8AACY/8AAmQBAAJkAwACZAUAAmQHAAJkCQACZAsAAmQNAAJkHAACZB8AAmQiAAJkJQACZCgAAmQrAAJkLgACZDEAAmQzAAJkcgACZHQAAmR2AAJkeAACZHsAAmR8AAJkfQACZH4AAmR/AAJkgQACZIMAAmSEAAJkhQACZIcAAmSIAAJkxwACZMkAAmTLAAJkzQACZNAAAmTRAAJk0gACZNMAAmTUAAJk1gACZNgAAmTZAAJk2gACZNwAAmTdAAJlHAACZR4AAmUgAAJlIgACZSUAAmUmAAJlJwACZSgAAmUpAAJlKwACZS0AAmUuAAJlLwACZTEAAmUyAAJlcQACZXMAAmV1AAJldwACZXoAAmV7AAJlfAACZX0AAmV+AAJlgAACZYIAAmWDAAJlhAACZYYAAmWHAAJlxgACZcgAAmXKAAJlzAACZc8AAmXQAAJl0QACZdIAAmXTAAJl1QACZdcAAmXYAAJl2QACZdsAAmXcAAJmGwACZh0AAmYfAAJmIQACZiQAAmYlAAJmJgACZicAAmYoAAJmKgACZiwAAmYtAAJmLgACZjAAAmYxAAJmcAACZnIAAmZ0AAJmdgACZnkAAmZ6AAJmewACZnwAAmZ9AAJmfwACZoEAAmaCAAJmgwACZoUAAmaGAAJmjwACZpAAAmaSAAJm1QACZvkAAmcdAAJnQAACZ2cAAmeHAAJnrgACZ9UAAmf1AAJoGQACaD0AAmg/AAJoQgACaEQAAmhGAAJoSAACaEsAAmhOAAJoUAACaFIAAmhVAAJoVwACaFkAAmhcAAJoXwACaGAAAmhlAAJocgACaHUAAmh3AAJoegACaH0AAmh/AAJopAACaMgAAmjvAAJpEwACaRYAAmkYAAJpGgACaRwAAmkeAAJpIAACaSEAAmkkAAJpMQACaUQAAmlGAAJpSAACaUoAAmlMAAJpTgACaVAAAmlSAAJpVAACaVYAAmlpAAJpbAACaW8AAmlyAAJpdQACaXgAAml7AAJpfgACaYEAAmmEAAJphgACacUAAmnHAAJpygACacwAAmnPAAJp0AACadEAAmnSAAJp0wACadUAAmnXAAJp2AACadkAAmnbAAJp3AACaeUAAmnmAAJp6AACaicAAmopAAJqKwACai0AAmowAAJqMQACajIAAmozAAJqNAACajYAAmo4AAJqOQACajoAAmo8AAJqPQACanwAAmp+AAJqgQACaoMAAmqGAAJqhwACaogAAmqJAAJqigACaowAAmqOAAJqjwACapAAAmqSAAJqkwACapwAAmqdAAJqnwACat4AAmrgAAJq4gACauQAAmrnAAJq6AACaukAAmrqAAJq6wACau0AAmrvAAJq8AACavEAAmrzAAJq9AACazMAAms1AAJrOAACazoAAms9AAJrPgACaz8AAmtAAAJrQQACa0MAAmtFAAJrRgACa0cAAmtJAAJrSgACa1MAAmtUAAJrVgACa5UAAmuXAAJrmQACa5sAAmueAAJrnwACa6AAAmuhAAJrogACa6QAAmumAAJrpwACa6gAAmuqAAJrqwACa+oAAmvsAAJr7wACa/EAAmv0AAJr9QACa/YAAmv3AAJr+AACa/oAAmv8AAJr/QACa/4AAmwAAAJsAQACbA4AAmwPAAJsEAACbBIAAmxRAAJsUwACbFUAAmxXAAJsWgACbFsAAmxcAAJsXQACbF4AAmxgAAJsYgACbGMAAmxkAAJsZgACbGcAAmymAAJsqAACbKsAAmytAAJssAACbLEAAmyyAAJsswACbLQAAmy2AAJsuAACbLkAAmy6AAJsvAACbL0AAmzZAAJs5gACbPEAAmz0AAJs9wACbPoAAmz9AAJtAAACbQsAAm0OAAJtEQACbRQAAm0XAAJtGgACbRwAAm0vAAJtPQACbUYAAm1YAAJtYAACbasAAm3OAAJt7gACbg4AAm4QAAJuEgACbhQAAm4WAAJuGQACbhoAAm4bAAJuHgACbh8AAm4hAAJuIgACbiQAAm4nAAJuKAACbikAAm4sAAJuLQACbjIAAm4/AAJuRAACbkYAAm5IAAJuTQACblAAAm5TAAJuVQACbnoAAm6eAAJuxQACbukAAm7sAAJu7gACbvAAAm7yAAJu9AACbvYAAm73AAJu+gACbwcAAm8YAAJvGgACbxwAAm8eAAJvIAACbyIAAm8kAAJvJgACbygAAm85AAJvPAACbz8AAm9CAAJvRQACb0gAAm9LAAJvTgACb1EAAm9TAAJvkgACb5QAAm+WAAJvmAACb5sAAm+cAAJvnQACb54AAm+fAAJvoQACb6MAAm+kAAJvpQACb6cAAm+oAAJv5wACb+kAAm/rAAJv7QACb/AAAm/xAAJv8gACb/MAAm/0AAJv9gACb/gAAm/5AAJv+gACb/wAAm/9AAJwPAACcD4AAnBBAAJwQwACcEYAAnBHAAJwSAACcEkAAnBKAAJwTAACcE4AAnBPAAJwUAACcFIAAnBTAAJwYAACcGEAAnBiAAJwZAACcKMAAnClAAJwpwACcKkAAnCsAAJwrQACcK4AAnCvAAJwsAACcLIAAnC0AAJwtQACcLYAAnC4AAJwuQACcPgAAnD6AAJw/AACcP4AAnEBAAJxAgACcQMAAnEEAAJxBQACcQcAAnEJAAJxCgACcQsAAnENAAJxDgACcU0AAnFPAAJxUQACcVMAAnFWAAJxVwACcVgAAnFZAAJxWgACcVwAAnFeAAJxXwACcWAAAnFiAAJxYwACcaIAAnGkAAJxpgACcagAAnGrAAJxrAACca0AAnGuAAJxrwACcbEAAnGzAAJxtAACcbUAAnG3AAJxuAACcfcAAnH5AAJx+wACcf0AAnIAAAJyAQACcgIAAnIDAAJyBAACcgYAAnIIAAJyCQACcgoAAnIMAAJyDQACcjIAAnJWAAJyfQACcqEAAnKkAAJypgACcqgAAnKqAAJyrAACcq4AAnKvAAJysgACcr8AAnLOAAJy0AACctIAAnLUAAJy1gACctgAAnLaAAJy3AACcusAAnLuAAJy8QACcvQAAnL3AAJy+gACcv0AAnMAAAJzAgACc0EAAnNDAAJzRQACc0cAAnNKAAJzSwACc0wAAnNNAAJzTgACc1AAAnNSAAJzUwACc1QAAnNWAAJzVwACc5YAAnOYAAJzmgACc5wAAnOfAAJzoAACc6EAAnOiAAJzowACc6UAAnOnAAJzqAACc6kAAnOrAAJzrAACc+sAAnPtAAJz7wACc/EAAnP0AAJz9QACc/YAAnP3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AAJ/jQACf48AAn/OAAJ/0AACf9IAAn/UAAJ/1wACf9gAAn/ZAAJ/2gACf9sAAn/dAAJ/3wACf+AAAn/hAAJ/4wACf+QAAoAjAAKAJQACgCcAAoApAAKALAACgC0AAoAuAAKALwACgDAAAoAyAAKANAACgDUAAoA2AAKAOAACgDkAAoB4AAKAegACgH0AAoB/AAKAggACgIMAAoCEAAKAhQACgIYAAoCIAAKAigACgIsAAoCMAAKAjgACgI8AAoCcAAKAnQACgJ4AAoCgAAKA3wACgOEAAoDjAAKA5QACgOgAAoDpAAKA6gACgOsAAoDsAAKA7gACgPAAAoDxAAKA8gACgPQAAoD1AAKBNAACgTYAAoE4AAKBOgACgT0AAoE+AAKBPwACgUAAAoFBAAKBQwACgUUAAoFGAAKBRwACgUkAAoFKAAKBiQACgYsAAoGNAAKBjwACgZIAAoGTAAKBlAACgZUAAoGWAAKBmAACgZoAAoGbAAKBnAACgZ4AAoGfAAKB3gACgeAAAoHiAAKB5AACgecAAoHoAAKB6QACgeoAAoHrAAKB7QACge8AAoHwAAKB8QACgfMAAoH0AAKCMwACgjUAAoI3AAKCOQACgjwAAoI9AAKCPgACgj8AAoJAAAKCQgACgkQAAoJFAAKCRgACgkgAAoJJAAKCbgACgpIAAoK5AAKC3QACguAAAoLiAAKC5AACguYAAoLoAAKC6gACgusAAoLuAAKC+wACgwoAAoMMAAKDDgACgxAAAoMSAAKDFAACgxYAAoMYAAKDJwACgyoAAoMtAAKDMAACgzMAAoM2AAKDOQACgzwAAoM+AAKDfQACg38AAoOBAAKDgwACg4YAAoOHAAKDiAACg4kAAoOKAAKDjAACg44AAoOPAAKDkAACg5IAAoOTAAKD0gACg9QAAoPWAAKD2AACg9sAAoPcAAKD3QACg94AAoPfAAKD4QACg+MAAoPkAAKD5QACg+cAAoPoAAKEJwAChCkAAoQrAAKELQAChDAAAoQxAAKEMgAChDMAAoQ0AAKENgAChDgAAoQ5AAKEOgAChDwAAoQ9AAKEfAAChH4AAoSAAAKEggAChIUAAoSGAAKEhwAChIgAAoSJAAKEiwAChI0AAoSOAAKEjwAChJEAAoSSAAKE0QAChNMAAoTVAAKE1wAChNoAAoTbAAKE3AAChN0AAoTeAAKE4AAChOIAAoTjAAKE5AAChOYAAoTnAAKFJgAChSgAAoUqAAKFLAAChS8AAoUwAAKFMQAChTIAAoUzAAKFNQAChTcAAoU4AAKFOQAChTsAAoU8AAKFewAChX0AAoV/AAKFgQAChYQAAoWFAAKFhgAChYcAAoWIAAKFigAChYwAAoWNAAKFjgAChZAAAoWRAAKF3AAChf8AAoYfAAKGPwAChkEAAoZDAAKGRQAChkcAAoZKAAKGSwAChkwAAoZPAAKGUAAChlIAAoZTAAKGVQAChlgAAoZZAAKGWgAChl0AAoZeAAKGYwAChnAAAoZ1AAKGdwAChnkAAoZ+AAKGgQAChoQAAoaGAAKGqwAChs8AAob2AAKHGgAChx0AAocfAAKHIQAChyMAAoclAAKHJwAChygAAocrAAKHOAACh0kAAodLAAKHTQACh08AAodRAAKHUwACh1UAAodXAAKHWQACh2oAAodtAAKHcAACh3MAAod2AAKHeQACh3wAAod/AAKHggACh4QAAofDAAKHxQACh8cAAofJAAKHzAACh80AAofOAAKHzwACh9AAAofSAAKH1AACh9UAAofWAAKH2AACh9kAAogYAAKIGgACiBwAAogeAAKIIQACiCIAAogjAAKIJAACiCUAAognAAKIKQACiCoAAogrAAKILQACiC4AAohtAAKIbwACiHIAAoh0AAKIdwACiHgAAoh5AAKIegACiHsAAoh9AAKIfwACiIAAAoiBAAKIgwACiIQAAoiRAAKIkgACiJMAAoiVAAKI1AACiNYAAojYAAKI2gACiN0AAojeAAKI3wACiOAAAojhAAKI4wACiOUAAojmAAKI5wACiOkAAojqAAKJKQACiSsAAoktAAKJLwACiTIAAokzAAKJNAACiTUAAok2AAKJOAACiToAAok7AAKJPAACiT4AAok/AAKJfgACiYAAAomCAAKJhAACiYcAAomIAAKJiQACiYoAAomLAAKJjQACiY8AAomQAAKJkQACiZMAAomUAAKJ0wACidUAAonXAAKJ2QACidwAAondAAKJ3gACid8AAongAAKJ4gACieQAAonlAAKJ5gACiegAAonpAAKKKAACiioAAoosAAKKLgACijEAAooyAAKKMwACijQAAoo1AAKKNwACijkAAoo6AAKKOwACij0AAoo+AAKKYwACiocAAoquAAKK0gACitUAAorXAAKK2QACitsAAordAAKK3wACiuAAAorjAAKK8AACiv0AAor/AAKLAQACiwMAAosFAAKLBwACiwkAAosWAAKLGQACixwAAosfAAKLIgACiyUAAosoAAKLKgACi2kAAotrAAKLbgACi3AAAotzAAKLdAACi3UAAot2AAKLdwACi3kAAot7AAKLfAACi30AAot/AAKLgAACi8MAAovnAAKMCwACjC4AAoxVAAKMdQACjJwAAozDAAKM4wACjQcAAo0rAAKNLQACjTAAAo0yAAKNNAACjTYAAo05AAKNPAACjT4AAo1AAAKNQwACjUUAAo1HAAKNSgACjU0AAo1OAAKNUwACjWAAAo1jAAKNZQACjWgAAo1rAAKNbQACjZIAAo22AAKN3QACjgEAAo4EAAKOBgACjggAAo4KAAKODAACjg4AAo4PAAKOEgACjh8AAo4yAAKONAACjjYAAo44AAKOOgACjjwAAo4+AAKOQAACjkIAAo5EAAKOVwACjloAAo5dAAKOYAACjmMAAo5mAAKOaQACjmwAAo5vAAKOcgACjnQAAo6zAAKOtQACjrgAAo66AAKOvQACjr4AAo6/AAKOwAACjsEAAo7DAAKOxQACjsYAAo7HAAKOyQACjsoAAo7TAAKO1AACjtYAAo8VAAKPFwACjxkAAo8bAAKPHgACjx8AAo8gAAKPIQACjyIAAo8kAAKPJgACjycAAo8oAAKPKgACjysAAo9qAAKPbAACj28AAo9xAAKPdAACj3UAAo92AAKPdwACj3gAAo96AAKPfAACj30AAo9+AAKPgAACj4EAAo+KAAKPiwACj40AAo/MAAKPzgACj9AAAo/SAAKP1QACj9YAAo/XAAKP2AACj9kAAo/bAAKP3QACj94AAo/fAAKP4QACj+IAApAhAAKQIwACkCYAApAoAAKQKwACkCwAApAtAAKQLgACkC8AApAxAAKQMwACkDQAApA1AAKQNwACkDgAApBBAAKQQgACkEQAApCDAAKQhQACkIcAApCJAAKQjAACkI0AApCOAAKQjwACkJAAApCSAAKQlAACkJUAApCWAAKQmAACkJkAApDYAAKQ2gACkN0AApDfAAKQ4gACkOMAApDkAAKQ5QACkOYAApDoAAKQ6gACkOsAApDsAAKQ7gACkO8AApD8AAKQ/QACkP4AApEAAAKRPwACkUEAApFDAAKRRQACkUgAApFJAAKRSgACkUsAApFMAAKRTgACkVAAApFRAAKRUgACkVQAApFVAAKRlAACkZYAApGZAAKRmwACkZ4AApGfAAKRoAACkaEAApGiAAKRpAACkaYAApGnAAKRqAACkaoAApGrAAKRugACkccAApHOAAKR0QACkdMAApHWAAKR3QACkeAAApHjAAKR5gACkegAApHwAAKR9QACkkAAApJjAAKSgwACkqMAApKlAAKSpwACkqkAApKrAAKSrgACkq8AApKwAAKSswACkrQAApK2AAKStwACkrkAApK8AAKSvQACkr4AApLBAAKSwgACkssAApLYAAKS3QACkt8AApLhAAKS5gACkukAApLsAAKS7gACkxMAApM3AAKTXgACk4IAApOFAAKThwACk4kAApOLAAKTjQACk48AApOQAAKTkwACk6AAApOxAAKTswACk7UAApO3AAKTuQACk7sAApO9AAKTvwACk8EAApPSAAKT1QACk9gAApPbAAKT3gACk+EAApPkAAKT5wACk+oAApPsAAKUKwAClC0AApQvAAKUMQAClDQAApQ1AAKUNgAClDcAApQ4AAKUOgAClDwAApQ9AAKUPgAClEAAApRBAAKUgAAClIIAApSEAAKUhgAClIkAApSKAAKUiwAClIwAApSNAAKUjwAClJEAApSSAAKUkwAClJUAApSWAAKU1QAClNcAApTaAAKU3AAClN8AApTgAAKU4QAClOIAApTjAAKU5QAClOcAApToAAKU6QAClOsAApTsAAKU+QAClPoAApT7AAKU/QAClTwAApU+AAKVQAAClUIAApVFAAKVRgAClUcAApVIAAKVSQAClUsAApVNAAKVTgAClU8AApVRAAKVUgAClZEAApWTAAKVlQAClZcAApWaAAKVmwAClZwAApWdAAKVngAClaAAApWiAAKVowAClaQAApWmAAKVpwACleYAApXoAAKV6gAClewAApXvAAKV8AAClfEAApXyAAKV8wAClfUAApX3AAKV+AAClfkAApX7AAKV/AACljsAApY9AAKWPwAClkEAApZEAAKWRQAClkYAApZHAAKWSAAClkoAApZMAAKWTQAClk4AApZQAAKWUQAClpAAApaSAAKWlAAClpYAApaZAAKWmgAClpsAApacAAKWnQAClp8AApahAAKWogAClqMAApalAAKWpgAClssAApbvAAKXFgAClzoAApc9AAKXPwACl0EAApdDAAKXRQACl0cAApdIAAKXSwACl1gAApdnAAKXaQACl2sAApdtAAKXbwACl3EAApdzAAKXdQACl4QAApeHAAKXigACl40AApeQAAKXkwACl5YAApeZAAKXmwACl9oAApfcAAKX3gACl+AAApfjAAKX5AACl+UAApfmAAKX5wACl+kAApfrAAKX7AACl+0AApfvAAKX8AACmC8AApgxAAKYMwACmDUAApg4AAKYOQACmDoAApg7AAKYPAACmD4AAphAAAKYQQACmEIAAphEAAKYRQACmIQAApiGAAKYiAACmIoAApiNAAKYjgACmI8AApiQAAKYkQACmJMAApiVAAKYlgACmJcAApiZAAKYmgACmNkAApjbAAKY3QACmN8AApjiAAKY4wACmOQAApjlAAKY5gACmOgAApjqAAKY6wACmOwAApjuAAKY7wACmS4AApkwAAKZMgACmTQAApk3AAKZOAACmTkAApk6AAKZOwACmT0AApk/AAKZQAACmUEAAplDAAKZRAACmYMAApmFAAKZhwACmYkAApmMAAKZjQACmY4AApmPAAKZkAACmZIAApmUAAKZlQACmZYAApmYAAKZmQACmdgAApnaAAKZ3AACmd4AApnhAAKZ4gACmeMAApnkAAKZ5QACmecAApnpAAKZ6gACmesAApntAAKZ7gACmjkAAppcAAKafAACmpwAApqeAAKaoAACmqIAApqkAAKapwACmqgAApqpAAKarAACmq0AApqvAAKasAACmrIAApq0AAKatQACmrYAApq5AAKaugACmr8AAprMAAKa0QACmtMAAprVAAKa2gACmt0AAprgAAKa4gACmwcAApsrAAKbUgACm3YAApt5AAKbewACm30AApt/AAKbgQACm4MAApuEAAKbhwACm5QAApulAAKbpwACm6kAApurAAKbrQACm68AApuxAAKbswACm7UAApvGAAKbyQACm8wAApvPAAKb0gACm9UAApvYAAKb2wACm94AApvgAAKcHwACnCEAApwjAAKcJQACnCgAApwpAAKcKgACnCsAApwsAAKcLgACnDAAApwxAAKcMgACnDQAApw1AAKcdAACnHYAApx4AAKcegACnH0AApx+AAKcfwACnIAAApyBAAKcgwACnIUAApyGAAKchwACnIkAApyKAAKcyQACnMsAApzOAAKc0AACnNMAApzUAAKc1QACnNYAApzXAAKc2QACnNsAApzcAAKc3QACnN8AApzgAAKc7QACnO4AApzvAAKc8QACnTAAAp0yAAKdNAACnTYAAp05AAKdOgACnTsAAp08AAKdPQACnT8AAp1BAAKdQgACnUMAAp1FAAKdRgACnYUAAp2HAAKdiQACnYsAAp2OAAKdjwACnZAAAp2RAAKdkgACnZQAAp2WAAKdlwACnZgAAp2aAAKdmwACndoAAp3cAAKd3gACneAAAp3jAAKd5AACneUAAp3mAAKd5wACnekAAp3rAAKd7AACne0AAp3vAAKd8AACni8AAp4xAAKeMwACnjUAAp44AAKeOQACnjoAAp47AAKePAACnj4AAp5AAAKeQQACnkIAAp5EAAKeRQACnoQAAp6GAAKeiAACnooAAp6NAAKejgACno8AAp6QAAKekQACnpMAAp6VAAKelgACnpcAAp6ZAAKemgACnr8AAp7jAAKfCgACny4AAp8xAAKfMwACnzUAAp83AAKfOQACnzsAAp88AAKfPwACn0wAAp9bAAKfXQACn18AAp9hAAKfYwACn2UAAp9nAAKfaQACn3gAAp97AAKffgACn4EAAp+EAAKfhwACn4oAAp+NAAKfjwACn84AAp/QAAKf0gACn9QAAp/XAAKf2AACn9kAAp/aAAKf2wACn90AAp/fAAKf4AACn+EAAp/jAAKf5AACoCMAAqAlAAKgJwACoCkAAqAsAAKgLQACoC4AAqAvAAKgMAACoDIAAqA0AAKgNQACoDYAAqA4AAKgOQACoHgAAqB6AAKgfAACoH4AAqCBAAKgggACoIMAAqCEAAKghQACoIcAAqCJAAKgigACoIsAAqCNAAKgjgACoM0AAqDPAAKg0QACoNMAAqDWAAKg1wACoNgAAqDZAAKg2gACoNwAAqDeAAKg3wACoOAAAqDiAAKg4wACoSIAAqEkAAKhJgACoSgAAqErAAKhLAACoS0AAqEuAAKhLwACoTEAAqEzAAKhNAACoTUAAqE3AAKhOAACoXcAAqF5AAKhewACoX0AAqGAAAKhgQACoYIAAqGDAAKhhAACoYYAAqGIAAKhiQACoYoAAqGMAAKhjQACocwAAqHOAAKh0AACodIAAqHVAAKh1gACodcAAqHYAAKh2QACodsAAqHdAAKh3gACod8AAqHhAAKh4gACoi0AAqJQAAKicAACopAAAqKSAAKilAACopYAAqKYAAKimwACopwAAqKdAAKioAACoqEAAqKjAAKipAACoqYAAqKpAAKiqgACoqsAAqKuAAKirwACorQAAqLBAAKixgACosgAAqLKAAKizwACotIAAqLVAAKi1wACovwAAqMgAAKjRwACo2sAAqNuAAKjcAACo3IAAqN0AAKjdgACo3gAAqN5AAKjfAACo4kAAqOaAAKjnAACo54AAqOgAAKjogACo6QAAqOmAAKjqAACo6oAAqO7AAKjvgACo8EAAqPEAAKjxwACo8oAAqPNAAKj0AACo9MAAqPVAAKkFAACpBYAAqQYAAKkGgACpB0AAqQeAAKkHwACpCAAAqQhAAKkIwACpCUAAqQmAAKkJwACpCkAAqQqAAKkaQACpGsAAqRtAAKkbwACpHIAAqRzAAKkdAACpHUAAqR2AAKkeAACpHoAAqR7AAKkfAACpH4AAqR/AAKkvgACpMAAAqTDAAKkxQACpMgAAqTJAAKkygACpMsAAqTMAAKkzgACpNAAAqTRAAKk0gACpNQAAqTVAAKk4gACpOMAAqTkAAKk5gACpSUAAqUnAAKlKQACpSsAAqUuAAKlLwACpTAAAqUxAAKlMgACpTQAAqU2AAKlNwACpTgAAqU6AAKlOwACpXoAAqV8AAKlfgACpYAAAqWDAAKlhAACpYUAAqWGAAKlhwACpYkAAqWLAAKljAACpY0AAqWPAAKlkAACpc8AAqXRAAKl0wACpdUAAqXYAAKl2QACpdoAAqXbAAKl3AACpd4AAqXgAAKl4QACpeIAAqXkAAKl5QACpiQAAqYmAAKmKAACpioAAqYtAAKmLgACpi8AAqYwAAKmMQACpjMAAqY1AAKmNgACpjcAAqY5AAKmOgACpnkAAqZ7AAKmfQACpn8AAqaCAAKmgwACpoQAAqaFAAKmhgACpogAAqaKAAKmiwACpowAAqaOAAKmjwACprQAAqbYAAKm/wACpyMAAqcmAAKnKAACpyoAAqcsAAKnLgACpzAAAqcxAAKnNAACp0EAAqdQAAKnUgACp1QAAqdWAAKnWAACp1oAAqdcAAKnXgACp20AAqdwAAKncwACp3YAAqd5AAKnfAACp38AAqeCAAKnhAACp8MAAqfFAAKnxwACp8kAAqfMAAKnzQACp84AAqfPAAKn0AACp9IAAqfUAAKn1QACp9YAAqfYAAKn2QACqBgAAqgaAAKoHAACqB4AAqghAAKoIgACqCMAAqgkAAKoJQACqCcAAqgpAAKoKgACqCsAAqgtAAKoLgACqG0AAqhvAAKocQACqHMAAqh2AAKodwACqHgAAqh5AAKoegACqHwAAqh+AAKofwACqIAAAqiCAAKogwACqMIAAqjEAAKoxwACqMkAAqjMAAKozQACqM4AAqjPAAKo0AACqNIAAqjUAAKo1QACqNYAAqjYAAKo2QACqNsAAqkaAAKpHAACqR4AAqkgAAKpIwACqSQAAqklAAKpJgACqScAAqkpAAKpKwACqSwAAqktAAKpLwACqTAAAqlvAAKpcQACqXMAAql1AAKpeAACqXkAAql6AAKpewACqXwAAql+AAKpgAACqYEAAqmCAAKphAACqYUAAqnEAAKpxgACqcgAAqnKAAKpzQACqc4AAqnPAAKp0AACqdEAAqnTAAKp1QACqdYAAqnXAAKp2QACqdoAAqnjAAKp5AACqeYAAqolAAKqJwACqikAAqorAAKqLgACqi8AAqowAAKqMQACqjIAAqo0AAKqNgACqjcAAqo4AAKqOgACqjsAAqp6AAKqfAACqn4AAqqAAAKqgwACqoQAAqqFAAKqhgACqocAAqqJAAKqiwACqowAAqqNAAKqjwACqpAAAqrPAAKq0QACqtMAAqrVAAKq2AACqtkAAqraAAKq2wACqtwAAqreAAKq4AACquEAAqriAAKq5AACquUAAqskAAKrJgACqygAAqsqAAKrLQACqy4AAqsvAAKrMAACqzEAAqszAAKrNQACqzYAAqs3AAKrOQACqzoAAqt5AAKrewACq30AAqt/AAKrggACq4MAAquEAAKrhQACq4YAAquIAAKrigACq4sAAquMAAKrjgACq48AAqvaAAKr/QACrB0AAqw9AAKsPwACrEEAAqxDAAKsRQACrEgAAqxJAAKsSgACrE0AAqxOAAKsUAACrFEAAqxTAAKsVgACrFcAAqxYAAKsWwACrFwAAqxhAAKsbgACrHMAAqx1AAKsdwACrHwAAqx/AAKsggACrIQAAqypAAKszQACrPQAAq0YAAKtGwACrR0AAq0fAAKtIQACrSMAAq0lAAKtJgACrSkAAq02AAKtRwACrUkAAq1LAAKtTQACrU8AAq1RAAKtUwACrVUAAq1XAAKtaAACrWsAAq1uAAKtcQACrXQAAq13AAKtegACrX0AAq2AAAKtggACrcEAAq3DAAKtxQACrccAAq3KAAKtywACrcwAAq3NAAKtzgACrdAAAq3SAAKt0wACrdQAAq3WAAKt1wACrhYAAq4YAAKuGgACrhwAAq4fAAKuIAACriEAAq4iAAKuIwACriUAAq4nAAKuKAACrikAAq4rAAKuLAACrmsAAq5tAAKucAACrnIAAq51AAKudgACrncAAq54AAKueQACrnsAAq59AAKufgACrn8AAq6BAAKuggACro8AAq6QAAKukQACrpMAAq7SAAKu1AACrtYAAq7YAAKu2wACrtwAAq7dAAKu3gACrt8AAq7hAAKu4wACruQAAq7lAAKu5wACrugAAq8nAAKvKQACrysAAq8tAAKvMAACrzEAAq8yAAKvMwACrzQAAq82AAKvOAACrzkAAq86AAKvPAACrz0AAq98AAKvfgACr4AAAq+CAAKvhQACr4YAAq+HAAKviAACr4kAAq+LAAKvjQACr44AAq+PAAKvkQACr5IAAq/RAAKv0wACr9UAAq/XAAKv2gACr9sAAq/cAAKv3QACr94AAq/gAAKv4gACr+MAAq/kAAKv5gACr+cAArAmAAKwKAACsCoAArAsAAKwLwACsDAAArAxAAKwMgACsDMAArA1AAKwNwACsDgAArA5AAKwOwACsDwAArBhAAKwhQACsKwAArDQAAKw0wACsNUAArDXAAKw2QACsNsAArDdAAKw3gACsOEAArDuAAKw/QACsP8AArEBAAKxAwACsQUAArEHAAKxCQACsQsAArEaAAKxHQACsSAAArEjAAKxJgACsSkAArEsAAKxLwACsTEAArFwAAKxcgACsXQAArF2AAKxeQACsXoAArF7AAKxfAACsX0AArF/AAKxgQACsYIAArGDAAKxhQACsYYAArHFAAKxxwACsckAArHLAAKxzgACsc8AArHQAAKx0QACsdIAArHUAAKx1gACsdcAArHYAAKx2gACsdsAArIaAAKyHAACsh4AArIgAAKyIwACsiQAArIlAAKyJgACsicAArIpAAKyKwACsiwAArItAAKyLwACsjAAArJvAAKycQACsnMAArJ1AAKyeAACsnkAArJ6AAKyewACsnwAArJ+AAKygAACsoEAArKCAAKyhAACsoUAArLEAAKyxgACssgAArLKAAKyzQACss4AArLPAAKy0AACstEAArLTAAKy1QACstYAArLXAAKy2QACstoAArMZAAKzGwACsx0AArMfAAKzIgACsyMAArMkAAKzJQACsyYAArMoAAKzKgACsysAArMsAAKzLgACsy8AArNuAAKzcAACs3IAArN0AAKzdwACs3gAArN5AAKzegACs3sAArN9AAKzfwACs4AAArOBAAKzgwACs4QAArONAAKzjgACs5AAArPTAAKz9wACtBsAArQ+AAK0ZQACtIUAArSsAAK00wACtPMAArUXAAK1OwACtT0AArVAAAK1QgACtUQAArVGAAK1SQACtUwAArVOAAK1UAACtVMAArVVAAK1VwACtVoAArVdAAK1XgACtWMAArVwAAK1cwACtXUAArV4AAK1ewACtX0AArWiAAK1xgACte0AArYRAAK2FAACthYAArYYAAK2GgACthwAArYeAAK2HwACtiIAArYvAAK2QgACtkQAArZGAAK2SAACtkoAArZMAAK2TgACtlAAArZSAAK2VAACtmcAArZqAAK2bQACtnAAArZzAAK2dgACtnkAArZ8AAK2fwACtoIAAraEAAK2wwACtsUAArbIAAK2ygACts0AArbOAAK2zwACttAAArbRAAK20wACttUAArbWAAK21wACttkAArbaAAK24wACtuQAArbmAAK3JQACtycAArcpAAK3KwACty4AArcvAAK3MAACtzEAArcyAAK3NAACtzYAArc3AAK3OAACtzoAArc7AAK3egACt3wAArd/AAK3gQACt4QAAreFAAK3hgACt4cAAreIAAK3igACt4wAAreNAAK3jgACt5AAAreRAAK3mgACt5sAAredAAK33AACt94AArfgAAK34gACt+UAArfmAAK35wACt+gAArfpAAK36wACt+0AArfuAAK37wACt/EAArfyAAK4MQACuDMAArg2AAK4OAACuDsAArg8AAK4PQACuD4AArg/AAK4QQACuEMAArhEAAK4RQACuEcAArhIAAK4UQACuFIAArhUAAK4kwACuJUAAriXAAK4mQACuJwAAridAAK4ngACuJ8AArigAAK4ogACuKQAArilAAK4pgACuKgAAripAAK46AACuOoAArjtAAK47wACuPIAArjzAAK49AACuPUAArj2AAK4+AACuPoAArj7AAK4/AACuP4AArj/AAK5DAACuQ0AArkOAAK5EAACuU8AArlRAAK5UwACuVUAArlYAAK5WQACuVoAArlbAAK5XAACuV4AArlgAAK5YQACuWIAArlkAAK5ZQACuaQAArmmAAK5qQACuasAArmuAAK5rwACubAAArmxAAK5sgACubQAArm2AAK5twACubgAArm6AAK5uwACuccAArnUAAK52QACudwAArnfAAK55AACuecAArnqAAK57AACufIAArn9AAK6SAACumsAArqLAAK6qwACuq0AArqvAAK6sQACurMAArq2AAK6twACurgAArq7AAK6vAACur4AArq/AAK6wQACusQAArrFAAK6xgACuskAArrKAAK6zwACutwAArrhAAK64wACuuUAArrqAAK67QACuvAAArryAAK7FwACuzsAArtiAAK7hgACu4kAAruLAAK7jQACu48AAruRAAK7kwACu5QAAruXAAK7pAACu7UAAru3AAK7uQACu7sAAru9AAK7vwACu8EAArvDAAK7xQACu9YAArvZAAK73AACu98AArviAAK75QACu+gAArvrAAK77gACu/AAArwvAAK8MQACvDMAArw1AAK8OAACvDkAArw6AAK8OwACvDwAArw+AAK8QAACvEEAArxCAAK8RAACvEUAAryEAAK8hgACvIgAAryKAAK8jQACvI4AAryPAAK8kAACvJEAAryTAAK8lQACvJYAAryXAAK8mQACvJoAArzZAAK82wACvN4AArzgAAK84wACvOQAArzlAAK85gACvOcAArzpAAK86wACvOwAArztAAK87wACvPAAArz9AAK8/gACvP8AAr0BAAK9QAACvUIAAr1EAAK9RgACvUkAAr1KAAK9SwACvUwAAr1NAAK9TwACvVEAAr1SAAK9UwACvVUAAr1WAAK9lQACvZcAAr2ZAAK9mwACvZ4AAr2fAAK9oAACvaEAAr2iAAK9pAACvaYAAr2nAAK9qAACvaoAAr2rAAK96gACvewAAr3uAAK98AACvfMAAr30AAK99QACvfYAAr33AAK9+QACvfsAAr38AAK9/QACvf8AAr4AAAK+PwACvkEAAr5DAAK+RQACvkgAAr5JAAK+SgACvksAAr5MAAK+TgACvlAAAr5RAAK+UgACvlQAAr5VAAK+lAACvpYAAr6YAAK+mgACvp0AAr6eAAK+nwACvqAAAr6hAAK+owACvqUAAr6mAAK+pwACvqkAAr6qAAK+zwACvvMAAr8aAAK/PgACv0EAAr9DAAK/RQACv0cAAr9JAAK/SwACv0wAAr9PAAK/XAACv2sAAr9tAAK/bwACv3EAAr9zAAK/dQACv3cAAr95AAK/iAACv4sAAr+OAAK/kQACv5QAAr+XAAK/mgACv50AAr+fAAK/3gACv+AAAr/iAAK/5AACv+cAAr/oAAK/6QACv+oAAr/rAAK/7QACv+8AAr/wAAK/8QACv/MAAr/0AALAMwACwDUAAsA3AALAOQACwDwAAsA9AALAPgACwD8AAsBAAALAQgACwEQAAsBFAALARgACwEgAAsBJAALAiAACwIoAAsCMAALAjgACwJEAAsCSAALAkwACwJQAAsCVAALAlwACwJkAAsCaAALAmwACwJ0AAsCeAALA3QACwN8AAsDhAALA4wACwOYAAsDnAALA6AACwOkAAsDqAALA7AACwO4AAsDvAALA8AACwPIAAsDzAALBMgACwTQAAsE2AALBOAACwTsAAsE8AALBPQACwT4AAsE/AALBQQACwUMAAsFEAALBRQACwUcAAsFIAALBhwACwYkAAsGLAALBjQACwZAAAsGRAALBkgACwZMAAsGUAALBlgACwZgAAsGZAALBmgACwZwAAsGdAALB3AACwd4AAsHgAALB4gACweUAAsHmAALB5wACwegAAsHpAALB6wACwe0AAsHuAALB7wACwfEAAsHyAALCPQACwmAAAsKAAALCoAACwqIAAsKkAALCpgACwqgAAsKrAALCrAACwq0AAsKwAALCsQACwrMAAsK0AALCtgACwrkAAsK6AALCuwACwr4AAsK/AALCxAACwtEAAsLWAALC2AACwtoAAsLfAALC4gACwuUAAsLnAALDDAACwzAAAsNXAALDewACw34AAsOAAALDggACw4QAAsOGAALDiAACw4kAAsOMAALDmQACw6oAAsOsAALDrgACw7AAAsOyAALDtAACw7YAAsO4AALDugACw8sAAsPOAALD0QACw9QAAsPXAALD2gACw90AAsPgAALD4wACw+UAAsQkAALEJgACxCgAAsQqAALELQACxC4AAsQvAALEMAACxDEAAsQzAALENQACxDYAAsQ3AALEOQACxDoAAsR5AALEewACxH0AAsR/AALEggACxIMAAsSEAALEhQACxIYAAsSIAALEigACxIsAAsSMAALEjgACxI8AAsTOAALE0AACxNMAAsTVAALE2AACxNkAAsTaAALE2wACxNwAAsTeAALE4AACxOEAAsTiAALE5AACxOUAAsTyAALE8wACxPQAAsT2AALFNQACxTcAAsU5AALFOwACxT4AAsU/AALFQAACxUEAAsVCAALFRAACxUYAAsVHAALFSAACxUoAAsVLAALFigACxYwAAsWOAALFkAACxZMAAsWUAALFlQACxZYAAsWXAALFmQACxZsAAsWcAALFnQACxZ8AAsWgAALF3wACxeEAAsXjAALF5QACxegAAsXpAALF6gACxesAAsXsAALF7gACxfAAAsXxAALF8gACxfQAAsX1AALGNAACxjYAAsY4AALGOgACxj0AAsY+AALGPwACxkAAAsZBAALGQwACxkUAAsZGAALGRwACxkkAAsZKAALGiQACxosAAsaNAALGjwACxpIAAsaTAALGlAACxpUAAsaWAALGmAACxpoAAsabAALGnAACxp4AAsafAALGxAACxugAAscPAALHMwACxzYAAsc4AALHOgACxzwAAsc+AALHQAACx0EAAsdEAALHUQACx2AAAsdiAALHZAACx2YAAsdoAALHagACx2wAAsduAALHfQACx4AAAseDAALHhgACx4kAAseMAALHjwACx5IAAseUAALH0wACx9UAAsfXAALH2QACx9wAAsfdAALH3gACx98AAsfgAALH4gACx+QAAsflAALH5gACx+gAAsfpAALIKAACyCoAAsgsAALILgACyDEAAsgyAALIMwACyDQAAsg1AALINwACyDkAAsg6AALIOwACyD0AAsg+AALIfQACyH8AAsiBAALIgwACyIYAAsiHAALIiAACyIkAAsiKAALIjAACyI4AAsiPAALIkAACyJIAAsiTAALI0gACyNQAAsjWAALI2AACyNsAAsjcAALI3QACyN4AAsjfAALI4QACyOMAAsjkAALI5QACyOcAAsjoAALJJwACySkAAskrAALJLQACyTAAAskxAALJMgACyTMAAsk0AALJNgACyTgAAsk5AALJOgACyTwAAsk9AALJfAACyX4AAsmAAALJggACyYUAAsmGAALJhwACyYgAAsmJAALJiwACyY0AAsmOAALJjwACyZEAAsmSAALJ0QACydMAAsnVAALJ1wACydoAAsnbAALJ3AACyd0AAsneAALJ4AACyeIAAsnjAALJ5AACyeYAAsnnAALJ8AACyfEAAsnzAALKNgACyloAAsp+AALKoQACysgAAsroAALLDwACyzYAAstWAALLegACy54AAsugAALLowACy6UAAsunAALLqQACy6wAAsuvAALLsQACy7MAAsu2AALLuAACy7oAAsu9AALLwAACy8EAAsvGAALL0wACy9YAAsvYAALL2wACy94AAsvgAALMBQACzCkAAsxQAALMdAACzHcAAsx5AALMewACzH0AAsx/AALMgQACzIIAAsyFAALMkgACzKUAAsynAALMqQACzKsAAsytAALMrwACzLEAAsyzAALMtQACzLcAAszKAALMzQACzNAAAszTAALM1gACzNkAAszcAALM3wACzOIAAszlAALM5wACzSYAAs0oAALNKwACzS0AAs0wAALNMQACzTIAAs0zAALNNAACzTYAAs04AALNOQACzToAAs08AALNPQACzUYAAs1HAALNSQACzYgAAs2KAALNjAACzY4AAs2RAALNkgACzZMAAs2UAALNlQACzZcAAs2ZAALNmgACzZsAAs2dAALNngACzd0AAs3fAALN4gACzeQAAs3nAALN6AACzekAAs3qAALN6wACze0AAs3vAALN8AACzfEAAs3zAALN9AACzf0AAs3+AALOAAACzj8AAs5BAALOQwACzkUAAs5IAALOSQACzkoAAs5LAALOTAACzk4AAs5QAALOUQACzlIAAs5UAALOVQACzpQAAs6WAALOmQACzpsAAs6eAALOnwACzqAAAs6hAALOogACzqQAAs6mAALOpwACzqgAAs6qAALOqwACzrQAAs61AALOtwACzvYAAs74AALO+gACzvwAAs7/AALPAAACzwEAAs8CAALPAwACzwUAAs8HAALPCAACzwkAAs8LAALPDAACz0sAAs9NAALPUAACz1IAAs9VAALPVgACz1cAAs9YAALPWQACz1sAAs9dAALPXgACz18AAs9hAALPYgACz28AAs9wAALPcQACz3MAAs+yAALPtAACz7YAAs+4AALPuwACz7wAAs+9AALPvgACz78AAs/B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AALbLAAC22sAAtttAALbcAAC23IAAtt1AALbdgAC23cAAtt4AALbeQAC23sAAtt9AALbfgAC238AAtuBAALbggAC248AAtuQAALbkQAC25MAAtvSAALb1AAC29YAAtvYAALb2wAC29wAAtvdAALb3gAC298AAtvhAALb4wAC2+QAAtvlAALb5wAC2+gAAtwnAALcKQAC3CsAAtwtAALcMAAC3DEAAtwyAALcMwAC3DQAAtw2AALcOAAC3DkAAtw6AALcPAAC3D0AAtx8AALcfgAC3IAAAtyCAALchQAC3IYAAtyHAALciAAC3IkAAtyLAALcjQAC3I4AAtyPAALckQAC3JIAAtzRAALc0wAC3NUAAtzXAALc2gAC3NsAAtzcAALc3QAC3N4AAtzgAALc4gAC3OMAAtzkAALc5gAC3OcAAt0mAALdKAAC3SoAAt0sAALdLwAC3TAAAt0xAALdMgAC3TMAAt01AALdNwAC3TgAAt05AALdOwAC3TwAAt1hAALdhQAC3awAAt3QAALd0wAC3dUAAt3XAALd2QAC3dsAAt3dAALd3gAC3eEAAt3uAALd/QAC3f8AAt4BAALeAwAC3gUAAt4HAALeCQAC3gsAAt4aAALeHQAC3iAAAt4jAALeJgAC3ikAAt4sAALeLwAC3jEAAt5wAALecgAC3nQAAt52AALeeQAC3noAAt57AALefAAC3n0AAt5/AALegQAC3oIAAt6DAALehQAC3oYAAt7FAALexwAC3skAAt7LAALezgAC3s8AAt7QAALe0QAC3tIAAt7UAALe1gAC3tcAAt7YAALe2gAC3tsAAt8aAALfHAAC3x4AAt8gAALfIwAC3yQAAt8lAALfJgAC3ycAAt8pAALfKwAC3ywAAt8tAALfLwAC3zAAAt9vAALfcQAC33QAAt92AALfeQAC33oAAt97AALffAAC330AAt9/AALfgQAC34IAAt+DAALfhQAC34YAAt/FAALfxwAC38kAAt/LAALfzgAC388AAt/QAALf0QAC39IAAt/UAALf1gAC39cAAt/YAALf2gAC39sAAuAaAALgHAAC4B4AAuAgAALgIwAC4CQAAuAlAALgJgAC4CcAAuApAALgKwAC4CwAAuAtAALgLwAC4DAAAuBvAALgcQAC4HMAAuB1AALgeAAC4HkAAuB6AALgewAC4HwAAuB+AALggAAC4IEAAuCCAALghAAC4IUAAuDQAALg8wAC4RMAAuEzAALhNQAC4TcAAuE5AALhOwAC4T4AAuE/AALhQAAC4UMAAuFEAALhRgAC4UcAAuFJAALhTAAC4U0AAuFOAALhUQAC4VIAAuFXAALhZAAC4WkAAuFrAALhbQAC4XIAAuF1AALheAAC4XoAAuGfAALhwwAC4eoAAuIOAALiEQAC4hMAAuIVAALiFwAC4hkAAuIbAALiHAAC4h8AAuIsAALiPQAC4j8AAuJBAALiQwAC4kUAAuJHAALiSQAC4ksAAuJNAALiXgAC4mEAAuJkAALiZwAC4moAAuJtAALicAAC4nMAAuJ2AALieAAC4rcAAuK5AALiuwAC4r0AAuLAAALiwQAC4sIAAuLDAALixAAC4sYAAuLIAALiyQAC4soAAuLMAALizQAC4wwAAuMOAALjEAAC4xIAAuMVAALjFgAC4xcAAuMYAALjGQAC4xsAAuMdAALjHgAC4x8AAuMhAALjIgAC42EAAuNjAALjZgAC42gAAuNrAALjbAAC420AAuNuAALjbwAC43EAAuNzAALjdAAC43UAAuN3AALjeAAC44UAAuOGAALjhwAC44kAAuPIAALjygAC48wAAuPOAALj0QAC49IAAuPTAALj1AAC49UAAuPXAALj2QAC49oAAuPbAALj3QAC494AAuQdAALkHwAC5CEAAuQjAALkJgAC5CcAAuQoAALkKQAC5CoAAuQsAALkLgAC5C8AAuQwAALkMgAC5DMAAuRyAALkdAAC5HYAAuR4AALkewAC5HwAAuR9AALkfgAC5H8AAuSBAALkgwAC5IQAAuSFAALkhwAC5IgAAuTHAALkyQAC5MsAAuTNAALk0AAC5NEAAuTSAALk0wAC5NQAAuTWAALk2AAC5NkAAuTaAALk3AAC5N0AAuUcAALlHgAC5SAAAuUiAALlJQAC5SYAAuUnAALlKAAC5SkAAuUrAALlLQAC5S4AAuUvAALlMQAC5TIAAuVXAALlewAC5aIAAuXGAALlyQAC5csAAuXNAALlzwAC5dEAAuXTAALl1AAC5dcAAuXkAALl8wAC5fUAAuX3AALl+QAC5fsAAuX9AALl/wAC5gEAAuYQAALmEwAC5hYAAuYZAALmHAAC5h8AAuYiAALmJQAC5icAAuZmAALmaAAC5moAAuZsAALmbwAC5nAAAuZxAALmcgAC5nMAAuZ1AALmdwAC5ngAAuZ5AALmewAC5nwAAua7AALmvQAC5r8AAubBAALmxAAC5sUAAubGAALmxwAC5sgAAubKAALmzAAC5s0AAubOAALm0AAC5tEAAucQAALnEgAC5xQAAucWAALnGQAC5xoAAucbAALnHAAC5x0AAucfAALnIQAC5yIAAucjAALnJQAC5yYAAudlAALnZwAC52kAAudrAALnbgAC528AAudwAALncQAC53IAAud0AALndgAC53cAAud4AALnegAC53sAAue6AALnvAAC574AAufAAALnwwAC58QAAufFAALnxgAC58cAAufJAALnywAC58wAAufNAALnzwAC59AAAugPAALoEQAC6BMAAugVAALoGAAC6BkAAugaAALoGwAC6BwAAugeAALoIAAC6CEAAugiAALoJAAC6CUAAuhkAALoZgAC6GgAAuhqAALobQAC6G4AAuhvAALocAAC6HEAAuhzAALodQAC6HYAAuh3AALoeQAC6HoAAujFAALo6AAC6QgAAukoAALpKgAC6SwAAukuAALpMAAC6TMAAuk0AALpNQAC6TgAAuk5AALpOwAC6TwAAuk+AALpQQAC6UIAAulDAALpRgAC6UcAAulMAALpWQAC6V4AAulgAALpYgAC6WcAAulqAALpbQAC6W8AAumUAALpuAAC6d8AAuoDAALqBgAC6ggAAuoKAALqDAAC6g4AAuoQAALqEQAC6hQAAuohAALqMgAC6jQAAuo2AALqOAAC6joAAuo8AALqPgAC6kAAAupCAALqUwAC6lYAAupZAALqXAAC6l8AAupiAALqZQAC6mgAAuprAALqbQAC6qwAAuquAALqsAAC6rIAAuq1AALqtgAC6rcAAuq4AALquQAC6rsAAuq9AALqvgAC6r8AAurBAALqwgAC6wEAAusDAALrBQAC6wcAAusKAALrCwAC6wwAAusNAALrDgAC6xAAAusSAALrEwAC6xQAAusWAALrFwAC61YAAutYAALrWwAC610AAutgAALrYQAC62IAAutjAALrZAAC62YAAutoAALraQAC62oAAutsAALrbQAC63oAAut7AALrfAAC634AAuu9AALrvwAC68EAAuvDAALrxgAC68cAAuvIAALryQAC68oAAuvMAALrzgAC688AAuvQAALr0gAC69MAAuwSAALsFAAC7BYAAuwYAALsGwAC7BwAAuwdAALsHgAC7B8AAuwhAALsIwAC7CQAAuwlAALsJwAC7CgAAuxnAALsaQAC7GsAAuxtAALscAAC7HEAAuxyAALscwAC7HQAAux2AALseAAC7HkAAux6AALsfAAC7H0AAuy8AALsvgAC7MAAAuzCAALsxQAC7MYAAuzHAALsyAAC7MkAAuzLAALszQAC7M4AAuzPAALs0QAC7NIAAu0RAALtEwAC7RUAAu0XAALtGgAC7RsAAu0cAALtHQAC7R4AAu0gAALtIgAC7SMAAu0kAALtJgAC7ScAAu1MAALtcAAC7ZcAAu27AALtvgAC7cAAAu3CAALtxAAC7cYAAu3IAALtyQAC7cwAAu3ZAALt6AAC7eoAAu3sAALt7gAC7fAAAu3yAALt9AAC7fYAAu4FAALuCAAC7gsAAu4OAALuEQAC7hQAAu4XAALuGgAC7hwAAu5bAALuXQAC7l8AAu5hAALuZAAC7mUAAu5mAALuZwAC7mgAAu5qAALubAAC7m0AAu5uAALucAAC7nEAAu6wAALusgAC7rQAAu62AALuuQAC7roAAu67AALuvAAC7r0AAu6/AALuwQAC7sIAAu7DAALuxQAC7sYAAu8FAALvBwAC7wkAAu8LAALvDgAC7w8AAu8QAALvEQAC7xIAAu8UAALvFgAC7xcAAu8YAALvGgAC7xsAAu9aAALvXAAC718AAu9hAALvZAAC72UAAu9mAALvZwAC72gAAu9qAALvbAAC720AAu9uAALvcAAC73EAAu+wAALvsgAC77QAAu+2AALvuQAC77oAAu+7AALvvAAC770AAu+/AALvwQAC78IAAu/DAALvxQAC78YAAvAFAALwBwAC8AkAAvALAALwDgAC8A8AAvAQAALwEQAC8BIAAvAUAALwFgAC8BcAAvAYAALwGgAC8BsAAvBaAALwXAAC8F4AAvBgAALwYwAC8GQAAvBlAALwZgAC8GcAAvBpAALwawAC8GwAAvBtAALwbwAC8HAAAvC7AALw3gAC8P4AAvEeAALxIAAC8SIAAvEkAALxJgAC8SkAAvEqAALxKwAC8S4AAvEvAALxMQAC8TIAAvE0AALxNwAC8TgAAvE5AALxPAAC8T0AAvFCAALxTwAC8VQAAvFWAALxWAAC8V0AAvFgAALxYwAC8WUAAvGKAALxrgAC8dUAAvH5AALx/AAC8f4AAvIAAALyAgAC8gQAAvIGAALyBwAC8goAAvIXAALyKAAC8ioAAvIsAALyLgAC8jAAAvIyAALyNAAC8jYAAvI4AALySQAC8kwAAvJPAALyUgAC8lUAAvJYAALyWwAC8l4AAvJhAALyYwAC8qIAAvKkAALypgAC8qgAAvKrAALyrAAC8q0AAvKuAALyrwAC8rEAAvKzAALytAAC8rUAAvK3AALyuAAC8vcAAvL5AALy+wAC8v0AAvMAAALzAQAC8wIAAvMDAALzBAAC8wYAAvMIAALzCQAC8woAAvMMAALzDQAC80wAAvNOAALzUQAC81MAAvNWAALzVwAC81gAAvNZAALzWgAC81wAAvNeAALzXwAC82AAAvNiAALzYwAC83AAAvNxAALzcgAC83QAAvOzAALztQAC87cAAvO5AALzvAAC870AAvO+AALzvwAC88AAAvPCAALzxAAC88UAAvPGAALzyAAC88kAAvQIAAL0CgAC9AwAAvQOAAL0EQAC9BIAAvQTAAL0FAAC9BUAAvQXAAL0GQAC9BoAAvQbAAL0HQAC9B4AAvRdAAL0XwAC9GEAAvRjAAL0ZgAC9GcAAvRoAAL0aQAC9GoAAvRsAAL0bgAC9G8AAvRwAAL0cgAC9HMAAvSyAAL0tAAC9LYAAvS4AAL0uwAC9LwAAvS9AAL0vgAC9L8AAvTBAAL0wwAC9MQAAvTFAAL0xwAC9MgAAvUHAAL1CQAC9QsAAvUNAAL1EAAC9REAAvUSAAL1EwAC9RQAAvUWAAL1GAAC9RkAAvUaAAL1HAAC9R0AAvVCAAL1ZgAC9Y0AAvWxAAL1tAAC9bYAAvW4AAL1ugAC9bwAAvW+AAL1vwAC9cIAAvXPAAL13gAC9eAAAvXiAAL15AAC9eYAAvXoAAL16gAC9ewAAvX7AAL1/gAC9gEAAvYEAAL2BwAC9goAAvYNAAL2EAAC9hIAAvZRAAL2UwAC9lUAAvZXAAL2WgAC9lsAAvZcAAL2XQAC9l4AAvZgAAL2YgAC9mMAAvZkAAL2ZgAC9mcAAvamAAL2qAAC9qoAAvasAAL2rwAC9rAAAvaxAAL2sgAC9rMAAva1AAL2twAC9rgAAva5AAL2uwAC9rwAAvb7AAL2/QAC9v8AAvcBAAL3BAAC9wUAAvcGAAL3BwAC9wgAAvcKAAL3DAAC9w0AAvcOAAL3EAAC9xEAAvdQAAL3UgAC91UAAvdXAAL3WgAC91sAAvdcAAL3XQAC914AAvdgAAL3YgAC92MAAvdkAAL3ZgAC92cAAvemAAL3qAAC96oAAvesAAL3rwAC97AAAvexAAL3sgAC97MAAve1AAL3twAC97gAAve5AAL3uwAC97wAAvf7AAL3/QAC9/8AAvgBAAL4BAAC+AUAAvgGAAL4BwAC+AgAAvgKAAL4DAAC+A0AAvgOAAL4EAAC+BEAAvhQAAL4UgAC+FQAAvhWAAL4WQAC+FoAAvhbAAL4XAAC+F0AAvhfAAL4YQAC+GIAAvhjAAL4ZQAC+GYAAvhvAAL4cAAC+HIAAvi1AAL42QAC+P0AAvkgAAL5RwAC+WcAAvmOAAL5tQAC+dUAAvn5AAL6HQAC+h8AAvoiAAL6JAAC+iYAAvooAAL6KwAC+i4AAvowAAL6MgAC+jUAAvo3AAL6OQAC+jwAAvo/AAL6QAAC+kUAAvpSAAL6VQAC+lcAAvpaAAL6XQAC+l8AAvqEAAL6qAAC+s8AAvrzAAL69gAC+vgAAvr6AAL6/AAC+v4AAvsAAAL7AQAC+wQAAvsRAAL7JAAC+yYAAvsoAAL7KgAC+ywAAvsuAAL7MAAC+zIAAvs0AAL7NgAC+0kAAvtMAAL7TwAC+1IAAvtVAAL7WAAC+1sAAvteAAL7YQAC+2QAAvtmAAL7pQAC+6cAAvuqAAL7rAAC+68AAvuwAAL7sQAC+7IAAvuzAAL7tQAC+7cAAvu4AAL7uQAC+7sAAvu8AAL7xQAC+8YAAvvIAAL8BwAC/AkAAvwLAAL8DQAC/BAAAvwRAAL8EgAC/BMAAvwUAAL8FgAC/BgAAvwZAAL8GgAC/BwAAvwdAAL8XAAC/F4AAvxhAAL8YwAC/GYAAvxnAAL8aAAC/GkAAvxqAAL8bAAC/G4AAvxvAAL8cAAC/HIAAvxzAAL8fAAC/H0AAvx/AAL8vgAC/MAAAvzCAAL8xAAC/McAAvzIAAL8yQAC/MoAAvzLAAL8zQAC/M8AAvzQAAL80QAC/NMAAvzUAAL9EwAC/RUAAv0YAAL9GgAC/R0AAv0eAAL9HwAC/SAAAv0hAAL9IwAC/SUAAv0mAAL9JwAC/SkAAv0qAAL9MwAC/TQAAv02AAL9dQAC/XcAAv15AAL9ewAC/X4AAv1/AAL9gAAC/YEAAv2CAAL9hAAC/YYAAv2HAAL9iAAC/YoAAv2LAAL9ygAC/cwAAv3PAAL90QAC/dQAAv3VAAL91gAC/dcAAv3YAAL92gAC/dwAAv3dAAL93gAC/eAAAv3hAAL97gAC/e8AAv3wAAL98gAC/jEAAv4zAAL+NQAC/jcAAv46AAL+OwAC/jwAAv49AAL+PgAC/kAAAv5CAAL+QwAC/kQAAv5GAAL+RwAC/oYAAv6IAAL+iwAC/o0AAv6QAAL+kQAC/pIAAv6TAAL+lAAC/pYAAv6YAAL+mQAC/poAAv6cAAL+nQAC/qgAAv61AAL+vgAC/sAAAv7CAAL+xQAC/sgAAv7RAAL+1AAC/tcAAv7aAAL+3QAC/t8AAv7nAAL+7wAC/zoAAv9dAAL/fQAC/50AAv+fAAL/oQAC/6MAAv+lAAL/qAAC/6kAAv+qAAL/rQAC/64AAv+wAAL/sQAC/7MAAv+1AAL/tgAC/7cAAv+6AAL/uwAC/8AAAv/NAAL/0gAC/9QAAv/WAAL/2wAC/94AAv/hAAL/4wADAAgAAwAsAAMAUwADAHcAAwB6AAMAfAADAH4AAwCAAAMAggADAIQAAwCFAAMAiAADAJUAAwCmAAMAqAADAKoAAwCsAAMArgADALAAAwCyAAMAtAADALYAAwDHAAMAygADAM0AAwDQAAMA0wADANYAAwDZAAMA3AADAN8AAwDhAAMBIAADASIAAwEkAAMBJgADASkAAwEqAAMBKwADASwAAwEtAAMBLwADATEAAwEyAAMBMwADATUAAwE2AAMBdQADAXcAAwF5AAMBewADAX4AAwF/AAMBgAADAYEAAwGCAAMBhAADAYYAAwGHAAMBiAADAYoAAwGLAAMBygADAcwAAwHPAAMB0QADAdQAAwHVAAMB1gADAdcAAwHYAAMB2gADAdwAAwHdAAMB3gADAeAAAwHhAAMB7gADAe8AAwHwAAMB8gADAjEAAwIzAAMCNQADAjcAAwI6AAMCOwADAjwAAwI9AAMCPgADAkAAAwJCAAMCQwADAkQAAwJGAAMCRwADAoYAAwKIAAMCigADAowAAwKPAAMCkAADApEAAwKSAAMCkwADApUAAwKXAAMCmAADApkAAwKbAAMCnAADAtsAAwLdAAMC3wADAuEAAwLkAAMC5QADAuYAAwLnAAMC6AADAuoAAwLsAAMC7QADAu4AAwLwAAMC8QADAzAAAwMyAAMDNAADAzYAAwM5AAMDOgADAzsAAwM8AAMDPQADAz8AAwNBAAMDQgADA0MAAwNFAAMDRgADA4UAAwOHAAMDiQADA4sAAwOOAAMDjwADA5AAAwORAAMDkgADA5QAAwOWAAMDlwADA5gAAwOaAAMDmwADA8AAAwPkAAMECwADBC8AAwQyAAMENAADBDYAAwQ4AAMEOgADBDwAAwQ9AAMEQAADBE0AAwRcAAMEXgADBGAAAwRiAAMEZAADBGYAAwRoAAMEagADBHkAAwR8AAMEfwADBIIAAwSFAAMEiAADBIsAAwSOAAMEkAADBM8AAwTRAAME0wADBNUAAwTYAAME2QADBNoAAwTbAAME3AADBN4AAwTgAAME4QADBOIAAwTkAAME5QADBSQAAwUmAAMFKAADBSoAAwUtAAMFLgADBS8AAwUwAAMFMQADBTMAAwU1AAMFNgADBTcAAwU5AAMFOgADBXkAAwV7AAMFfQADBX8AAwWCAAMFgwADBYQAAwWFAAMFhgADBYgAAwWKAAMFiwADBYwAAwWOAAMFjwADBc4AAwXQAAMF0gADBdQAAwXXAAMF2AADBdkAAwXaAAMF2wADBd0AAwXfAAMF4AADBeEAAwXjAAMF5AADBiMAAwYlAAMGJwADBikAAwYsAAMGLQADBi4AAwYvAAMGMAADBjIAAwY0AAMGNQADBjYAAwY4AAMGOQADBngAAwZ6AAMGfAADBn4AAwaBAAMGggADBoMAAwaEAAMGhQADBocAAwaJAAMGigADBosAAwaNAAMGjgADBs0AAwbPAAMG0QADBtMAAwbWAAMG1wADBtgAAwbZAAMG2gADBtwAAwbeAAMG3wADBuAAAwbiAAMG4wADBy4AAwdRAAMHcQADB5EAAweTAAMHlQADB5cAAweZAAMHnAADB50AAweeAAMHoQADB6IAAwekAAMHpQADB6cAAwepAAMHqgADB6sAAweuAAMHrwADB7QAAwfBAAMHxgADB8gAAwfKAAMHzwADB9IAAwfVAAMH1wADB/wAAwggAAMIRwADCGsAAwhuAAMIcAADCHIAAwh0AAMIdgADCHgAAwh5AAMIfAADCIkAAwiaAAMInAADCJ4AAwigAAMIogADCKQAAwimAAMIqAADCKoAAwi7AAMIvgADCMEAAwjEAAMIxwADCMoAAwjNAAMI0AADCNMAAwjVAAMJFAADCRYAAwkYAAMJGgADCR0AAwkeAAMJHwADCSAAAwkhAAMJIwADCSUAAwkmAAMJJwADCSkAAwkqAAMJaQADCWsAAwltAAMJbwADCXIAAwlzAAMJdAADCXUAAwl2AAMJeAADCXoAAwl7AAMJfAADCX4AAwl/AAMJvgADCcAAAwnDAAMJxQADCcgAAwnJAAMJygADCcsAAwnMAAMJzgADCdAAAwnRAAMJ0gADCdQAAwnVAAMJ4gADCeMAAwnkAAMJ5gADCiUAAwonAAMKKQADCisAAwouAAMKLwADCjAAAwoxAAMKMgADCjQAAwo2AAMKNwADCjgAAwo6AAMKOwADCnoAAwp8AAMKfgADCoAAAwqDAAMKhAADCoUAAwqGAAMKhwADCokAAwqLAAMKjAADCo0AAwqPAAMKkAADCs8AAwrRAAMK0wADCtUAAwrYAAMK2QADCtoAAwrbAAMK3AADCt4AAwrgAAMK4QADCuIAAwrkAAMK5QADCyQAAwsmAAMLKAADCyoAAwstAAMLLgADCy8AAwswAAMLMQADCzMAAws1AAMLNgADCzcAAws5AAMLOgADC3kAAwt7AAMLfQADC38AAwuCAAMLgwADC4QAAwuFAAMLhgADC4gAAwuKAAMLiwADC4wAAwuOAAMLjwADC7QAAwvYAAML/wADDCMAAwwmAAMMKAADDCoAAwwsAAMMLgADDDAAAwwxAAMMNAADDEEAAwxQAAMMUgADDFQAAwxWAAMMWAADDFoAAwxcAAMMXgADDG0AAwxwAAMMcwADDHYAAwx5AAMMfAADDH8AAwyCAAMMhAADDMMAAwzFAAMMxwADDMkAAwzMAAMMzQADDM4AAwzPAAMM0AADDNIAAwzUAAMM1QADDNYAAwzYAAMM2QADDRgAAw0aAAMNHAADDR4AAw0hAAMNIgADDSMAAw0kAAMNJQADDScAAw0pAAMNKgADDSsAAw0tAAMNLgADDW0AAw1vAAMNcQADDXMAAw12AAMNdwADDXgAAw15AAMNegADDXwAAw1+AAMNfwADDYAAAw2CAAMNgwADDcIAAw3EAAMNxgADDcgAAw3LAAMNzAADDc0AAw3OAAMNzwADDdEAAw3TAAMN1AADDdUAAw3XAAMN2AADDhcAAw4ZAAMOGwADDh0AAw4gAAMOIQADDiIAAw4jAAMOJAADDiYAAw4oAAMOKQADDioAAw4sAAMOLQADDmwAAw5uAAMOcAADDnIAAw51AAMOdgADDncAAw54AAMOeQADDnsAAw59AAMOfgADDn8AAw6BAAMOggADDsEAAw7DAAMOxQADDscAAw7KAAMOywADDswAAw7NAAMOzgADDtAAAw7SAAMO0wADDtQAAw7WAAMO1wADDyIAAw9FAAMPZQADD4UAAw+HAAMPiQADD4sAAw+NAAMPkAADD5EAAw+SAAMPlQADD5YAAw+YAAMPmQADD5sAAw+eAAMPnwADD6AAAw+jAAMPpAADD6kAAw+2AAMPuwADD70AAw+/AAMPxAADD8cAAw/KAAMPzAADD/EAAxAVAAMQPAADEGAAAxBjAAMQZQADEGcAAxBpAAMQawADEG0AAxBuAAMQcQADEH4AAxCPAAMQkQADEJMAAxCVAAMQlwADEJkAAxCbAAMQnQADEJ8AAxCwAAMQswADELYAAxC5AAMQvAADEL8AAxDCAAMQxQADEMgAAxDKAAMRCQADEQsAAxENAAMRDwADERIAAxETAAMRFAADERUAAxEWAAMRGAADERoAAxEbAAMRHAADER4AAxEfAAMRXgADEWAAAxFiAAMRZAADEWcAAxFoAAMRaQADEWoAAxFrAAMRbQADEW8AAxFwAAMRcQADEXMAAxF0AAMRswADEbUAAxG4AAMRugADEb0AAxG+AAMRvwADEcAAAxHBAAMRwwADEcUAAxHGAAMRxwADEckAAxHKAAMR1wADEdgAAxHZAAMR2wADEhoAAxIcAAMSHgADEiAAAxIjAAMSJAADEiUAAxImAAMSJwADEikAAxIrAAMSLAADEi0AAxIvAAMSMAADEm8AAxJxAAMScwADEnUAAxJ4AAMSeQADEnoAAxJ7AAMSfAADEn4AAxKAAAMSgQADEoIAAxKEAAMShQADEsQAAxLGAAMSyAADEsoAAxLNAAMSzgADEs8AAxLQAAMS0QADEtMAAxLVAAMS1gADEtcAAxLZAAMS2gADExkAAxMbAAMTHQADEx8AAxMiAAMTIwADEyQAAxMlAAMTJgADEygAAxMqAAMTKwADEywAAxMuAAMTLwADE24AAxNwAAMTcgADE3QAAxN3AAMTeAADE3kAAxN6AAMTewADE30AAxN/AAMTgAADE4EAAxODAAMThAADE6kAAxPNAAMT9AADFBgAAxQbAAMUHQADFB8AAxQhAAMUIwADFCUAAxQmAAMUKQADFDYAAxRFAAMURwADFEkAAxRLAAMUTQADFE8AAxRRAAMUUwADFGIAAxRlAAMUaAADFGsAAxRuAAMUcQADFHQAAxR3AAMUeQADFLgAAxS6AAMUvAADFL4AAxTBAAMUwgADFMMAAxTEAAMUxQADFMcAAxTJAAMUygADFMsAAxTNAAMUzgADFQ0AAxUPAAMVEQADFRMAAxUWAAMVFwADFRgAAxUZAAMVGgADFRwAAxUeAAMVHwADFSAAAxUiAAMVIwADFWIAAxVkAAMVZgADFWgAAxVrAAMVbAADFW0AAxVuAAMVbwADFXEAAxVzAAMVdAADFXUAAxV3AAMVeAADFbcAAxW5AAMVuwADFb0AAxXAAAMVwQADFcIAAxXDAAMVxAADFcYAAxXIAAMVyQADFcoAAxXMAAMVzQADFgwAAxYOAAMWEAADFhIAAxYVAAMWFgADFhcAAxYYAAMWGQADFhsAAxYdAAMWHgADFh8AAxYhAAMWIgADFmEAAxZjAAMWZQADFmcAAxZqAAMWawADFmwAAxZtAAMWbgADFnAAAxZyAAMWcwADFnQAAxZ2AAMWdwADFrYAAxa4AAMWugADFrwAAxa/AAMWwAADFsEAAxbCAAMWwwADFsUAAxbHAAMWyAADFskAAxbLAAMWzAADFxcAAxc6AAMXWgADF3oAAxd8AAMXfgADF4AAAxeCAAMXhQADF4YAAxeHAAMXigADF4sAAxeNAAMXjgADF5AAAxeTAAMXlAADF5UAAxeYAAMXmQADF54AAxerAAMXsAADF7IAAxe0AAMXuQADF7wAAxe/AAMXwQADF+YAAxgKAAMYMQADGFUAAxhYAAMYWgADGFwAAxheAAMYYAADGGIAAxhjAAMYZgADGHMAAxiEAAMYhgADGIgAAxiKAAMYjAADGI4AAxiQAAMYkgADGJQAAxilAAMYqAADGKsAAxiuAAMYsQADGLQAAxi3AAMYugADGL0AAxi/AAMY/gADGQAAAxkCAAMZBAADGQcAAxkIAAMZCQADGQoAAxkLAAMZDQADGQ8AAxkQAAMZEQADGRMAAxkUAAMZUwADGVUAAxlXAAMZWQADGVwAAxldAAMZXgADGV8AAxlgAAMZYgADGWQAAxllAAMZZgADGWgAAxlpAAMZqAADGaoAAxmtAAMZrwADGbIAAxmzAAMZtAADGbUAAxm2AAMZuAADGboAAxm7AAMZvAADGb4AAxm/AAMZzAADGc0AAxnOAAMZ0AADGg8AAxoRAAMaEwADGhUAAxoYAAMaGQADGhoAAxobAAMaHAADGh4AAxogAAMaIQADGiIAAxokAAMaJQADGmQAAxpmAAMaaAADGmoAAxptAAMabgADGm8AAxpwAAMacQADGnMAAxp1AAMadgADGncAAxp5AAMaegADGrkAAxq7AAMavQADGr8AAxrCAAMawwADGsQAAxrFAAMaxgADGsgAAxrKAAMaywADGswAAxrOAAMazwADGw4AAxsQAAMbEgADGxQAAxsXAAMbGAADGxkAAxsaAAMbGwADGx0AAxsfAAMbIAADGyEAAxsjAAMbJAADG2MAAxtlAAMbZwADG2kAAxtsAAMbbQADG24AAxtvAAMbcAADG3IAAxt0AAMbdQADG3YAAxt4AAMbeQADG54AAxvCAAMb6QADHA0AAxwQAAMcEgADHBQAAxwWAAMcGAADHBoAAxwbAAMcHgADHCsAAxw6AAMcPAADHD4AAxxAAAMcQgADHEQAAxxGAAMcSAADHFcAAxxaAAMcXQADHGAAAxxjAAMcZgADHGkAAxxsAAMcbgADHK0AAxyvAAMcsQADHLMAAxy2AAMctwADHLgAAxy5AAMcugADHLwAAxy+AAMcvwADHMAAAxzCAAMcwwADHQIAAx0EAAMdBgADHQgAAx0LAAMdDAADHQ0AAx0OAAMdDwADHREAAx0TAAMdFAADHRUAAx0XAAMdGAADHVcAAx1ZAAMdWwADHV0AAx1gAAMdYQADHWIAAx1jAAMdZAADHWYAAx1oAAMdaQADHWoAAx1sAAMdbQADHawAAx2uAAMdsAADHbIAAx21AAMdtgADHbcAAx24AAMduQADHbsAAx29AAMdvgADHb8AAx3BAAMdwgADHgEAAx4DAAMeBQADHgcAAx4KAAMeCwADHgwAAx4NAAMeDgADHhAAAx4SAAMeEwADHhQAAx4WAAMeFwADHlYAAx5YAAMeWgADHlwAAx5fAAMeYAADHmEAAx5iAAMeYwADHmUAAx5nAAMeaAADHmkAAx5rAAMebAADHqsAAx6tAAMerwADHrEAAx60AAMetQADHrYAAx63AAMeuAADHroAAx68AAMevQADHr4AAx7AAAMewQADHsoAAx7LAAMezQADHxAAAx80AAMfWAADH3sAAx+iAAMfwgADH+kAAyAQAAMgMAADIFQAAyB4AAMgegADIH0AAyB/AAMggQADIIMAAyCGAAMgiQADIIsAAyCNAAMgkAADIJIAAyCUAAMglwADIJoAAyCbAAMgoAADIK0AAyCwAAMgsgADILUAAyC4AAMgugADIN8AAyEDAAMhKgADIU4AAyFRAAMhUwADIVUAAyFXAAMhWQADIVsAAyFcAAMhXwADIWwAAyF/AAMhgQADIYMAAyGFAAMhhwADIYkAAyGLAAMhjQADIY8AAyGRAAMhpAADIacAAyGqAAMhrQADIbAAAyGzAAMhtgADIbkAAyG8AAMhvwADIcEAAyIAAAMiAgADIgUAAyIHAAMiCgADIgsAAyIMAAMiDQADIg4AAyIQAAMiEgADIhMAAyIUAAMiFgADIhcAAyIgAAMiIQADIiMAAyJiAAMiZAADImYAAyJoAAMiawADImwAAyJtAAMibgADIm8AAyJxAAMicwADInQAAyJ1AAMidwADIngAAyK3AAMiuQADIrwAAyK+AAMiwQADIsIAAyLDAAMixAADIsUAAyLHAAMiyQADIsoAAyLLAAMizQADIs4AAyLXAAMi2AADItoAAyMZAAMjGwADIx0AAyMfAAMjIgADIyMAAyMkAAMjJQADIyYAAyMoAAMjKgADIysAAyMsAAMjLgADIy8AAyNuAAMjcAADI3MAAyN1AAMjeAADI3kAAyN6AAMjewADI3wAAyN+AAMjgAADI4EAAyOCAAMjhAADI4UAAyOOAAMjjwADI5EAAyPQAAMj0gADI9QAAyPWAAMj2QADI9oAAyPbAAMj3AADI90AAyPfAAMj4QADI+IAAyPjAAMj5QADI+YAAyQlAAMkJwADJCoAAyQsAAMkLwADJDAAAyQxAAMkMgADJDMAAyQ1AAMkNwADJDgAAyQ5AAMkOwADJDwAAyRJAAMkSgADJEsAAyRNAAMkjAADJI4AAySQAAMkkgADJJUAAySWAAMklwADJJgAAySZAAMkmwADJJ0AAySeAAMknwADJKEAAySiAAMk4QADJOMAAyTmAAMk6AADJOsAAyTsAAMk7QADJO4AAyTvAAMk8QADJPMAAyT0AAMk9QADJPcAAyT4AAMlEwADJSAAAyU3AAMlOgADJT0AAyVAAAMlQwADJUYAAyVJAAMlTAADJU8AAyVSAAMlVQADJVgAAyVvAAMlcgADJXUAAyV4AAMlewADJX4AAyWBAAMlhAADJYcAAyWKAAMljQADJZAAAyWSAAMlmQADJaAAAyWpAAMlrgADJbkAAyXFAAMlzgADJdIAAyXcAAMl5AADJi8AAyZSAAMmcgADJpIAAyaUAAMmlgADJpgAAyaaAAMmnQADJp4AAyafAAMmogADJqMAAyalAAMmpgADJqgAAyarAAMmrAADJq0AAyawAAMmsQADJrYAAybDAAMmyAADJsoAAybMAAMm0QADJtQAAybXAAMm2QADJv4AAyciAAMnSQADJ20AAydwAAMncgADJ3QAAyd2AAMneAADJ3oAAyd7AAMnfgADJ4sAAyecAAMnngADJ6AAAyeiAAMnpAADJ6YAAyeoAAMnqgADJ6wAAye9AAMnwAADJ8MAAyfGAAMnyQADJ8wAAyfPAAMn0gADJ9UAAyfXAAMoFgADKBgAAygaAAMoHAADKB8AAyggAAMoIQADKCIAAygjAAMoJQADKCcAAygoAAMoKQADKCsAAygsAAMoawADKG0AAyhvAAMocQADKHQAAyh1AAModgADKHcAAyh4AAMoegADKHwAAyh9AAMofgADKIAAAyiBAAMowAADKMIAAyjFAAMoxwADKMoAAyjLAAMozAADKM0AAyjOAAMo0AADKNIAAyjTAAMo1AADKNYAAyjXAAMo5AADKOUAAyjmAAMo6AADKScAAykpAAMpKwADKS0AAykwAAMpMQADKTIAAykzAAMpNAADKTYAAyk4AAMpOQADKToAAyk8AAMpPQADKXwAAyl+AAMpgAADKYIAAymFAAMphgADKYcAAymIAAMpiQADKYsAAymNAAMpjgADKY8AAymRAAMpkgADKdEAAynTAAMp1QADKdcAAynaAAMp2wADKdwAAyndAAMp3gADKeAAAyniAAMp4wADKeQAAynmAAMp5wADKiYAAyooAAMqKgADKiwAAyovAAMqMAADKjEAAyoyAAMqMwADKjUAAyo3AAMqOAADKjkAAyo7AAMqPAADKnsAAyp9AAMqfwADKoEAAyqEAAMqhQADKoYAAyqHAAMqiAADKooAAyqMAAMqjQADKo4AAyqQAAMqkQADKrYAAyraAAMrAQADKyUAAysoAAMrKgADKywAAysuAAMrMAADKzIAAyszAAMrNgADK0MAAytSAAMrVAADK1YAAytYAAMrWgADK1wAAyteAAMrYAADK28AAytyAAMrdQADK3gAAyt7AAMrfgADK4EAAyuEAAMrhgADK8UAAyvHAAMryQADK8sAAyvOAAMrzwADK9AAAyvRAAMr0gADK9QAAyvWAAMr1wADK9gAAyvaAAMr2wADLBoAAywcAAMsHgADLCAAAywjAAMsJAADLCUAAywmAAMsJwADLCkAAywrAAMsLAADLC0AAywvAAMsMAADLG8AAyxxAAMscwADLHUAAyx4AAMseQADLHoAAyx7AAMsfAADLH4AAyyAAAMsgQADLIIAAyyEAAMshQADLMQAAyzGAAMsyAADLMoAAyzNAAMszgADLM8AAyzQAAMs0QADLNMAAyzVAAMs1gADLNcAAyzZAAMs2gADLRkAAy0bAAMtHQADLR8AAy0iAAMtIwADLSQAAy0lAAMtJgADLSgAAy0qAAMtKwADLSwAAy0uAAMtLwADLW4AAy1wAAMtcgADLXQAAy13AAMteAADLXkAAy16AAMtewADLX0AAy1/AAMtgAADLYEAAy2DAAMthAADLcMAAy3FAAMtxwADLckAAy3MAAMtzQADLc4AAy3PAAMt0AADLdIAAy3UAAMt1QADLdYAAy3YAAMt2QADLiQAAy5HAAMuZwADLocAAy6JAAMuiwADLo0AAy6PAAMukgADLpMAAy6UAAMulwADLpgAAy6aAAMumwADLp0AAy6gAAMuoQADLqIAAy6lAAMupgADLqsAAy64AAMuvQADLr8AAy7BAAMuxgADLskAAy7MAAMuzgADLvMAAy8XAAMvPgADL2IAAy9lAAMvZwADL2kAAy9rAAMvbQADL28AAy9wAAMvcwADL4AAAy+RAAMvkwADL5UAAy+XAAMvmQADL5sAAy+dAAMvnwADL6EAAy+yAAMvtQADL7gAAy+7AAMvvgADL8EAAy/EAAMvxwADL8oAAy/MAAMwCwADMA0AAzAPAAMwEQADMBQAAzAVAAMwFgADMBcAAzAYAAMwGgADMBwAAzAdAAMwHgADMCAAAzAhAAMwYAADMGIAAzBkAAMwZgADMGkAAzBqAAMwawADMGwAAzBtAAMwbwADMHEAAzByAAMwcwADMHUAAzB2AAMwtQADMLcAAzC6AAMwvAADML8AAzDAAAMwwQADMMIAAzDDAAMwxQADMMcAAzDIAAMwyQADMMsAAzDMAAMw2QADMNoAAzDbAAMw3QADMRwAAzEeAAMxIAADMSIAAzElAAMxJgADMScAAzEoAAMxKQADMSsAAzEtAAMxLgADMS8AAzExAAMxMgADMXEAAzFzAAMxdQADMXcAAzF6AAMxewADMXwAAzF9AAMxfgADMYAAAzGCAAMxgwADMYQAAzGGAAMxhwADMcYAAzHIAAMxygADMcwAAzHPAAMx0AADMdEAAzHSAAMx0wADMdUAAzHXAAMx2AADMdkAAzHbAAMx3AADMhsAAzIdAAMyHwADMiEAAzIkAAMyJQADMiYAAzInAAMyKAADMioAAzIsAAMyLQADMi4AAzIwAAMyMQADMnAAAzJyAAMydAADMnYAAzJ5AAMyegADMnsAAzJ8AAMyfQADMn8AAzKBAAMyggADMoMAAzKFAAMyhgADMqsAAzLPAAMy9gADMxoAAzMdAAMzHwADMyEAAzMjAAMzJQADMycAAzMoAAMzKwADMzgAAzNHAAMzSQADM0sAAzNNAAMzTwADM1EAAzNTAAMzVQADM2QAAzNnAAMzagADM20AAzNwAAMzcwADM3YAAzN5AAMzewADM7oAAzO8AAMzvgADM8AAAzPDAAMzxAADM8UAAzPGAAMzxwADM8kAAzPLAAMzzAADM80AAzPPAAMz0AADNA8AAzQRAAM0EwADNBUAAzQYAAM0GQADNBoAAzQbAAM0HAADNB4AAzQgAAM0IQADNCIAAzQkAAM0JQADNGQAAzRmAAM0aAADNGoAAzRtAAM0bgADNG8AAzRwAAM0cQADNHMAAzR1AAM0dgADNHcAAzR5AAM0egADNLkAAzS7AAM0vQADNL8AAzTCAAM0wwADNMQAAzTFAAM0xgADNMgAAzTKAAM0ywADNMwAAzTOAAM0zwADNQ4AAzUQAAM1EgADNRQAAzUXAAM1GAADNRkAAzUaAAM1GwADNR0AAzUfAAM1IAADNSEAAzUjAAM1JAADNWMAAzVlAAM1ZwADNWkAAzVsAAM1bQADNW4AAzVvAAM1cAADNXIAAzV0AAM1dQADNXYAAzV4AAM1eQADNbgAAzW6AAM1vAADNb4AAzXBAAM1wgADNcMAAzXEAAM1xQADNccAAzXJAAM1ygADNcsAAzXNAAM1zgADNhkAAzY8AAM2XAADNnwAAzZ+AAM2gAADNoIAAzaEAAM2hwADNogAAzaJAAM2jAADNo0AAzaPAAM2kAADNpIAAzaVAAM2lgADNpcAAzaaAAM2mwADNqAAAzatAAM2sgADNrQAAza2AAM2uwADNr4AAzbBAAM2wwADNugAAzcMAAM3MwADN1cAAzdaAAM3XAADN14AAzdgAAM3YgADN2QAAzdlAAM3aAADN3UAAzeGAAM3iAADN4oAAzeMAAM3jgADN5AAAzeSAAM3lAADN5YAAzenAAM3qgADN60AAzewAAM3swADN7YAAze5AAM3vAADN78AAzfBAAM4AAADOAIAAzgEAAM4BgADOAkAAzgKAAM4CwADOAwAAzgNAAM4DwADOBEAAzgSAAM4EwADOBUAAzgWAAM4VQADOFcAAzhZAAM4WwADOF4AAzhfAAM4YAADOGEAAzhiAAM4ZAADOGYAAzhnAAM4aAADOGoAAzhrAAM4qgADOKwAAzivAAM4sQADOLQAAzi1AAM4tgADOLcAAzi4AAM4ugADOLwAAzi9AAM4vgADOMAAAzjBAAM4zgADOM8AAzjQAAM40gADOREAAzkTAAM5FQADORcAAzkaAAM5GwADORwAAzkdAAM5HgADOSAAAzkiAAM5IwADOSQAAzkmAAM5JwADOWYAAzloAAM5agADOWwAAzlvAAM5cAADOXEAAzlyAAM5cwADOXUAAzl3AAM5eAADOXkAAzl7AAM5fAADObsAAzm9AAM5vwADOcEAAznEAAM5xQADOcYAAznHAAM5yAADOcoAAznMAAM5zQADOc4AAznQAAM50QADOhAAAzoSAAM6FAADOhYAAzoZAAM6GgADOhsAAzocAAM6HQADOh8AAzohAAM6IgADOiMAAzolAAM6JgADOmUAAzpnAAM6aQADOmsAAzpuAAM6bwADOnAAAzpxAAM6cgADOnQAAzp2AAM6dwADOngAAzp6AAM6ewADOqAAAzrEAAM66wADOw8AAzsSAAM7FAADOxYAAzsYAAM7GgADOxwAAzsdAAM7IAADOy0AAzs8AAM7PgADO0AAAztCAAM7RAADO0YAAztIAAM7SgADO1kAAztcAAM7XwADO2IAAztlAAM7aAADO2sAAztuAAM7cAADO68AAzuxAAM7swADO7UAAzu4AAM7uQADO7oAAzu7AAM7vAADO74AAzvAAAM7wQADO8IAAzvEAAM7xQADPAQAAzwGAAM8CAADPAoAAzwNAAM8DgADPA8AAzwQAAM8EQADPBMAAzwVAAM8FgADPBcAAzwZAAM8GgADPFkAAzxbAAM8XQADPF8AAzxiAAM8YwADPGQAAzxlAAM8ZgADPGgAAzxqAAM8awADPGwAAzxuAAM8bwADPK4AAzywAAM8sgADPLQAAzy3AAM8uAADPLkAAzy6AAM8uwADPL0AAzy/AAM8wAADPMEAAzzDAAM8xAADPQMAAz0FAAM9BwADPQkAAz0MAAM9DQADPQ4AAz0PAAM9EAADPRIAAz0UAAM9FQADPRYAAz0YAAM9GQADPVgAAz1aAAM9XAADPV4AAz1hAAM9YgADPWMAAz1kAAM9ZQADPWcAAz1pAAM9agADPWsAAz1tAAM9bgADPa0AAz2vAAM9sQADPbMAAz22AAM9twADPbgAAz25AAM9ugADPbwAAz2+AAM9vwADPcAAAz3CAAM9wwADPg4AAz4xAAM+UQADPnEAAz5zAAM+dQADPncAAz55AAM+fAADPn0AAz5+AAM+gQADPoIAAz6EAAM+hQADPocAAz6KAAM+iwADPowAAz6PAAM+kAADPpUAAz6iAAM+pwADPqkAAz6rAAM+sAADPrMAAz62AAM+uAADPt0AAz8BAAM/KAADP0wAAz9PAAM/UQADP1MAAz9VAAM/VwADP1kAAz9aAAM/XQADP2oAAz97AAM/fQADP38AAz+BAAM/gwADP4UAAz+HAAM/iQADP4sAAz+cAAM/nwADP6IAAz+lAAM/qAADP6sAAz+uAAM/sQADP7QAAz+2AAM/9QADP/cAAz/5AAM/+wADP/4AAz//AANAAAADQAEAA0ACAANABAADQAYAA0AHAANACAADQAoAA0ALAANASgADQEwAA0BOAANAUAADQFMAA0BUAANAVQADQFYAA0BXAANAWQADQFsAA0BcAANAXQADQF8AA0BgAANAnwADQKEAA0CkAANApgADQKkAA0CqAANAqwADQKwAA0CtAANArwADQLEAA0CyAANAswADQLUAA0C2AANAwwADQMQAA0DFAANAxwADQQYAA0EIAANBCgADQQwAA0EPAANBEAADQREAA0ESAANBEwADQRUAA0EXAANBGAADQRkAA0EbAANBHAADQVsAA0FdAANBXwADQWEAA0FkAANBZQADQWYAA0FnAANBaAADQWoAA0FsAANBbQADQW4AA0FwAANBcQADQbAAA0GyAANBtAADQbYAA0G5AANBugADQbsAA0G8AANBvQADQb8AA0HBAANBwgADQcMAA0HFAANBxgADQgUAA0IHAANCCQADQgsAA0IOAANCDwADQhAAA0IRAANCEgADQhQAA0IWAANCFwADQhgAA0IaAANCGwADQloAA0JcAANCXgADQmAAA0JjAANCZAADQmUAA0JmAANCZwADQmkAA0JrAANCbAADQm0AA0JvAANCcAADQpUAA0K5AANC4AADQwQAA0MHAANDCQADQwsAA0MNAANDDwADQxEAA0MSAANDFQADQyIAA0MxAANDMwADQzUAA0M3AANDOQADQzsAA0M9AANDPwADQ04AA0NRAANDVAADQ1cAA0NaAANDXQADQ2AAA0NjAANDZQADQ6QAA0OmAANDqAADQ6oAA0OtAANDrgADQ68AA0OwAANDsQADQ7MAA0O1AANDtgADQ7cAA0O5AANDugADQ/kAA0P7AAND/QADQ/8AA0QCAANEAwADRAQAA0QFAANEBgADRAgAA0QKAANECwADRAwAA0QOAANEDwADRE4AA0RQAANEUgADRFQAA0RXAANEWAADRFkAA0RaAANEWwADRF0AA0RfAANEYAADRGEAA0RjAANEZAADRKMAA0SlAANEqAADRKoAA0StAANErgADRK8AA0SwAANEsQADRLMAA0S1AANEtgADRLcAA0S5AANEugADRPkAA0T7AANE/QADRP8AA0UCAANFAwADRQQAA0UFAANFBgADRQgAA0UKAANFCwADRQwAA0UOAANFDwADRU4AA0VQAANFUgADRVQAA0VXAANFWAADRVkAA0VaAANFWwADRV0AA0VfAANFYAADRWEAA0VjAANFZAADRaMAA0WlAANFpwADRakAA0WsAANFrQADRa4AA0WvAANFsAADRbIAA0W0AANFtQADRbYAA0W4AANFuQADRgQAA0YnAANGRwADRmcAA0ZpAANGawADRm0AA0ZvAANGcgADRnMAA0Z0AANGdwADRngAA0Z6AANGewADRn0AA0aAAANGgQADRoIAA0aFAANGhgADRosAA0aYAANGnQADRp8AA0ahAANGpgADRqkAA0asAANGrgADRtMAA0b3AANHHgADR0IAA0dFAANHRwADR0kAA0dLAANHTQADR08AA0dQAANHUwADR2AAA0dxAANHcwADR3UAA0d3AANHeQADR3sAA0d9AANHfwADR4EAA0eSAANHlQADR5gAA0ebAANHngADR6EAA0ekAANHpwADR6oAA0esAANH6wADR+0AA0fvAANH8QADR/QAA0f1AANH9gADR/cAA0f4AANH+gADR/wAA0f9AANH/gADSAAAA0gBAANIQAADSEIAA0hEAANIRgADSEkAA0hKAANISwADSEwAA0hNAANITwADSFEAA0hSAANIUwADSFUAA0hWAANIlQADSJcAA0iaAANInAADSJ8AA0igAANIoQADSKIAA0ijAANIpQADSKcAA0ioAANIqQADSKsAA0isAANIuQADSLoAA0i7AANIvQADSPwAA0j+AANJAAADSQIAA0kFAANJBgADSQcAA0kIAANJCQADSQsAA0kNAANJDgADSQ8AA0kRAANJEgADSVEAA0lTAANJVQADSVcAA0laAANJWwADSVwAA0ldAANJXgADSWAAA0liAANJYwADSWQAA0lmAANJZwADSaYAA0moAANJqgADSawAA0mvAANJsAADSbEAA0myAANJswADSbUAA0m3AANJuAADSbkAA0m7AANJvAADSfsAA0n9AANJ/wADSgEAA0oEAANKBQADSgYAA0oHAANKCAADSgoAA0oMAANKDQADSg4AA0oQAANKEQADSlAAA0pSAANKVAADSlYAA0pZAANKWgADSlsAA0pcAANKXQADSl8AA0phAANKYgADSmMAA0plAANKZgADSosAA0qvAANK1gADSvoAA0r9AANK/wADSwEAA0sDAANLBQADSwcAA0sIAANLCwADSxgAA0snAANLKQADSysAA0stAANLLwADSzEAA0szAANLNQADS0QAA0tHAANLSgADS00AA0tQAANLUwADS1YAA0tZAANLWwADS5oAA0ucAANLngADS6AAA0ujAANLpAADS6UAA0umAANLpwADS6kAA0urAANLrAADS60AA0uvAANLsAADS+8AA0vxAANL8wADS/UAA0v4AANL+QADS/oAA0v7AANL/AADS/4AA0wAAANMAQADTAIAA0wEAANMBQADTEQAA0xGAANMSAADTEoAA0xNAANMTgADTE8AA0xQAANMUQADTFMAA0xVAANMVgADTFcAA0xZAANMWgADTJkAA0ybAANMnQADTJ8AA0yiAANMowADTKQAA0ylAANMpgADTKgAA0yqAANMqwADTKwAA0yuAANMrwADTO4AA0zwAANM8gADTPQAA0z3AANM+AADTPkAA0z6AANM+wADTP0AA0z/AANNAAADTQEAA00DAANNBAADTUMAA01FAANNRwADTUkAA01MAANNTQADTU4AA01PAANNUAADTVIAA01UAANNVQADTVYAA01YAANNWQADTZgAA02aAANNnAADTZ4AA02hAANNogADTaMAA02kAANNpQADTacAA02pAANNqgADTasAA02tAANNrgADTfkAA04cAANOPAADTlwAA05eAANOYAADTmIAA05kAANOZwADTmgAA05pAANObAADTm0AA05vAANOcAADTnIAA051AANOdgADTncAA056AANOewADToQAA06RAANOlgADTpgAA06aAANOnwADTqIAA06lAANOpwADTswAA07wAANPFwADTzsAA08+AANPQAADT0IAA09EAANPRgADT0gAA09JAANPTAADT1kAA09qAANPbAADT24AA09wAANPcgADT3QAA092AANPeAADT3oAA0+LAANPjgADT5EAA0+UAANPlwADT5oAA0+dAANPoAADT6MAA0+lAANP5AADT+YAA0/oAANP6gADT+0AA0/uAANP7wADT/AAA0/xAANP8wADT/UAA0/2AANP9wADT/kAA0/6AANQOQADUDsAA1A9AANQPwADUEIAA1BDAANQRAADUEUAA1BGAANQSAADUEoAA1BLAANQTAADUE4AA1BPAANQjgADUJAAA1CTAANQlQADUJgAA1CZAANQmgADUJsAA1CcAANQngADUKAAA1ChAANQogADUKQAA1ClAANQsgADULMAA1C0AANQtgADUPUAA1D3AANQ+QADUPsAA1D+AANQ/wADUQAAA1EBAANRAgADUQQAA1EGAANRBwADUQgAA1EKAANRCwADUUoAA1FMAANRTgADUVAAA1FTAANRVAADUVUAA1FWAANRVwADUVkAA1FbAANRXAADUV0AA1FfAANRYAADUZ8AA1GhAANRowADUaUAA1GoAANRqQADUaoAA1GrAANRrAADUa4AA1GwAANRsQADUbIAA1G0AANRtQADUfQAA1H2AANR+AADUfoAA1H9AANR/gADUf8AA1IAAANSAQADUgMAA1IFAANSBgADUgcAA1IJAANSCgADUkkAA1JLAANSTQADUk8AA1JSAANSUwADUlQAA1JVAANSVgADUlgAA1JaAANSWwADUlwAA1JeAANSXwADUoQAA1KoAANSzwADUvMAA1L2AANS+AADUvoAA1L8AANS/gADUwAAA1MBAANTBAADUxEAA1MgAANTIgADUyQAA1MmAANTKAADUyoAA1MsAANTLgADUz0AA1NAAANTQwADU0YAA1NJAANTTAADU08AA1NSAANTVAADU5MAA1OVAANTlwADU5kAA1OcAANTnQADU54AA1OfAANToAADU6IAA1OkAANTpQADU6YAA1OoAANTqQADU+gAA1PqAANT7AADU+4AA1PxAANT8gADU/MAA1P0AANT9QADU/cAA1P5AANT+gADU/sAA1P9AANT/gADVD0AA1Q/AANUQQADVEMAA1RGAANURwADVEgAA1RJAANUSgADVEwAA1ROAANUTwADVFAAA1RSAANUUwADVJIAA1SUAANUlwADVJkAA1ScAANUnQADVJ4AA1SfAANUoAADVKIAA1SkAANUpQADVKYAA1SoAANUqQADVOgAA1TqAANU7AADVO4AA1TxAANU8gADVPMAA1T0AANU9QADVPcAA1T5AANU+gADVPsAA1T9AANU/gADVT0AA1U/AANVQQADVUMAA1VGAANVRwADVUgAA1VJAANVSgADVUwAA1VOAANVTwADVVAAA1VSAANVUwADVZIAA1WUAANVlgADVZgAA1WbAANVnAADVZ0AA1WeAANVnwADVaEAA1WjAANVpAADVaUAA1WnAANVqAADVfMAA1YWAANWNgADVlYAA1ZYAANWWgADVlwAA1ZeAANWYQADVmIAA1ZjAANWZgADVmcAA1ZpAANWagADVmwAA1ZvAANWcAADVnEAA1Z0AANWdQADVnoAA1aHAANWjAADVo4AA1aQAANWlQADVpgAA1abAANWnQADVsIAA1bmAANXDQADVzEAA1c0AANXNgADVzgAA1c6AANXPAADVz4AA1c/AANXQgADV08AA1dgAANXYgADV2QAA1dmAANXaAADV2oAA1dsAANXbgADV3AAA1eBAANXhAADV4cAA1eKAANXjQADV5AAA1eTAANXlgADV5kAA1ebAANX2gADV9wAA1feAANX4AADV+MAA1fkAANX5QADV+YAA1fnAANX6QADV+sAA1fsAANX7QADV+8AA1fwAANYLwADWDEAA1gzAANYNQADWDgAA1g5AANYOgADWDsAA1g8AANYPgADWEAAA1hBAANYQgADWEQAA1hFAANYhAADWIYAA1iJAANYiwADWI4AA1iPAANYkAADWJEAA1iSAANYlAADWJYAA1iXAANYmAADWJoAA1ibAANYqAADWKkAA1iqAANYrAADWOsAA1jtAANY7wADWPEAA1j0AANY9QADWPYAA1j3AANY+AADWPoAA1j8AANY/QADWP4AA1kAAANZAQADWUAAA1lCAANZRAADWUYAA1lJAANZSgADWUsAA1lMAANZTQADWU8AA1lRAANZUgADWVMAA1lVAANZVgADWZUAA1mXAANZmQADWZsAA1meAANZnwADWaAAA1mhAANZogADWaQAA1mmAANZpwADWagAA1mqAANZqwADWeoAA1nsAANZ7gADWfAAA1nzAANZ9AADWfUAA1n2AANZ9wADWfkAA1n7AANZ/AADWf0AA1n/AANaAAADWj8AA1pBAANaQwADWkUAA1pIAANaSQADWkoAA1pLAANaTAADWk4AA1pQAANaUQADWlIAA1pUAANaVQADWnoAA1qeAANaxQADWukAA1rsAANa7gADWvAAA1ryAANa9AADWvYAA1r3AANa+gADWwcAA1sWAANbGAADWxoAA1scAANbHgADWyAAA1siAANbJAADWzMAA1s2AANbOQADWzwAA1s/AANbQgADW0UAA1tIAANbSgADW4kAA1uLAANbjQADW48AA1uSAANbkwADW5QAA1uVAANblgADW5gAA1uaAANbmwADW5wAA1ueAANbnwADW94AA1vgAANb4gADW+QAA1vnAANb6AADW+kAA1vqAANb6wADW+0AA1vvAANb8AADW/EAA1vzAANb9AADXDMAA1w1AANcNwADXDkAA1w8AANcPQADXD4AA1w/AANcQAADXEIAA1xEAANcRQADXEYAA1xIAANcSQADXIgAA1yKAANcjAADXI4AA1yRAANckgADXJMAA1yUAANclQADXJcAA1yZAANcmgADXJsAA1ydAANcngADXN0AA1zfAANc4QADXOMAA1zmAANc5wADXOgAA1zpAANc6gADXOwAA1zuAANc7wADXPAAA1zyAANc8wADXTIAA100AANdNgADXTgAA107AANdPAADXT0AA10+AANdPwADXUEAA11DAANdRAADXUUAA11HAANdSAADXYcAA12JAANdiwADXY0AA12QAANdkQADXZIAA12TAANdlAADXZYAA12YAANdmQADXZoAA12cAANdnQADXegAA14LAANeKwADXksAA15NAANeTwADXlEAA15TAANeVgADXlcAA15YAANeWwADXlwAA15eAANeXwADXmEAA15kAANeZQADXmYAA15pAANeagADXm8AA158AANegQADXoMAA16FAANeigADXo0AA16QAANekgADXrcAA17bAANfAgADXyYAA18pAANfKwADXy0AA18vAANfMQADXzMAA180AANfNwADX0QAA19VAANfVwADX1kAA19bAANfXQADX18AA19hAANfYwADX2UAA192AANfeQADX3wAA19/AANfggADX4UAA1+IAANfiwADX44AA1+QAANfzwADX9EAA1/TAANf1QADX9gAA1/ZAANf2gADX9sAA1/cAANf3gADX+AAA1/hAANf4gADX+QAA1/lAANgJAADYCYAA2AoAANgKgADYC0AA2AuAANgLwADYDAAA2AxAANgMwADYDUAA2A2AANgNwADYDkAA2A6AANgeQADYHsAA2B+AANggAADYIMAA2CEAANghQADYIYAA2CHAANgiQADYIsAA2CMAANgjQADYI8AA2CQAANgnQADYJ4AA2CfAANgoQADYOAAA2DiAANg5AADYOYAA2DpAANg6gADYOsAA2DsAANg7QADYO8AA2DxAANg8gADYPMAA2D1AANg9gADYTUAA2E3AANhOQADYTsAA2E+AANhPwADYUAAA2FBAANhQgADYUQAA2FGAANhRwADYUgAA2FKAANhSwADYYoAA2GMAANhjgADYZAAA2GTAANhlAADYZUAA2GWAANhlwADYZkAA2GbAANhnAADYZ0AA2GfAANhoAADYd8AA2HhAANh4wADYeUAA2HoAANh6QADYeoAA2HrAANh7AADYe4AA2HwAANh8QADYfIAA2H0AANh9QADYjQAA2I2AANiOAADYjoAA2I9AANiPgADYj8AA2JAAANiQQADYkMAA2JFAANiRgADYkcAA2JJAANiSgADYm8AA2KTAANiugADYt4AA2LhAANi4wADYuUAA2LnAANi6QADYusAA2LsAANi7wADYvwAA2MLAANjDQADYw8AA2MRAANjEwADYxUAA2MXAANjGQADYygAA2MrAANjLgADYzEAA2M0AANjNwADYzoAA2M9AANjPwADY34AA2OAAANjggADY4QAA2OHAANjiAADY4kAA2OKAANjiwADY40AA2OPAANjkAADY5EAA2OTAANjlAADY9MAA2PVAANj1wADY9kAA2PcAANj3QADY94AA2PfAANj4AADY+IAA2PkAANj5QADY+YAA2PoAANj6QADZCgAA2QqAANkLAADZC4AA2QxAANkMgADZDMAA2Q0AANkNQADZDcAA2Q5AANkOgADZDsAA2Q9AANkPgADZH0AA2R/AANkgQADZIMAA2SGAANkhwADZIgAA2SJAANkigADZIwAA2SOAANkjwADZJAAA2SSAANkkwADZNIAA2TUAANk1gADZNgAA2TbAANk3AADZN0AA2TeAANk3wADZOEAA2TjAANk5AADZOUAA2TnAANk6AADZScAA2UpAANlKwADZS0AA2UwAANlMQADZTIAA2UzAANlNAADZTYAA2U4AANlOQADZToAA2U8AANlPQADZXwAA2V+AANlgAADZYIAA2WFAANlhgADZYcAA2WIAANliQADZYsAA2WNAANljgADZY8AA2WRAANlkgADZd0AA2YAAANmIAADZkAAA2ZCAANmRAADZkYAA2ZIAANmSwADZkwAA2ZNAANmUAADZlEAA2ZTAANmVAADZlYAA2ZZAANmWgADZlsAA2ZeAANmXwADZmQAA2ZxAANmdgADZngAA2Z6AANmfwADZoIAA2aFAANmhwADZqwAA2bQAANm9wADZxsAA2ceAANnIAADZyIAA2ckAANnJgADZygAA2cpAANnLAADZzkAA2dKAANnTAADZ04AA2dQAANnUgADZ1QAA2dWAANnWAADZ1oAA2drAANnbgADZ3EAA2d0AANndwADZ3oAA2d9AANngAADZ4MAA2eFAANnxAADZ8YAA2fIAANnygADZ80AA2fOAANnzwADZ9AAA2fRAANn0wADZ9UAA2fWAANn1wADZ9kAA2faAANoGQADaBsAA2gdAANoHwADaCIAA2gjAANoJAADaCUAA2gmAANoKAADaCoAA2grAANoLAADaC4AA2gvAANobgADaHAAA2hzAANodQADaHgAA2h5AANoegADaHsAA2h8AANofgADaIAAA2iBAANoggADaIQAA2iFAANokgADaJMAA2iUAANolgADaNUAA2jXAANo2QADaNsAA2jeAANo3wADaOAAA2jhAANo4gADaOQAA2jmAANo5wADaOgAA2jqAANo6wADaSoAA2ksAANpLgADaTAAA2kzAANpNAADaTUAA2k2AANpNwADaTkAA2k7AANpPAADaT0AA2k/AANpQAADaX8AA2mBAANpgwADaYUAA2mIAANpiQADaYoAA2mLAANpjAADaY4AA2mQAANpkQADaZIAA2mUAANplQADadQAA2nWAANp2AADadoAA2ndAANp3gADad8AA2ngAANp4QADaeMAA2nlAANp5gADaecAA2npAANp6gADaikAA2orAANqLQADai8AA2oyAANqMwADajQAA2o1AANqNgADajgAA2o6AANqOwADajwAA2o+AANqPwADamQAA2qIAANqrwADatMAA2rWAANq2AADatoAA2rcAANq3gADauAAA2rhAANq5AADavEAA2sAAANrAgADawQAA2sGAANrCAADawoAA2sMAANrDgADax0AA2sgAANrIwADayYAA2spAANrLAADay8AA2syAANrNAADa3MAA2t1AANrdwADa3kAA2t8AANrfQADa34AA2t/AANrgAADa4IAA2uEAANrhQADa4YAA2uIAANriQADa8gAA2vKAANrzAADa84AA2vRAANr0gADa9MAA2vUAANr1QADa9cAA2vZAANr2gADa9sAA2vdAANr3gADbB0AA2wfAANsIQADbCMAA2wmAANsJwADbCgAA2wpAANsKgADbCwAA2wuAANsLwADbDAAA2wyAANsMwADbHIAA2x0AANsdgADbHgAA2x7AANsfAADbH0AA2x+AANsfwADbIEAA2yDAANshAADbIUAA2yHAANsiAADbMcAA2zJAANsywADbM0AA2zQAANs0QADbNIAA2zTAANs1AADbNYAA2zYAANs2QADbNoAA2zcAANs3QADbRwAA20eAANtIAADbSIAA20lAANtJgADbScAA20oAANtKQADbSsAA20tAANtLgADbS8AA20xAANtMgADbXEAA21zAANtdQADbXcAA216AANtewADbXwAA219AANtfgADbYAAA22CAANtgwADbYQAA22GAANthwADbdIAA231AANuFQADbjUAA243AANuOQADbjsAA249AANuQAADbkEAA25CAANuRQADbkYAA25IAANuSQADbksAA25OAANuTwADblAAA25TAANuVAADblkAA25mAANuawADbm0AA25vAANudAADbncAA256AANufAADbqEAA27FAANu7AADbxAAA28TAANvFQADbxcAA28ZAANvGwADbx0AA28eAANvIQADby4AA28/AANvQQADb0MAA29FAANvRwADb0kAA29LAANvTQADb08AA29gAANvYwADb2YAA29pAANvbAADb28AA29yAANvdQADb3gAA296AANvuQADb7sAA2+9AANvvwADb8IAA2/DAANvxAADb8UAA2/GAANvyAADb8oAA2/LAANvzAADb84AA2/PAANwDgADcBAAA3ASAANwFAADcBcAA3AYAANwGQADcBoAA3AbAANwHQADcB8AA3AgAANwIQADcCMAA3AkAANwYwADcGUAA3BoAANwagADcG0AA3BuAANwbwADcHAAA3BxAANwcwADcHUAA3B2AANwdwADcHkAA3B6AANwhwADcIgAA3CJAANwiwADcMoAA3DMAANwzgADcNAAA3DTAANw1AADcNUAA3DWAANw1wADcNkAA3DbAANw3AADcN0AA3DfAANw4AADcR8AA3EhAANxIwADcSUAA3EoAANxKQADcSoAA3ErAANxLAADcS4AA3EwAANxMQADcTIAA3E0AANxNQADcXQAA3F2AANxeAADcXoAA3F9AANxfgADcX8AA3GAAANxgQADcYMAA3GFAANxhgADcYcAA3GJAANxigADcckAA3HLAANxzQADcc8AA3HSAANx0wADcdQAA3HVAANx1gADcdgAA3HaAANx2wADcdwAA3HeAANx3wADch4AA3IgAANyIgADciQAA3InAANyKAADcikAA3IqAANyKwADci0AA3IvAANyMAADcjEAA3IzAANyNAADclkAA3J9AANypAADcsgAA3LLAANyzQADcs8AA3LRAANy0wADctUAA3LWAANy2QADcuYAA3L1AANy9wADcvkAA3L7AANy/QADcv8AA3MBAANzAwADcxIAA3MVAANzGAADcxsAA3MeAANzIQADcyQAA3MnAANzKQADc2gAA3NqAANzbAADc24AA3NxAANzcgADc3MAA3N0AANzdQADc3cAA3N5AANzegADc3sAA3N9AANzfgADc70AA3O/AANzwQADc8MAA3PGAANzxwADc8gAA3PJAANzygADc8wAA3POAANzzwADc9AAA3PSAANz0wADdBIAA3QUAAN0FgADdBgAA3QbAAN0HAADdB0AA3QeAAN0HwADdCEAA3QjAAN0JAADdCUAA3QnAAN0KAADdGcAA3RpAAN0bAADdG4AA3RxAAN0cgADdHMAA3R0AAN0dQADdHcAA3R5AAN0egADdHsAA3R9AAN0fgADdL0AA3S/AAN0wQADdMMAA3TGAAN0xwADdMgAA3TJAAN0ygADdMwAA3TOAAN0zwADdNAAA3TSAAN00wADdRIAA3UUAAN1FgADdRgAA3UbAAN1HAADdR0AA3UeAAN1HwADdSEAA3UjAAN1JAADdSUAA3UnAAN1KAADdWcAA3VpAAN1awADdW0AA3VwAAN1cQADdXIAA3VzAAN1dAADdXYAA3V4AAN1eQADdXoAA3V8AAN1fQADdcgAA3XrAAN2CwADdisAA3YtAAN2LwADdjEAA3YzAAN2NgADdjcAA3Y4AAN2OwADdjwAA3Y+AAN2PwADdkEAA3ZEAAN2RQADdkYAA3ZJAAN2SgADdk8AA3ZcAAN2YQADdmMAA3ZlAAN2agADdm0AA3ZwAAN2cgADdpcAA3a7AAN24gADdwYAA3cJAAN3CwADdw0AA3cPAAN3EQADdxMAA3cUAAN3FwADdyQAA3c1AAN3NwADdzkAA3c7AAN3PQADdz8AA3dBAAN3QwADd0UAA3dWAAN3WQADd1wAA3dfAAN3YgADd2UAA3doAAN3awADd24AA3dwAAN3rwADd7EAA3ezAAN3tQADd7gAA3e5AAN3ugADd7sAA3e8AAN3vgADd8AAA3fBAAN3wgADd8QAA3fFAAN4BAADeAYAA3gIAAN4CgADeA0AA3gOAAN4DwADeBAAA3gRAAN4EwADeBUAA3gWAAN4FwADeBkAA3gaAAN4WQADeFsAA3heAAN4YAADeGMAA3hkAAN4ZQADeGYAA3hnAAN4aQADeGsAA3hsAAN4bQADeG8AA3hwAAN4fQADeH4AA3h/AAN4gQADeMAAA3jCAAN4xAADeMYAA3jJAAN4ygADeMsAA3jMAAN4zQADeM8AA3jRAAN40gADeNMAA3jVAAN41gADeRUAA3kXAAN5GQADeRsAA3keAAN5HwADeSAAA3khAAN5IgADeSQAA3kmAAN5JwADeSgAA3kqAAN5KwADeWoAA3lsAAN5bgADeXAAA3lzAAN5dAADeXUAA3l2AAN5dwADeXkAA3l7AAN5fAADeX0AA3l/AAN5gAADeb8AA3nBAAN5wwADecUAA3nIAAN5yQADecoAA3nLAAN5zAADec4AA3nQAAN50QADedIAA3nUAAN51QADehQAA3oWAAN6GAADehoAA3odAAN6HgADeh8AA3ogAAN6IQADeiMAA3olAAN6JgADeicAA3opAAN6KgADek8AA3pzAAN6mgADer4AA3rBAAN6wwADesUAA3rHAAN6yQADessAA3rMAAN6zwADetwAA3rrAAN67QADeu8AA3rxAAN68wADevUAA3r3AAN6+QADewgAA3sLAAN7DgADexEAA3sUAAN7FwADexoAA3sdAAN7HwADe14AA3tgAAN7YgADe2QAA3tnAAN7aAADe2kAA3tqAAN7awADe20AA3tvAAN7cAADe3EAA3tzAAN7dAADe7MAA3u1AAN7twADe7kAA3u8AAN7vQADe74AA3u/AAN7wAADe8IAA3vEAAN7xQADe8YAA3vIAAN7yQADfAgAA3wKAAN8DAADfA4AA3wRAAN8EgADfBMAA3wUAAN8FQADfBcAA3wZAAN8GgADfBsAA3wdAAN8HgADfF0AA3xfAAN8YQADfGMAA3xmAAN8ZwADfGgAA3xpAAN8agADfGwAA3xuAAN8bwADfHAAA3xyAAN8cwADfLIAA3y0AAN8tgADfLgAA3y7AAN8vAADfL0AA3y+AAN8vwADfMEAA3zDAAN8xAADfMUAA3zHAAN8yAADfQcAA30JAAN9CwADfQ0AA30QAAN9EQADfRIAA30TAAN9FAADfRYAA30YAAN9GQADfRoAA30cAAN9HQADfVwAA31eAAN9YAADfWIAA31lAAN9ZgADfWcAA31oAAN9aQADfWsAA31tAAN9bgADfW8AA31xAAN9cgADfXsAA318AAN9fgADfcEAA33lAAN+CQADfiwAA35TAAN+cwADfpoAA37BAAN+4QADfwUAA38pAAN/KwADfy4AA38wAAN/MgADfzQAA383AAN/OgADfzwAA38+AAN/QQADf0MAA39FAAN/SAADf0sAA39M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AAOKagADimsAA4psAAOKbQADim8AA4pxAAOKcgADinMAA4p1AAOKdgADirUAA4q3AAOKuQADirsAA4q+AAOKvwADisAAA4rBAAOKwgADisQAA4rGAAOKxwADisgAA4rKAAOKywADiwoAA4sMAAOLDgADixAAA4sTAAOLFAADixUAA4sWAAOLFwADixkAA4sbAAOLHAADix0AA4sfAAOLIAADi18AA4thAAOLYwADi2UAA4toAAOLaQADi2oAA4trAAOLbAADi24AA4twAAOLcQADi3IAA4t0AAOLdQADi7QAA4u2AAOLuAADi7oAA4u9AAOLvgADi78AA4vAAAOLwQADi8MAA4vFAAOLxgADi8cAA4vJAAOLygADjBUAA4w4AAOMWAADjHgAA4x6AAOMfAADjH4AA4yAAAOMgwADjIQAA4yFAAOMiAADjIkAA4yLAAOMjAADjI4AA4yQAAOMkQADjJIAA4yVAAOMlgADjJsAA4yoAAOMrQADjK8AA4yxAAOMtgADjLkAA4y8AAOMvgADjOMAA40HAAONLgADjVIAA41VAAONVwADjVkAA41bAAONXQADjV8AA41gAAONYwADjXAAA42BAAONgwADjYUAA42HAAONiQADjYsAA42NAAONjwADjZEAA42iAAONpQADjagAA42rAAONrgADjbEAA420AAONtwADjboAA428AAON+wADjf0AA43/AAOOAQADjgQAA44FAAOOBgADjgcAA44IAAOOCgADjgwAA44NAAOODgADjhAAA44RAAOOUAADjlIAA45UAAOOVgADjlkAA45aAAOOWwADjlwAA45dAAOOXwADjmEAA45iAAOOYwADjmUAA45mAAOOpQADjqcAA46qAAOOrAADjq8AA46wAAOOsQADjrIAA46zAAOOtQADjrcAA464AAOOuQADjrsAA468AAOOyQADjsoAA47LAAOOzQADjwwAA48OAAOPEAADjxIAA48VAAOPFgADjxcAA48YAAOPGQADjxsAA48dAAOPHgADjx8AA48hAAOPIgADj2EAA49jAAOPZQADj2cAA49qAAOPawADj2wAA49tAAOPbgADj3AAA49yAAOPcwADj3QAA492AAOPdwADj7YAA4+4AAOPugADj7wAA4+/AAOPwAADj8EAA4/CAAOPwwADj8UAA4/HAAOPyAADj8kAA4/L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AAOa/wADmwEAA5sDAAObBAADmwUAA5sHAAObCAADm0cAA5tJAAObSwADm00AA5tQAAObUQADm1IAA5tTAAObVAADm1YAA5tYAAObWQADm1oAA5tcAAObXQADm5wAA5ueAAOboAADm6IAA5ulAAObpgADm6cAA5uoAAObqQADm6sAA5utAAObrgADm68AA5uxAAObsgADm7sAA5u8AAObvgADnAEAA5wlAAOcSQADnGwAA5yTAAOcswADnNoAA50BAAOdIQADnUUAA51pAAOdawADnW4AA51wAAOdcgADnXQAA513AAOdegADnXwAA51+AAOdgQADnYMAA52FAAOdiAADnYsAA52MAAOdkQADnZ4AA52hAAOdowADnaYAA52pAAOdqwADndAAA530AAOeGwADnj8AA55CAAOeRAADnkYAA55IAAOeSgADnkwAA55NAAOeUAADnl0AA55wAAOecgADnnQAA552AAOeeAADnnoAA558AAOefgADnoAAA56CAAOelQADnpgAA56bAAOengADnqEAA56kAAOepwADnqoAA56tAAOesAADnrIAA57xAAOe8wADnvYAA574AAOe+wADnvwAA579AAOe/gADnv8AA58BAAOfAwADnwQAA58FAAOfBwADnwgAA58RAAOfEgADnxQAA59TAAOfVQADn1cAA59ZAAOfXAADn10AA59eAAOfXwADn2AAA59iAAOfZAADn2UAA59mAAOfaAADn2kAA5+oAAOfqgADn60AA5+vAAOfsgADn7MAA5+0AAOftQADn7YAA5+4AAOfugADn7sAA5+8AAOfvgADn78AA5/IAAOfyQADn8sAA6AKAAOgDAADoA4AA6AQAAOgEwADoBQAA6AVAAOgFgADoBcAA6AZAAOgGwADoBwAA6AdAAOgHwADoCAAA6BfAAOgYQADoGQAA6BmAAOgaQADoGoAA6BrAAOgbAADoG0AA6BvAAOgcQADoHIAA6BzAAOgdQADoHYAA6B/AAOggAADoIIAA6DBAAOgwwADoMUAA6DHAAOgygADoMsAA6DMAAOgzQADoM4AA6DQAAOg0gADoNMAA6DUAAOg1gADoNcAA6EWAAOhGAADoRsAA6EdAAOhIAADoSEAA6EiAAOhIwADoSQAA6EmAAOhKAADoSkAA6EqAAOhLAADoS0AA6E6AAOhOwADoTwAA6E+AAOhfQADoX8AA6GBAAOhgwADoYYAA6GHAAOhiAADoYkAA6GKAAOhjAADoY4AA6GPAAOhkAADoZIAA6GTAAOh0gADodQAA6HXAAOh2QADodwAA6HdAAOh3gADod8AA6HgAAOh4gADoeQAA6HlAAOh5gADoegAA6HpAAOh+AADogUAA6IMAAOiDwADohIAA6IVAAOiHAADoh8AA6IiAAOiJQADoicAA6IuAAOiOAADooMAA6KmAAOixgADouYAA6LoAAOi6gADouwAA6LuAAOi8QADovIAA6LzAAOi9gADovcAA6L5AAOi+gADovwAA6L/AAOjAAADowEAA6MEAAOjBQADowoAA6MXAAOjHAADox4AA6MgAAOjJQADoygAA6MrAAOjLQADo1IAA6N2AAOjnQADo8EAA6PEAAOjxgADo8gAA6PKAAOjzAADo84AA6PPAAOj0gADo98AA6PwAAOj8gADo/QAA6P2AAOj+AADo/oAA6P8AAOj/gADpAAAA6QRAAOkFAADpBcAA6QaAAOkHQADpCAAA6QjAAOkJgADpCkAA6QrAAOkagADpGwAA6RuAAOkcAADpHMAA6R0AAOkdQADpHYAA6R3AAOkeQADpHsAA6R8AAOkfQADpH8AA6SAAAOkvwADpMEAA6TDAAOkxQADpMgAA6TJAAOkygADpMsAA6TMAAOkzgADpNAAA6TRAAOk0gADpNQAA6TVAAOlFAADpRYAA6UZAAOlGwADpR4AA6UfAAOlIAADpSEAA6UiAAOlJAADpSYAA6UnAAOlKAADpSoAA6UrAAOlOAADpTkAA6U6AAOlPAADpXsAA6V9AAOlfwADpYEAA6WEAAOlhQADpYYAA6WHAAOliAADpYoAA6WMAAOljQADpY4AA6WQAAOlkQADpdAAA6XSAAOl1AADpdYAA6XZAAOl2gADpdsAA6XcAAOl3QADpd8AA6XhAAOl4gADpeMAA6XlAAOl5gADpiUAA6YnAAOmKQADpisAA6YuAAOmLwADpjAAA6YxAAOmMgADpjQAA6Y2AAOmNwADpjgAA6Y6AAOmOwADpnoAA6Z8AAOmfgADpoAAA6aDAAOmhAADpoUAA6aGAAOmhwADpokAA6aLAAOmjAADpo0AA6aPAAOmkAADps8AA6bRAAOm0wADptUAA6bYAAOm2QADptoAA6bbAAOm3AADpt4AA6bgAAOm4QADpuIAA6bkAAOm5QADpwoAA6cuAAOnVQADp3kAA6d8AAOnfgADp4AAA6eCAAOnhAADp4YAA6eHAAOnigADp5cAA6emAAOnqAADp6oAA6esAAOnrgADp7AAA6eyAAOntAADp8MAA6fGAAOnyQADp8wAA6fPAAOn0gADp9UAA6fYAAOn2gADqBkAA6gbAAOoHQADqB8AA6giAAOoIwADqCQAA6glAAOoJgADqCgAA6gqAAOoKwADqCwAA6guAAOoLwADqG4AA6hwAAOocgADqHQAA6h3AAOoeAADqHkAA6h6AAOoewADqH0AA6h/AAOogAADqIEAA6iDAAOohAADqMMAA6jFAAOoxwADqMkAA6jMAAOozQADqM4AA6jPAAOo0AADqNIAA6jUAAOo1QADqNYAA6jYAAOo2QADqRgAA6kaAAOpHAADqR4AA6khAAOpIgADqSMAA6kkAAOpJQADqScAA6kpAAOpKgADqSsAA6ktAAOpLgADqW0AA6lvAAOpcQADqXMAA6l2AAOpdwADqXgAA6l5AAOpegADqXwAA6l+AAOpfwADqYAAA6mCAAOpgwADqcIAA6nEAAOpxgADqcgAA6nLAAOpzAADqc0AA6nOAAOpzwADqdEAA6nTAAOp1AADqdUAA6nXAAOp2AADqhcAA6oZAAOqGwADqh0AA6ogAAOqIQADqiIAA6ojAAOqJAADqiYAA6ooAAOqKQADqioAA6osAAOqLQADqngAA6qbAAOquwADqtsAA6rdAAOq3wADquEAA6rjAAOq5gADqucAA6roAAOq6wADquwAA6ruAAOq7wADqvEAA6r0AAOq9QADqvYAA6r5AAOq+gADqwMAA6sQAAOrFQADqxcAA6sZAAOrHgADqyEAA6skAAOrJgADq0sAA6tvAAOrlgADq7oAA6u9AAOrvwADq8EAA6vDAAOrxQADq8cAA6vIAAOrywADq9gAA6vpAAOr6wADq+0AA6vvAAOr8QADq/MAA6v1AAOr9wADq/kAA6wKAAOsDQADrBAAA6wTAAOsFgADrBkAA6wcAAOsHwADrCIAA6wkAAOsYwADrGUAA6xnAAOsaQADrGwAA6xtAAOsbgADrG8AA6xwAAOscgADrHQAA6x1AAOsdgADrHgAA6x5AAOsuAADrLoAA6y8AAOsvgADrMEAA6zCAAOswwADrMQAA6zFAAOsxwADrMkAA6zKAAOsywADrM0AA6zOAAOtDQADrQ8AA60SAAOtFAADrRcAA60YAAOtGQADrRoAA60bAAOtHQADrR8AA60gAAOtIQADrSMAA60kAAOtMQADrTIAA60zAAOtNQADrXQAA612AAOteAADrXoAA619AAOtfgADrX8AA62AAAOtgQADrYMAA62FAAOthgADrYcAA62JAAOtigADrckAA63LAAOtzQADrc8AA63SAAOt0wADrdQAA63VAAOt1gADrdgAA63aAAOt2wADrdwAA63eAAOt3wADrh4AA64gAAOuIgADriQAA64nAAOuKAADrikAA64qAAOuKwADri0AA64vAAOuMAADrjEAA64zAAOuNAADrnMAA651AAOudwADrnkAA658AAOufQADrn4AA65/AAOugAADroIAA66EAAOuhQADroYAA66IAAOuiQADrsgAA67KAAOuzAADrs4AA67RAAOu0gADrtMAA67UAAOu1QADrtcAA67ZAAOu2gADrtsAA67dAAOu3gADrwMAA68nAAOvTgADr3IAA691AAOvdwADr3kAA697AAOvfQADr38AA6+AAAOvgwADr5AAA6+fAAOvoQADr6MAA6+lAAOvpwADr6kAA6+rAAOvrQADr7wAA6+/AAOvwgADr8UAA6/IAAOvywADr84AA6/RAAOv0wADsBIAA7AUAAOwFgADsBgAA7AbAAOwHAADsB0AA7AeAAOwHwADsCEAA7AjAAOwJAADsCUAA7AnAAOwKAADsGcAA7BpAAOwawADsG0AA7BwAAOwcQADsHIAA7BzAAOwdAADsHYAA7B4AAOweQADsHoAA7B8AAOwfQADsLwAA7C+AAOwwAADsMIAA7DFAAOwxgADsMcAA7DIAAOwyQADsMsAA7DNAAOwzgADsM8AA7DRAAOw0gADsREAA7ETAAOxFQADsRcAA7EaAAOxGwADsRwAA7EdAAOxHgADsSAAA7EiAAOxIwADsSQAA7EmAAOxJwADsWYAA7FoAAOxagADsWwAA7FvAAOxcAADsXEAA7FyAAOxcwADsXUAA7F3AAOxeAADsXkAA7F7AAOxfAADsbsAA7G9AAOxvwADscEAA7HEAAOxxQADscYAA7HHAAOxyAADscoAA7HMAAOxzQADsc4AA7HQAAOx0QADshAAA7ISAAOyFAADshYAA7IZAAOyGgADshsAA7IcAAOyHQADsh8AA7IhAAOyIgADsiMAA7IlAAOyJgADsnEAA7KUAAOytAADstQAA7LWAAOy2AADstoAA7LcAAOy3wADsuAAA7LhAAOy5AADsuUAA7LnAAOy6AADsuoAA7LtAAOy7gADsu8AA7LyAAOy8wADsvgAA7MFAAOzCgADswwAA7MOAAOzEwADsxYAA7MZAAOzGwADs0AAA7NkAAOziwADs68AA7OyAAOztAADs7YAA7O4AAOzugADs7wAA7O9AAOzwAADs80AA7PeAAOz4AADs+IAA7PkAAOz5gADs+gAA7PqAAOz7AADs+4AA7P/AAO0AgADtAUAA7QIAAO0CwADtA4AA7QRAAO0FAADtBcAA7QZAAO0WAADtFoAA7RcAAO0XgADtGEAA7RiAAO0YwADtGQAA7RlAAO0ZwADtGkAA7RqAAO0awADtG0AA7RuAAO0rQADtK8AA7SxAAO0swADtLYAA7S3AAO0uAADtLkAA7S6AAO0vAADtL4AA7S/AAO0wAADtMIAA7TDAAO1AgADtQQAA7UHAAO1CQADtQwAA7UNAAO1DgADtQ8AA7UQAAO1EgADtRQAA7UVAAO1FgADtRgAA7UZAAO1JgADtScAA7UoAAO1KgADtWkAA7VrAAO1bQADtW8AA7VyAAO1cwADtXQAA7V1AAO1dgADtXgAA7V6AAO1ewADtXwAA7V+AAO1fwADtb4AA7XAAAO1wgADtcQAA7XHAAO1yAADtckAA7XKAAO1ywADtc0AA7XPAAO10AADtdEAA7XTAAO11AADthMAA7YVAAO2FwADthkAA7YcAAO2HQADth4AA7YfAAO2IAADtiIAA7YkAAO2JQADtiYAA7YoAAO2KQADtmgAA7ZqAAO2bAADtm4AA7ZxAAO2cgADtnMAA7Z0AAO2dQADtncAA7Z5AAO2egADtnsAA7Z9AAO2fgADtr0AA7a/AAO2wQADtsMAA7bGAAO2xwADtsgAA7bJAAO2ygADtswAA7bOAAO2zwADttAAA7bSAAO20wADtvgAA7ccAAO3QwADt2cAA7dqAAO3bAADt24AA7dwAAO3cgADt3QAA7d1AAO3eAADt4UAA7eUAAO3lgADt5gAA7eaAAO3nAADt54AA7egAAO3ogADt7EAA7e0AAO3twADt7oAA7e9AAO3wAADt8MAA7fGAAO3yAADuAcAA7gJAAO4CwADuA0AA7gQAAO4EQADuBIAA7gTAAO4FAADuBYAA7gYAAO4GQADuBoAA7gcAAO4HQADuFwAA7heAAO4YAADuGIAA7hlAAO4ZgADuGcAA7hoAAO4aQADuGsAA7htAAO4bgADuG8AA7hxAAO4cgADuLEAA7izAAO4tQADuLcAA7i6AAO4uwADuLwAA7i9AAO4vgADuMAAA7jCAAO4wwADuMQAA7jGAAO4xwADuQYAA7kIAAO5CgADuQwAA7kPAAO5EAADuREAA7kSAAO5EwADuRUAA7kXAAO5GAADuRkAA7kbAAO5HAADuVsAA7ldAAO5XwADuWEAA7lkAAO5ZQADuWYAA7lnAAO5aAADuWoAA7lsAAO5bQADuW4AA7lwAAO5cQADubAAA7myAAO5tAADubYAA7m5AAO5ugADubsAA7m8AAO5vQADub8AA7nBAAO5wgADucMAA7nFAAO5xgADugUAA7oHAAO6CQADugsAA7oOAAO6DwADuhAAA7oRAAO6EgADuhQAA7oWAAO6FwADuhgAA7oaAAO6GwADuiQAA7olAAO6JwADumoAA7qOAAO6sgADutUAA7r8AAO7HAADu0MAA7tqAAO7igADu64AA7vSAAO71AADu9cAA7vZAAO72wADu90AA7vgAAO74wADu+UAA7vnAAO76gADu+wAA7vuAAO78QADu/QAA7v1AAO7/gADvAsAA7wOAAO8EAADvBMAA7wWAAO8GAADvD0AA7xhAAO8iAADvKwAA7yvAAO8sQADvLMAA7y1AAO8twADvLkAA7y6AAO8vQADvMoAA7zdAAO83wADvOEAA7zjAAO85QADvOcAA7zpAAO86wADvO0AA7zvAAO9AgADvQUAA70IAAO9CwADvQ4AA70RAAO9FAADvRcAA70aAAO9HQADvR8AA71eAAO9YAADvWMAA71lAAO9aAADvWkAA71qAAO9awADvWwAA71uAAO9cAADvXEAA71yAAO9dAADvXUAA71+AAO9fwADvYEAA73AAAO9wgADvcQAA73GAAO9yQADvcoAA73LAAO9zAADvc0AA73PAAO90QADvdIAA73TAAO91QADvdYAA74VAAO+FwADvhoAA74cAAO+HwADviAAA74hAAO+IgADviMAA74lAAO+JwADvigAA74pAAO+KwADviwAA741AAO+NgADvjgAA753AAO+eQADvnsAA759AAO+gAADvoEAA76CAAO+gwADvoQAA76GAAO+iAADvokAA76KAAO+jAADvo0AA77MAAO+zgADvtEAA77TAAO+1gADvtcAA77YAAO+2QADvtoAA77cAAO+3gADvt8AA77gAAO+4gADvuMAA77sAAO+7QADvu8AA78uAAO/MAADvzIAA780AAO/NwADvzgAA785AAO/OgADvzsAA789AAO/PwADv0AAA79BAAO/QwADv0QAA7+DAAO/hQADv4gAA7+KAAO/jQADv44AA7+PAAO/kAADv5EAA7+TAAO/lQADv5YAA7+XAAO/mQADv5oAA7+nAAO/qAADv6kAA7+rAAO/6gADv+wAA7/uAAO/8AADv/MAA7/0AAO/9QADv/YAA7/3AAO/+QADv/sAA7/8AAO//QADv/8AA8AAAAPAPwADwEEAA8BEAAPARgADwEkAA8BKAAPASwADwEwAA8BNAAPATwADwFEAA8BSAAPAUwADwFUAA8BWAAPAawADwHgAA8B9AAPAgAADwIMAA8CIAAPAiwADwI4AA8CQAAPAlQADwOAAA8EDAAPBIwADwUMAA8FFAAPBRwADwUkAA8FLAAPBTgADwU8AA8FQAAPBUwADwVQAA8FWAAPBVwADwVkAA8FcAAPBXQADwV4AA8FhAAPBYgADwWcAA8F0AAPBeQADwXsAA8F9AAPBggADwYUAA8GIAAPBigADwa8AA8HTAAPB+gADwh4AA8IhAAPCIwADwiUAA8InAAPCKQADwisAA8IsAAPCLwADwjwAA8JNAAPCTwADwlEAA8JTAAPCVQADwlcAA8JZAAPCWwADwl0AA8JuAAPCcQADwnQAA8J3AAPCegADwn0AA8KAAAPCgwADwoYAA8KIAAPCxwADwskAA8LLAAPCzQADwtAAA8LRAAPC0gADwtMAA8LUAAPC1gADwtgAA8LZAAPC2gADwtwAA8LdAAPDHAADwx4AA8MgAAPDIgADwyUAA8MmAAPDJwADwygAA8MpAAPDKwADwy0AA8MuAAPDLwADwzEAA8MyAAPDcQADw3MAA8N2AAPDeAADw3sAA8N8AAPDfQADw34AA8N/AAPDgQADw4MAA8OEAAPDhQADw4cAA8OIAAPDlQADw5YAA8OXAAPDmQADw9gAA8PaAAPD3AADw94AA8PhAAPD4gADw+MAA8PkAAPD5QADw+cAA8PpAAPD6gADw+sAA8PtAAPD7gADxC0AA8QvAAPEMQADxDMAA8Q2AAPENwADxDgAA8Q5AAPEOgADxDwAA8Q+AAPEPwADxEAAA8RCAAPEQwADxIIAA8SEAAPEhgADxIgAA8SLAAPEjAADxI0AA8SOAAPEjwADxJEAA8STAAPElAADxJUAA8SXAAPEmAADxNcAA8TZAAPE2wADxN0AA8TgAAPE4QADxOIAA8TjAAPE5AADxOYAA8ToAAPE6QADxOoAA8TsAAPE7QADxSwAA8UuAAPFMAADxTIAA8U1AAPFNgADxTcAA8U4AAPFOQADxTsAA8U9AAPFPgADxT8AA8VBAAPFQgADxWcAA8WLAAPFsgADxdYAA8XZAAPF2wADxd0AA8XfAAPF4QADxeMAA8XkAAPF5wADxfQAA8YDAAPGBQADxgcAA8YJAAPGCwADxg0AA8YPAAPGEQADxiAAA8YjAAPGJgADxikAA8YsAAPGLwADxjIAA8Y1AAPGNwADxnYAA8Z4AAPGegADxnwAA8Z/AAPGgAADxoEAA8aCAAPGgwADxoUAA8aHAAPGiAADxokAA8aLAAPGjAADxssAA8bNAAPGzwADxtEAA8bUAAPG1QADxtYAA8bXAAPG2AADxtoAA8bcAAPG3QADxt4AA8bgAAPG4QADxyAAA8ciAAPHJAADxyYAA8cpAAPHKgADxysAA8csAAPHLQADxy8AA8cxAAPHMgADxzMAA8c1AAPHNgADx3UAA8d3AAPHegADx3wAA8d/AAPHgAADx4EAA8eCAAPHgwADx4UAA8eHAAPHiAADx4kAA8eLAAPHjAADx8sAA8fNAAPHzwADx9EAA8fUAAPH1QADx9YAA8fXAAPH2AADx9oAA8fcAAPH3QADx94AA8fgAAPH4QADyCAAA8giAAPIJAADyCYAA8gpAAPIKgADyCsAA8gsAAPILQADyC8AA8gxAAPIMgADyDMAA8g1AAPINgADyHUAA8h3AAPIeQADyHsAA8h+AAPIfwADyIAAA8iBAAPIggADyIQAA8iGAAPIhwADyIgAA8iKAAPIiwADyNYAA8j5AAPJGQADyTkAA8k7AAPJPQADyT8AA8lBAAPJRAADyUUAA8lGAAPJSQADyUoAA8lMAAPJTQADyU8AA8lSAAPJUwADyVQAA8lXAAPJWAADyWEAA8luAAPJcwADyXUAA8l3AAPJfAADyX8AA8mCAAPJhAADyakAA8nNAAPJ9AADyhgAA8obAAPKHQADyh8AA8ohAAPKIwADyiUAA8omAAPKKQADyjYAA8pHAAPKSQADyksAA8pNAAPKTwADylEAA8pTAAPKVQADylcAA8poAAPKawADym4AA8pxAAPKdAADyncAA8p6AAPKfQADyoAAA8qCAAPKwQADysMAA8rFAAPKxwADysoAA8rLAAPKzAADys0AA8rOAAPK0AADytIAA8rTAAPK1AADytYAA8rXAAPLFgADyxgAA8saAAPLHAADyx8AA8sgAAPLIQADyyIAA8sjAAPLJQADyycAA8soAAPLKQADyysAA8ssAAPLawADy20AA8twAAPLcgADy3UAA8t2AAPLdwADy3gAA8t5AAPLewADy30AA8t+AAPLfwADy4EAA8uCAAPLjwADy5AAA8uRAAPLkwADy9IAA8vUAAPL1gADy9gAA8vbAAPL3AADy90AA8veAAPL3wADy+EAA8vjAAPL5AADy+UAA8vnAAPL6AADzCcAA8wpAAPMKwADzC0AA8wwAAPMMQADzDIAA8wzAAPMNAADzDYAA8w4AAPMOQADzDoAA8w8AAPMPQADzHwAA8x+AAPMgAADzIIAA8yFAAPMhgADzIcAA8yIAAPMiQADzIsAA8yNAAPMjgADzI8AA8yRAAPMkgADzNEAA8zTAAPM1QADzNcAA8zaAAPM2wADzNwAA8zdAAPM3gADzOAAA8ziAAPM4wADzOQAA8zmAAPM5wADzSYAA80oAAPNKgADzSwAA80vAAPNMAADzTEAA80yAAPNMwADzTUAA803AAPNOAADzTkAA807AAPNPAADzWEAA82FAAPNrAADzdAAA83TAAPN1QADzdcAA83ZAAPN2wADzd0AA83eAAPN4QADze4AA839AAPN/wADzgEAA84DAAPOBQADzgcAA84JAAPOCwADzhoAA84dAAPOIAADziMAA84mAAPOKQADziwAA84vAAPOMQADznAAA85yAAPOdAADznYAA855AAPOegADznsAA858AAPOfQADzn8AA86BAAPOggADzoMAA86FAAPOhgADzsUAA87HAAPOyQADzssAA87OAAPOzwADztAAA87RAAPO0gADztQAA87WAAPO1wADztgAA87aAAPO2wADzxoAA88cAAPPHgADzyAAA88jAAPPJAADzyUAA88mAAPPJwADzykAA88rAAPPLAADzy0AA88vAAPPMAADz28AA89xAAPPcwADz3UAA894AAPPeQADz3oAA897AAPPfAADz34AA8+AAAPPgQADz4IAA8+EAAPPhQADz8QAA8/GAAPPyAADz8oAA8/NAAPPzgADz88AA8/QAAPP0QADz9MAA8/VAAPP1gADz9cAA8/ZAAPP2gAD0BkAA9AbAAPQHQAD0B8AA9AiAAPQIwAD0CQAA9AlAAPQJgAD0CgAA9AqAAPQKwAD0CwAA9AuAAPQLwAD0G4AA9BwAAPQcgAD0HQAA9B3AAPQeAAD0HkAA9B6AAPQewAD0H0AA9B/AAPQgAAD0IEAA9CDAAPQhAAD0I0AA9COAAPQkAAD0J0AA9CeAAPQnwAD0KEAA9CuAAPQrwAD0LAAA9CyAAPQvwAD0MAAA9DBAAPQwwAD0MwAA9DbAAPQ6AAD0PcAA9EJAAPRHQAD0TQAA9FGAAPRTwAD0VAAA9FSAAPRXwAD0WAAA9FhAAPRYwAD0WwAA9F2AAPRfQAAAAAAAAQCAAAAAAAAkzcAAAAAAAAAAAAAAAAAA9GF +cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxELiAALAAwAGwA3ADgAOQBhAGIAYwBkAGUAZgBnAGgAaQBqAGsAbABtAG4AbwBwAHEAcgCNAI4AjwCVAJYAogC4ALkAugC7ALwAvQC+AL8AwADBANoA3QDkAOoA+QEIAQsBGgEpASwAjAE8AUsBTwFTAWIBaAFpAXEBgAGBAYoBlgGXAZgBmQGaAa8BsAG4AbkBugHGAdoB2wHcAd0B3gHfAeAB4QHiAfECAAIPAhMCIgIxAjICQQJQAl8CawJ9An4CfwKAAoECggKDAoQAMQKTAqICowKyAsEC2wLcAuIC7gMEAxMDFgMlAzQDOAM8Az0DTANbA14DbQN8A4ADjwOeA9gD2QPaA9sD3APdA94D3wPgA+ED4gPjA+QD5QPmA+cD6APpA+oD6wPsA+0D7gPvA/AD8QQGBAcEDwQbBC8EPgRNBFwEYARvBH4EjQScBKsEtwTJBNgE5wT2BQUFFAUjBTIFOgVPBVAFWAVZBWUFeQWIBZcFpgWqBbkFyAXXBeYF9QYBBhMGFAYVBhYGFwYYBhkGGgYpBioGOQZIBlcGWAZnBnYGhQaNBqIGowarBrcGywbaBukG+Ab8BwsHGgcpBzgHRwdTB2UHdAeDB5IHoQeiB7EHwAfPB+QH5QftB/kIDQgcCCsIOgg+CE0IXAhrCHoIiQiVCKcItgjFCNQI4wjkCPMJAgkRCSYJJwkvCTsJTwleCW0JfAmACY8JngmtCbwJywnXCekJ+AoHChYKJQomCjUKRApFClQKaQpqCnIKfgqSCqEKsAq/CsMK0grhCvAK/wsOCxoLLAs7CzwLSwtaC2kLagt5C4gLlwusC60LtQvBC9UL5AvzDAIMBgwVDCQMMwxCDFEMXQxvDH4MjQycDKsMugzJDNgM7QzuDPYNAg0WDSUNNA1DDUcNVg1lDXQNgw2SDZ4NsA2/Dc4N3Q3sDfsOCg4ZDi4OLw43DkMOVw5mDnUOhA6IDpcOpg61DsQO0w7fDvEPAA8PDx4PLQ88D0sPWg9vD3APeA+ED5gPpw+2D8UPyQ/YD+cP9hAFEBQQIBAyEEEQUBBfEG4QfRCMEJsQsBCxELkQxRDZEOgQ9xEGEQoRGREoETcRRhFVEWERcxGCEZERoBGvEb4RzRHcEfER8hH6EgYSGhI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EWJNYolixWMBY1VjWWN5Y6lj+WQ1ZHFkrWS9ZPllNWVxZa1l6WYZZmFmnWbZZxVnUWdVZ5FnzWgJaF1oYWiBaLFpAWk9aXlptWnFagFqPWp5arVq8Wsha2lrpWvhbB1sWWyVbNFtDW1hbWVthW21bgVuQW59brluyW8Fb0FvfW+5b/VwJXBtcKlw5XEhcV1xmXHVchFyHXKFcolyoXLRcylzZXNxc61z6XP1dDF0bXR5dLV08XUBdT11eXV9dbV1uXW9dcF1xXXJdh12IXZBdnF2wXb9dzl3dXeFd8F3/Xg5eHV4sXjheSl5ZXmhed16GXpVepF6lXrReyV7KXtJe3l7yXwFfEF8fXyNfMl9BX1BfX19uX3pfjF+bX6pfuV/IX9df5l/nX/ZgC2AMYBRgIGA0YENgUmBhYGVgdGCDYJJgoWCwYLxgzmDdYOxg+2EKYRlhKGE3YUxhTWFVYWFhdWGEYZNhomGmYbVhxGHTYeJh8WH9Yg1iHGI2YjdiPWJJYl9ibmJxYoBij2KSYqFisGKzYsJi0WLVYuRi82L0Yv5i/2MAYxVjFmMeYypjPmNNY1xja2NvY35jjWOcY6tjumPGY9hj52P2ZAVkFGQjZDJkQWRWZFdkX2RrZH9kjmSdZKxksGS/ZM5k3WTsZPtlB2UZZShlN2VGZVVlZGVzZYJll2WYZaBlrGXAZc9l3mXtZfFmAGYPZh5mLWY8ZkhmWmZpZnhmh2aWZpdmpma1ZsRmx2bWZuVm9GcDZxJnJ2coZzBnPGdQZ19nbmd9Z4FnkGefZ65nvWfMZ9hn6mf5aAhoF2gmaDVoRGhTaFZocGhxaHdog2iZaKhoq2i6aMlozGjbaOpo7Wj8aQtpD2keaS1pLmk2aTdpOGlNaU5pVmliaXZphWmUaaNpp2m2acVp1GnjafJp/moQah9qLmo9akxqW2pqanlqjmqPapdqo2q3asZq1Wrkauhq92sGaxVrJGszaz9rUWtga29rfmuNa5xrq2u6a71r12vYa95r6mwAbA9sEmwhbDBsM2xCbFFsVGxjbHJsdmyFbJRslWyjbKRspWymbLtsvGzEbNBs5GzzbQJtEW0VbSRtM21CbVFtYG1sbX5tjW2cbattum3Jbdht5238bf1uBW4RbiVuNG5DblJuVm5lbnRug26SbqFurW6/bs5u3W7sbvtvCm8ZbyhvPW8+b0ZvUm9mb3VvhG+Tb5dvpm+1b8Rv02/ib+5wAHAPcB5wLXA8cEtwWnBpcH5wf3CHcJNwp3C2cMVw1HDYcOdw9nEFcRRxI3EvcUFxUHFfcW5xfXGMcZtxqnG/ccBxyHHUcehx93IGchVyGXIocjdyRnJVcmRycHKCcpFyoHKvcr5yzXLccuty7nMIcwlzD3MbczFzQHNDc1JzYXNkc3NzgnOFc5Rzo3Onc7ZzxXPGc9Jz03PUc+lz6nPyc/50EnQhdDB0P3RDdFJ0YXRwdH90jnSadKx0u3TKdNl06HT3dQZ1FXUqdSt1M3U/dVN1YnVxdYB1hHWTdaJ1sXXAdc9123Xtdfx2C3Yadil2OHZHdlZ2a3ZsdnR2gHaUdqN2snbBdsV21HbjdvJ3AXcQdxx3Lnc9d0x3W3dqd3l3iHeXd6x3rXe1d8F31Xfkd/N4AngGeBV4JHgzeEJ4UXhdeG94fniNeJx4q3i6eMl42HjbePV49nj8eQh5HnkteTB5P3lOeVF5YHlveXJ5gXmQeZR5o3myebN5zXnOec950HnRedJ503nUedV51nnXeex57Xn1egF6FXokejN6QnpGelV6ZHpzeoJ6kXqdeq96vnrNetx663r6ewl7GHstey57NntCe1Z7ZXt0e4N7h3uWe6V7tHvDe9J73nvwe/98DnwdfCx8O3xKfFl8bnxvfHd8g3yXfKZ8tXzEfMh813zmfPV9BH0TfR99MX1AfU99Xn1tfXx9i32afa99sH24fcR92H3nffZ+BX4Jfhh+J342fkV+VH5gfnJ+gX6Qfp9+rn69fsx+237wfvF++X8Ffxl/KH83f0Z/Sn9Zf2h/d3+Gf5V/oX+zf8J/0X/gf+9//oANgByAMYAygDqARoBagGmAeICHgIuAmoCpgLiAx4DWgOKA9IEDgRKBIYEwgT+BToFdgXKBc4F7gYeBm4GqgbmByIHMgduB6oH5ggiCF4IjgjWCRIJTgmKCcYKAgo+CnoKzgrSCvILIgtyC64L6gwmDDYMcgyuDOoNJg1iDZIN2g4WDlIOjg7KDwYPQg9+D9IP1g/2ECYQdhCyEO4RKhE6EXYRshHuEioSZhKWEt4TGhNWE5ITzhQKFEYUghTWFNoU+hUqFXoVthXyFi4WPhZ6FrYW8hcuF2oXmhfiGB4YWhiWGNIZDhlKGYYZ2hneGf4aLhp+Groa9hsyG0Ibfhu6G/YcMhxuHJ4c5h0iHV4dmh3WHhIeTh6KHpYe/h8CHxofSh+iH94f6iAmIGIgbiCqIOYg8iEuIWoheiG2IfIiGiJuInIikiLCIxIjTiOKI8Yj1iQSJE4kiiTGJQIlMiV6JbYl8iYuJmompibiJx4ncid2J5YnxigWKFIojijKKNopFilSKY4pyioGKjYqfiq6KvYrMituK6or5iwiLHYseiyaLMotGi1WLZItzi3eLhouVi6SLs4vCi86L4Ivvi/6MDYwcjCuMOoxJjEyMZoxnjG2MeYyPjJ6MoYywjL+MwozRjOCM44zyjQGNBY0UjSONJI0ujS+NMI1FjUaNTo1ajW6NfY2MjZuNn42ujb2NzI3bjeqN9o4IjheOJo41jkSOU45ijnGOho6Hjo+Om46vjr6OzY7cjuCO747+jw2PHI8rjzePSY9Yj2ePdo+Fj5SPo4+yj8ePyI/Qj9yP8I//kA6QHZAhkDCQP5BOkF2QbJB4kIqQmZCokLeQxpDVkOSQ85D2kRCREZEXkSOROZFIkUuRWpFpkWyRe5GKkY2RnJGrka+RvpHNkc6R1pHXkeyR7ZH1kgGSFZIkkjOSQpJGklWSZJJzkoKSkZKdkq+SvpLNktyS65L6kwmTGJMtky6TNpNCk1aTZZN0k4OTh5OWk6WTtJPDk9KT3pPwk/+UDpQdlCyUO5RKlFmUXJRglGSUaJRwlHOUd1UkbnVsbNcADQAOAA8AEAARABIAEwAUABUAFgAXABgAFwAaXxAPX3hkX3Jvb3RQYWNrYWdlViRjbGFzc1xfeGRfY29tbWVudHNfEBBfeGRfbW9kZWxNYW5hZ2VyXxAVX2NvbmZpZ3VyYXRpb25zQnlOYW1lXV94ZF9tb2RlbE5hbWVfEBdfbW9kZWxWZXJzaW9uSWRlbnRpZmllcoACgQuHgQuFgACBC4aAAIEEGt4AHAAdAB4AHwAgACEAIgAOACMAJAAlACYAJwAoACkAKgArAAkAKQAXAC8AMAAxADIAMwApACkAF18QHFhEQnVja2V0Rm9yQ2xhc3Nlc3dhc0VuY29kZWRfEBpYREJ1Y2tldEZvclBhY2thZ2Vzc3RvcmFnZV8QHFhEQnVja2V0Rm9ySW50ZXJmYWNlc3N0b3JhZ2VfEA9feGRfb3duaW5nTW9kZWxfEB1YREJ1Y2tldEZvclBhY2thZ2Vzd2FzRW5jb2RlZFZfb3duZXJfEBtYREJ1Y2tldEZvckRhdGFUeXBlc3N0b3JhZ2VbX3Zpc2liaWxpdHlfEBlYREJ1Y2tldEZvckNsYXNzZXNzdG9yYWdlVV9uYW1lXxAfWERCdWNrZXRGb3JJbnRlcmZhY2Vzd2FzRW5jb2RlZF8QHlhEQnVja2V0Rm9yRGF0YVR5cGVzd2FzRW5jb2RlZF8QEF91bmlxdWVFbGVtZW50SUSABIELg4ELgYABgASAAIELgoELhBAAgAWAA4AEgASAAFBTWUVT0wA6ADsADgA8AE4AYFdOUy5rZXlzWk5TLm9iamVjdHOvEBEAPQA+AD8AQABBAEIAQwBEAEUARgBHAEgASQBKAEsATABNgAaAB4AIgAmACoALgAyADYAOgA+AEIARgBKAE4AUgBWAFq8QEQBPAFAAUQBSAFMAVABVAFYAVwBYAFkAWgBbAFwAXQBeAF+AF4BqgQZrgQG4gQaxgQc+gQTwgQgpgQhugQevgQj5gQPEgQlsgQV5gQqIgQrhgQs9gDVdQ0RFeHRlcm5hbEFwaVdDRENoYWluXUNEU2luZ2xlVmFsdWVXQ0RBc3NldF1DRENvbnRhY3RJdGVtXxAZQ0RQb2xrYXN3YXBSZW1vdGVTZXR0aW5nc18QEENEQ2hhaW5YY21Db25maWdbQ0RTdGFzaEl0ZW1fEBVDRFJ1bnRpbWVNZXRhZGF0YUl0ZW1eQ0RQb2xrYXN3YXBEZXhaQ0RTY2FtSW5mb1tDRENoYWluTm9kZV8QGENEVHJhbnNhY3Rpb25IaXN0b3J5SXRlbV8QGUNEWGNtQXZhaWxhYmxlRGVzdGluYXRpb25ZQ0RDb250YWN0XkNEUGhpc2hpbmdJdGVtXxASQ0RDaGFpblN0b3JhZ2VJdGVt3xAQAHMAdAB1AHYAIQB3AHgAIwB5AHoADgAlAHsAfAAoAH0AfgB/ACkAKQAUAIMAhAAxACkAfgCHAD0AfgCKAIsAjF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZVtfaXNBYnN0cmFjdIAZgD2ABIAEgAKAGoEDS4AEgBmBA02ABoAZgQZqgBgIEwAAAAEYayQ4V29yZGVyZWTTADoAOwAOAJAAkgBgoQCRgBuhAJOAHIA1XlhEX1BTdGVyZW90eXBl2QAhACUAlwAOACgAmAAjAH0AmQBPAJEAfgCdABcAKQAxAIwAoV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYAXgBuAGYA8gACABAiAHdMAOgA7AA4AowCtAGCpAKQApQCmAKcAqACpAKoAqwCsgB6AH4AggCGAIoAjgCSAJYAmqQCuAK8AsACxALIAswC0ALUAtoAngCuALIAugC+AMYAzgDaAOoA1XxATWERQTUNvbXBvdW5kSW5kZXhlc18QEFhEX1BTS19lbGVtZW50SURfEBlYRFBNVW5pcXVlbmVzc0NvbnN0cmFpbnRzXxAaWERfUFNLX3ZlcnNpb25IYXNoTW9kaWZpZXJfEBlYRF9QU0tfZmV0Y2hSZXF1ZXN0c0FycmF5XxARWERfUFNLX2lzQWJzdHJhY3RfEA9YRF9QU0tfdXNlckluZm9fEBNYRF9QU0tfY2xhc3NNYXBwaW5nXxAWWERfUFNLX2VudGl0eUNsYXNzTmFtZd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAM0AFwCTAIwAjACMADEAjADUAKQAjACMABcAjFVfdHlwZVhfZGVmYXVsdFxfYXNzb2NpYXRpb25bX2lzUmVhZE9ubHlZX2lzU3RhdGljWV9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F3IEF84EGCoA1WWV4cGxvcmVyc11hZGRyZXNzUHJlZml4XXN0YWtpbmdBcGlVcmxXb3B0aW9uc11oYXNDcm93ZGxvYW5zVGljb25eaGlzdG9yeUFwaVR5cGVdaXNUaXBSZXF1aXJlZFRuYW1lXxARbWluaW1hbEFwcFZlcnNpb25WYXNzZXRzXxATdHlwZXNPdmVycmlkZUNvbW1vbllpc1Rlc3RuZXRec3Rha2luZ0FwaVR5cGVVbm9kZXNcc2VsZWN0ZWROb2RlWHBhcmVudElkVmlzT3JtbFhkaXNhYmxlZF8QEWNyb3dkbG9hbnNBcGlUeXBlXxAQY3Jvd2Rsb2Fuc0FwaVVybFl4Y21Db25maWdfEA9pc0V0aGVyZXVtQmFzZWRdaGlzdG9yeUFwaVVybFtjdXN0b21Ob2Rlc98QEgDCAMMAxAPyACEAxgDHA/MAIwDFA/QAyAAOACUAyQDKACgAywAXABcAFwApAFAAjACMA/wAMQCMAH4AjAGpA6AAjACMBAQAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgGoICICaCIAZCICvgH8ICICZCBJPT7+H0wA6ADsADgQIBAsAYKIBsgGzgEWARqIEDAQNgJuApoA12QAhACUEEAAOACgEEQAjAH0EEgO8AbIAfgCdABcAKQAxAIwEGl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYCYgEWAGYA8gACABAiAnNMAOgA7AA4EHAQlAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoBCYEJwQoBCkEKgQrBCwELYCdgJ6An4ChgKKAo4CkgKWANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFwQMAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAICbCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMU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ICAgIgCqAUAgIgAAI2QAhACUSlwAOACgSmAAjAH0SmQPHAbMAfgCdABcAKQAxAIwSoV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEBp4BGgBmAPIAAgAQIgQG20wA6ADsADhKjEqoAYKYCcAJyAm0CbgJvAnGAYIBigF2AXoBfgGGmEqsSrBKtEq4SrxKwgQG3gQNOgQNPgQNQgQNRgQNSgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwBSABcR+ACMAIwAjAAxAIwA1AJwAIwAjAAXAIyAAIEBuIAAgQG1CAgICIAqgGAICIAACN8QEBLCEsMSxBLFACESxhLHACMSyBLJAA4AJRLKEssAKAB9AH4SzQApACkAFBLRAIQAMQApAH4AhwBAAH4S2BLZAIxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2WAGYEByoAEgASAAoEBuoEDS4AEgBmBA02ACYAZgQNMgQG5CBKwZdhq0wA6ADsADhLdEt8AYKEAkYAboRLggQG7gDXZACEAJRLjAA4AKBLkACMAfRLlAFIAkQB+AJ0AFwApADEAjBLtXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQG4gBuAGYA8gACABAiBAbzTADoAOwAOEu8S+QBgqQCkAKUApgCnAKgAqQCqAKsArIAegB+AIIAhgCKAI4AkgCWAJqkS+hL7EvwS/RL+Ev8TABMBEwKBAb2BAb+BAcCBAcKBAcOBAcWBAcaBAciBAcmANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXEwYAFxLgAIwAjACMADEAjADUAKQAjACMABcAjIAAgQG+gACBAbsICAgIgCqAHggIgAAI0gA7AA4TFADcoIAp3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXEuAAjACMAIwAMQCMANQApQCMAIwAFwCMgACAAIAAgQG7CAgICIAqgB8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXEycAFxLgAIwAjACMADEAjADUAKYAjACMABcAjIAAgQHBgACBAbsICAgIgCqAIAgIgAAI0gA7AA4TNQDcoIAp3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXEuAAjACMAIwAMQCMANQApwCMAIwAFwCMgACAAIAAgQG7CAgICIAqgCEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXE0gAFxLgAIwAjACMADEAjADUAKgAjACMABcAjIAAgQHEgACBAbsICAgIgCqAIggIgAAI0gA7AA4TVgDcoIAp3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXEuAAjACMAIwAMQCMANQAqQCMAIwAFwCMgACAMoAAgQG7CAgICIAqgCMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXE2kAFxLgAIwAjACMADEAjADUAKoAjACMABcAjIAAgQHHgACBAbsICAgIgCqAJAgIgAAI0wA6ADsADhN3E3gAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwFVABcS4ACMAIwAjAAxAIwA1ACrAIwAjAAXAIyAAIA3gACBAbsICAgIgCqAJQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAQAAXEuAAjACMAIwAMQCMANQArACMAIwAFwCMgACACYAAgQG7CAgICIAqgCYICIAACNMAOgA7AA4TmROqAGCvEBATmgGOE5wTnROeE58ToBOhE6ITowOmE6UTphOnA6kTqYEBy4BAgQHMgQHNgQHOgQHPgQHQgQHRgQHSgQHTgISBAdSBAdWBAdaAh4EB168QEBOrE6wTrROuE68TsBOxE7ITsxO0E7UTthO3E7gTuRO6gQHYgQHvgQIGgQIdgQI2gQJNgQJkgQJ7gQKSgQKpgQLAgQLXgQLugQMFgQMdgQM0gDVSaWRWc3ltYm9sXWZpYXREYXlDaGFuZ2VVY29sb3JVcHJpY2VXcHJpY2VJZFpjdXJyZW5jeUlkWXByZWNpc2lvblhpc05hdGl2ZVlpc1V0aWxpdHlfEBJleGlzdGVudGlhbERlcG9zaXRfEBFwdXJjaGFzZVByb3ZpZGVyc1dzdGFraW5n3xASAMIAwwDEE8oAIQDGAMcTywAjAMUTzADIAA4AJQDJAMoAKADLABcAFwAXACkAUgCMAIwT1AAxAIwAfgCMBUkTmgCMAIwT3ACMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAbgICIEB2giAGQiA0YEBywgIgQHZCBKeTHZ70wA6ADsADhPgE+MAYKIBsgVTgEWAs6IT5BPlgQHbgQHmgDXZACEAJRPoAA4AKBPpACMAfRPqE6sBsgB+AJ0AFwApADEAjBPyXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQHYgEWAGYA8gACABAiBAdzTADoAOwAOE/QT/QBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqBP+E/8UABQBFAIUAxQEFAWBAd2BAd6BAd+BAeGBAeKBAeOBAeSBAeWANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxPkAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEB2wgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcT5ACMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBAdsICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcUJwAXE+QAjACMAIwAMQCMANQBygCMAIwAFwCMgACBAeCAAIEB2wgICAiAKoBLCAiAAAjTADoAOwAOFDUUNgBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxPkAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEB2wgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcT5ACMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIAygACBAdsICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXE+QAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQHbCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxPkAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEB2wgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcT5ACMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBAdsICAgIgCqAUAgIgAAI2QAhACUUhAAOACgUhQAjAH0UhhOrBVMAfgCdABcAKQAxAIwUjl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEB2ICzgBmAPIAAgAQIgQHn0wA6ADsADhSQFJgAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHpxSZFJoUmxScFJ0UnhSfgQHogQHpgQHqgQHrgQHsgQHtgQHugDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcT5QCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBAeYICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXE+UAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQHmCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxPlAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEB5ggICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABcT5QCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBAeYICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXE+UAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQHmCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxPlAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEB5ggICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcT5QCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBAeYICAgIgCqAxwgIgAAI3xASAMIAwwDEFQsAIQDGAMcVDAAjAMUVDQDIAA4AJQDJAMoAKADLABcAFwAXACkAUgCMAIwVFQAxAIwAfgCMBUkBjgCMAIwVHQCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAbgICIEB8QiAGQiA0YBACAiBAfAIEmHmmHDTADoAOwAOFSEVJABgogGyBVOARYCzohUlFSaBAfKBAf2ANdkAIQAlFSkADgAoFSoAIwB9FSsTrAGyAH4AnQAXACkAMQCMFTNfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAe+ARYAZgDyAAIAECIEB89MAOgA7AA4VNRU+AGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoFT8VQBVBFUIVQxVEFUUVRoEB9IEB9YEB9oEB+IEB+YEB+oEB+4EB/IA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXFSUAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQHyCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxUlAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEB8ggICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFxVoABcVJQCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEB94AAgQHyCAgICIAqgEsICIAACNMAOgA7AA4VdhV3AGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXFSUAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQHyCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFxUlAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEB8ggICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcVJQCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBAfIICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXFSUAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQHyCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxUlAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEB8ggICAiAKoBQCAiAAAjZACEAJRXFAA4AKBXGACMAfRXHE6wFUwB+AJ0AFwApADEAjBXPXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQHvgLOAGYA8gACABAiBAf7TADoAOwAOFdEV2QBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenFdoV2xXcFd0V3hXfFeCBAf+BAgCBAgGBAgKBAgOBAgSBAgWANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxUmAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEB/QgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcVJgCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBAf0ICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXFSYAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQH9CAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAFxUmAIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIEB/QgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcVJgCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBAf0ICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXFSYAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQH9CAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxUmAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEB/QgICAiAKoDHCAiAAAjfEBIAwgDDAMQWTAAhAMYAxxZNACMAxRZOAMgADgAlAMkAygAoAMsAFwAXABcAKQBSAIwAjBZWADEAjAB+AIwFSROcAIwAjBZeAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEBuAgIgQIICIAZCIDRgQHMCAiBAgcIEn3d7VTTADoAOwAOFmIWZQBgogGyBVOARYCzohZmFmeBAgmBAhSANdkAIQAlFmoADgAoFmsAIwB9FmwTrQGyAH4AnQAXACkAMQCMFnRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAgaARYAZgDyAAIAECIECCtMAOgA7AA4WdhZ/AGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoFoAWgRaCFoMWhBaFFoYWh4ECC4ECDIECDYECD4ECEIECEYECEoECE4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXFmYAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQIJCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxZmAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIECCQgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFxapABcWZgCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIECDoAAgQIJCAgICIAqgEsICIAACNMAOgA7AA4Wtxa4AGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXFmYAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQIJCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFxZmAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIECCQgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcWZgCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBAgkICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXFmYAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQIJCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxZmAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIECCQgICAiAKoBQCAiAAAjZACEAJRcGAA4AKBcHACMAfRcIE60FUwB+AJ0AFwApADEAjBcQXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQIGgLOAGYA8gACABAiBAhXTADoAOwAOFxIXGgBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenFxsXHBcdFx4XHxcgFyGBAhaBAheBAhiBAhmBAhqBAhuBAhyANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxZnAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIECFAgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcWZwCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBAhQICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXFmcAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQIUCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAFxZnAIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIECFAgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcWZwCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBAhQICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXFmcAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQIUCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxZnAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIECFAgICAiAKoDHCAiAAAjfEBIAwgDDAMQXjQAhAMYAxxeOACMAxRePAMgADgAlAMkAygAoAMsAFwAXABcAKQBSAIwAjBeXADEAjAB+AIwFSROdAIwAjBefAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEBuAgIgQIfCIAZCIDRgQHNCAiBAh4IEksCSLbTADoAOwAOF6MXpgBgogGyBVOARYCzohenF6iBAiCBAiuANdkAIQAlF6sADgAoF6wAIwB9F60TrgGyAH4AnQAXACkAMQCMF7VfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAh2ARYAZgDyAAIAECIECIdMAOgA7AA4XtxfAAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoF8EXwhfDF8QXxRfGF8cXyIECIoECI4ECJIECJoECJ4ECKIECKYECKoA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXF6cAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQIgCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxenAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIECIAgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFxfqABcXpwCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIECJYAAgQIgCAgICIAqgEsICIAACNMAOgA7AA4X+Bf5AGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXF6cAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQIgCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFxenAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIECIAgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcXpwCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBAiAICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXF6cAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQIgCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxenAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIECIAgICAiAKoBQCAiAAAjZACEAJRhHAA4AKBhIACMAfRhJE64FUwB+AJ0AFwApADEAjBhRXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQIdgLOAGYA8gACABAiBAizTADoAOwAOGFMYWwBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenGFwYXRheGF8YYBhhGGKBAi2BAi+BAjCBAjGBAjOBAjSBAjWANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXGGYAFxeoAIwAjACMADEAjADUBgMAjACMABcAjIAAgQIugACBAisICAgIgCqAwQgIgAAIUzAuMN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxeoAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIECKwgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcXqACMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBAisICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcYlAAXF6gAjACMAIwAMQCMANQGBgCMAIwAFwCMgACBAjKAAIECKwgICAiAKoDECAiAAAgRAZDfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcXqACMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBAisICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXF6gAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQIrCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxeoAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIECKwgICAiAKoDHCAiAAAjfEBIAwgDDAMQY0AAhAMYAxxjRACMAxRjSAMgADgAlAMkAygAoAMsAFwAXABcAKQBSAIwAjBjaADEAjAB+AIwFSROeAIwAjBjiAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEBuAgIgQI4CIAZCIDRgQHOCAiBAjcIEr6HOvTTADoAOwAOGOYY6QBgogGyBVOARYCzohjqGOuBAjmBAkSANdkAIQAlGO4ADgAoGO8AIwB9GPATrwGyAH4AnQAXACkAMQCMGPhfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAjaARYAZgDyAAIAECIECOtMAOgA7AA4Y+hkDAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoGQQZBRkGGQcZCBkJGQoZC4ECO4ECPIECPYECP4ECQIECQYECQoECQ4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXGOoAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQI5CAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxjqAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIECOQgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFxktABcY6gCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIECPoAAgQI5CAgICIAqgEsICIAACNMAOgA7AA4ZOxk8AGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXGOoAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQI5CAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFxjqAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIECOQgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcY6gCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBAjkICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXGOoAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQI5CAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxjqAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIECOQgICAiAKoBQCAiAAAjZACEAJRmKAA4AKBmLACMAfRmME68FUwB+AJ0AFwApADEAjBmUXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQI2gLOAGYA8gACABAiBAkXTADoAOwAOGZYZngBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenGZ8ZoBmhGaIZoxmkGaWBAkaBAkeBAkiBAkmBAkqBAkuBAkyANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxjrAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIECRAgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcY6wCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBAkQICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXGOsAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQJECAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAFxjrAIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIECRAgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcY6wCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBAkQICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXGOsAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQJECAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxjrAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIECRAgICAiAKoDHCAiAAAjfEBIAwgDDAMQaEQAhAMYAxxoSACMAxRoTAMgADgAlAMkAygAoAMsAFwAXABcAKQBSAIwAjBobADEAjAB+AIwFSROfAIwAjBojAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEBuAgIgQJPCIAZCIDRgQHPCAiBAk4IEva6nSbTADoAOwAOGicaKgBgogGyBVOARYCzohorGiyBAlCBAluANdkAIQAlGi8ADgAoGjAAIwB9GjETsAGyAH4AnQAXACkAMQCMGjlfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAk2ARYAZgDyAAIAECIECUdMAOgA7AA4aOxpEAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoGkUaRhpHGkgaSRpKGksaTIECUoECU4ECVIECVoECV4ECWIECWYECWoA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXGisAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQJQCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxorAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIECUAgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFxpuABcaKwCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIECVYAAgQJQCAgICIAqgEsICIAACNMAOgA7AA4afBp9AGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXGisAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQJQCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFxorAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIECUAgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcaKwCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBAlAICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXGisAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQJQCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxorAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIECUAgICAiAKoBQCAiAAAjZACEAJRrLAA4AKBrMACMAfRrNE7AFUwB+AJ0AFwApADEAjBrVXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQJNgLOAGYA8gACABAiBAlzTADoAOwAOGtca3wBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenGuAa4RriGuMa5BrlGuaBAl2BAl6BAl+BAmCBAmGBAmKBAmOANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXGGYAFxosAIwAjACMADEAjADUBgMAjACMABcAjIAAgQIugACBAlsICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXGiwAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQJbCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxosAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIECWwgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFxiUABcaLACMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIECMoAAgQJbCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxosAIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIECWwgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcaLACMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBAlsICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXGiwAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQJbCAgICIAqgMcICIAACN8QEgDCAMMAxBtSACEAxgDHG1MAIwDFG1QAyAAOACUAyQDKACgAywAXABcAFwApAFIAjACMG1wAMQCMAH4AjAVJE6AAjACMG2QAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQG4CAiBAmYIgBkIgNGBAdAICIECZQgSwqDqCdMAOgA7AA4baBtrAGCiAbIFU4BFgLOiG2wbbYECZ4ECcoA12QAhACUbcAAOACgbcQAjAH0bchOxAbIAfgCdABcAKQAxAIwbel8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECZIBFgBmAPIAAgAQIgQJo0wA6ADsADht8G4UAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKgbhhuHG4gbiRuKG4sbjBuNgQJpgQJqgQJrgQJtgQJugQJvgQJwgQJxgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcbbACMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBAmcICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXG2wAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQJnCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXG68AFxtsAIwAjACMADEAjADUAcoAjACMABcAjIAAgQJsgACBAmcICAgIgCqASwgIgAAI0wA6ADsADhu9G74AYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcbbACMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBAmcICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXG2wAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQJnCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxtsAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIECZwgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcbbACMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBAmcICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXG2wAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQJnCAgICIAqgFAICIAACNkAIQAlHAwADgAoHA0AIwB9HA4TsQVTAH4AnQAXACkAMQCMHBZfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAmSAs4AZgDyAAIAECIECc9MAOgA7AA4cGBwgAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6ccIRwiHCMcJBwlHCYcJ4ECdIECdYECdoECd4ECeIECeYECeoA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXG20AjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQJyCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxttAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIECcggICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcbbQCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBAnIICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcHlAAXG20AjACMAIwAMQCMANQGBgCMAIwAFwCMgACA5oAAgQJyCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxttAIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIECcggICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcbbQCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBAnIICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXG20AjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQJyCAgICIAqgMcICIAACN8QEgDCAMMAxByTACEAxgDHHJQAIwDFHJUAyAAOACUAyQDKACgAywAXABcAFwApAFIAjACMHJ0AMQCMAH4AjAVJE6EAjACMHKUAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQG4CAiBAn0IgBkIgNGBAdEICIECfAgS87IdkNMAOgA7AA4cqRysAGCiAbIFU4BFgLOiHK0croECfoECiYA12QAhACUcsQAOACgcsgAjAH0csxOyAbIAfgCdABcAKQAxAIwcu18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECe4BFgBmAPIAAgAQIgQJ/0wA6ADsADhy9HMYAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKgcxxzIHMkcyhzLHMwczRzOgQKAgQKBgQKCgQKEgQKFgQKGgQKHgQKIgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABccrQCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBAn4ICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXHK0AjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQJ+CAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXHPAAFxytAIwAjACMADEAjADUAcoAjACMABcAjIAAgQKDgACBAn4ICAgIgCqASwgIgAAI0wA6ADsADhz+HP8AYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABccrQCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBAn4ICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXHK0AjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQJ+CAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxytAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIECfggICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABccrQCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBAn4ICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXHK0AjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQJ+CAgICIAqgFAICIAACNkAIQAlHU0ADgAoHU4AIwB9HU8TsgVTAH4AnQAXACkAMQCMHVdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAnuAs4AZgDyAAIAECIECitMAOgA7AA4dWR1hAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6cdYh1jHWQdZR1mHWcdaIECi4ECjIECjYECjoECj4ECkIECkYA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXHK4AjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQKJCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFxyuAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIECiQgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABccrgCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBAokICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcHlAAXHK4AjACMAIwAMQCMANQGBgCMAIwAFwCMgACA5oAAgQKJCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFxyuAIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIECiQgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABccrgCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBAokICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXHK4AjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQKJCAgICIAqgMcICIAACN8QEgDCAMMAxB3UACEAxgDHHdUAIwDFHdYAyAAOACUAyQDKACgAywAXABcAFwApAFIAjACMHd4AMQCMAH4AjAVJE6IAjACMHeYAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQG4CAiBApQIgBkIgNGBAdIICIECkwgSsP2PZ9MAOgA7AA4d6h3tAGCiAbIFU4BFgLOiHe4d74EClYECoIA12QAhACUd8gAOACgd8wAjAH0d9BOzAbIAfgCdABcAKQAxAIwd/F8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECkoBFgBmAPIAAgAQIgQKW0wA6ADsADh3+HgcAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKgeCB4JHgoeCx4MHg0eDh4PgQKXgQKYgQKZgQKbgQKcgQKdgQKegQKfgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcd7gCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBApUICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXHe4AjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQKVCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXHjEAFx3uAIwAjACMADEAjADUAcoAjACMABcAjIAAgQKagACBApUICAgIgCqASwgIgAAI0wA6ADsADh4/HkAAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcd7gCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBApUICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXHe4AjACMAIwAMQCMANQBzACMAIwAFwCMgACAMoAAgQKVCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFx3uAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEClQgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcd7gCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBApUICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXHe4AjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQKVCAgICIAqgFAICIAACNkAIQAlHo4ADgAoHo8AIwB9HpATswVTAH4AnQAXACkAMQCMHphfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBApKAs4AZgDyAAIAECIECodMAOgA7AA4emh6iAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6ceox6kHqUeph6nHqgeqYECooECo4ECpIECpYECpoECp4ECqIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcGHAAXHe8AjACMAIwAMQCMANQGAwCMAIwAFwCMgACAyYAAgQKgCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFx3vAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIECoAgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcd7wCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBAqAICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcGSgAXHe8AjACMAIwAMQCMANQGBgCMAIwAFwCMgACAzYAAgQKgCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFx3vAIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIECoAgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcd7wCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBAqAICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXHe8AjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQKgCAgICIAqgMcICIAACN8QEgDCAMMAxB8VACEAxgDHHxYAIwDFHxcAyAAOACUAyQDKACgAywAXABcAFwApAFIAjACMHx8AMQCMAH4AjAVJE6MAjACMHycAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQG4CAiBAqsIgBkIgNGBAdMICIECqggSP3fu3dMAOgA7AA4fKx8uAGCiAbIFU4BFgLOiHy8fMIECrIECt4A12QAhACUfMwAOACgfNAAjAH0fNRO0AbIAfgCdABcAKQAxAIwfPV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECqYBFgBmAPIAAgAQIgQKt0wA6ADsADh8/H0gAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKgfSR9KH0sfTB9NH04fTx9QgQKugQKvgQKwgQKygQKzgQK0gQK1gQK2gDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcfLwCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBAqwICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXHy8AjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQKsCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXH3IAFx8vAIwAjACMADEAjADUAcoAjACMABcAjIAAgQKxgACBAqwICAgIgCqASwgIgAAI0wA6ADsADh+AH4EAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcfLwCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBAqwICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXHy8AjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQKsCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFx8vAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIECrAgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcfLwCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBAqwICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXHy8AjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQKsCAgICIAqgFAICIAACNkAIQAlH88ADgAoH9AAIwB9H9ETtAVTAH4AnQAXACkAMQCMH9lfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAqmAs4AZgDyAAIAECIECuNMAOgA7AA4f2x/jAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6cf5B/lH+Yf5x/oH+kf6oECuYECuoECu4ECvIECvYECvoECv4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXHzAAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQK3CAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFx8wAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIECtwgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcfMACMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBArcICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcLXAAXHzAAjACMAIwAMQCMANQGBgCMAIwAFwCMgACBATCAAIECtwgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcfMACMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBArcICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXHzAAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQK3CAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFx8wAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIECtwgICAiAKoDHCAiAAAjfEBIAwgDDAMQgVgAhAMYAxyBXACMAxSBYAMgADgAlAMkAygAoAMsAFwAXABcAKQBSAIwAjCBgADEAjAB+AIwFSQOmAIwAjCBoAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEBuAgIgQLCCIAZCIDRgIQICIECwQgS/d9vJtMAOgA7AA4gbCBvAGCiAbIFU4BFgLOiIHAgcYECw4ECzoA12QAhACUgdAAOACggdQAjAH0gdhO1AbIAfgCdABcAKQAxAIwgfl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYECwIBFgBmAPIAAgAQIgQLE0wA6ADsADiCAIIkAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKggiiCLIIwgjSCOII8gkCCRgQLFgQLGgQLHgQLJgQLKgQLLgQLMgQLNgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcgcACMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBAsMICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXIHAAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQLDCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXILMAFyBwAIwAjACMADEAjADUAcoAjACMABcAjIAAgQLIgACBAsMICAgIgCqASwgIgAAI0wA6ADsADiDBIMIAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcgcACMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBAsMICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXIHAAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQLDCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyBwAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIECwwgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcgcACMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBAsMICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXIHAAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQLDCAgICIAqgFAICIAACNkAIQAlIRAADgAoIREAIwB9IRITtQVTAH4AnQAXACkAMQCMIRpfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAsCAs4AZgDyAAIAECIECz9MAOgA7AA4hHCEkAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6chJSEmISchKCEpISohK4EC0IEC0YEC0oEC04EC1IEC1YEC1oA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXIHEAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQLOCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyBxAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIECzggICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcgcQCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBAs4ICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcI1gAXIHEAjACMAIwAMQCMANQGBgCMAIwAFwCMgACA/oAAgQLOCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyBxAIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIECzggICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcgcQCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBAs4ICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXIHEAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQLOCAgICIAqgMcICIAACN8QEgDCAMMAxCGXACEAxgDHIZgAIwDFIZkAyAAOACUAyQDKACgAywAXABcAFwApAFIAjACMIaEAMQCMAH4AjAVJE6UAjACMIakAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQG4CAiBAtkIgBkIgNGBAdQICIEC2AgSxCSRgNMAOgA7AA4hrSGwAGCiAbIFU4BFgLOiIbEhsoEC2oEC5YA12QAhACUhtQAOACghtgAjAH0htxO2AbIAfgCdABcAKQAxAIwhv18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEC14BFgBmAPIAAgAQIgQLb0wA6ADsADiHBIcoAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKghyyHMIc0hziHPIdAh0SHSgQLcgQLdgQLegQLggQLhgQLigQLjgQLkgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABchsQCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBAtoICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXIbEAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQLaCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXIfQAFyGxAIwAjACMADEAjADUAcoAjACMABcAjIAAgQLfgACBAtoICAgIgCqASwgIgAAI0wA6ADsADiICIgMAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABchsQCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBAtoICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXIbEAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQLaCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyGxAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEC2ggICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABchsQCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBAtoICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXIbEAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQLaCAgICIAqgFAICIAACNkAIQAlIlEADgAoIlIAIwB9IlMTtgVTAH4AnQAXACkAMQCMIltfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAteAs4AZgDyAAIAECIEC5tMAOgA7AA4iXSJlAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6ciZiJnImgiaSJqImsibIEC54EC6IEC6YEC6oEC64EC7IEC7YA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXIbIAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQLlCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyGyAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEC5QgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABchsgCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBAuUICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcLXAAXIbIAjACMAIwAMQCMANQGBgCMAIwAFwCMgACBATCAAIEC5QgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABchsgCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBAuUICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXIbIAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQLlCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyGyAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEC5QgICAiAKoDHCAiAAAjfEBIAwgDDAMQi2AAhAMYAxyLZACMAxSLaAMgADgAlAMkAygAoAMsAFwAXABcAKQBSAIwAjCLiADEAjAB+AIwFSROmAIwAjCLqAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEBuAgIgQLwCIAZCIDRgQHVCAiBAu8IEs6kohzTADoAOwAOIu4i8QBgogGyBVOARYCzoiLyIvOBAvGBAvyANdkAIQAlIvYADgAoIvcAIwB9IvgTtwGyAH4AnQAXACkAMQCMIwBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAu6ARYAZgDyAAIAECIEC8tMAOgA7AA4jAiMLAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoIwwjDSMOIw8jECMRIxIjE4EC84EC9IEC9YEC94EC+IEC+YEC+oEC+4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXIvIAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQLxCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyLyAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEC8QgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFyM1ABci8gCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEC9oAAgQLxCAgICIAqgEsICIAACNMAOgA7AA4jQyNEAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXIvIAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQLxCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFyLyAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEC8QgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABci8gCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBAvEICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXIvIAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQLxCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyLyAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEC8QgICAiAKoBQCAiAAAjZACEAJSOSAA4AKCOTACMAfSOUE7cFUwB+AJ0AFwApADEAjCOcXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQLugLOAGYA8gACABAiBAv3TADoAOwAOI54jpgBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenI6cjqCOpI6ojqyOsI62BAv6BAv+BAwCBAwGBAwKBAwOBAwSANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyLzAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEC/AgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABci8wCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBAvwICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXIvMAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQL8CAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAFyLzAIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIEC/AgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABci8wCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBAvwICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXIvMAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQL8CAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyLzAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEC/AgICAiAKoDHCAiAAAjfEBIAwgDDAMQkGQAhAMYAxyQaACMAxSQbAMgADgAlAMkAygAoAMsAFwAXABcAKQBSAIwAjCQjADEAjAB+AIwFSROnAIwAjCQrAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEBuAgIgQMHCIAZCIDRgQHWCAiBAwYIEn23ckHTADoAOwAOJC8kMgBgogGyBVOARYCzoiQzJDSBAwiBAxOANdkAIQAlJDcADgAoJDgAIwB9JDkTuAGyAH4AnQAXACkAMQCMJEFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBAwWARYAZgDyAAIAECIEDCdMAOgA7AA4kQyRMAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoJE0kTiRPJFAkUSRSJFMkVIEDCoEDC4EDDIEDDoEDD4EDEIEDEYEDEoA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXJDMAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQMICAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyQzAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEDCAgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFyR2ABckMwCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEDDYAAgQMICAgICIAqgEsICIAACNMAOgA7AA4khCSFAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXJDMAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQMICAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFyQzAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEDCAgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABckMwCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBAwgICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXJDMAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQMICAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyQzAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEDCAgICAiAKoBQCAiAAAjZACEAJSTTAA4AKCTUACMAfSTVE7gFUwB+AJ0AFwApADEAjCTdXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQMFgLOAGYA8gACABAiBAxTTADoAOwAOJN8k5wBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenJOgk6STqJOsk7CTtJO6BAxWBAxaBAxeBAxiBAxmBAxqBAxyANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyQ0AIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEDEwgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABckNACMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBAxMICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXJDQAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQMTCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXChgAFyQ0AIwAjACMADEAjADUBgYAjACMABcAjIAAgQEWgACBAxMICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXJDQAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQMTCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXJT0AFyQ0AIwAjACMADEAjADUBggAjACMABcAjIAAgQMbgACBAxMICAgIgCqAxggIgAAIXxAkTlNTZWN1cmVVbmFyY2hpdmVGcm9tRGF0YVRyYW5zZm9ybWVy3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXJDQAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQMTCAgICIAqgMcICIAACN8QEgDCAMMAxCVbACEAxgDHJVwAIwDFJV0AyAAOACUAyQDKACgAywAXABcAFwApAFIAjACMJWUAMQCMAH4AjAVJA6kAjACMJW0AjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQG4CAiBAx8IgBkIgNGAhwgIgQMeCBKqOnol0wA6ADsADiVxJXQAYKIBsgVTgEWAs6IldSV2gQMggQMrgDXZACEAJSV5AA4AKCV6ACMAfSV7E7kBsgB+AJ0AFwApADEAjCWDXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQMdgEWAGYA8gACABAiBAyHTADoAOwAOJYUljgBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqCWPJZAlkSWSJZMllCWVJZaBAyKBAyOBAySBAyaBAyeBAyiBAymBAyqANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyV1AIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEDIAgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcldQCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBAyAICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcluAAXJXUAjACMAIwAMQCMANQBygCMAIwAFwCMgACBAyWAAIEDIAgICAiAKoBLCAiAAAjTADoAOwAOJcYlxwBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyV1AIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEDIAgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABcldQCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBAyAICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXJXUAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQMgCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyV1AIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEDIAgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcldQCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBAyAICAgIgCqAUAgIgAAI2QAhACUmFQAOACgmFgAjAH0mFxO5BVMAfgCdABcAKQAxAIwmH18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDHYCzgBmAPIAAgAQIgQMs0wA6ADsADiYhJikAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHpyYqJismLCYtJi4mLyYwgQMtgQMugQMvgQMwgQMxgQMygQMzgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcldgCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBAysICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXJXYAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQMrCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyV2AIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEDKwgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABcldgCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBAysICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXJXYAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQMrCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyV2AIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEDKwgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcldgCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBAysICAgIgCqAxwgIgAAI3xASAMIAwwDEJpwAIQDGAMcmnQAjAMUmngDIAA4AJQDJAMoAKADLABcAFwAXACkAUgCMAIwmpgAxAIwAfgCMBUkTqQCMAIwmrgCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBAbgICIEDNgiAGQiA0YEB1wgIgQM1CBI4mtJL0wA6ADsADiayJrUAYKIBsgVTgEWAs6Imtia3gQM3gQNCgDXZACEAJSa6AA4AKCa7ACMAfSa8E7oBsgB+AJ0AFwApADEAjCbEXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQM0gEWAGYA8gACABAiBAzjTADoAOwAOJsYmzwBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqCbQJtEm0ibTJtQm1SbWJteBAzmBAzqBAzuBAz2BAz6BAz+BA0CBA0GANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFya2AIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEDNwgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcmtgCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBAzcICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcm+QAXJrYAjACMAIwAMQCMANQBygCMAIwAFwCMgACBAzyAAIEDNwgICAiAKoBLCAiAAAjTADoAOwAOJwcnCABgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFya2AIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEDNwgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABcmtgCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBAzcICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXJrYAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQM3CAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFya2AIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEDNwgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcmtgCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBAzcICAgIgCqAUAgIgAAI2QAhACUnVgAOACgnVwAjAH0nWBO6BVMAfgCdABcAKQAxAIwnYF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDNICzgBmAPIAAgAQIgQND0wA6ADsADidiJ2oAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHpydrJ2wnbSduJ28ncCdxgQNEgQNFgQNGgQNHgQNIgQNJgQNKgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcmtwCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBA0IICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXJrcAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQNCCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFya3AIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEDQggICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABcmtwCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBA0IICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXJrcAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQNCCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFya3AIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEDQggICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcmtwCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBA0IICAgIgCqAxwgIgAAIWmR1cGxpY2F0ZXPSADsADifeANyggCnSAN4A3yfhJ+JaWERQTUVudGl0eacn4yfkJ+Un5ifnJ+gA41pYRFBNRW50aXR5XVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXEfgAjACMAIwAMQCMANQCcgCMAIwAFwCMgACAMoAAgQG1CAgICIAqgGIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAoYAFxH4AIwAjACMADEAjADUAm0AjACMABcAjIAAgGWAAIEBtQgICAiAKoBdCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwKVABcR+ACMAIwAjAAxAIwA1AJuAIwAjAAXAIyAAIBngACBAbUICAgIgCqAXggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcChgAXEfgAjACMAIwAMQCMANQCbwCMAIwAFwCMgACAZYAAgQG1CAgICIAqgF8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFxH4AIwAjACMADEAjADUAnEAjACMABcAjIAAgFeAAIEBtQgICAiAKoBhCAiAAAjfEBIAwgDDAMQoNQAhAMYAxyg2ACMAxSg3AMgADgAlAMkAygAoAMsAFwAXABcAKQBQAIwAjCg/ADEAjAB+AIwFSQGNAIwAjChHAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIBqCAiBA1UIgBkIgNGAPwgIgQNUCBLhfjR80wA6ADsADihLKE4AYKIBsgVTgEWAs6IoTyhQgQNWgQNhgDXZACEAJShTAA4AKChUACMAfShVA8gBsgB+AJ0AFwApADEAjChdXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQNTgEWAGYA8gACABAiBA1fTADoAOwAOKF8oaABgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqChpKGooayhsKG0obihvKHCBA1iBA1mBA1qBA1yBA12BA16BA1+BA2CANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyhPAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEDVggICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcoTwCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBA1YICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcokgAXKE8AjACMAIwAMQCMANQBygCMAIwAFwCMgACBA1uAAIEDVggICAiAKoBLCAiAAAjTADoAOwAOKKAooQBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyhPAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEDVggICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABcoTwCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBA1YICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXKE8AjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQNWCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyhPAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEDVggICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcoTwCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBA1YICAgIgCqAUAgIgAAI2QAhACUo7wAOACgo8AAjAH0o8QPIBVMAfgCdABcAKQAxAIwo+V8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDU4CzgBmAPIAAgAQIgQNi0wA6ADsADij7KQMAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHpykEKQUpBikHKQgpCSkKgQNjgQNkgQNlgQNmgQNngQNogQNpgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcoUACMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBA2EICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXKFAAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQNhCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyhQAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEDYQgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwjWABcoUACMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAID+gACBA2EICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXKFAAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQNhCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyhQAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEDYQgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcoUACMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBA2EICAgIgCqAxwgIgAAI3xASAMIAwwDEKXYAIQDGAMcpdwAjAMUpeADIAA4AJQDJAMoAKADLABcAFwAXACkAUACMAIwpgAAxAIwAfgCMBUkDrQCMAIwpiACMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASAaggIgQNsCIAZCIDRgIoICIEDawgStE9LW9MAOgA7AA4pjCmPAGCiAbIFU4BFgLOiKZApkYEDbYEDeIA12QAhACUplAAOACgplQAjAH0plgPJAbIAfgCdABcAKQAxAIwpnl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDaoBFgBmAPIAAgAQIgQNu0wA6ADsADimgKakAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKgpqimrKawprSmuKa8psCmxgQNvgQNwgQNxgQNzgQN0gQN1gQN2gQN3gDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcpkACMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBA20ICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXKZAAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQNtCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXKdMAFymQAIwAjACMADEAjADUAcoAjACMABcAjIAAgQNygACBA20ICAgIgCqASwgIgAAI0wA6ADsADinhKeIAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcpkACMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBA20ICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXKZAAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQNtCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFymQAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEDbQgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcpkACMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBA20ICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXKZAAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQNtCAgICIAqgFAICIAACNkAIQAlKjAADgAoKjEAIwB9KjIDyQVTAH4AnQAXACkAMQCMKjpfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA2qAs4AZgDyAAIAECIEDedMAOgA7AA4qPCpEAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6cqRSpGKkcqSCpJKkoqS4EDeoEDe4EDfIEDfYEDfoEDf4EDgIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXKZEAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQN4CAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFymRAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEDeAgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcpkQCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBA3gICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcLXAAXKZEAjACMAIwAMQCMANQGBgCMAIwAFwCMgACBATCAAIEDeAgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcpkQCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBA3gICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXKZEAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQN4CAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFymRAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEDeAgICAiAKoDHCAiAAAjfEBIAwgDDAMQqtwAhAMYAxyq4ACMAxSq5AMgADgAlAMkAygAoAMsAFwAXABcAKQBQAIwAjCrBADEAjAB+AIwFSQOuAIwAjCrJAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIBqCAiBA4MIgBkIgNGAiwgIgQOCCBKpj9n40wA6ADsADirNKtAAYKIBsgVTgEWAs6Iq0SrSgQOEgQOPgDXZACEAJSrVAA4AKCrWACMAfSrXA8oBsgB+AJ0AFwApADEAjCrfXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQOBgEWAGYA8gACABAiBA4XTADoAOwAOKuEq6gBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqCrrKuwq7SruKu8q8CrxKvKBA4aBA4eBA4iBA4qBA4uBA4yBA42BA46ANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyrRAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEDhAgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcq0QCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBA4QICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcrFAAXKtEAjACMAIwAMQCMANQBygCMAIwAFwCMgACBA4mAAIEDhAgICAiAKoBLCAiAAAjTADoAOwAOKyIrIwBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyrRAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEDhAgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcq0QCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIAygACBA4QICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXKtEAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQOECAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyrRAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEDhAgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcq0QCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBA4QICAgIgCqAUAgIgAAI2QAhACUrcQAOACgrcgAjAH0rcwPKBVMAfgCdABcAKQAxAIwre18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDgYCzgBmAPIAAgAQIgQOQ0wA6ADsADit9K4UAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHpyuGK4criCuJK4oriyuMgQORgQOSgQOTgQOUgQOVgQOWgQOXgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwsuABcq0gCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIEBLIAAgQOPCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFyrSAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEDjwgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcq0gCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBA48ICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcLXAAXKtIAjACMAIwAMQCMANQGBgCMAIwAFwCMgACBATCAAIEDjwgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcq0gCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBA48ICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXKtIAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQOPCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFyrSAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEDjwgICAiAKoDHCAiAAAjfEBIAwgDDAMQr+AAhAMYAxyv5ACMAxSv6AMgADgAlAMkAygAoAMsAFwAXABcAKQBQAIwAjCwCADEAjAB+AIwFSQOvAIwAjCwKAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIBqCAiBA5oIgBkIgNGAjAgIgQOZCBJcESZI0wA6ADsADiwOLBEAYKIBsgVTgEWAs6IsEiwTgQObgQOmgDXZACEAJSwWAA4AKCwXACMAfSwYA8sBsgB+AJ0AFwApADEAjCwgXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQOYgEWAGYA8gACABAiBA5zTADoAOwAOLCIsKwBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqCwsLC0sLiwvLDAsMSwyLDOBA52BA56BA5+BA6GBA6KBA6OBA6SBA6WANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFywSAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEDmwgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcsEgCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBA5sICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcsVQAXLBIAjACMAIwAMQCMANQBygCMAIwAFwCMgACBA6CAAIEDmwgICAiAKoBLCAiAAAjTADoAOwAOLGMsZABgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFywSAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEDmwgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABcsEgCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBA5sICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXLBIAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQObCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFywSAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEDmwgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcsEgCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBA5sICAgIgCqAUAgIgAAI2QAhACUssgAOACgsswAjAH0stAPLBVMAfgCdABcAKQAxAIwsvF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDmICzgBmAPIAAgAQIgQOn0wA6ADsADiy+LMYAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHpyzHLMgsySzKLMsszCzNgQOogQOpgQOqgQOrgQOsgQOtgQOugDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcsEwCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBA6YICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXLBMAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQOmCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFywTAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEDpggICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABcsEwCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBA6YICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXLBMAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQOmCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFywTAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEDpggICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcsEwCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBA6YICAgIgCqAxwgIgAAI3xASAMIAwwDELTkAIQDGAMctOgAjAMUtOwDIAA4AJQDJAMoAKADLABcAFwAXACkAUACMAIwtQwAxAIwAfgCMAakDsACMAIwtSwCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASAaggIgQOxCIAZCICvgI0ICIEDsAgSQKfpttMAOgA7AA4tTy1SAGCiAbIBs4BFgEaiLVMtVIEDsoEDvYA12QAhACUtVwAOACgtWAAjAH0tWQPMAbIAfgCdABcAKQAxAIwtYV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDr4BFgBmAPIAAgAQIgQOz0wA6ADsADi1jLWwAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKgtbS1uLW8tcC1xLXItcy10gQO0gQO1gQO2gQO4gQO5gQO6gQO7gQO8gDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABctUwCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBA7IICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXLVMAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQOyCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXLZYAFy1TAIwAjACMADEAjADUAcoAjACMABcAjIAAgQO3gACBA7IICAgIgCqASwgIgAAI0wA6ADsADi2kLaUAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABctUwCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBA7IICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXLVMAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQOyCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFy1TAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEDsggICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABctUwCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBA7IICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXLVMAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQOyCAgICIAqgFAICIAACNkAIQAlLfMADgAoLfQAIwB9LfUDzAGzAH4AnQAXACkAMQCMLf1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBA6+ARoAZgDyAAIAECIEDvtMAOgA7AA4t/y4HAGCnAm0CbgJvAnACcQJyAnOAXYBegF+AYIBhgGKAY6cuCC4JLgouCy4MLg0uDoEDv4EDwIEDwoEDw4EEUIEEUYEEUoA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcClQAXLVQAjACMAIwAMQCMANQCbQCMAIwAFwCMgACAZ4AAgQO9CAgICIAqgF0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXLiEAFy1UAIwAjACMADEAjADUAm4AjACMABcAjIAAgQPBgACBA70ICAgIgCqAXggIgAAIEALfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwKGABctVACMAIwAjAAxAIwA1AJvAIwAjAAXAIyAAIBlgACBA70ICAgIgCqAXwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAWgAXLVQAjACMAIwAMQCMANQCcACMAIwAFwCMgACBA8SAAIEDvQgICAiAKoBgCAiAAAjfEBAuTi5PLlAuUQAhLlIuUwAjLlQuVQAOACUuVi5XACgAfQB+LlkAKQApABQuXQCEADEAKQB+AIcASAB+LmQuZQCMXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgBmBA9iABIAEgAKBA8aBA0uABIAZgQNNgBGAGYEET4EDxQgSYeZUa9MAOgA7AA4uaS5rAGChAJGAG6EubIEDx4A12QAhACUubwAOACgucAAjAH0ucQBaAJEAfgCdABcAKQAxAIwueV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEDxIAbgBmAPIAAgAQIgQPI0wA6ADsADi57LoUAYKkApAClAKYApwCoAKkAqgCrAKyAHoAfgCCAIYAigCOAJIAlgCapLoYuhy6ILokuii6LLowujS6OgQPJgQPLgQPMgQPPgQPQgQPSgQPTgQPVgQPWgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFy6SABcubACMAIwAjAAxAIwA1ACkAIwAjAAXAIyAAIEDyoAAgQPHCAgICIAqgB4ICIAACNIAOwAOLqAA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFy5sAIwAjACMADEAjADUAKUAjACMABcAjIAAgACAAIEDxwgICAiAKoAfCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFy6zABcubACMAIwAjAAxAIwA1ACmAIwAjAAXAIyAAIEDzYAAgQPHCAgICIAqgCAICIAACNIAOwAOLsEA3KEuwoEDzoAp0gA7AA4uxQDcoQGPgEGAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFy5sAIwAjACMADEAjADUAKcAjACMABcAjIAAgACAAIEDxwgICAiAKoAhCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFy7ZABcubACMAIwAjAAxAIwA1ACoAIwAjAAXAIyAAIED0YAAgQPHCAgICIAqgCIICIAACNIAOwAOLucA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFy5sAIwAjACMADEAjADUAKkAjACMABcAjIAAgDKAAIEDxwgICAiAKoAjCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFy76ABcubACMAIwAjAAxAIwA1ACqAIwAjAAXAIyAAIED1IAAgQPHCAgICIAqgCQICIAACNMAOgA7AA4vCC8JAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBVQAXLmwAjACMAIwAMQCMANQAqwCMAIwAFwCMgACAN4AAgQPHCAgICIAqgCUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXLxwAFy5sAIwAjACMADEAjADUAKwAjACMABcAjIAAgQPXgACBA8cICAgIgCqAJggIgAAIW0NEQ2hhaW5Ob2Rl0wA6ADsADi8rLzEAYKUBjwGMA6kvLy8wgEGAPoCHgQPZgQPapS8yLzMvNC81LzaBA9uBA/KBBAmBBCGBBDiANVphcGlLZXlOYW1lXGFwaVF1ZXJ5TmFtZd8QEgDCAMMAxC87ACEAxgDHLzwAIwDFLz0AyAAOACUAyQDKACgAywAXABcAFwApAFoAjACML0UAMQCMAH4AjAVJAY8AjACML00AjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQPECAiBA90IgBkIgNGAQQgIgQPcCBLYoyLZ0wA6ADsADi9RL1QAYKIBsgVTgEWAs6IvVS9WgQPegQPpgDXZACEAJS9ZAA4AKC9aACMAfS9bLzIBsgB+AJ0AFwApADEAjC9jXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQPbgEWAGYA8gACABAiBA9/TADoAOwAOL2UvbgBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqC9vL3AvcS9yL3MvdC91L3aBA+CBA+GBA+KBA+SBA+WBA+aBA+eBA+iANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFy9VAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIED3ggICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcvVQCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBA94ICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcvmAAXL1UAjACMAIwAMQCMANQBygCMAIwAFwCMgACBA+OAAIED3ggICAiAKoBLCAiAAAjTADoAOwAOL6YvpwBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFy9VAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIED3ggICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcvVQCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIAygACBA94ICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXL1UAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQPeCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFy9VAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIED3ggICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcvVQCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBA94ICAgIgCqAUAgIgAAI2QAhACUv9QAOACgv9gAjAH0v9y8yBVMAfgCdABcAKQAxAIwv/18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYED24CzgBmAPIAAgAQIgQPq0wA6ADsADjABMAkAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHpzAKMAswDDANMA4wDzAQgQPrgQPsgQPtgQPugQPvgQPwgQPxgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcvVgCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBA+kICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXL1YAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQPpCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFy9WAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIED6QgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwjWABcvVgCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAID+gACBA+kICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXL1YAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQPpCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFy9WAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIED6QgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcvVgCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBA+kICAgIgCqAxwgIgAAI3xASAMIAwwDEMHwAIQDGAMcwfQAjAMUwfgDIAA4AJQDJAMoAKADLABcAFwAXACkAWgCMAIwwhgAxAIwAfgCMAakBjACMAIwwjgCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBA8QICIED9AiAGQiAr4A+CAiBA/MIEwAAAAEExGSu0wA6ADsADjCSMJUAYKIBsgGzgEWARqIwljCXgQP1gQQAgDXZACEAJTCaAA4AKDCbACMAfTCcLzMBsgB+AJ0AFwApADEAjDCkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQPygEWAGYA8gACABAiBA/bTADoAOwAOMKYwrwBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqDCwMLEwsjCzMLQwtTC2MLeBA/eBA/iBA/mBA/uBA/yBA/2BA/6BA/+ANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFzCWAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIED9QgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcwlgCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBA/UICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcw2QAXMJYAjACMAIwAMQCMANQBygCMAIwAFwCMgACBA/qAAIED9QgICAiAKoBLCAiAAAjTADoAOwAOMOcw6ABgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFzCWAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIED9QgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABcwlgCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBA/UICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXMJYAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQP1CAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFzCWAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIED9QgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcwlgCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBA/UICAgIgCqAUAgIgAAI2QAhACUxNgAOACgxNwAjAH0xOC8zAbMAfgCdABcAKQAxAIwxQF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYED8oBGgBmAPIAAgAQIgQQB0wA6ADsADjFCMUoAYKcCbQJuAm8CcAJxAnICc4BdgF6AX4BggGGAYoBjpzFLMUwxTTFOMU8xUDFRgQQCgQQDgQQEgQQFgQQGgQQHgQQIgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwKGABcwlwCMAIwAjAAxAIwA1AJtAIwAjAAXAIyAAIBlgACBBAAICAgIgCqAXQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcClQAXMJcAjACMAIwAMQCMANQCbgCMAIwAFwCMgACAZ4AAgQQACAgICIAqgF4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXApUAFzCXAIwAjACMADEAjADUAm8AjACMABcAjIAAgGeAAIEEAAgICAiAKoBfCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwBQABcwlwCMAIwAjAAxAIwA1AJwAIwAjAAXAIyAAIBqgACBBAAICAgIgCqAYAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXMJcAjACMAIwAMQCMANQCcQCMAIwAFwCMgACAMoAAgQQACAgICIAqgGEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFzCXAIwAjACMADEAjADUAnIAjACMABcAjIAAgDKAAIEEAAgICAiAKoBiCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwPMABcwlwCMAIwAjAAxAIwA1AJzAIwAjAAXAIyAAIEDr4AAgQQACAgICIAqgGMICIAACN8QEgDCAMMAxDG9ACEAxgDHMb4AIwDFMb8AyAAOACUAyQDKACgAywAXABcAFwApAFoAjACMMccAMQCMAH4AjAVJA6kAjACMMc8AjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQPECAiBBAsIgBkIgNGAhwgIgQQKCBK3lOkT0wA6ADsADjHTMdYAYKIBsgVTgEWAs6Ix1zHYgQQMgQQXgDXZACEAJTHbAA4AKDHcACMAfTHdLzQBsgB+AJ0AFwApADEAjDHlXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQQJgEWAGYA8gACABAiBBA3TADoAOwAOMecx8ABgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqDHxMfIx8zH0MfUx9jH3MfiBBA6BBA+BBBCBBBKBBBOBBBSBBBWBBBaANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFzHXAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEEDAgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcx1wCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBBAwICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcyGgAXMdcAjACMAIwAMQCMANQBygCMAIwAFwCMgACBBBGAAIEEDAgICAiAKoBLCAiAAAjTADoAOwAOMigyKQBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFzHXAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEEDAgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcx1wCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIAygACBBAwICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXMdcAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQQMCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFzHXAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEEDAgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcx1wCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBBAwICAgIgCqAUAgIgAAI2QAhACUydwAOACgyeAAjAH0yeS80BVMAfgCdABcAKQAxAIwygV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEECYCzgBmAPIAAgAQIgQQY0wA6ADsADjKDMosAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHpzKMMo0yjjKPMpAykTKSgQQZgQQbgQQcgQQdgQQegQQfgQQggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAaABcx2ACMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIEEGoAAgQQXCAgICIAqgMEICIAACFDfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABcx2ACMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBBBcICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXMdgAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQQXCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAFzHYAIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIEEFwgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABcx2ACMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBBBcICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXMdgAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQQXCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFzHYAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEEFwgICAiAKoDHCAiAAAjfEBIAwgDDAMQy/wAhAMYAxzMAACMAxTMBAMgADgAlAMkAygAoAMsAFwAXABcAKQBaAIwAjDMJADEAjAB+AIwFSS8vAIwAjDMRAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEDxAgIgQQjCIAZCIDRgQPZCAiBBCIIEoCRiwDTADoAOwAOMxUzGABgogGyBVOARYCzojMZMxqBBCSBBC+ANdkAIQAlMx0ADgAoMx4AIwB9Mx8vNQGyAH4AnQAXACkAMQCMMydfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBCGARYAZgDyAAIAECIEEJdMAOgA7AA4zKTMyAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoMzMzNDM1MzYzNzM4MzkzOoEEJoEEJ4EEKIEEKoEEK4EELIEELYEELoA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXMxkAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQQkCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFzMZAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEEJAgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFzNcABczGQCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEEKYAAgQQkCAgICIAqgEsICIAACNMAOgA7AA4zajNrAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXMxkAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQQkCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFzMZAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEEJAgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABczGQCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBBCQICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXMxkAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQQkCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFzMZAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEEJAgICAiAKoBQCAiAAAjZACEAJTO5AA4AKDO6ACMAfTO7LzUFUwB+AJ0AFwApADEAjDPDXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQQhgLOAGYA8gACABAiBBDDTADoAOwAOM8UzzQBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenM84zzzPQM9Ez0jPTM9SBBDGBBDKBBDOBBDSBBDWBBDaBBDeANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFzMaAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEELwgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABczGgCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBBC8ICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXMxoAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQQvCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAFzMaAIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIEELwgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABczGgCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBBC8ICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXMxoAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQQvCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFzMaAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEELwgICAiAKoDHCAiAAAjfEBIAwgDDAMQ0QAAhAMYAxzRBACMAxTRCAMgADgAlAMkAygAoAMsAFwAXABcAKQBaAIwAjDRKADEAjAB+AIwFSS8wAIwAjDRSAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEDxAgIgQQ6CIAZCIDRgQPaCAiBBDkIEo64D9nTADoAOwAONFY0WQBgogGyBVOARYCzojRaNFuBBDuBBEaANdkAIQAlNF4ADgAoNF8AIwB9NGAvNgGyAH4AnQAXACkAMQCMNGhfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBBDiARYAZgDyAAIAECIEEPNMAOgA7AA40ajRzAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoNHQ0dTR2NHc0eDR5NHo0e4EEPYEEPoEEP4EEQYEEQoEEQ4EERIEERYA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXNFoAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQQ7CAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFzRaAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEEOwgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFzSdABc0WgCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEEQIAAgQQ7CAgICIAqgEsICIAACNMAOgA7AA40qzSsAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXNFoAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQQ7CAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAFzRaAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEEOwgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABc0WgCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBBDsICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXNFoAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQQ7CAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AFzRaAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEEOwgICAiAKoBQCAiAAAjZACEAJTT6AA4AKDT7ACMAfTT8LzYFUwB+AJ0AFwApADEAjDUEXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQQ4gLOAGYA8gACABAiBBEfTADoAOwAONQY1DgBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenNQ81EDURNRI1EzUUNRWBBEiBBEmBBEqBBEuBBEyBBE2BBE6ANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFzRbAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEERggICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABc0WwCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBBEYICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXNFsAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQRGCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAFzRbAIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIEERggICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABc0WwCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBBEYICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXNFsAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQRGCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAFzRbAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEERggICAiAKoDHCAiAAAjSADsADjWBANyggCnfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABctVACMAIwAjAAxAIwA1AJxAIwAjAAXAIyAAIBXgACBA70ICAgIgCqAYQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXLVQAjACMAIwAMQCMANQCcgCMAIwAFwCMgACAMoAAgQO9CAgICIAqgGIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXLzMAFy1UAIwAjACMADEAjADUAnMAjACMABcAjIAAgQPygACBA70ICAgIgCqAYwgIgAAI3xASAMIAwwDENbEAIQDGAMc1sgAjAMU1swDIAA4AJQDJAMoAKADLABcAFwAXACkAUACMAIw1uwAxAIw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SADsADmhUANyggCnfEBBoV2hYaFloWgAhaFtoXAAjaF1oXgAOACVoX2hgACgAfQB+aGIAKQApABRoZgCEADEAKQB+AIcARAB+aG1obgCMXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgBmBCDyABIAEgAKBCCuBA0uABIAZgQNNgA2AGYEIbYEIKggSa44ZL9MAOgA7AA5ocmh0AGChAJGAG6FodYEILIA12QAhACVoeAAOAChoeQAjAH1oegBWAJEAfgCdABcAKQAxAIxogl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEIKYAbgBmAPIAAgAQIgQgt0wA6ADsADmiEaI4AYKkApAClAKYApwCoAKkAqgCrAKyAHoAfgCCAIYAigCOAJIAlgCapaI9okGiRaJJok2iUaJVolmiXgQgugQgwgQgxgQgzgQg0gQg2gQg3gQg5gQg6gDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF2ibABdodQCMAIwAjAAxAIwA1ACkAIwAjAAXAIyAAIEIL4AAgQgsCAgICIAqgB4ICIAACNIAOwAOaKkA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF2h1AIwAjACMADEAjADUAKUAjACMABcAjIAAgACAAIEILAgICAiAKoAfCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF2i8ABdodQCMAIwAjAAxAIwA1ACmAIwAjAAXAIyAAIEIMoAAgQgsCAgICIAqgCAICIAACNIAOwAOaMoA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF2h1AIwAjACMADEAjADUAKcAjACMABcAjIAAgACAAIEILAgICAiAKoAhCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF2jdABdodQCMAIwAjAAxAIwA1ACoAIwAjAAXAIyAAIEINYAAgQgsCAgICIAqgCIICIAACNIAOwAOaOsA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF2h1AIwAjACMADEAjADUAKkAjACMABcAjIAAgDKAAIEILAgICAiAKoAjCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF2j+ABdodQCMAIwAjAAxAIwA1ACqAIwAjAAXAIyAAIEIOIAAgQgsCAgICIAqgCQICIAACNMAOgA7AA5pDGkNAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBVQAXaHUAjACMAIwAMQCMANQAqwCMAIwAFwCMgACAN4AAgQgsCAgICIAqgCUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXaSAAF2h1AIwAjACMADEAjADUAKwAjACMABcAjIAAgQg7gACBCCwICAgIgCqAJggIgAAIW0NEU3Rhc2hJdGVt0wA6ADsADmkvaTIAYKJpMGkxgQg9gQg+omkzaTSBCD+BCFaANVVzdGFzaFpjb250cm9sbGVy3xASAMIAwwDEaTkAIQDGAMdpOgAjAMVpOwDIAA4AJQDJAMoAKADLABcAFwAXACkAVgCMAIxpQwAxAIwAfgCMBUlpMACMAIxpSwCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCCkICIEIQQiAGQiA0YEIPQgIgQhACBJLw/i60wA6ADsADmlPaVIAYKIBsgVTgEWAs6JpU2lUgQhCgQhNgDXZACEAJWlXAA4AKGlYACMAfWlZaTMBsgB+AJ0AFwApADEAjGlhXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQg/gEWAGYA8gACABAiBCEPTADoAOwAOaWNpbABgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqGltaW5pb2lwaXFpcmlzaXSBCESBCEWBCEaBCEiBCEmBCEqBCEuBCEyANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF2lTAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEIQggICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdpUwCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCEIICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdplgAXaVMAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCEeAAIEIQggICAiAKoBLCAiAAAjTADoAOwAOaaRppQBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF2lTAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEIQggICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABdpUwCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCEIICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXaVMAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQhCCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF2lTAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEIQggICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdpUwCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCEIICAgIgCqAUAgIgAAI2QAhACVp8wAOAChp9AAjAH1p9WkzBVMAfgCdABcAKQAxAIxp/V8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEIP4CzgBmAPIAAgAQIgQhO0wA6ADsADmn/agcAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp2oIaglqCmoLagxqDWoOgQhPgQhQgQhRgQhSgQhTgQhUgQhVgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdpVACMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCE0ICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXaVQAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQhNCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF2lUAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEITQgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABdpVACMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCE0ICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXaVQAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQhNCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF2lUAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEITQgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdpVACMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCE0ICAgIgCqAxwgIgAAI3xASAMIAwwDEanoAIQDGAMdqewAjAMVqfADIAA4AJQDJAMoAKADLABcAFwAXACkAVgCMAIxqhAAxAIwAfgCMBUlpMQCMAIxqjACMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCCkICIEIWAiAGQiA0YEIPggIgQhXCBJG09jJ0wA6ADsADmqQapMAYKIBsgVTgEWAs6JqlGqVgQhZgQhkgDXZACEAJWqYAA4AKGqZACMAfWqaaTQBsgB+AJ0AFwApADEAjGqiXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQhWgEWAGYA8gACABAiBCFrTADoAOwAOaqRqrQBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqGquaq9qsGqxarJqs2q0arWBCFuBCFyBCF2BCF+BCGCBCGGBCGKBCGOANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF2qUAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEIWQgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdqlACMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCFkICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdq1wAXapQAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCF6AAIEIWQgICAiAKoBLCAiAAAjTADoAOwAOauVq5gBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF2qUAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEIWQgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABdqlACMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCFkICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXapQAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQhZCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF2qUAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEIWQgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdqlACMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCFkICAgIgCqAUAgIgAAI2QAhACVrNAAOAChrNQAjAH1rNmk0BVMAfgCdABcAKQAxAIxrPl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEIVoCzgBmAPIAAgAQIgQhl0wA6ADsADmtAa0gAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp2tJa0prS2tMa01rTmtPgQhmgQhngQhogQhpgQhqgQhrgQhsgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdqlQCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCGQICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXapUAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQhkCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF2qVAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEIZAgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABdqlQCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCGQICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXapUAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQhkCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF2qVAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEIZAgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdqlQCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCGQICAgIgCqAxwgIgAAI0gA7AA5ruwDcoIAp3xAQa75rv2vAa8EAIWvCa8MAI2vEa8UADgAla8ZrxwAoAH0AfmvJACkAKQAUa80AhAAxACkAfgCHAEUAfmvUa9UAjF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZYAZgQiBgASABIACgQhwgQNLgASAGYEDTYAOgBmBCPiBCG8IEqriu67TADoAOwAOa9lr2wBgoQCRgBuha9yBCHGANdkAIQAla98ADgAoa+AAIwB9a+EAVwCRAH4AnQAXACkAMQCMa+lfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCG6AG4AZgDyAAIAECIEIctMAOgA7AA5r62v1AGCpAKQApQCmAKcAqACpAKoAqwCsgB6AH4AggCGAIoAjgCSAJYAmqWv2a/dr+Gv5a/pr+2v8a/1r/oEIc4EIdYEIdoEIeIEIeYEIe4EIfIEIfoEIf4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdsAgAXa9wAjACMAIwAMQCMANQApACMAIwAFwCMgACBCHSAAIEIcQgICAiAKoAeCAiAAAjSADsADmwQANyggCnfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdr3ACMAIwAjAAxAIwA1AClAIwAjAAXAIyAAIAAgACBCHEICAgIgCqAHwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdsIwAXa9wAjACMAIwAMQCMANQApgCMAIwAFwCMgACBCHeAAIEIcQgICAiAKoAgCAiAAAjSADsADmwxANyggCnfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdr3ACMAIwAjAAxAIwA1ACnAIwAjAAXAIyAAIAAgACBCHEICAgIgCqAIQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdsRAAXa9wAjACMAIwAMQCMANQAqACMAIwAFwCMgACBCHqAAIEIcQgICAiAKoAiCAiAAAjSADsADmxSANyggCnfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdr3ACMAIwAjAAxAIwA1ACpAIwAjAAXAIyAAIAygACBCHEICAgIgCqAIwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdsZQAXa9wAjACMAIwAMQCMANQAqgCMAIwAFwCMgACBCH2AAIEIcQgICAiAKoAkCAiAAAjTADoAOwAObHNsdABgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAVUAF2vcAIwAjACMADEAjADUAKsAjACMABcAjIAAgDeAAIEIcQgICAiAKoAlCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF2yHABdr3ACMAIwAjAAxAIwA1ACsAIwAjAAXAIyAAIEIgIAAgQhxCAgICIAqgCYICIAACF8QFUNEUnVudGltZU1ldGFkYXRhSXRlbdMAOgA7AA5slmycAGClbJdsmFLHbJpdZYEIgoEIg4EGgIEIhIEHVqVsnWyebJ9soGyhgQiFgQicgQizgQjKgQjhgDVYbWV0YWRhdGFYcmVzb2x2ZXJZdHhWZXJzaW9u3xASAMIAwwDEbKcAIQDGAMdsqAAjAMVsqQDIAA4AJQDJAMoAKADLABcAFwAXACkAVwCMAIxssQAxAIwAfgCMBUlslwCMAIxsuQCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCG4ICIEIhwiAGQiA0YEIgggIgQiGCBMAAAABJ9k8otMAOgA7AA5svWzAAGCiAbIFU4BFgLOibMFswoEIiIEIk4A12QAhACVsxQAOAChsxgAjAH1sx2ydAbIAfgCdABcAKQAxAIxsz18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEIhYBFgBmAPIAAgAQIgQiJ0wA6ADsADmzRbNoAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKhs22zcbN1s3mzfbOBs4WzigQiKgQiLgQiMgQiOgQiPgQiQgQiRgQiSgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdswQCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBCIgICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXbMEAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQiICAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXbQQAF2zBAIwAjACMADEAjADUAcoAjACMABcAjIAAgQiNgACBCIgICAgIgCqASwgIgAAI0wA6ADsADm0SbRMAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdswQCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBCIgICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXbMEAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQiICAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF2zBAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEIiAgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdswQCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBCIgICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXbMEAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQiICAgICIAqgFAICIAACNkAIQAlbWEADgAobWIAIwB9bWNsnQVTAH4AnQAXACkAMQCMbWtfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCIWAs4AZgDyAAIAECIEIlNMAOgA7AA5tbW11AGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6dtdm13bXhteW16bXttfIEIlYEIloEIl4EImIEImYEImoEIm4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXbMIAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQiTCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF2zCAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEIkwgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdswgCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBCJMICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdT1QAXbMIAjACMAIwAMQCMANQGBgCMAIwAFwCMgACBBpWAAIEIkwgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdswgCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBCJMICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXbMIAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQiTCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF2zCAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEIkwgICAiAKoDHCAiAAAjfEBIAwgDDAMRt6AAhAMYAx23pACMAxW3qAMgADgAlAMkAygAoAMsAFwAXABcAKQBXAIwAjG3yADEAjAB+AIwFSWyYAIwAjG36AIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEIbggIgQieCIAZCIDRgQiDCAiBCJ0IEsIlrOHTADoAOwAObf5uAQBgogGyBVOARYCzom4CbgOBCJ+BCKqANdkAIQAlbgYADgAobgcAIwB9bghsngGyAH4AnQAXACkAMQCMbhBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCJyARYAZgDyAAIAECIEIoNMAOgA7AA5uEm4bAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCobhxuHW4ebh9uIG4hbiJuI4EIoYEIooEIo4EIpYEIpoEIp4EIqIEIqYA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXbgIAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQifCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF24CAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEInwgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF25FABduAgCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEIpIAAgQifCAgICIAqgEsICIAACNMAOgA7AA5uU25UAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXbgIAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQifCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAF24CAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEInwgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABduAgCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBCJ8ICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXbgIAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQifCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF24CAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEInwgICAiAKoBQCAiAAAjZACEAJW6iAA4AKG6jACMAfW6kbJ4FUwB+AJ0AFwApADEAjG6sXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQicgLOAGYA8gACABAiBCKvTADoAOwAObq5utgBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenbrduuG65brpuu268br2BCKyBCK2BCK6BCK+BCLCBCLGBCLKANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF24DAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEIqggICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABduAwCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBCKoICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXbgMAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQiqCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXU9UAF24DAIwAjACMADEAjADUBgYAjACMABcAjIAAgQaVgACBCKoICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXbgMAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQiqCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF24DAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEIqggICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABduAwCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCKoICAgIgCqAxwgIgAAI3xASAMIAwwDEbykAIQDGAMdvKgAjAMVvKwDIAA4AJQDJAMoAKADLABcAFwAXACkAVwCMAIxvMwAxAIwAfgCMBUlSxwCMAIxvOwCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCG4ICIEItQiAGQiA0YEGgAgIgQi0CBJiVQsh0wA6ADsADm8/b0IAYKIBsgVTgEWAs6JvQ29EgQi2gQjBgDXZACEAJW9HAA4AKG9IACMAfW9JbJ8BsgB+AJ0AFwApADEAjG9RXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQizgEWAGYA8gACABAiBCLfTADoAOwAOb1NvXABgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqG9db15vX29gb2FvYm9jb2SBCLiBCLmBCLqBCLyBCL2BCL6BCL+BCMCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF29DAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEItggICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdvQwCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCLYICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdvhgAXb0MAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCLuAAIEItggICAiAKoBLCAiAAAjTADoAOwAOb5RvlQBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF29DAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEItggICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABdvQwCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCLYICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXb0MAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQi2CAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF29DAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEItggICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdvQwCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCLYICAgIgCqAUAgIgAAI2QAhACVv4wAOAChv5AAjAH1v5WyfBVMAfgCdABcAKQAxAIxv7V8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEIs4CzgBmAPIAAgAQIgQjC0wA6ADsADm/vb/cAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp2/4b/lv+m/7b/xv/W/+gQjDgQjEgQjFgQjGgQjHgQjIgQjJgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdvRACMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCMEICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXb0QAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQjBCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF29EAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEIwQgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABdvRACMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCMEICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXb0QAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQjBCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF29EAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEIwQgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdvRACMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCMEICAgIgCqAxwgIgAAI3xASAMIAwwDEcGoAIQDGAMdwawAjAMVwbADIAA4AJQDJAMoAKADLABcAFwAXACkAVwCMAIxwdAAxAIwAfgCMBUlsmgCMAIxwfACMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCG4ICIEIzAiAGQiA0YEIhAgIgQjLCBKPqPYL0wA6ADsADnCAcIMAYKIBsgVTgEWAs6JwhHCFgQjNgQjYgDXZACEAJXCIAA4AKHCJACMAfXCKbKABsgB+AJ0AFwApADEAjHCSXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQjKgEWAGYA8gACABAiBCM7TADoAOwAOcJRwnQBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqHCecJ9woHChcKJwo3CkcKWBCM+BCNCBCNGBCNOBCNSBCNWBCNaBCNeANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3CEAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEIzQgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdwhACMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCM0ICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdwxwAXcIQAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCNKAAIEIzQgICAiAKoBLCAiAAAjTADoAOwAOcNVw1gBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3CEAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEIzQgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABdwhACMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCM0ICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXcIQAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQjNCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3CEAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEIzQgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdwhACMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCM0ICAgIgCqAUAgIgAAI2QAhACVxJAAOAChxJQAjAH1xJmygBVMAfgCdABcAKQAxAIxxLl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEIyoCzgBmAPIAAgAQIgQjZ0wA6ADsADnEwcTgAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp3E5cTpxO3E8cT1xPnE/gQjagQjbgQjcgQjdgQjegQjfgQjggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwYcABdwhQCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIDJgACBCNgICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXcIUAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQjYCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3CFAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEI2AgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF2aJABdwhQCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIEIB4AAgQjYCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3CFAIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIEI2AgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdwhQCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBCNgICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXcIUAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQjYCAgICIAqgMcICIAACN8QEgDCAMMAxHGrACEAxgDHcawAIwDFca0AyAAOACUAyQDKACgAywAXABcAFwApAFcAjACMcbUAMQCMAH4AjAVJXWUAjACMcb0AjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQhuCAiBCOMIgBkIgNGBB1YICIEI4ggSTLr7CtMAOgA7AA5xwXHEAGCiAbIFU4BFgLOiccVxxoEI5IEI74A12QAhACVxyQAOAChxygAjAH1xy2yhAbIAfgCdABcAKQAxAIxx018QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEI4YBFgBmAPIAAgAQIgQjl0wA6ADsADnHVcd4AYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKhx33HgceFx4nHjceRx5XHmgQjmgQjngQjogQjqgQjrgQjsgQjtgQjugDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdxxQCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBCOQICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXccUAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQjkCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXcggAF3HFAIwAjACMADEAjADUAcoAjACMABcAjIAAgQjpgACBCOQICAgIgCqASwgIgAAI0wA6ADsADnIWchcAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdxxQCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBCOQICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXccUAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQjkCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3HFAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEI5AgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdxxQCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBCOQICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXccUAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQjkCAgICIAqgFAICIAACNkAIQAlcmUADgAocmYAIwB9cmdsoQVTAH4AnQAXACkAMQCMcm9fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCOGAs4AZgDyAAIAECIEI8NMAOgA7AA5ycXJ5AGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6dyenJ7cnxyfXJ+cn9ygIEI8YEI8oEI84EI9IEI9YEI9oEI94A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcGHAAXccYAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAyYAAgQjvCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3HGAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEI7wgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdxxgCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBCO8ICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdmiQAXccYAjACMAIwAMQCMANQGBgCMAIwAFwCMgACBCAeAAIEI7wgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdxxgCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBCO8ICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXccYAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQjvCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3HGAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEI7wgICAiAKoDHCAiAAAjSADsADnLsANyggCnfEBBy73LwcvFy8gAhcvNy9AAjcvVy9gAOACVy93L4ACgAfQB+cvoAKQApABRy/gCEADEAKQB+AIcARwB+cwVzBgCMXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgBmBCQyABIAEgAKBCPuBA0uABIAZgQNNgBCAGYEJa4EI+ggSm7s+3tMAOgA7AA5zCnMMAGChAJGAG6FzDYEI/IA12QAhACVzEAAOAChzEQAjAH1zEgBZAJEAfgCdABcAKQAxAIxzGl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEI+YAbgBmAPIAAgAQIgQj90wA6ADsADnMccyYAYKkApAClAKYApwCoAKkAqgCrAKyAHoAfgCCAIYAigCOAJIAlgCapcydzKHMpcypzK3Mscy1zLnMvgQj+gQkAgQkBgQkDgQkEgQkGgQkHgQkJgQkKgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF3MzABdzDQCMAIwAjAAxAIwA1ACkAIwAjAAXAIyAAIEI/4AAgQj8CAgICIAqgB4ICIAACNIAOwAOc0EA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3MNAIwAjACMADEAjADUAKUAjACMABcAjIAAgACAAIEI/AgICAiAKoAfCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF3NUABdzDQCMAIwAjAAxAIwA1ACmAIwAjAAXAIyAAIEJAoAAgQj8CAgICIAqgCAICIAACNIAOwAOc2IA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3MNAIwAjACMADEAjADUAKcAjACMABcAjIAAgACAAIEI/AgICAiAKoAhCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF3N1ABdzDQCMAIwAjAAxAIwA1ACoAIwAjAAXAIyAAIEJBYAAgQj8CAgICIAqgCIICIAACNIAOwAOc4MA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3MNAIwAjACMADEAjADUAKkAjACMABcAjIAAgDKAAIEI/AgICAiAKoAjCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF3OWABdzDQCMAIwAjAAxAIwA1ACqAIwAjAAXAIyAAIEJCIAAgQj8CAgICIAqgCQICIAACNMAOgA7AA5zpHOlAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBVQAXcw0AjACMAIwAMQCMANQAqwCMAIwAFwCMgACAN4AAgQj8CAgICIAqgCUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXc7gAF3MNAIwAjACMADEAjADUAKwAjACMABcAjIAAgQkLgACBCPwICAgIgCqAJggIgAAIWkNEU2NhbUluZm/TADoAOwAOc8dzzABgpAGOA6lzynPLgECAh4EJDYEJDqRzzXPOc89z0IEJD4EJJoEJPYEJVIA1V3N1YnR5cGVXYWRkcmVzc98QEgDCAMMAxHPVACEAxgDHc9YAIwDFc9cAyAAOACUAyQDKACgAywAXABcAFwApAFkAjACMc98AMQCMAH4AjAVJAY4AjACMc+cAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQj5CAiBCREIgBkIgNGAQAgIgQkQCBJrkEZY0wA6ADsADnPrc+4AYKIBsgVTgEWAs6Jz73PwgQkSgQkdgDXZACEAJXPzAA4AKHP0ACMAfXP1c80BsgB+AJ0AFwApADEAjHP9XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQkPgEWAGYA8gACABAiBCRPTADoAOwAOc/90CABgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqHQJdAp0C3QMdA10DnQPdBCBCRSBCRWBCRaBCRiBCRmBCRqBCRuBCRyANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3PvAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEJEggICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdz7wCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCRIICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd0MgAXc+8AjACMAIwAMQCMANQBygCMAIwAFwCMgACBCReAAIEJEggICAiAKoBLCAiAAAjTADoAOwAOdEB0QQBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3PvAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEJEggICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABdz7wCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCRIICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXc+8AjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQkSCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3PvAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEJEggICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABdz7wCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCRIICAgIgCqAUAgIgAAI2QAhACV0jwAOACh0kAAjAH10kXPNBVMAfgCdABcAKQAxAIx0mV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEJD4CzgBmAPIAAgAQIgQke0wA6ADsADnSbdKMAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp3SkdKV0pnSndKh0qXSqgQkfgQkggQkhgQkigQkjgQkkgQklgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdz8ACMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCR0ICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXc/AAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQkdCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3PwAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEJHQgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABdz8ACMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCR0ICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXc/AAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQkdCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3PwAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEJHQgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABdz8ACMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCR0ICAgIgCqAxwgIgAAI3xASAMIAwwDEdRYAIQDGAMd1FwAjAMV1GADIAA4AJQDJAMoAKADLABcAFwAXACkAWQCMAIx1IAAxAIwAfgCMBUkDqQCMAIx1KACMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCPkICIEJKAiAGQiA0YCHCAiBCScIEwAAAAEaIHVC0wA6ADsADnUsdS8AYKIBsgVTgEWAs6J1MHUxgQkpgQk0gDXZACEAJXU0AA4AKHU1ACMAfXU2c84BsgB+AJ0AFwApADEAjHU+XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQkmgEWAGYA8gACABAiBCSrTADoAOwAOdUB1SQBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqHVKdUt1THVNdU51T3VQdVGBCSuBCSyBCS2BCS+BCTCBCTGBCTKBCTOANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3UwAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEJKQgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd1MACMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCSkICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd1cwAXdTAAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCS6AAIEJKQgICAiAKoBLCAiAAAjTADoAOwAOdYF1ggBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3UwAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEJKQgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABd1MACMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCSkICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXdTAAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQkpCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3UwAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEJKQgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd1MACMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCSkICAgIgCqAUAgIgAAI2QAhACV10AAOACh10QAjAH110nPOBVMAfgCdABcAKQAxAIx12l8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEJJoCzgBmAPIAAgAQIgQk10wA6ADsADnXcdeQAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp3XldeZ153Xodel16nXrgQk2gQk3gQk4gQk5gQk6gQk7gQk8gDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd1MQCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCTQICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXdTEAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQk0CAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3UxAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEJNAgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABd1MQCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCTQICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXdTEAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQk0CAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3UxAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEJNAgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd1MQCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCTQICAgIgCqAxwgIgAAI3xASAMIAwwDEdlcAIQDGAMd2WAAjAMV2WQDIAA4AJQDJAMoAKADLABcAFwAXACkAWQCMAIx2YQAxAIwAfgCMBUlzygCMAIx2aQCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCPkICIEJPwiAGQiA0YEJDQgIgQk+CBI++vEK0wA6ADsADnZtdnAAYKIBsgVTgEWAs6J2cXZygQlAgQlLgDXZACEAJXZ1AA4AKHZ2ACMAfXZ3c88BsgB+AJ0AFwApADEAjHZ/XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQk9gEWAGYA8gACABAiBCUHTADoAOwAOdoF2igBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqHaLdox2jXaOdo92kHaRdpKBCUKBCUOBCUSBCUaBCUeBCUiBCUmBCUqANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3ZxAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEJQAgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd2cQCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCUAICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd2tAAXdnEAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCUWAAIEJQAgICAiAKoBLCAiAAAjTADoAOwAOdsJ2wwBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3ZxAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEJQAgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABd2cQCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCUAICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXdnEAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQlACAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3ZxAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEJQAgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd2cQCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCUAICAgIgCqAUAgIgAAI2QAhACV3EQAOACh3EgAjAH13E3PPBVMAfgCdABcAKQAxAIx3G18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEJPYCzgBmAPIAAgAQIgQlM0wA6ADsADncddyUAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp3cmdyd3KHcpdyp3K3csgQlNgQlOgQlPgQlQgQlRgQlSgQlTgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd2cgCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCUsICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXdnIAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQlLCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3ZyAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEJSwgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABd2cgCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCUsICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXdnIAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQlLCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3ZyAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEJSwgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd2cgCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCUsICAgIgCqAxwgIgAAI3xASAMIAwwDEd5gAIQDGAMd3mQAjAMV3mgDIAA4AJQDJAMoAKADLABcAFwAXACkAWQCMAIx3ogAxAIwAfgCMBUlzywCMAIx3qgCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCPkICIEJVgiAGQiA0YEJDggIgQlVCBJaLwbS0wA6ADsADneud7EAYKIBsgVTgEWAs6J3snezgQlXgQligDXZACEAJXe2AA4AKHe3ACMAfXe4c9ABsgB+AJ0AFwApADEAjHfAXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQlUgEWAGYA8gACABAiBCVjTADoAOwAOd8J3ywBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqHfMd813znfPd9B30XfSd9OBCVmBCVqBCVuBCV2BCV6BCV+BCWCBCWGANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3eyAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEJVwgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd3sgCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCVcICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd39QAXd7IAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCVyAAIEJVwgICAiAKoBLCAiAAAjTADoAOwAOeAN4BABgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3eyAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEJVwgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABd3sgCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCVcICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXd7IAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQlXCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3eyAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEJVwgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd3sgCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCVcICAgIgCqAUAgIgAAI2QAhACV4UgAOACh4UwAjAH14VHPQBVMAfgCdABcAKQAxAIx4XF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEJVICzgBmAPIAAgAQIgQlj0wA6ADsADnheeGYAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp3hneGh4aXhqeGt4bHhtgQlkgQllgQlmgQlngQlogQlpgQlqgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd3swCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCWIICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXd7MAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQliCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3ezAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEJYggICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABd3swCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCWIICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXd7MAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQliCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3ezAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEJYggICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd3swCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCWIICAgIgCqAxwgIgAAI0gA7AA542QDcoIAp3xAQeNx43XjeeN8AIXjgeOEAI3jieOMADgAleOR45QAoAH0AfnjnACkAKQAUeOsAhAAxACkAfgCHAEkAfnjyePMAjF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZYAZgQl/gASABIACgQlugQNLgASAGYEDTYASgBmBCoeBCW0IEloY287TADoAOwAOePd4+QBgoQCRgBuhePqBCW+ANdkAIQAleP0ADgAoeP4AIwB9eP8AWwCRAH4AnQAXACkAMQCMeQdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCWyAG4AZgDyAAIAECIEJcNMAOgA7AA55CXkTAGCpAKQApQCmAKcAqACpAKoAqwCsgB6AH4AggCGAIoAjgCSAJYAmqXkUeRV5FnkXeRh5GXkaeRt5HIEJcYEJc4EJdIEJdoEJd4EJeYEJeoEJfIEJfYA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd5IAAXePoAjACMAIwAMQCMANQApACMAIwAFwCMgACBCXKAAIEJbwgICAiAKoAeCAiAAAjSADsADnkuANyggCnfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd4+gCMAIwAjAAxAIwA1AClAIwAjAAXAIyAAIAAgACBCW8ICAgIgCqAHwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd5QQAXePoAjACMAIwAMQCMANQApgCMAIwAFwCMgACBCXWAAIEJbwgICAiAKoAgCAiAAAjSADsADnlPANyggCnfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd4+gCMAIwAjAAxAIwA1ACnAIwAjAAXAIyAAIAAgACBCW8ICAgIgCqAIQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd5YgAXePoAjACMAIwAMQCMANQAqACMAIwAFwCMgACBCXiAAIEJbwgICAiAKoAiCAiAAAjSADsADnlwANyggCnfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd4+gCMAIwAjAAxAIwA1ACpAIwAjAAXAIyAAIAygACBCW8ICAgIgCqAIwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd5gwAXePoAjACMAIwAMQCMANQAqgCMAIwAFwCMgACBCXuAAIEJbwgICAiAKoAkCAiAAAjTADoAOwAOeZF5kgBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAVUAF3j6AIwAjACMADEAjADUAKsAjACMABcAjIAAgDeAAIEJbwgICAiAKoAlCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF3mlABd4+gCMAIwAjAAxAIwA1ACsAIwAjAAXAIyAAIEJfoAAgQlvCAgICIAqgCYICIAACF8QGENEVHJhbnNhY3Rpb25IaXN0b3J5SXRlbdMAOgA7AA55tHnAAGCrebV5tnm3ebh5uXm6ebtSx3m9eb55v4EJgIEJgYEJgoEJg4EJhIEJhYEJhoEGgIEJh4EJiIEJiat5wXnCecN5xHnFecZ5x3nIecl5ynnLgQmKgQmhgQm4gQnPgQnmgQn9gQoUgQorgQpCgQpZgQpwgDVWc2VuZGVyVnN0YXR1c1hyZWNlaXZlclRjYWxsWm1vZHVsZU5hbWVbYmxvY2tOdW1iZXJYY2FsbE5hbWVTZmVlWXRpbWVzdGFtcFd0eEluZGV43xASAMIAwwDEedgAIQDGAMd52QAjAMV52gDIAA4AJQDJAMoAKADLABcAFwAXACkAWwCMAIx54gAxAIwAfgCMBUl5tQCMAIx56gCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCWwICIEJjAiAGQiA0YEJgAgIgQmLCBLOPhan0wA6ADsADnnuefEAYKIBsgVTgEWAs6J58nnzgQmNgQmYgDXZACEAJXn2AA4AKHn3ACMAfXn4ecEBsgB+AJ0AFwApADEAjHoAXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQmKgEWAGYA8gACABAiBCY7TADoAOwAOegJ6CwBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqHoMeg16DnoPehB6EXoSehOBCY+BCZCBCZGBCZOBCZSBCZWBCZaBCZeANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3nyAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEJjQgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd58gCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCY0ICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd6NQAXefIAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCZKAAIEJjQgICAiAKoBLCAiAAAjTADoAOwAOekN6RABgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3nyAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEJjQgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABd58gCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCY0ICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXefIAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQmNCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3nyAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEJjQgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd58gCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCY0ICAgIgCqAUAgIgAAI2QAhACV6kgAOACh6kwAjAH16lHnBBVMAfgCdABcAKQAxAIx6nF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEJioCzgBmAPIAAgAQIgQmZ0wA6ADsADnqeeqYAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp3qneqh6qXqqeqt6rHqtgQmagQmbgQmcgQmdgQmegQmfgQmggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd58wCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCZgICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXefMAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQmYCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3nzAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEJmAgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABd58wCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCZgICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXefMAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQmYCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3nzAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEJmAgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd58wCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCZgICAgIgCqAxwgIgAAI3xASAMIAwwDEexkAIQDGAMd7GgAjAMV7GwDIAA4AJQDJAMoAKADLABcAFwAXACkAWwCMAIx7IwAxAIwAfgCMBUl5tgCMAIx7KwCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCWwICIEJowiAGQiA0YEJgQgIgQmiCBMAAAABGVgnh9MAOgA7AA57L3syAGCiAbIFU4BFgLOiezN7NIEJpIEJr4A12QAhACV7NwAOACh7OAAjAH17OXnCAbIAfgCdABcAKQAxAIx7QV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEJoYBFgBmAPIAAgAQIgQml0wA6ADsADntDe0wAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKh7TXtOe097UHtRe1J7U3tUgQmmgQmngQmogQmqgQmrgQmsgQmtgQmugDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd7MwCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBCaQICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXezMAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQmkCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXe3YAF3szAIwAjACMADEAjADUAcoAjACMABcAjIAAgQmpgACBCaQICAgIgCqASwgIgAAI0wA6ADsADnuEe4UAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd7MwCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBCaQICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXezMAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQmkCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3szAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEJpAgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd7MwCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBCaQICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXezMAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQmkCAgICIAqgFAICIAACNkAIQAle9MADgAoe9QAIwB9e9V5wgVTAH4AnQAXACkAMQCMe91fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCaGAs4AZgDyAAIAECIEJsNMAOgA7AA5733vnAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6d76Hvpe+p763vse+177oEJsYEJsoEJs4EJtIEJtYEJtoEJt4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcGHAAXezQAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAyYAAgQmvCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3s0AIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEJrwgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd7NACMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBCa8ICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcGSgAXezQAjACMAIwAMQCMANQGBgCMAIwAFwCMgACAzYAAgQmvCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3s0AIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIEJrwgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd7NACMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBCa8ICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXezQAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQmvCAgICIAqgMcICIAACN8QEgDCAMMAxHxaACEAxgDHfFsAIwDFfFwAyAAOACUAyQDKACgAywAXABcAFwApAFsAjACMfGQAMQCMAH4AjAVJebcAjACMfGwAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQlsCAiBCboIgBkIgNGBCYIICIEJuQgTAAAAAQOl0xHTADoAOwAOfHB8cwBgogGyBVOARYCzonx0fHWBCbuBCcaANdkAIQAlfHgADgAofHkAIwB9fHp5wwGyAH4AnQAXACkAMQCMfIJfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCbiARYAZgDyAAIAECIEJvNMAOgA7AA58hHyNAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCofI58j3yQfJF8knyTfJR8lYEJvYEJvoEJv4EJwYEJwoEJw4EJxIEJxYA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXfHQAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQm7CAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3x0AIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEJuwgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF3y3ABd8dACMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEJwIAAgQm7CAgICIAqgEsICIAACNMAOgA7AA58xXzGAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXfHQAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQm7CAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAF3x0AIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEJuwgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd8dACMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBCbsICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXfHQAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQm7CAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF3x0AIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEJuwgICAiAKoBQCAiAAAjZACEAJX0UAA4AKH0VACMAfX0WecMFUwB+AJ0AFwApADEAjH0eXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQm4gLOAGYA8gACABAiBCcfTADoAOwAOfSB9KABgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenfSl9Kn0rfSx9LX0ufS+BCciBCcmBCcqBCcuBCcyBCc2BCc6ANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3x1AIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEJxggICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd8dQCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBCcYICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXfHUAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQnGCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAF3x1AIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIEJxggICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd8dQCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBCcYICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXfHUAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQnGCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF3x1AIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEJxggICAiAKoDHCAiAAAjfEBIAwgDDAMR9mwAhAMYAx32cACMAxX2dAMgADgAlAMkAygAoAMsAFwAXABcAKQBbAIwAjH2lADEAjAB+AIwFSXm4AIwAjH2tAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEJbAgIgQnRCIAZCIDRgQmDCAiBCdAIErJUxqzTADoAOwAOfbF9tABgogGyBVOARYCzon21fbaBCdKBCd2ANdkAIQAlfbkADgAofboAIwB9fbt5xAGyAH4AnQAXACkAMQCMfcNfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCc+ARYAZgDyAAIAECIEJ09MAOgA7AA59xX3OAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCofc990H3RfdJ9033UfdV91oEJ1IEJ1YEJ1oEJ2IEJ2YEJ2oEJ24EJ3IA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXfbUAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQnSCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF321AIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEJ0ggICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF334ABd9tQCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEJ14AAgQnSCAgICIAqgEsICIAACNMAOgA7AA5+Bn4HAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXfbUAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQnSCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAF321AIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEJ0ggICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd9tQCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBCdIICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXfbUAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQnSCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF321AIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEJ0ggICAiAKoBQCAiAAAjZACEAJX5VAA4AKH5WACMAfX5XecQFUwB+AJ0AFwApADEAjH5fXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQnPgLOAGYA8gACABAiBCd7TADoAOwAOfmF+aQBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenfmp+a35sfm1+bn5vfnCBCd+BCeCBCeGBCeKBCeOBCeSBCeWANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF322AIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEJ3QgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd9tgCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBCd0ICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXfbYAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQndCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXU9UAF322AIwAjACMADEAjADUBgYAjACMABcAjIAAgQaVgACBCd0ICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXfbYAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQndCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF322AIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEJ3QgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd9tgCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCd0ICAgIgCqAxwgIgAAI3xASAMIAwwDEftwAIQDGAMd+3QAjAMV+3gDIAA4AJQDJAMoAKADLABcAFwAXACkAWwCMAIx+5gAxAIwAfgCMBUl5uQCMAIx+7gCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCWwICIEJ6AiAGQiA0YEJhAgIgQnnCBJvABg20wA6ADsADn7yfvUAYKIBsgVTgEWAs6J+9n73gQnpgQn0gDXZACEAJX76AA4AKH77ACMAfX78ecUBsgB+AJ0AFwApADEAjH8EXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQnmgEWAGYA8gACABAiBCerTADoAOwAOfwZ/DwBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqH8QfxF/En8TfxR/FX8WfxeBCeuBCeyBCe2BCe+BCfCBCfGBCfKBCfOANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF372AIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEJ6QgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd+9gCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCekICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABd/OQAXfvYAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCe6AAIEJ6QgICAiAKoBLCAiAAAjTADoAOwAOf0d/SABgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF372AIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEJ6QgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd+9gCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIAygACBCekICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXfvYAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQnpCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF372AIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEJ6QgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABd+9gCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCekICAgIgCqAUAgIgAAI2QAhACV/lgAOACh/lwAjAH1/mHnFBVMAfgCdABcAKQAxAIx/oF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEJ5oCzgBmAPIAAgAQIgQn10wA6ADsADn+if6oAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp3+rf6x/rX+uf69/sH+xgQn2gQn3gQn4gQn5gQn6gQn7gQn8gDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd+9wCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCfQICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXfvcAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQn0CAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF373AIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEJ9AgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABd+9wCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCfQICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXfvcAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQn0CAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF373AIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEJ9AgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABd+9wCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCfQICAgIgCqAxwgIgAAI3xASAMIAwwDEgB0AIQDGAMeAHgAjAMWAHwDIAA4AJQDJAMoAKADLABcAFwAXACkAWwCMAIyAJwAxAIwAfgCMBUl5ugCMAIyALwCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCWwICIEJ/wiAGQiA0YEJhQgIgQn+CBKllc/p0wA6ADsADoAzgDYAYKIBsgVTgEWAs6KAN4A4gQoAgQoLgDXZACEAJYA7AA4AKIA8ACMAfYA9ecYBsgB+AJ0AFwApADEAjIBFXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQn9gEWAGYA8gACABAiBCgHTADoAOwAOgEeAUABgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqIBRgFKAU4BUgFWAVoBXgFiBCgKBCgOBCgSBCgaBCgeBCgiBCgmBCgqANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4A3AIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEKAAgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeANwCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCgAICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABeAegAXgDcAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCgWAAIEKAAgICAiAKoBLCAiAAAjTADoAOwAOgIiAiQBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4A3AIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEKAAgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABeANwCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCgAICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXgDcAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQoACAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4A3AIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEKAAgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeANwCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCgAICAgIgCqAUAgIgAAI2QAhACWA1wAOACiA2AAjAH2A2XnGBVMAfgCdABcAKQAxAIyA4V8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEJ/YCzgBmAPIAAgAQIgQoM0wA6ADsADoDjgOsAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp4DsgO2A7oDvgPCA8YDygQoNgQoOgQoPgQoQgQoRgQoSgQoTgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeAOACMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCgsICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXgDgAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQoLCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4A4AIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEKCwgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF1nHABeAOACMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIEHC4AAgQoLCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4A4AIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIEKCwgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeAOACMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBCgsICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXgDgAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQoLCAgICIAqgMcICIAACN8QEgDCAMMAxIFeACEAxgDHgV8AIwDFgWAAyAAOACUAyQDKACgAywAXABcAFwApAFsAjACMgWgAMQCMAH4AjAVJebsAjACMgXAAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQlsCAiBChYIgBkIgNGBCYYICIEKFQgSVIcHtNMAOgA7AA6BdIF3AGCiAbIFU4BFgLOigXiBeYEKF4EKIoA12QAhACWBfAAOACiBfQAjAH2BfnnHAbIAfgCdABcAKQAxAIyBhl8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEKFIBFgBmAPIAAgAQIgQoY0wA6ADsADoGIgZEAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKiBkoGTgZSBlYGWgZeBmIGZgQoZgQoagQobgQodgQoegQofgQoggQohgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeBeACMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBChcICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXgXgAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQoXCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXgbsAF4F4AIwAjACMADEAjADUAcoAjACMABcAjIAAgQocgACBChcICAgIgCqASwgIgAAI0wA6ADsADoHJgcoAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeBeACMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBChcICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXgXgAjACMAIwAMQCMANQBzACMAIwAFwCMgACAMoAAgQoXCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4F4AIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEKFwgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeBeACMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBChcICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXgXgAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQoXCAgICIAqgFAICIAACNkAIQAlghgADgAoghkAIwB9ghp5xwVTAH4AnQAXACkAMQCMgiJfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBChSAs4AZgDyAAIAECIEKI9MAOgA7AA6CJIIsAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6eCLYIugi+CMIIxgjKCM4EKJIEKJYEKJoEKJ4EKKIEKKYEKKoA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXgXkAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQoiCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4F5AIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEKIggICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeBeQCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBCiIICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcHlAAXgXkAjACMAIwAMQCMANQGBgCMAIwAFwCMgACA5oAAgQoiCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4F5AIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIEKIggICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeBeQCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBCiIICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXgXkAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQoiCAgICIAqgMcICIAACN8QEgDCAMMAxIKfACEAxgDHgqAAIwDFgqEAyAAOACUAyQDKACgAywAXABcAFwApAFsAjACMgqkAMQCMAH4AjAVJUscAjACMgrEAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQlsCAiBCi0IgBkIgNGBBoAICIEKLAgS+eI5H9MAOgA7AA6CtYK4AGCiAbIFU4BFgLOigrmCuoEKLoEKOYA12QAhACWCvQAOACiCvgAjAH2Cv3nIAbIAfgCdABcAKQAxAIyCx18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEKK4BFgBmAPIAAgAQIgQov0wA6ADsADoLJgtIAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKiC04LUgtWC1oLXgtiC2YLagQowgQoxgQoygQo0gQo1gQo2gQo3gQo4gDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeCuQCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBCi4ICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXgrkAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQouCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXgvwAF4K5AIwAjACMADEAjADUAcoAjACMABcAjIAAgQozgACBCi4ICAgIgCqASwgIgAAI0wA6ADsADoMKgwsAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeCuQCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBCi4ICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXgrkAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQouCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4K5AIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEKLggICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeCuQCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBCi4ICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXgrkAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQouCAgICIAqgFAICIAACNkAIQAlg1kADgAog1oAIwB9g1t5yAVTAH4AnQAXACkAMQCMg2NfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCiuAs4AZgDyAAIAECIEKOtMAOgA7AA6DZYNtAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6eDboNvg3CDcYNyg3ODdIEKO4EKPIEKPYEKPoEKP4EKQIEKQYA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXgroAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQo5CAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4K6AIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEKOQgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeCugCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBCjkICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcHlAAXgroAjACMAIwAMQCMANQGBgCMAIwAFwCMgACA5oAAgQo5CAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4K6AIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIEKOQgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeCugCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBCjkICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXgroAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQo5CAgICIAqgMcICIAACN8QEgDCAMMAxIPgACEAxgDHg+EAIwDFg+IAyAAOACUAyQDKACgAywAXABcAFwApAFsAjACMg+oAMQCMAH4AjAVJeb0AjACMg/IAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQlsCAiBCkQIgBkIgNGBCYcICIEKQwgS1ZAYtNMAOgA7AA6D9oP5AGCiAbIFU4BFgLOig/qD+4EKRYEKUIA12QAhACWD/gAOACiD/wAjAH2EAHnJAbIAfgCdABcAKQAxAIyECF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEKQoBFgBmAPIAAgAQIgQpG0wA6ADsADoQKhBMAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKiEFIQVhBaEF4QYhBmEGoQbgQpHgQpIgQpJgQpLgQpMgQpNgQpOgQpPgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeD+gCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBCkUICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXg/oAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQpFCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXhD0AF4P6AIwAjACMADEAjADUAcoAjACMABcAjIAAgQpKgACBCkUICAgIgCqASwgIgAAI0wA6ADsADoRLhEwAYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeD+gCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBCkUICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXg/oAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQpFCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4P6AIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEKRQgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeD+gCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBCkUICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXg/oAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQpFCAgICIAqgFAICIAACNkAIQAlhJoADgAohJsAIwB9hJx5yQVTAH4AnQAXACkAMQCMhKRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCkKAs4AZgDyAAIAECIEKUdMAOgA7AA6EpoSuAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6eEr4SwhLGEsoSzhLSEtYEKUoEKU4EKVIEKVYEKVoEKV4EKWIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXg/sAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQpQCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4P7AIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEKUAgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeD+wCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBClAICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcHlAAXg/sAjACMAIwAMQCMANQGBgCMAIwAFwCMgACA5oAAgQpQCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4P7AIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIEKUAgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeD+wCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBClAICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXg/sAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQpQCAgICIAqgMcICIAACN8QEgDCAMMAxIUhACEAxgDHhSIAIwDFhSMAyAAOACUAyQDKACgAywAXABcAFwApAFsAjACMhSsAMQCMAH4AjAVJeb4AjACMhTMAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQlsCAiBClsIgBkIgNGBCYgICIEKWggSLle8r9MAOgA7AA6FN4U6AGCiAbIFU4BFgLOihTuFPIEKXIEKZ4A12QAhACWFPwAOACiFQAAjAH2FQXnKAbIAfgCdABcAKQAxAIyFSV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEKWYBFgBmAPIAAgAQIgQpd0wA6ADsADoVLhVQAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKiFVYVWhVeFWIVZhVqFW4VcgQpegQpfgQpggQpigQpjgQpkgQplgQpmgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeFOwCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBClwICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXhTsAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQpcCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXhX4AF4U7AIwAjACMADEAjADUAcoAjACMABcAjIAAgQphgACBClwICAgIgCqASwgIgAAI0wA6ADsADoWMhY0AYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeFOwCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBClwICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXhTsAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQpcCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4U7AIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEKXAgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeFOwCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBClwICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXhTsAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQpcCAgICIAqgFAICIAACNkAIQAlhdsADgAohdwAIwB9hd15ygVTAH4AnQAXACkAMQCMheVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBClmAs4AZgDyAAIAECIEKaNMAOgA7AA6F54XvAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6eF8IXxhfKF84X0hfWF9oEKaYEKaoEKa4EKbIEKbYEKboEKb4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcGHAAXhTwAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAyYAAgQpnCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4U8AIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIEKZwgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeFPACMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBCmcICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABdZxwAXhTwAjACMAIwAMQCMANQGBgCMAIwAFwCMgACBBwuAAIEKZwgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeFPACMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBCmcICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXhTwAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQpnCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4U8AIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEKZwgICAiAKoDHCAiAAAjfEBIAwgDDAMSGYgAhAMYAx4ZjACMAxYZkAMgADgAlAMkAygAoAMsAFwAXABcAKQBbAIwAjIZsADEAjAB+AIwFSXm/AIwAjIZ0AIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEJbAgIgQpyCIAZCIDRgQmJCAiBCnEIEljs5tfTADoAOwAOhniGewBgogGyBVOARYCzooZ8hn2BCnOBCn6ANdkAIQAlhoAADgAohoEAIwB9hoJ5ywGyAH4AnQAXACkAMQCMhopfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCnCARYAZgDyAAIAECIEKdNMAOgA7AA6GjIaVAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCohpaGl4aYhpmGmoabhpyGnYEKdYEKdoEKd4EKeYEKeoEKe4EKfIEKfYA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXhnwAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQpzCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4Z8AIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEKcwgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4a/ABeGfACMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEKeIAAgQpzCAgICIAqgEsICIAACNMAOgA7AA6GzYbOAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXhnwAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQpzCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAF4Z8AIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEKcwgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeGfACMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBCnMICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXhnwAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQpzCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4Z8AIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEKcwgICAiAKoBQCAiAAAjZACEAJYccAA4AKIcdACMAfYceecsFUwB+AJ0AFwApADEAjIcmXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQpwgLOAGYA8gACABAiBCn/TADoAOwAOhyiHMABgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenhzGHMoczhzSHNYc2hzeBCoCBCoGBCoKBCoOBCoSBCoWBCoaANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4Z9AIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEKfggICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeGfQCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBCn4ICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXhn0AjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQp+CAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXBkoAF4Z9AIwAjACMADEAjADUBgYAjACMABcAjIAAgM2AAIEKfggICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeGfQCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBCn4ICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXhn0AjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQp+CAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4Z9AIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEKfggICAiAKoDHCAiAAAjSADsADoejANyggCnfEBCHpoenh6iHqQAhh6qHqwAjh6yHrQAOACWHroevACgAfQB+h7EAKQApABSHtQCEADEAKQB+AIcASwB+h7yHvQCMXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgBmBCpqABIAEgAKBCoqBA0uABIAZgQNNgBSAGYEK4IEKiQgSWM8f/NMAOgA7AA6HwYfDAGChAJGAG6GHxIEKi4A12QAhACWHxwAOACiHyAAjAH2HyQBdAJEAfgCdABcAKQAxAIyH0V8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEKiIAbgBmAPIAAgAQIgQqM0wA6ADsADofTh90AYKkApAClAKYApwCoAKkAqgCrAKyAHoAfgCCAIYAigCOAJIAlgCaph96H34fgh+GH4ofjh+SH5YfmgQqNgQqPgQqQgQqSgQqTgQqVgQqWgQqYgQqZgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4fqABeHxACMAIwAjAAxAIwA1ACkAIwAjAAXAIyAAIEKjoAAgQqLCAgICIAqgB4ICIAACNIAOwAOh/gA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4fEAIwAjACMADEAjADUAKUAjACMABcAjIAAgACAAIEKiwgICAiAKoAfCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4gLABeHxACMAIwAjAAxAIwA1ACmAIwAjAAXAIyAAIEKkYAAgQqLCAgICIAqgCAICIAACNIAOwAOiBkA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4fEAIwAjACMADEAjADUAKcAjACMABcAjIAAgACAAIEKiwgICAiAKoAhCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4gsABeHxACMAIwAjAAxAIwA1ACoAIwAjAAXAIyAAIEKlIAAgQqLCAgICIAqgCIICIAACNIAOwAOiDoA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4fEAIwAjACMADEAjADUAKkAjACMABcAjIAAgDKAAIEKiwgICAiAKoAjCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4hNABeHxACMAIwAjAAxAIwA1ACqAIwAjAAXAIyAAIEKl4AAgQqLCAgICIAqgCQICIAACNMAOgA7AA6IW4hcAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBVQAXh8QAjACMAIwAMQCMANQAqwCMAIwAFwCMgACAN4AAgQqLCAgICIAqgCUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAEsAF4fEAIwAjACMADEAjADUAKwAjACMABcAjIAAgBSAAIEKiwgICAiAKoAmCAiAAAjTADoAOwAOiH2IgQBgo3PLAzoDqYEJDoB1gIejiIKIg4iEgQqbgQqygQrJgDXfEBIAwgDDAMSIhwAhAMYAx4iIACMAxYiJAMgADgAlAMkAygAoAMsAFwAXABcAKQBdAIwAjIiRADEAjAB+AIwFSXPLAIwAjIiZAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEKiAgIgQqdCIAZCIDRgQkOCAiBCpwIEwAAAAERhwrc0wA6ADsADoidiKAAYKIBsgVTgEWAs6KIoYiigQqegQqpgDXZACEAJYilAA4AKIimACMAfYiniIIBsgB+AJ0AFwApADEAjIivXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQqbgEWAGYA8gACABAiBCp/TADoAOwAOiLGIugBgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqIi7iLyIvYi+iL+IwIjBiMKBCqCBCqGBCqKBCqSBCqWBCqaBCqeBCqiANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4ihAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIEKnggICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeIoQCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBCp4ICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABeI5AAXiKEAjACMAIwAMQCMANQBygCMAIwAFwCMgACBCqOAAIEKnggICAiAKoBLCAiAAAjTADoAOwAOiPKI8wBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4ihAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIEKnggICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABeIoQCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBCp4ICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXiKEAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQqeCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4ihAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIEKnggICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeIoQCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBCp4ICAgIgCqAUAgIgAAI2QAhACWJQQAOACiJQgAjAH2JQ4iCBVMAfgCdABcAKQAxAIyJS18QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEKm4CzgBmAPIAAgAQIgQqq0wA6ADsADolNiVUAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp4lWiVeJWIlZiVqJW4lcgQqrgQqsgQqtgQqugQqvgQqwgQqxgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeIogCMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBCqkICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXiKIAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQqpCAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4iiAIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIEKqQgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABeIogCMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBCqkICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXiKIAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQqpCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4iiAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIEKqQgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeIogCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBCqkICAgIgCqAxwgIgAAI3xASAMIAwwDEicgAIQDGAMeJyQAjAMWJygDIAA4AJQDJAMoAKADLABcAFwAXACkAXQCMAIyJ0gAxAIwAfgCMBUkDOgCMAIyJ2gCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCogICIEKtAiAGQiA0YB1CAiBCrMIEoXBNc7TADoAOwAOid6J4QBgogGyBVOARYCzooniieOBCrWBCsCANdkAIQAlieYADgAoiecAIwB9ieiIgwGyAH4AnQAXACkAMQCMifBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCrKARYAZgDyAAIAECIEKttMAOgA7AA6J8on7AGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoifyJ/Yn+if+KAIoBigKKA4EKt4EKuIEKuYEKu4EKvIEKvYEKvoEKv4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXieIAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQq1CAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4niAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEKtQgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4olABeJ4gCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEKuoAAgQq1CAgICIAqgEsICIAACNMAOgA7AA6KM4o0AGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXieIAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQq1CAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAF4niAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEKtQgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeJ4gCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBCrUICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXieIAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQq1CAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4niAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEKtQgICAiAKoBQCAiAAAjZACEAJYqCAA4AKIqDACMAfYqEiIMFUwB+AJ0AFwApADEAjIqMXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQqygLOAGYA8gACABAiBCsHTADoAOwAOio6KlgBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenipeKmIqZipqKm4qcip2BCsKBCsOBCsSBCsWBCsaBCseBCsiANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4njAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEKwAgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeJ4wCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBCsAICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXieMAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQrACAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAF4njAIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIEKwAgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeJ4wCMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBCsAICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXieMAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQrACAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4njAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEKwAgICAiAKoDHCAiAAAjfEBIAwgDDAMSLCQAhAMYAx4sKACMAxYsLAMgADgAlAMkAygAoAMsAFwAXABcAKQBdAIwAjIsTADEAjAB+AIwFSQOpAIwAjIsbAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIEKiAgIgQrLCIAZCIDRgIcICIEKyggTAAAAARgur4jTADoAOwAOix+LIgBgogGyBVOARYCzoosjiySBCsyBCteANdkAIQAliycADgAoiygAIwB9iymIhAGyAH4AnQAXACkAMQCMizFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCsmARYAZgDyAAIAECIEKzdMAOgA7AA6LM4s8AGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCoiz2LPos/i0CLQYtCi0OLRIEKzoEKz4EK0IEK0oEK04EK1IEK1YEK1oA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXiyMAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQrMCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4sjAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIEKzAgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4tmABeLIwCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIEK0YAAgQrMCAgICIAqgEsICIAACNMAOgA7AA6LdIt1AGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXiyMAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQrMCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAF4sjAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIEKzAgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeLIwCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBCswICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXiyMAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQrMCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4sjAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIEKzAgICAiAKoBQCAiAAAjZACEAJYvDAA4AKIvEACMAfYvFiIQFUwB+AJ0AFwApADEAjIvNXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQrJgLOAGYA8gACABAiBCtjTADoAOwAOi8+L1wBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMeni9iL2Yvai9uL3Ivdi96BCtmBCtqBCtuBCtyBCt2BCt6BCt+ANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4skAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIEK1wgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeLJACMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBCtcICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXiyQAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQrXCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXB5QAF4skAIwAjACMADEAjADUBgYAjACMABcAjIAAgOaAAIEK1wgICAiAKoDECAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeLJACMAIwAjAAxAIwA1AYHAIwAjAAXAIyAAIAAgACBCtcICAgIgCqAxQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXiyQAjACMAIwAMQCMANQGCACMAIwAFwCMgACAAIAAgQrXCAgICIAqgMYICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4skAIwAjACMADEAjADUBgkAjACMABcAjIAAgACAAIEK1wgICAiAKoDHCAiAAAjSADsADoxKANyggCnfEBCMTYxOjE+MUAAhjFGMUgAjjFOMVAAOACWMVYxWACgAfQB+jFgAKQApABSMXACEADEAKQB+AIcATAB+jGOMZACMXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlgBmBCvSABIAEgAKBCuOBA0uABIAZgQNNgBWAGYELPIEK4ggStb0/n9MAOgA7AA6MaIxqAGChAJGAG6GMa4EK5IA12QAhACWMbgAOACiMbwAjAH2McABeAJEAfgCdABcAKQAxAIyMeF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEK4YAbgBmAPIAAgAQIgQrl0wA6ADsADox6jIQAYKkApAClAKYApwCoAKkAqgCrAKyAHoAfgCCAIYAigCOAJIAlgCapjIWMhoyHjIiMiYyKjIuMjIyNgQrmgQrogQrpgQrrgQrsgQrugQrvgQrxgQrygDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4yRABeMawCMAIwAjAAxAIwA1ACkAIwAjAAXAIyAAIEK54AAgQrkCAgICIAqgB4ICIAACNIAOwAOjJ8A3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4xrAIwAjACMADEAjADUAKUAjACMABcAjIAAgACAAIEK5AgICAiAKoAfCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4yyABeMawCMAIwAjAAxAIwA1ACmAIwAjAAXAIyAAIEK6oAAgQrkCAgICIAqgCAICIAACNIAOwAOjMAA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4xrAIwAjACMADEAjADUAKcAjACMABcAjIAAgACAAIEK5AgICAiAKoAhCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4zTABeMawCMAIwAjAAxAIwA1ACoAIwAjAAXAIyAAIEK7YAAgQrkCAgICIAqgCIICIAACNIAOwAOjOEA3KCAKd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4xrAIwAjACMADEAjADUAKkAjACMABcAjIAAgDKAAIEK5AgICAiAKoAjCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF4z0ABeMawCMAIwAjAAxAIwA1ACqAIwAjAAXAIyAAIEK8IAAgQrkCAgICIAqgCQICIAACNMAOgA7AA6NAo0DAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBVQAXjGsAjACMAIwAMQCMANQAqwCMAIwAFwCMgACAN4AAgQrkCAgICIAqgCUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXjRYAF4xrAIwAjACMADEAjADUAKwAjACMABcAjIAAgQrzgACBCuQICAgIgCqAJggIgAAIXkNEUGhpc2hpbmdJdGVt0wA6ADsADo0ljSkAYKONJo0nUseBCvWBCvaBBoCjjSqNK40sgQr3gQsOgQslgDVWc291cmNlWXB1YmxpY0tled8QEgDCAMMAxI0xACEAxgDHjTIAIwDFjTMAyAAOACUAyQDKACgAywAXABcAFwApAF4AjACMjTsAMQCMAH4AjAVJjSYAjACMjUMAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQrhCAiBCvkIgBkIgNGBCvUICIEK+AgSVrCiwtMAOgA7AA6NR41KAGCiAbIFU4BFgLOijUuNTIEK+oELBYA12QAhACWNTwAOACiNUAAjAH2NUY0qAbIAfgCdABcAKQAxAIyNWV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYEK94BFgBmAPIAAgAQIgQr70wA6ADsADo1bjWQAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKiNZY1mjWeNaI1pjWqNa41sgQr8gQr9gQr+gQsAgQsBgQsCgQsDgQsEgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeNSwCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBCvoICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXjUsAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQr6CAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXjY4AF41LAIwAjACMADEAjADUAcoAjACMABcAjIAAgQr/gACBCvoICAgIgCqASwgIgAAI0wA6ADsADo2cjZ0AYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeNSwCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBCvoICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXjUsAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQr6CAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF41LAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIEK+ggICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeNSwCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBCvoICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXjUsAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQr6CAgICIAqgFAICIAACNkAIQAljesADgAojewAIwB9je2NKgVTAH4AnQAXACkAMQCMjfVfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCveAs4AZgDyAAIAECIELBtMAOgA7AA6N943/AGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6eOAI4BjgKOA44EjgWOBoELB4ELCIELCYELCoELC4ELDIELDYA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXjUwAjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQsFCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF41MAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIELBQgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeNTACMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBCwUICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcHlAAXjUwAjACMAIwAMQCMANQGBgCMAIwAFwCMgACA5oAAgQsFCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF41MAIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIELBQgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeNTACMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBCwUICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXjUwAjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQsFCAgICIAqgMcICIAACN8QEgDCAMMAxI5yACEAxgDHjnMAIwDFjnQAyAAOACUAyQDKACgAywAXABcAFwApAF4AjACMjnwAMQCMAH4AjAVJjScAjACMjoQAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQrhCAiBCxAIgBkIgNGBCvYICIELDwgSZSTXTNMAOgA7AA6OiI6LAGCiAbIFU4BFgLOijoyOjYELEYELHIA12QAhACWOkAAOACiOkQAjAH2Oko0rAbIAfgCdABcAKQAxAIyOml8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYELDoBFgBmAPIAAgAQIgQsS0wA6ADsADo6cjqUAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKiOpo6njqiOqY6qjquOrI6tgQsTgQsUgQsVgQsXgQsYgQsZgQsagQsbgDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeOjACMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBCxEICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXjowAjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQsRCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXjs8AF46MAIwAjACMADEAjADUAcoAjACMABcAjIAAgQsWgACBCxEICAgIgCqASwgIgAAI0wA6ADsADo7djt4AYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeOjACMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBCxEICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXjowAjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQsRCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF46MAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIELEQgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeOjACMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBCxEICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXjowAjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQsRCAgICIAqgFAICIAACNkAIQAljywADgAojy0AIwB9jy6NKwVTAH4AnQAXACkAMQCMjzZfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCw6As4AZgDyAAIAECIELHdMAOgA7AA6POI9AAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6ePQY9Cj0OPRI9Fj0aPR4ELHoELH4ELIIELIYELIoELI4ELJIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXjo0AjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQscCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF46NAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIELHAgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeOjQCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBCxwICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcHlAAXjo0AjACMAIwAMQCMANQGBgCMAIwAFwCMgACA5oAAgQscCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF46NAIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIELHAgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeOjQCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBCxwICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXjo0AjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQscCAgICIAqgMcICIAACN8QEgDCAMMAxI+zACEAxgDHj7QAIwDFj7UAyAAOACUAyQDKACgAywAXABcAFwApAF4AjACMj70AMQCMAH4AjAVJUscAjACMj8UAjF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgQrhCAiBCycIgBkIgNGBBoAICIELJggSjYPZFtMAOgA7AA6PyY/MAGCiAbIFU4BFgLOij82PzoELKIELM4A12QAhACWP0QAOACiP0gAjAH2P040sAbIAfgCdABcAKQAxAIyP218QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYELJYBFgBmAPIAAgAQIgQsp0wA6ADsADo/dj+YAYKgByAHJAcoBywHMAc0BzgHPgEmASoBLgEyATYBOgE+AUKiP54/oj+mP6o/rj+yP7Y/ugQsqgQsrgQssgQsugQsvgQswgQsxgQsygDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABePzQCMAIwAjAAxAIwA1AHIAIwAjAAXAIyAAIAygACBCygICAgIgCqASQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXj80AjACMAIwAMQCMANQByQCMAIwAFwCMgACAAIAAgQsoCAgICIAqgEoICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXkBAAF4/NAIwAjACMADEAjADUAcoAjACMABcAjIAAgQstgACBCygICAgIgCqASwgIgAAI0wA6ADsADpAekB8AYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABePzQCMAIwAjAAxAIwA1AHLAIwAjAAXAIyAAIAygACBCygICAgIgCqATAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcCJAAXj80AjACMAIwAMQCMANQBzACMAIwAFwCMgACAV4AAgQsoCAgICIAqgE0ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4/NAIwAjACMADEAjADUAc0AjACMABcAjIAAgDKAAIELKAgICAiAKoBOCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABePzQCMAIwAjAAxAIwA1AHOAIwAjAAXAIyAAIAAgACBCygICAgIgCqATwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXj80AjACMAIwAMQCMANQBzwCMAIwAFwCMgACAMoAAgQsoCAgICIAqgFAICIAACNkAIQAlkG0ADgAokG4AIwB9kG+NLAVTAH4AnQAXACkAMQCMkHdfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBCyWAs4AZgDyAAIAECIELNNMAOgA7AA6QeZCBAGCnBgMGBAYFBgYGBwYIBgmAwYDCgMOAxIDFgMaAx6eQgpCDkISQhZCGkIeQiIELNYELNoELN4ELOIELOYELOoELO4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXj84AjACMAIwAMQCMANQGAwCMAIwAFwCMgACAAIAAgQszCAgICIAqgMEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF4/OAIwAjACMADEAjADUBgQAjACMABcAjIAAgDKAAIELMwgICAiAKoDCCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABePzgCMAIwAjAAxAIwA1AYFAIwAjAAXAIyAAIAAgACBCzMICAgIgCqAwwgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcHlAAXj84AjACMAIwAMQCMANQGBgCMAIwAFwCMgACA5oAAgQszCAgICIAqgMQICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF4/OAIwAjACMADEAjADUBgcAjACMABcAjIAAgACAAIELMwgICAiAKoDFCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABePzgCMAIwAjAAxAIwA1AYIAIwAjAAXAIyAAIAAgACBCzMICAgIgCqAxggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXj84AjACMAIwAMQCMANQGCQCMAIwAFwCMgACAAIAAgQszCAgICIAqgMcICIAACNIAOwAOkPQA3KCAKd8QEJD3kPiQ+ZD6ACGQ+5D8ACOQ/ZD+AA4AJZD/kQAAKAB9AH6RAgApACkAFJEGAIQAMQApAH4AhwBNAH6RDZEOAIxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2WAGYELUIAEgASAAoELP4EDS4AEgBmBA02AFoAZgQuAgQs+CBK4ilVe0wA6ADsADpESkRQAYKEAkYAboZEVgQtAgDXZACEAJZEYAA4AKJEZACMAfZEaAF8AkQB+AJ0AFwApADEAjJEiXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQs9gBuAGYA8gACABAiBC0HTADoAOwAOkSSRLgBgqQCkAKUApgCnAKgAqQCqAKsArIAegB+AIIAhgCKAI4AkgCWAJqmRL5EwkTGRMpEzkTSRNZE2kTeBC0KBC0SBC0WBC0eBC0iBC0qBC0uBC02BC06ANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXkTsAF5EVAIwAjACMADEAjADUAKQAjACMABcAjIAAgQtDgACBC0AICAgIgCqAHggIgAAI0gA7AA6RSQDcoIAp3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXkRUAjACMAIwAMQCMANQApQCMAIwAFwCMgACAAIAAgQtACAgICIAqgB8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXkVwAF5EVAIwAjACMADEAjADUAKYAjACMABcAjIAAgQtGgACBC0AICAgIgCqAIAgIgAAI0gA7AA6RagDcoIAp3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXkRUAjACMAIwAMQCMANQApwCMAIwAFwCMgACAAIAAgQtACAgICIAqgCEICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXkX0AF5EVAIwAjACMADEAjADUAKgAjACMABcAjIAAgQtJgACBC0AICAgIgCqAIggIgAAI0gA7AA6RiwDcoIAp3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXkRUAjACMAIwAMQCMANQAqQCMAIwAFwCMgACAMoAAgQtACAgICIAqgCMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXkZ4AF5EVAIwAjACMADEAjADUAKoAjACMABcAjIAAgQtMgACBC0AICAgIgCqAJAgIgAAI0wA6ADsADpGska0AYKCggDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwFVABeRFQCMAIwAjAAxAIwA1ACrAIwAjAAXAIyAAIA3gACBC0AICAgIgCqAJQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABeRwAAXkRUAjACMAIwAMQCMANQArACMAIwAFwCMgACBC0+AAIELQAgICAiAKoAmCAiAAAhfEBJDRENoYWluU3RvcmFnZUl0ZW3TADoAOwAOkc+R0gBgopHQUseBC1GBBoCikdOR1IELUoELaYA1VGRhdGHfEBIAwgDDAMSR2AAhAMYAx5HZACMAxZHaAMgADgAlAMkAygAoAMsAFwAXABcAKQBfAIwAjJHiADEAjAB+AIwFSZHQAIwAjJHqAIxfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIELPQgIgQtUCIAZCIDRgQtRCAiBC1MIEpMp//fTADoAOwAOke6R8QBgogGyBVOARYCzopHykfOBC1WBC2CANdkAIQAlkfYADgAokfcAIwB9kfiR0wGyAH4AnQAXACkAMQCMkgBfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WBC1KARYAZgDyAAIAECIELVtMAOgA7AA6SApILAGCoAcgByQHKAcsBzAHNAc4Bz4BJgEqAS4BMgE2AToBPgFCokgySDZIOkg+SEJIRkhKSE4ELV4ELWIELWYELW4ELXIELXYELXoELX4A13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXkfIAjACMAIwAMQCMANQByACMAIwAFwCMgACAMoAAgQtVCAgICIAqgEkICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF5HyAIwAjACMADEAjADUAckAjACMABcAjIAAgACAAIELVQgICAiAKoBKCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAF5I1ABeR8gCMAIwAjAAxAIwA1AHKAIwAjAAXAIyAAIELWoAAgQtVCAgICIAqgEsICIAACNMAOgA7AA6SQ5JEAGCgoIA13xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXkfIAjACMAIwAMQCMANQBywCMAIwAFwCMgACAMoAAgQtVCAgICIAqgEwICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAiQAF5HyAIwAjACMADEAjADUAcwAjACMABcAjIAAgFeAAIELVQgICAiAKoBNCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeR8gCMAIwAjAAxAIwA1AHNAIwAjAAXAIyAAIAygACBC1UICAgIgCqATggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXkfIAjACMAIwAMQCMANQBzgCMAIwAFwCMgACAAIAAgQtVCAgICIAqgE8ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF5HyAIwAjACMADEAjADUAc8AjACMABcAjIAAgDKAAIELVQgICAiAKoBQCAiAAAjZACEAJZKSAA4AKJKTACMAfZKUkdMFUwB+AJ0AFwApADEAjJKcXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQtSgLOAGYA8gACABAiBC2HTADoAOwAOkp6SpgBgpwYDBgQGBQYGBgcGCAYJgMGAwoDDgMSAxYDGgMenkqeSqJKpkqqSq5Kskq2BC2KBC2OBC2SBC2WBC2aBC2eBC2iANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF5HzAIwAjACMADEAjADUBgMAjACMABcAjIAAgACAAIELYAgICAiAKoDBCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeR8wCMAIwAjAAxAIwA1AYEAIwAjAAXAIyAAIAygACBC2AICAgIgCqAwggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXkfMAjACMAIwAMQCMANQGBQCMAIwAFwCMgACAAIAAgQtgCAgICIAqgMMICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXU9UAF5HzAIwAjACMADEAjADUBgYAjACMABcAjIAAgQaVgACBC2AICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXkfMAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQtgCAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF5HzAIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIELYAgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeR8wCMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBC2AICAgIgCqAxwgIgAAI3xASAMIAwwDEkxkAIQDGAMeTGgAjAMWTGwDIAA4AJQDJAMoAKADLABcAFwAXACkAXwCMAIyTIwAxAIwAfgCMBUlSxwCMAIyTKwCMXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASBCz0ICIELawiAGQiA0YEGgAgIgQtqCBKxfj4F0wA6ADsADpMvkzIAYKIBsgVTgEWAs6KTM5M0gQtsgQt3gDXZACEAJZM3AA4AKJM4ACMAfZM5kdQBsgB+AJ0AFwApADEAjJNBXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgQtpgEWAGYA8gACABAiBC23TADoAOwAOk0OTTABgqAHIAckBygHLAcwBzQHOAc+ASYBKgEuATIBNgE6AT4BQqJNNk06TT5NQk1GTUpNTk1SBC26BC2+BC3CBC3KBC3OBC3SBC3WBC3aANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF5MzAIwAjACMADEAjADUAcgAjACMABcAjIAAgDKAAIELbAgICAiAKoBJCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeTMwCMAIwAjAAxAIwA1AHJAIwAjAAXAIyAAIAAgACBC2wICAgIgCqASggIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABeTdgAXkzMAjACMAIwAMQCMANQBygCMAIwAFwCMgACBC3GAAIELbAgICAiAKoBLCAiAAAjTADoAOwAOk4SThQBgoKCANd8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXAS4AF5MzAIwAjACMADEAjADUAcsAjACMABcAjIAAgDKAAIELbAgICAiAKoBMCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwIkABeTMwCMAIwAjAAxAIwA1AHMAIwAjAAXAIyAAIBXgACBC2wICAgIgCqATQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXkzMAjACMAIwAMQCMANQBzQCMAIwAFwCMgACAMoAAgQtsCAgICIAqgE4ICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF5MzAIwAjACMADEAjADUAc4AjACMABcAjIAAgACAAIELbAgICAiAKoBPCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwEuABeTMwCMAIwAjAAxAIwA1AHPAIwAjAAXAIyAAIAygACBC2wICAgIgCqAUAgIgAAI2QAhACWT0wAOACiT1AAjAH2T1ZHUBVMAfgCdABcAKQAxAIyT3V8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYELaYCzgBmAPIAAgAQIgQt40wA6ADsADpPfk+cAYKcGAwYEBgUGBgYHBggGCYDBgMKAw4DEgMWAxoDHp5Pok+mT6pPrk+yT7ZPugQt5gQt6gQt7gQt8gQt9gQt+gQt/gDXfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeTNACMAIwAjAAxAIwA1AYDAIwAjAAXAIyAAIAAgACBC3cICAgIgCqAwQgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcBLgAXkzQAjACMAIwAMQCMANQGBACMAIwAFwCMgACAMoAAgQt3CAgICIAqgMIICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF5M0AIwAjACMADEAjADUBgUAjACMABcAjIAAgACAAIELdwgICAiAKoDDCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFweUABeTNACMAIwAjAAxAIwA1AYGAIwAjAAXAIyAAIDmgACBC3cICAgIgCqAxAgIgAAI3xAPAMIAwwDEACEAxQDGAMcAIwDIAA4AJQDJAMoAKADLABcAFwAXkzQAjACMAIwAMQCMANQGBwCMAIwAFwCMgACAAIAAgQt3CAgICIAqgMUICIAACN8QDwDCAMMAxAAhAMUAxgDHACMAyAAOACUAyQDKACgAywAXABcAF5M0AIwAjACMADEAjADUBggAjACMABcAjIAAgACAAIELdwgICAiAKoDGCAiAAAjfEA8AwgDDAMQAIQDFAMYAxwAjAMgADgAlAMkAygAoAMsAFwAXABeTNACMAIwAjAAxAIwA1AYJAIwAjAAXAIyAAIAAgACBC3cICAgIgCqAxwgIgAAI0gA7AA6UWgDcoIAp0wA6ADsADpRdlF4AYKCggDXTADoAOwAOlGGUYgBgoKCANdMAOgA7AA6UZZRmAGCgoIA10gDeAN+UaZRqXlhETW9kZWxQYWNrYWdlppRrlGyUbZRulG8A415YRE1vZGVsUGFja2FnZV8QD1hEVU1MUGFja2FnZUltcF8QEVhEVU1MTmFtZXNwYWNlSW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDSADsADpRxANyggCnTADoAOwAOlHSUdQBgoKCANdIA3gDflHiUeVlYRFBNTW9kZWyjlHiUegDjV1hETW9kZWwAAAAIAAAAGQAAACIAAAAsAAAAMQAAADoAAAA/AAAAUQAAAFYAAABbAAAAXQAAF3EAABd3AAAXlAAAF6YAABetAAAXugAAF80AABflAAAX8wAAGA0AABgPAAAYEgAAGBUAABgXAAAYGgAAGBwAABgfAAAYWAAAGHcAABiUAAAYswAAGMUAABjlAAAY7AAAGQoAABkWAAAZMgAAGTgAABlaAAAZewAAGY4AABmQAAAZkwAAGZYAABmYAAAZmgAAGZwAABmfAAAZogAAGaQAABmmAAAZqAAAGaoAABmsAAAZrgAAGa8AABmzAAAZwAAAGcgAABnTAAAZ+AAAGfoAABn8AAAZ/gAAGgAAABoCAAAaBAAAGgYAABoIAAAaCgAAGgwAABoOAAAaEAAAGhIAABoUAAAaFgAAGhgAABoaAAAaPwAAGkEAABpDAAAaRgAAGkkAABpMAAAaTwAAGlIAABpVAAAaWAAAGlsAABpeAAAaYQAAGmQAABpnAAAaagAAGm0AABpwAAAacgAAGoAAABqIAAAalgAAGp4AABqsAAAayAAAGtsAABrnAAAa/wAAGw4AABsZAAAbJQAAG0AAABtcAAAbZgAAG3UAABuKAAAbzQAAG/EAABwVAAAcOAAAHF8AABx/AAAcpgAAHM0AABztAAAdEQAAHTUAAB1BAAAdQwAAHUUAAB1HAAAdSQAAHUsAAB1NAAAdUAAAHVIAAB1UAAAdVwAAHVkAAB1bAAAdXgAAHWAAAB1hAAAdagAAHXIAAB1/AAAdggAAHYQAAB2HAAAdiQAAHYsAAB2aAAAdvwAAHeMAAB4KAAAeLgAAHjAAAB4yAAAeNAAAHjYAAB44AAAeOgAAHjsAAB49AAAeSgAAHl0AAB5fAAAeYQAAHmMAAB5lAAAeZwAAHmkAAB5rAAAebQAAHm8AAB6CAAAehAAAHoYAAB6IAAAeigAAHowAAB6OAAAekAAAHpIAAB6UAAAelgAAHqwAAB6/AAAe2wAAHvgAAB8UAAAfKAAAHzoAAB9QAAAfaQAAH6gAAB+uAAAftwAAH8QAAB/QAAAf2gAAH+QAAB/vAAAf+gAAIAcAACAPAAAgEQAAIBMAACAVAAAgFwAAIBgAACAZAAAgGgAAIBsAACAdAAAgHwAAICAAACAhAAAgIwAAICQAACAtAAAgLgAAIDAAACA5AAAgRAAAIE0AACBcAAAgYwAAIGsAACB0AAAgfQAAIJAAACCZAAAgrAAAIMMAACDVAAAhFAAAIRYAACEYAAAhGgAAIRwAACEdAAAhHgAAIR8AACEgAAAhIgAAISQAACElAAAhJgAAISgAACEpAAAhaAAAIWoAACFsAAAhbgAAIXAAACFxAAAhcgAAIXMAACF0AAAhdgAAIXgAACF5AAAhegAAIXwAACF9AAAhhgAAIYcAACGJAAAhyAAAIcoAACHMAAAhzgAAIdAAACHRAAAh0gAAIdMAACHUAAAh1gAAIdgAACHZAAAh2gAAIdwAACHdAAAiHAAAIh4AACIgAAAiIgAAIiQAACIlAAAiJgAAIicAACIoAAAiKgAAIiwAACItAAAiLgAAIjAAACIxAAAiOgAAIjsAACI9AAAifAAAIn4AACKAAAAiggAAIoQAACKFAAAihgAAIocAACKIAAAiigAAIowAACKNAAAijgAAIpAAACKRAAAikgAAItEAACLTAAAi1QAAItcAACLZAAAi2gAAItsAACLcAAAi3QAAIt8AACLhAAAi4gAAIuMAACLlAAAi5gAAIvMAACL0AAAi9QAAIvcAACMAAAAjFgAAIx0AACMqAAAjaQAAI2sAACNtAAAjbwAAI3EAACNyAAAjcwAAI3QAACN1AAAjdwAAI3kAACN6AAAjewAAI30AACN+AAAjlwAAI5kAACObAAAjnQAAI54AACOgAAAjtwAAI8AAACPOAAAj2wAAI+kAACP+AAAkEgAAJCkAACQ7AAAkegAAJHwAACR+AAAkgAAAJIIAACSDAAAkhAAAJIUAACSGAAAkiAAAJIoAACSLAAAkjAAAJI4AACSPAAAknQAAJKYAACS7AAAkygAAJN8AACTtAAAlAgAAJRYAACUtAAAlPwAAJUwAACVVAAAlVwAAJVkAACVbAAAlXQAAJWYAACVoAAAlawAAJW4AACVxAAAlcwAAJXkAACV/AAAlhAAAJYgAACXTAAAl9gAAJhYAACY2AAAmOAAAJjoAACY8AAAmPgAAJkAAACZBAAAmQgAAJkQAACZFAAAmRwAAJkgAACZKAAAmTAAAJk0AACZOAAAmUAAAJlEAACZWAAAmYwAAJmgAACZqAAAmbAAAJnEAACZzAAAmdQAAJncAACaMAAAmnwAAJsQAACboAAAnDwAAJzMAACc1AAAnNwAAJzkAACc7AAAnPQAAJz8AACdAAAAnQgAAJ08AACdgAAAnYgAAJ2QAACdmAAAnaAAAJ2oAACdsAAAnbgAAJ3AAACeBAAAngwAAJ4UAACeHAAAniQAAJ4sAACeNAAAnjwAAJ5EAACeTAAAnsQAAJ88AACfiAAAn9gAAKAsAACgoAAAoPAAAKFIAACiRAAAokwAAKJUAACiXAAAomQAAKJoAACibAAAonAAAKJ0AACifAAAooQAAKKIAACijAAAopQAAKKYAACjlAAAo5wAAKOkAACjrAAAo7QAAKO4AACjvAAAo8AAAKPEAACjzAAAo9QAAKPYAACj3AAAo+QAAKPoAACk5AAApOwAAKT0AACk/AAApQQAAKUIAAClDAAApRAAAKUUAAClHAAApSQAAKUoAAClLAAApTQAAKU4AAClbAAApXAAAKV0AAClfAAApngAAKaAAACmiAAAppAAAKaYAACmnAAApqAAAKakAACmqAAAprAAAKa4AACmvAAApsAAAKbIAACmzAAAp8gAAKfQAACn2AAAp+AAAKfoAACn7AAAp/AAAKf0AACn+AAAqAAAAKgIAACoDAAAqBAAAKgYAACoHAAAqCAAAKkcAACpJAAAqSwAAKk0AACpPAAAqUAAAKlEAACpSAAAqUwAAKlUAACpXAAAqWAAAKlkAACpbAAAqXAAAKpsAACqdAAAqnwAAKqEAACqjAAAqpAAAKqUAACqmAAAqpwAAKqkAACqrAAAqrAAAKq0AACqvAAAqsAAAKu8AACrxAAAq8wAAKvUAACr3AAAq+AAAKvkAACr6AAAq+wAAKv0AACr/AAArAAAAKwEAACsDAAArBAAAKykAACtNAAArdAAAK5gAACuaAAArnAAAK54AACugAAArogAAK6QAACulAAArpwAAK7QAACvDAAArxQAAK8cAACvJAAArywAAK80AACvPAAAr0QAAK+AAACviAAAr5AAAK+YAACvoAAAr6wAAK+4AACvxAAAr8wAALAUAACwZAAAsKwAALEAAACxSAAAsYQAALH4AACy9AAAsvwAALMEAACzDAAAsxQAALMYAACzHAAAsyAAALMkAACzLAAAszQAALM4AACzPAAAs0QAALNIAAC0RAAAtEwAALRUAAC0XAAAtGQAALRoAAC0bAAAtHAAALR0AAC0fAAAtIQAALSIAAC0jAAAtJQAALSYAAC0oAAAtZwAALWkAAC1rAAAtbQAALW8AAC1wAAAtcQAALXIAAC1zAAAtdQAALXcAAC14AAAteQAALXsAAC18AAAtuwAALb0AAC2/AAAtwQAALcMAAC3EAAAtxQAALcYAAC3HAAAtyQAALcsAAC3MAAAtzQAALc8AAC3QAAAuEwAALjcAAC5bAAAufgAALqUAAC7FAAAu7AAALxMAAC8zAAAvVwAAL3sAAC99AAAvfwAAL4EAAC+DAAAvhQAAL4cAAC+KAAAvjAAAL44AAC+RAAAvkwAAL5UAAC+YAAAvmgAAL5sAAC+gAAAvrQAAL7AAAC+yAAAvtQAAL7cAAC+5AAAv3gAAMAIAADApAAAwTQAAME8AADBRAAAwUwAAMFUAADBXAAAwWQAAMFoAADBcAAAwaQAAMHwAADB+AAAwgAAAMIIAADCEAAAwhgAAMIgAADCKAAAwjAAAMI4AADChAAAwowAAMKUAADCnAAAwqQAAMKsAADCtAAAwrwAAMLEAADCzAAAwtQAAMPQAADD2AAAw+AAAMPoAADD8AAAw/QAAMP4AADD/AAAxAAAAMQIAADEEAAAxBQAAMQYAADEIAAAxCQAAMRIAADETAAAxFQAAMVQAADFWAAAxWAAAMVoAADFcAAAxXQAAMV4AADFfAAAxYAAAMWIAADFkAAAxZQAAMWYAADFoAAAxaQAAMagAADGqAAAxrAAAMa4AADGwAAAxsQAAMbIAADGzAAAxtAAAMbYAADG4AAAxuQAAMboAADG8AAAxvQAAMcYAADHJAAAxywAAMc0AADHWAAAx2QAAMdsAADHdAAAx5QAAMiQAADImAAAyKAAAMioAADIsAAAyLQAAMi4AADIvAAAyMAAAMjIAADI0AAAyNQAAMjYAADI4AAAyOQAAMngAADJ6AAAyfAAAMn4AADKAAAAygQAAMoIAADKDAAAyhAAAMoYAADKIAAAyiQAAMooAADKMAAAyjQAAMpYAADKXAAAymQAAMtgAADLaAAAy3AAAMt4AADLgAAAy4QAAMuIAADLjAAAy5AAAMuYAADLoAAAy6QAAMuoAADLsAAAy7QAAMywAADMuAAAzMAAAMzIAADM0AAAzNQAAMzYAADM3AAAzOAAAMzoAADM8AAAzPQAAMz4AADNAAAAzQQAAM04AADNPAAAzUAAAM1IAADORAAAzkwAAM5UAADOXAAAzmQAAM5oAADObAAAznAAAM50AADOfAAAzoQAAM6IAADOjAAAzpQAAM6YAADPlAAAz5wAAM+kAADPrAAAz7QAAM+4AADPvAAAz8AAAM/EAADPzAAAz9QAAM/YAADP3AAAz+QAAM/oAADQHAAA0QAAANEIAADREAAA0RgAANEgAADRKAAA0TAAANE4AADRQAAA0UgAANFQAADRWAAA0WAAANFoAADRcAAA0XgAANGAAADRiAAA0ZAAANGYAADRoAAA0agAANGwAADRuAAA0cAAANHIAADR0AAA0dgAANK8AADSxAAA0swAANLUAADS3AAA0ugAANL0AADTAAAA0wwAANMYAADTJAAA0zAAANM8AADTSAAA01QAANNgAADTbAAA03gAANOEAADTkAAA05wAANOoAADTtAAA08AAANPMAADT2AAA0+QAANPwAADT+AAA1CAAANRYAADUkAAA1LAAANToAADU/AAA1TgAANVwAADVhAAA1dQAANXwAADWSAAA1nAAANasAADWxAAA1vgAANccAADXOAAA11wAANesAADX+AAA2CAAANhoAADYoAAA2NAAANn8AADaiAAA2wgAANuIAADbkAAA25gAANugAADbqAAA27AAANu0AADbuAAA28AAANvEAADbzAAA29AAANvYAADb4AAA2+QAANvoAADb8AAA2/QAANwIAADcPAAA3FAAANxYAADcYAAA3HQAANx8AADchAAA3IwAAN0gAADdsAAA3kwAAN7cAADe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FAABChgAAQsUAAELHAABCyQAAQssAAELNAABCzgAAQs8AAELQAABC0QAAQtMAAELVAABC1gAAQtcAAELZAABC2gAAQxkAAEMbAABDHQAAQx8AAEMhAABDIgAAQyMAAEMkAABDJQAAQycAAEMpAABDKgAAQysAAEMtAABDLgAAQ1MAAEN3AABDngAAQ8IAAEPEAABDxgAAQ8gAAEPKAABDzAAAQ84AAEPPAABD0QAAQ94AAEPtAABD7wAAQ/EAAEPzAABD9QAAQ/cAAEP5AABD+wAARAoAAEQMAABEDgAARBAAAEQSAABEFAAARBYAAEQYAABEGgAARDoAAERlAABEfwAARJgAAESyAABE0gAARPUAAEU0AABFNgAARTgAAEU6AABFPAAART0AAEU+AABFPwAARUAAAEVCAABFRAAARUUAAEVGAABFSAAARUkAAEVLAABFigAARYwAAEWOAABFkAAARZIAAEWTAABFlAAARZUAAEWWAABFmAAARZoAAEWbAABFnAAARZ4AAEWfAABF3gAAReAAAEXiAABF5AAAReYAAEXnAABF6AAARekAAEXqAABF7AAARe4AAEXvAABF8AAARfIAAEXzAABGMgAARjQAAEY2AABGOAAARjoAAEY7AABGPAAARj0AAEY+AABGQAAARkIAAEZDAABGRAAARkYAAEZHAABGSQAARogAAEaKAABGjAAARo4AAEaQAABGkQAARpIAAEaTAABGlAAARpYAAEaYAABGmQAARpoAAEacAABGnQAARtwAAEbeAABG4AAARuIAAEbkAABG5QAARuYAAEbnAABG6AAARuoAAEbsAABG7QAARu4AAEbwAABG8QAARzAAAEcyAABHNAAARzYAAEc4AABHOQAARzoAAEc7AABHPAAARz4AAEdAAABHQQAAR0IAAEdEAABHRQAAR04AAEdcAABHaQAAR3cAAEeEAABHlwAAR64AAEfAAABICwAASC4AAEhOAABIbgAASHAAAEhyAABIdAAASHYAAEh4AABIeQAASHoAAEh8AABIfQAASH8AAEiAAABIggAASIQAAEiFAABIhgAASIgAAEiJAABIjgAASJsAAEigAABIogAASKQAAEipAABIqwAASK0AAEivAABI1AAASPgAAEkfAABJQwAASUUAAElHAABJSQAASUsAAElNAABJTwAASVAAAElSAABJXwAASXAAAElyAABJdAAASXYAAEl4AABJegAASXwAAEl+AABJgAAASZEAAEmTAABJlQAASZcAAEmZAABJmwAASZ0AAEmfAABJoQAASaMAAEniAABJ5AAASeYAAEnoAABJ6gAASesAAEnsAABJ7QAASe4AAEnwAABJ8gAASfMAAEn0AABJ9gAASfcAAEo2AABKOAAASjoAAEo8AABKPgAASj8AAEpAAABKQQAASkIAAEpEAABKRgAASkcAAEpIAABKSgAASksAAEqKAABKjAAASo4AAEqQAABKkgAASpMAAEqUAABKlQAASpYAAEqYAABKmgAASpsAAEqcAABKngAASp8AAEqsAABKrQAASq4AAEqwAABK7wAASvEAAErzAABK9QAASvcAAEr4AABK+QAASvoAAEr7AABK/QAASv8AAEsAAABLAQAASwMAAEsEAABLQwAAS0UAAEtHAABLSQAAS0sAAEtMAABLTQAAS04AAEtPAABLUQAAS1MAAEtUAABLVQAAS1cAAEtYAABLlwAAS5kAAEubAABLnQAAS58AAEugAABLoQAAS6IAAEujAABLpQAAS6cAAEuoAABLqQAAS6sAAEusAABL6wAAS+0AAEvvAABL8QAAS/MAAEv0AABL9QAAS/YAAEv3AABL+QAAS/sAAEv8AABL/QAAS/8AAEwAAABMPwAATEEAAExDAABMRQAATEcAAExIAABMSQAATEoAAExLAABMTQAATE8AAExQAABMUQAATFMAAExUAABMeQAATJ0AAEzEAABM6AAATOoAAEzsAABM7gAATPAAAEzyAABM9AAATPUAAEz3AABNBAAATRMAAE0VAABNFwAATRkAAE0bAABNHQAATR8AAE0hAABNMAAATTIAAE00AABNNgAATTgAAE06AABNPAAATT4AAE1AAABNfwAATYEAAE2DAABNhQAATYcAAE2IAABNiQAATYoAAE2LAABNjQAATY8AAE2QAABNkQAATZMAAE2UAABN0wAATdUAAE3XAABN2QAATdsAAE3cAABN3QAATd4AAE3fAABN4QAATeMAAE3kAABN5QAATecAAE3oAABOJwAATikAAE4rAABOLQAATi8AAE4wAABOMQAATjIAAE4zAABONQAATjcAAE44AABOOQAATjsAAE48AABOewAATn0AAE5/AABOgQAAToMAAE6EAABOhQAAToYAAE6HAABOiQAATosAAE6MAABOjQAATo8AAE6QAABOkwAATtIAAE7UAABO1gAATtgAAE7aAABO2wAATtwAAE7dAABO3gAATuAAAE7iAABO4wAATuQAAE7mAABO5wAATyYAAE8oAABPKgAATywAAE8uAABPLwAATzAAAE8xAABPMgAATzQAAE82AABPNwAATzgAAE86AABPOwAAT3oAAE98AABPfgAAT4AAAE+CAABPgwAAT4QAAE+FAABPhgAAT4gAAE+KAABPiwAAT4wAAE+OAABPjwAAT9oAAE/9AABQHQAAUD0AAFA/AABQQQAAUEMAAFBFAABQRwAAUEgAAFBJAABQSwAAUEwAAFBOAABQTwAAUFEAAFBTAABQVAAAUFUAAFBXAABQWAAAUF0AAFBqAABQbwAAUHEAAFBzAABQeAAAUHoAAFB8AABQfgAAUKMAAFDHAABQ7gAAURIAAFEUAABRFgAAURgAAFEaAABRHAAAUR4AAFEfAABRIQAAUS4AAFE/AABRQQAAUUMAAFFFAABRRwAAUUkAAFFLAABRTQAAUU8AAFFgAABRYgAAUWQAAFFmAABRaAAAUWoAAFFsAABRbgAAUXAAAFFyAABRsQAAUbMAAFG1AABRtwAAUbkAAFG6AABRuwAAUbwAAFG9AABRvwAAUcEAAFHCAABRwwAAUcUAAFHGAABSBQAAUgcAAFIJAABSCwAAUg0AAFIOAABSDwAAUhAAAFIRAABSEwAAUhUAAFIWAABSFwAAUhkAAFIaAABSWQAAUlsAAFJdAABSXwAAUmEAAFJiAABSYwAAUmQAAFJlAABSZwAAUmkAAFJqAABSawAAUm0AAFJuAABSewAAUnwAAFJ9AABSfwAAUr4AAFLAAABSwgAAUsQAAFLGAABSxwAAUsgAAFLJAABSygAAUswAAFLOAABSzwAAUtAAAFLSAABS0wAAUxIAAFMUAABTFgAAUxgAAFMaAABTGwAAUxwAAFMdAABTHgAAUyAAAFMiAABTIwAAUyQAAFMmAABTJwAAU2YAAFNoAABTagAAU2wAAFNuAABTbwAAU3AAAFNxAABTcgAAU3QAAFN2AABTdwAAU3gAAFN6AABTewAAU7oAAFO8AABTvgAAU8AAAFPCAABTwwAAU8QAAFPFAABTxgAAU8gAAFPKAABTywAAU8wAAFPOAABTzwAAVA4AAFQQAABUEgAAVBQAAFQWAABUFwAAVBgAAFQZAABUGgAAVBwAAFQeAABUHwAAVCAAAFQiAABUIwAAVEgAAFRsAABUkwAAVLcAAFS5AABUuwAAVL0AAFS/AABUwQAAVMMAAFTEAABUxgAAVNMAAFTiAABU5AAAVOYAAFToAABU6gAAVOwAAFTuAABU8AAAVP8AAFUBAABVAwAAVQUAAFUHAABVCQAAVQwAAFUPAABVEQAAVVAAAFVSAABVVAAAVVYAAFVYAABVWQAAVVoAAFVbAABVXAAAVV4AAFVgAABVYQAAVWIAAFVkAABVZQAAVaQAAFWmAABVqAAAVaoAAFWsAABVrQAAVa4AAFWvAABVsAAAVbIAAFW0AABVtQAAVbYAAFW4AABVuQAAVfgAAFX6AABV/AAAVf4AAFYAAABWAQAAVgIAAFYDAABWBAAAVgYAAFYIAABWCQAAVgoAAFYMAABWDQAAVkwAAFZOAABWUAAAVlIAAFZUAABWVQAAVlYAAFZXAABWWAAAVloAAFZcAABWXQAAVl4AAFZgAABWYQAAVmQAAFajAABWpQAAVqcAAFapAABWqwAAVqwAAFatAABWrgAAVq8AAFaxAABWswAAVrQAAFa1AABWtwAAVrgAAFb3AABW+QAAVvsAAFb9AABW/wAAVwAAAFcBAABXAgAAVwMAAFcFAABXBwAAVwgAAFcJAABXCwAAVwwAAFdLAABXTQAAV08AAFdRAABXUwAAV1QAAFdVAABXVgAAV1cAAFdZAABXWwAAV1wAAFddAABXXwAAV2AAAFerAABXzgAAV+4AAFgOAABYEAAAWBIAAFgUAABYFgAAWBgAAFgZAABYGgAAWB0AAFgeAABYIAAAWCEAAFgjAABYJQAAWCYAAFgnAABYKgAAWCsAAFgwAABYPQAAWEIAAFhEAABYRgAAWEsAAFhOAABYUQAAWFMAAFh4AABYnAAAWMMAAFjnAABY6gAAWOwAAFjuAABY8AAAWPIAAFj0AABY9QAAWPgAAFkFAABZFgAAWRgAAFkaAABZHAAAWR4AAFkgAABZIgAAWSQAAFkmAABZNwAAWToAAFk9AABZQAAAWUMAAFlGAABZSQAAWUwAAFlPAABZUQAAWZAAAFmSAABZlAAAWZYAAFmZAABZmgAAWZsAAFmcAABZnQAAWZ8AAFmhAABZogAAWaMAAFmlAABZpgAAWeUAAFnnAABZ6QAAWesAAFnuAABZ7wAAWfAAAFnxAABZ8gAAWfQAAFn2AABZ9wAAWfgAAFn6AABZ+wAAWjoAAFo8AABaPwAAWkEAAFpEAABaRQAAWkYAAFpHAABaSAAAWkoAAFpMAABaTQAAWk4AAFpQAABaUQAAWl4AAFpfAABaYAAAWmIAAFqhAABaowAAWqUAAFqnAABaqgAAWqsAAFqsAABarQAAWq4AAFqwAABasgAAWrMAAFq0AABatgAAWrcAAFr2AABa+AAAWvoAAFr8AABa/wAAWwAAAFsBAABbAgAAWwMAAFsFAABbBwAAWwgAAFsJAABbCwAAWwwAAFtLAABbTQAAW08AAFtRAABbVAAAW1UAAFtWAABbVwAAW1gAAFtaAABbXAAAW10AAFteAABbYAAAW2EAAFugAABbogAAW6QAAFumAABbqQAAW6oAAFurAABbrAAAW60AAFuvAABbsQAAW7IAAFuzAABbtQAAW7YAAFv1AABb9wAAW/kAAFv7AABb/gAAW/8AAFwAAABcAQAAXAIAAFwEAABcBgAAXAcAAFwIAABcCgAAXAsAAFwwAABcVAAAXHsAAFyfAABcogAAXKQAAFymAABcqAAAXKoAAFysAABcrQAAXLAAAFy9AABczAAAXM4AAFzQAABc0gAAXNQAAFzWAABc2AAAXNoAAFzpAABc7AAAXO8AAFzyAABc9QAAXPgAAFz7AABc/gAAXQAAAF0/AABdQQAAXUMAAF1FAABdSAAAXUkAAF1KAABdSwAAXUwAAF1OAABdUAAAXVEAAF1SAABdVAAAXVUAAF2UAABdlgAAXZgAAF2aAABdnQAAXZ4AAF2fAABdoAAAXaEAAF2jAABdpQAAXaYAAF2nAABdqQAAXaoAAF3pAABd6wAAXe0AAF3vAABd8gAAXfMAAF30AABd9QAAXfYAAF34AABd+gAAXfsAAF38AABd/gAAXf8AAF4+AABeQAAAXkMAAF5FAABeSAAAXkkAAF5KAABeSwAAXkwAAF5OAABeUAAAXlEAAF5SAABeVAAAXlUAAF5YAABelwAAXpkAAF6bAABenQAAXqAAAF6hAABeogAAXqMAAF6kAABepgAAXqgAAF6pAABeqgAAXqwAAF6tAABe7AAAXu4AAF7xAABe8wAAXvYAAF73AABe+AAAXvkAAF76AABe/AAAXv4AAF7/AABfAAAAXwIAAF8DAABfKgAAX2kAAF9rAABfbQAAX28AAF9yAABfcwAAX3QAAF91AABfdgAAX3gAAF96AABfewAAX3wAAF9+AABffwAAX8oAAF/tAABgDQAAYC0AAGAvAABgMQAAYDMAAGA1AABgNwAAYDgAAGA5AABgPAAAYD0AAGA/AABgQAAAYEIAAGBEAABgRQAAYEYAAGBJAABgSgAAYE8AAGBcAABgYQAAYGMAAGBlAABgagAAYG0AAGBwAABgcgAAYJcAAGC7AABg4gAAYQYAAGEJAABhCwAAYQ0AAGEPAABhEQAAYRMAAGEUAABhFwAAYSQAAGE1AABhNwAAYTkAAGE7AABhPQAAYT8AAGFBAABhQwAAYUUAAGFWAABhWQAAYVwAAGFfAABhYgAAYWUAAGFoAABhawAAYW4AAGFwAABhrwAAYbEAAGGzAABhtQAAYbgAAGG5AABhugAAYbsAAGG8AABhvgAAYcAAAGHBAABhwgAAYcQAAGHFAABiBAAAYgYAAGIIAABiCgAAYg0AAGIOAABiDwAAYhAAAGIRAABiEwAAYhUAAGIWAABiFwAAYhkAAGIaAABiWQAAYlsAAGJeAABiYAAAYmMAAGJkAABiZQAAYmYAAGJnAABiaQAAYmsAAGJsAABibQAAYm8AAGJwAABifQAAYn4AAGJ/AABigQAAYsAAAGLCAABixAAAYsYAAGLJAABiygAAYssAAGLMAABizQAAYs8AAGLRAABi0gAAYtMAAGLVAABi1gAAYxUAAGMXAABjGQAAYxsAAGMeAABjHwAAYyAAAGMhAABjIgAAYyQAAGMmAABjJwAAYygAAGMqAABjKwAAY2oAAGNsAABjbgAAY3AAAGNzAABjdAAAY3UAAGN2AABjdwAAY3kAAGN7AABjfAAAY30AAGN/AABjgAAAY78AAGPBAABjwwAAY8UAAGPIAABjyQAAY8oAAGPLAABjzAAAY84AAGPQAABj0QAAY9IAAGPUAABj1QAAZBQAAGQWAABkGAAAZBoAAGQdAABkHgAAZB8AAGQgAABkIQAAZCMAAGQlAABkJgAAZCcAAGQpAABkKgAAZE8AAGRzAABkmgAAZL4AAGTBAABkwwAAZMUAAGTHAABkyQAAZMsAAGTMAABkzwAAZNwAAGT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fAABwIQAAcCMAAHAlAABwJgAAcCcAAHAqAABwKwAAcC0AAHAuAABwMAAAcDIAAHAzAABwNAAAcDcAAHA4AABwPQAAcEoAAHBPAABwUQAAcFMAAHBYAABwWwAAcF4AAHBgAABwhQAAcKkAAHDQAABw9AAAcPcAAHD5AABw+wAAcP0AAHD/AABxAQAAcQIAAHEFAABxEgAAcSMAAHElAABxJwAAcSkAAHErAABxLQAAcS8AAHExAABxMwAAcUQAAHFHAABxSgAAcU0AAHFQAABxUwAAcVYAAHFZAABxXAAAcV4AAHGdAABxnwAAcaEAAHGjAABxpgAAcacAAHGoAABxqQAAcaoAAHGsAABxrgAAca8AAHGwAABxsgAAcbMAAHHyAABx9AAAcfYAAHH4AABx+wAAcfwAAHH9AABx/gAAcf8AAHIBAAByAwAAcgQAAHIFAAByBwAAcggAAHJHAABySQAAckwAAHJOAAByUQAAclIAAHJTAAByVAAAclUAAHJXAAByWQAAcloAAHJbAAByXQAAcl4AAHJrAABybAAAcm0AAHJvAAByrgAAcrAAAHKyAABytAAAcrcAAHK4AAByuQAAcroAAHK7AAByvQAAcr8AAHLAAABywQAAcsMAAHLEAABzAwAAcwUAAHMHAABzCQAAcwwAAHMNAABzDgAAcw8AAHMQAABzEgAAcxQAAHMVAABzFgAAcxgAAHMZAABzWAAAc1oAAHNcAABzXgAAc2EAAHNiAABzYwAAc2QAAHNlAABzZwAAc2kAAHNqAABzawAAc20AAHNuAABzrQAAc68AAHOxAABzswAAc7YAAHO3AABzuAAAc7kAAHO6AABzvAAAc74AAHO/AABzwAAAc8IAAHPDAAB0AgAAdAQAAHQGAAB0CAAAdAsAAHQMAAB0DQAAdA4AAHQPAAB0EQAAdBMAAHQUAAB0FQAAdBcAAHQYAAB0PQAAdGEAAHSIAAB0rAAAdK8AAHSxAAB0swAAdLUAAHS3AAB0uQAAdLoAAHS9AAB0ygAAdNkAAHTbAAB03QAAdN8AAHThAAB04wAAdOUAAHTnAAB09gAAdPkAAHT8AAB0/wAAdQIAAHUFAAB1CAAAdQsAAHUNAAB1TAAAdU4AAHVQAAB1UgAAdVUAAHVWAAB1VwAAdVgAAHVZAAB1WwAAdV0AAHVeAAB1XwAAdWEAAHV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6AACGPAAAhj8AAIZAAACGQQAAhkIAAIZDAACGRQAAhkcAAIZIAACGSQAAhksAAIZMAACGiwAAho0AAIaPAACGkQAAhpQAAIaVAACGlgAAhpcAAIaYAACGmgAAhpwAAIadAACGngAAhqAAAIahAACG4AAAhuIAAIbkAACG5gAAhukAAIbqAACG6wAAhuwAAIbtAACG7wAAhvEAAIbyAACG8wAAhvUAAIb2AACHNQAAhzcAAIc5AACHOwAAhz4AAIc/AACHQAAAh0EAAIdCAACHRAAAh0YAAIdHAACHSAAAh0oAAIdLAACHlgAAh7kAAIfZAACH+QAAh/sAAIf9AACH/wAAiAEAAIgDAACIBAAAiAUAAIgIAACICQAAiAsAAIgMAACIDgAAiBAAAIgRAACIEgAAiBUAAIgWAACIHwAAiCwAAIgxAACIMwAAiDUAAIg6AACIPQAAiEAAAIhCAACIZwAAiIsAAIiyAACI1gAAiNkAAIjbAACI3QAAiN8AAIjhAACI4wAAiOQAAIjnAACI9AAAiQUAAIkHAACJCQAAiQsAAIkNAACJDwAAiREAAIkTAACJFQAAiSYAAIkpAACJLAAAiS8AAIkyAACJNQAAiTgAAIk7AACJPgAAiUAAAIl/AACJgQAAiYMAAImFAACJiAAAiYkAAImKAACJiwAAiYwAAImOAACJkAAAiZEAAImSAACJlAAAiZUAAInUAACJ1gAAidgAAInaAACJ3QAAid4AAInfAACJ4AAAieEAAInjAACJ5QAAieYAAInnAACJ6QAAieoAAIopAACKKwAAii4AAIowAACKMwAAijQAAIo1AACKNgAAijcAAIo5AACKOwAAijwAAIo9AACKPwAAikAAAIpNAACKTgAAik8AAIpRAACKkAAAipIAAIqUAACKlgAAipkAAIqaAACKmwAAipwAAIqdAACKnwAAiqEAAIqiAACKowAAiqUAAIqmAACK5QAAiucAAIrpAACK6wAAiu4AAIrvAACK8AAAivEAAIryAACK9AAAivYAAIr3AACK+AAAivoAAIr7AACLOgAAizwAAIs+AACLQAAAi0MAAItEAACLRQAAi0YAAItHAACLSQAAi0sAAItMAACLTQAAi08AAItQAACLjwAAi5EAAIuTAACLlQAAi5gAAIuZAACLmgAAi5sAAIucAACLngAAi6AAAIu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iAACYZAAAmGcAAJhpAACYbAAAmG0AAJhuAACYbwAAmHAAAJhyAACYdAAAmHUAAJh2AACYeAAAmHkAAJiCAACYgwAAmIUAAJjEAACYxgAAmMgAAJjKAACYzQAAmM4AAJjPAACY0AAAmNEAAJjTAACY1QAAmNYAAJjXAACY2QAAmNoAAJkZAACZGwAAmR4AAJkgAACZIwAAmSQAAJklAACZJgAAmScAAJkpAACZKwAAmSwAAJktAACZLwAAmTAAAJk5AACZOgAAmTwAAJl7AACZfQAAmX8AAJmBAACZhAAAmYUAAJmGAACZhwAAmYgAAJmKAACZjAAAmY0AAJmOAACZkAAAmZEAAJnQAACZ0gAAmdUAAJnXAACZ2gAAmdsAAJncAACZ3QAAmd4AAJngAACZ4gAAmeMAAJnkAACZ5gAAmecAAJnwAACZ8QAAmfMAAJoyAACaNAAAmjYAAJo4AACaOwAAmjwAAJo9AACaPgAAmj8AAJpBAACaQwAAmkQAAJpFAACaRwAAmkgAAJqHAACaiQAAmowAAJqOAACakQAAmpIAAJqTAACalAAAmpUAAJqXAACamQAAmpoAAJqbAACanQAAmp4AAJqrAACarAAAmq0AAJqvAACa7gAAmvAAAJryAACa9AAAmvcAAJr4AACa+QAAmvoAAJr7AACa/QAAmv8AAJsAAACbAQAAmwMAAJsEAACbQwAAm0UAAJtHAACbSQAAm0wAAJtNAACbTgAAm08AAJtQAACbUgAAm1QAAJtVAACbVgAAm1gAAJtZAACbZgAAm4kAAJuMAACbjgAAm5EAAJuUAACblwAAm5oAAJudAACboAAAm6MAAJumAACbqAAAm6sAAJuuAACbsQAAm7MAAJu2AACb2QAAm9wAAJvfAACb4gAAm+UAAJvoAACb6wAAm+4AAJvxAACb9AAAm/cAAJv6AACb/QAAnAAAAJwDAACcBgAAnAkAAJwLAACcDgAAnBUAAJwjAACcKQAAnC8AAJw3AACcQgAAnEwAAJxVAACcXwAAnHQAAJyIAACckAAAnNsAAJz+AACdHgAAnT4AAJ1AAACdQgAAnUQAAJ1GAACdSQAAnUoAAJ1LAACdTgAAnU8AAJ1RAACdUgAAnVQAAJ1XAACdWAAAnVkAAJ1cAACdXQAAnWIAAJ1vAACddAAAnXYAAJ14AACdfQAAnYAAAJ2DAACdhQAAnaoAAJ3OAACd9QAAnhkAAJ4cAACeHgAAniAAAJ4iAACeJAAAniYAAJ4nAACeKgAAnjcAAJ5IAACeSgAAnkwAAJ5OAACeUAAAnlIAAJ5UAACeVgAAnlgAAJ5pAACebAAAnm8AAJ5yAACedQAAnngAAJ57AACefgAAnoEAAJ6DAACewgAAnsQAAJ7GAACeyAAAnssAAJ7MAACezQAAns4AAJ7PAACe0QAAntMAAJ7UAACe1QAAntcAAJ7YAACfFwAAnxkAAJ8bAACfHQAAnyAAAJ8hAACfIgAAnyMAAJ8kAACfJgAAnygAAJ8pAACfKgAAnywAAJ8tAACfbAAAn24AAJ9xAACfcwAAn3YAAJ93AACfeAAAn3kAAJ96AACffAAAn34AAJ9/AACfgAAAn4IAAJ+DAACfkAAAn5EAAJ+SAACflAAAn9MAAJ/VAACf1wAAn9kAAJ/cAACf3QAAn94AAJ/fAACf4AAAn+IAAJ/kAACf5QAAn+YAAJ/oAACf6QAAoCgAAKAqAACgLAAAoC4AAKAxAACgMgAAoDMAAKA0AACgNQAAoDcAAKA5AACgOgAAoDsAAKA9AACgPgAAoH0AAKB/AACggQAAoIMAAKCGAACghwAAoIgAAKCJAACgigAAoIwAAKCOAACgjwAAoJAAAKCSAACgkwAAoNIAAKDUAACg1gAAoNgAAKDbAACg3AAAoN0AAKDeAACg3wAAoOEAAKDjAACg5AAAoOUAAKDnAACg6AAAoScAAKEpAAChKwAAoS0AAKEwAAChMQAAoTIAAKEzAAChNAAAoTYAAKE4AAChOQAAoToAAKE8AAChPQAAoWIAAKGGAAChrQAAodEAAKHUAACh1gAAodgAAKHaAACh3AAAod4AAKHfAACh4gAAoe8AAKH+AACiAAAAogIAAKIEAACiBgAAoggAAKIKAACiDAAAohsAAKIeAACiIQAAoiQAAKInAACiKgAAoi0AAKIwAACiMgAAonEAAKJzAACidQAAoncAAKJ6AACiewAAonwAAKJ9AACifgAAooAAAKKCAACigwAAooQAAKKGAACihwAAosYAAKLIAACiygAAoswAAKLPAACi0AAAotEAAKLSAACi0wAAotUAAKLXAACi2AAAotkAAKLbAACi3AAAoxsAAKMdAACjHwAAoyEAAKMkAACjJQAAoyYAAKMnAACjKAAAoyoAAKMsAACjLQAAoy4AAKMwAACjMQAAo3AAAKNyAACjdAAAo3YAAKN5AACjegAAo3sAAKN8AACjfQAAo38AAKOBAACjggAAo4MAAKOFAACjhgAAo8UAAKPHAACjyQAAo8sAAKPOAACjzwAAo9AAAKPRAACj0gAAo9QAAKPWAACj1wAAo9gAAKPaAACj2wAApBoAAKQcAACkHgAApCAAAKQjAACkJAAApCUAAKQmAACkJwAApCkAAKQrAACkLAAApC0AAKQvAACkMAAApG8AAKRxAACkcwAApHUAAKR4AACkeQAApHoAAKR7AACkfAAApH4AAKSAAACkgQAApIIAAKSEAACkhQAApNAAAKTzAAClEwAApTMAAKU1AAClNwAApTkAAKU7AAClPgAApT8AAKVAAAClQwAApUQAAKVGAAClRwAApUkAAKVLAAClTAAApU0AAKVQAAClUQAApVYAAKVjAAClaAAApWoAAKVsAAClcQAApXQAAKV3AACleQAApZ4AAKXCAACl6QAApg0AAKYQAACmEgAAphQAAKYWAACmGAAAphoAAKYbAACmHgAApisAAKY8AACmPgAApkAAAKZCAACmRAAApkYAAKZIAACmSgAApkwAAKZdAACmYAAApmMAAKZmAACmaQAApmwAAKZvAACmcgAApnUAAKZ3AACmtgAAprgAAKa6AACmvAAApr8AAKbAAACmwQAApsIAAKbDAACmxQAApscAAKbIAACmyQAApssAAKbMAACnCwAApw0AAKcPAACnEQAApxQAAKcVAACnFgAApxcAAKcYAACnGgAApxwAAKcdAACnHgAApyAAAKchAACnYAAAp2IAAKdlAACnZwAAp2oAAKdrAACnbAAAp20AAKduAACncAAAp3IAAKdzAACndAAAp3YAAKd3AACnhAAAp4UAAKeGAACniAAAp8cAAKfJAACnywAAp80AAKfQAACn0QAAp9IAAKfTAACn1AAAp9YAAKfYAACn2QAAp9oAAKfcAACn3QAAqBwAAKgeAACoIAAAqCIAAKglAACoJgAAqCcAAKgoAACoKQAAqCsAAKgtAACoLgAAqC8AAKgxAACoMgAAqHEAAKhzAACodQAAqHcAAKh6AACoewAAqHwAAKh9AACofgAAqIAAAKiCAACogwAAqIQAAKiGAACohwAAqMYAAKjIAACoygAAqMwAAKjPAACo0AAAqNEAAKjSAACo0wAAqNUAAKjXAACo2AAAqNkAAKjbAACo3AAAqRsAAKkdAACpHwAAqSEAAKkkAACpJQAAqSYAAKknAACpKAAAqSoAAKksAACpLQAAqS4AAKkwAACpMQAAqVYAAKl6AACpoQAAqcUAAKnIAACpygAAqcwAAKnOAACp0AAAqdIAAKnTAACp1gAAqeMAAKnyAACp9AAAqfYAAKn4AACp+gAAqfwAAKn+AACqAAAAqg8AAKoSAACqFQAAqhgAAKobAACqHgAAqiEAAKokAACqJgAAqmUAAKpnAACqaQAAqmsAAKpuAACqbwAAqnAAAKpxAACqcgAAqnQAAKp2AACqdwAAqngAAKp6AACqewAAqroAAKq8AACqvgAAqsAAAKrDAACqxAAAqsUAAKrGAACqxwAAqskAAKrLAACqzAAAqs0AAKrPAACq0AAAqw8AAKsRAACrEwAAqxUAAKsYAACrGQAAqxoAAKsbAACrHAAAqx4AAKsgAACrIQAAqyIAAKskAACrJQAAq2QAAKtmAACraAAAq2oAAKttAACrbgAAq28AAKtwAACrcQAAq3MAAKt1AACrdgAAq3cAAKt5AACregAAq7kAAKu7AACrvQAAq78AAKvCAACrwwAAq8QAAKvFAACrxgAAq8gAAKvKAACrywAAq8wAAKvOAACrzwAArA4AAKwQAACsEgAArBQAAKwXAACsGAAArBkAAKwaAACsGwAArB0AAKwfAACsIAAArCEAAKwjAACsJAAArGMAAKxlAACsZwAArGkAAKxsAACsbQAArG4AAKxvAACscAAArHIAAKx0AACsdQAArHYAAKx4AACseQAArMQAAKznAACtBwAArScAAK0pAACtKwAArS0AAK0vAACtMgAArTMAAK00AACtNwAArTgAAK06AACtOwAArT0AAK1AAACtQQAArUIAAK1FAACtRgAArUsAAK1YAACtXQAArV8AAK1hAACtZgAArWkAAK1sAACtbgAArZMAAK23AACt3gAArgIAAK4FAACuBwAArgkAAK4LAACuDQAArg8AAK4QAACuEwAAriAAAK4xAACuMwAArjUAAK43AACuOQAArjsAAK49AACuPwAArkEAAK5SAACuVQAArlgAAK5bAACuXgAArmEAAK5kAACuZwAArmoAAK5sAACuqwAArq0AAK6vAACusQAArrQAAK61AACutgAArrcAAK64AACuugAArrwAAK69AACuvgAArsAAAK7BAACvAAAArwIAAK8EAACvBgAArwkAAK8KAACvCwAArwwAAK8NAACvDwAArxEAAK8SAACvEwAArxUAAK8WAACvVQAAr1cAAK9aAACvXAAAr18AAK9gAACvYQAAr2IAAK9jAACvZQAAr2cAAK9oAACvaQAAr2sAAK9sAACveQAAr3oAAK97AACvfQAAr7wAAK++AACvwAAAr8IAAK/FAACvxgAAr8cAAK/IAACvyQAAr8sAAK/NAACvzgAAr88AAK/RAACv0gAAsBEAALATAACwFQAAsBcAALAaAACwGwAAsBwAALAdAACwHgAAsCAAALAiAACwIwAAsCQAALAmAACwJwAAsGYAALBoAACwagAAsGwAALBvAACwcAAAsHEAALByAACwcwAAsHUAALB3AACweAAAsHkAALB7AACwfAAAsLsAALC9AACwvwAAsMEAALDEAACwxQAAsMYAALDHAACwyAAAsMoAALDMAACwzQAAsM4AALDQAACw0QAAsRAAALESAACxFAAAsRYAALEZAACxGgAAsRsAALEcAACxHQAAsR8AALEhAACxIgAAsSMAALElAACxJgAAsUsAALFvAACxlgAAsboAALG9AACxvwAAscEAALHDAACxxQAAsccAALHIAACxywAAsdgAALHnAACx6QAAsesAALHtAACx7wAAsfEAALHzAACx9QAAsgQAALIHAACyCgAAsg0AALIQAACyEwAAshYAALIZAACyGwAAsloAALJcAACyXgAAsmAAALJjAACyZAAAsmUAALJmAACyZwAAsmkAALJrAACybAAAsm0AALJvAACycAAAsq8AALKxAACyswAAsrUAALK4AACyuQAAsroAALK7AACyvAAAsr4AALLAAACywQAAssIAALLEAACyxQAAswQAALMGAACzCAAAswoAALMNAACzDgAAsw8AALMQAACzEQAAsxMAALMVAACzFgAAsxcAALMZAACzGgAAs1kAALNbAACzXQAAs18AALNiAACzYwAAs2QAALNlAACzZgAAs2gAALNqAACzawAAs2wAALNuAACzbwAAs64AALOwAACzsgAAs7QAALO3AACzuAAAs7kAALO6AACzuwAAs70AALO/AACzwAAAs8EAALPDAACzxAAAtAMAALQFAAC0BwAAtAkAALQMAAC0DQAAtA4AALQPAAC0EAAAtBIAALQUAAC0FQAAtBYAALQYAAC0GQAAtFgAALRaAAC0XAAAtF4AALRhAAC0YgAAtGMAALRkAAC0ZQAAtGcAALRpAAC0agAAtGsAALRtAAC0bgAAtLkAALTcAAC0/AAAtRwAALUeAAC1IAAAtSIAALUkAAC1JwAAtSgAALUpAAC1LAAAtS0AALUvAAC1MAAAtTIAALU1AAC1NgAAtTcAALU6AAC1OwAAtUAAALVNAAC1UgAAtVQAALVWAAC1WwAAtV4AALVhAAC1YwAAtYgAALWsAAC10wAAtfcAALX6AAC1/AAAtf4AALYAAAC2AgAAtgQAALYFAAC2CAAAthUAALYmAAC2KAAAtioAALYsAAC2LgAAtjAAALYyAAC2NAAAtjYAALZHAAC2SgAAtk0AALZQAAC2UwAAtlYAALZZAAC2XAAAtl8AALZhAAC2oAAAtqIAALakAAC2pgAAtqkAALaqAAC2qwAAtqwAALatAAC2rwAAtrEAALayAAC2swAAtrUAALa2AAC29QAAtvcAALb5AAC2+wAAtv4AALb/AAC3AAAAtwEAALcCAAC3BAAAtwYAALcHAAC3CAAAtwoAALcLAAC3SgAAt0wAALdPAAC3UQAAt1QAALdVAAC3VgAAt1cAALdYAAC3WgAAt1wAALddAAC3XgAAt2AAALdhAAC3bgAAt28AALdwAAC3cgAAt7EAALezAAC3tQAAt7cAALe6AAC3uwAAt7wAALe9AAC3vgAAt8AAALfCAAC3wwAAt8QAALfGAAC3xwAAuAYAALgIAAC4CgAAuAwAALgPAAC4EAAAuBEAALgSAAC4EwAAuBUAALgXAAC4GAAAuBkAALgbAAC4HAAAuFsAALhdAAC4XwAAuGEAALhkAAC4ZQAAuGYAALhnAAC4aAAAuGoAALhsAAC4bQAAuG4AALhwAAC4cQAAuLAAALiyAAC4tAAAuLYAALi5AAC4ugAAuLsAALi8AAC4vQAAuL8AALjBAAC4wgAAuMMAALjFAAC4xgAAuQUAALkHAAC5CQAAuQsAALkOAAC5DwAAuRAAALkRAAC5EgAAuRQAALkWAAC5FwAAuRgAALkaAAC5GwAAuUAAALlkAAC5iwAAua8AALmyAAC5tAAAubYAALm4AAC5ugAAubwAALm9AAC5wAAAuc0AALncAAC53gAAueAAALniAAC55AAAueYAALnoAAC56gAAufkAALn8AAC5/wAAugIAALoFAAC6CAAAugsAALoOAAC6EAAAuk8AALpRAAC6VAAAulYAALpZAAC6WgAAulsAALpcAAC6XQAAul8AALphAAC6YgAAumMAALplAAC6ZgAAumoAALqpAAC6qwAAuq0AALqvAAC6sgAAurMAALq0AAC6tQAAurYAALq4AAC6ugAAursAALq8AAC6vgAAur8AALr+AAC7AAAAuwIAALsEAAC7BwAAuwgAALsJAAC7CgAAuwsAALsNAAC7DwAAuxAAALsRAAC7EwAAuxQAALtTAAC7VQAAu1gAALtaAAC7XQAAu14AALtfAAC7YAAAu2EAALtjAAC7ZQAAu2YAALtnAAC7aQAAu2oAALttAAC7rAAAu64AALuwAAC7sgAAu7UAALu2AAC7twAAu7gAALu5AAC7uwAAu70AALu+AAC7vwAAu8EAALvCAAC8AQAAvAMAALwFAAC8BwAAvAoAALwLAAC8DAAAvA0AALwOAAC8EAAAvBIAALwTAAC8FAAAvBYAALwXAAC8VgAAvFgAALxaAAC8XAAAvF8AALxgAAC8YQAAvGIAALxjAAC8ZQAAvGcAALxoAAC8aQAAvGsAALxsAAC8twAAvNoAALz6AAC9GgAAvRwAAL0eAAC9IAAAvSIAAL0lAAC9JgAAvScAAL0qAAC9KwAAvS0AAL0uAAC9MAAAvTMAAL00AAC9NQAAvTgAAL05AAC9PgAAvUsAAL1QAAC9UgAAvVQAAL1ZAAC9XAAAvV8AAL1hAAC9hgAAvaoAAL3RAAC99QAAvfgAAL36AAC9/AAAvf4AAL4AAAC+AgAAvgMAAL4GAAC+EwAAviQAAL4mAAC+KAAAvioAAL4sAAC+LgAAvjAAAL4yAAC+NAAAvkUAAL5IAAC+SwAAvk4AAL5RAAC+VAAAvlcAAL5aAAC+XQAAvl8AAL6eAAC+oAAAvqIAAL6kAAC+pwAAvqgAAL6pAAC+qgAAvqsAAL6tAAC+rwAAvrAAAL6xAAC+swAAvrQAAL7zAAC+9QAAvvcAAL75AAC+/AAAvv0AAL7+AAC+/wAAvwAAAL8CAAC/BAAAvwUAAL8GAAC/CAAAvwkAAL9IAAC/SgAAv00AAL9PAAC/UgAAv1MAAL9UAAC/VQAAv1YAAL9YAAC/WgAAv1sAAL9cAAC/XgAAv18AAL9sAAC/bQAAv24AAL9wAAC/rwAAv7EAAL+zAAC/tQAAv7gAAL+5AAC/ugAAv7sAAL+8AAC/vgAAv8AAAL/BAAC/wgAAv8QAAL/FAADABAAAwAYAAMAIAADACgAAwA0AAMAOAADADwAAwBAAAMARAADAEwAAwBUAAMAWAADAFwAAwBkAAMAaAADAWQAAwFsAAMBdAADAXwAAwGIAAMBjAADAZAAAwGUAAMBmAADAaAAAwGoAAMBrAADAbAAAwG4AAMBvAADArgAAwLAAAMCyAADAtAAAwLcAAMC4AADAuQAAwLoAAMC7AADAvQAAwL8AAMDAAADAwQAAwMMAAMDEAADBAwAAwQUAAMEHAADBCQAAwQwAAMENAADBDgAAwQ8AAMEQAADBEgAAwRQAAMEVAADBFgAAwRgAAMEZAADBPgAAwWIAAMGJAADBrQAAwbAAAMGyAADBtAAAwbYAAMG4AADBugAAwbsAAMG+AADBywAAwdoAAMHcAADB3gAAweAAAMHiAADB5AAAweYAAMHoAADB9wAAwfoAAMH9AADCAAAAwgMAAMIGAADCCQAAwgwAAMIOAADCTQAAwk8AAMJRAADCUwAAwlYAAMJXAADCWAAAwlkAAMJaAADCXAAAwl4AAMJfAADCYAAAwmIAAMJjAADCogAAwqQAAMKmAADCqAAAwqsAAMKsAADCrQAAwq4AAMKvAADCsQAAwrMAAMK0AADCtQAAwrcAAMK4AADC9wAAwvkAAML7AADC/QAAwwAAAMMBAADDAgAAwwMAAMMEAADDBgAAwwgAAMMJAADDCgAAwwwAAMMNAADDTAAAw04AAMNQAADDUgAAw1UAAMNWAADDVwAAw1gAAMNZAADDWwAAw10AAMNeAADDXwAAw2EAAMNiAADDoQAAw6MAAMOlAADDpwAAw6oAAMOrAADDrAAAw60AAMOuAADDsAAAw7IAAMOzAADDtAAAw7YAAMO3AADD9gAAw/gAAMP6AADD/AAAw/8AAMQAAADEAQAAxAIAAMQDAADEBQAAxAcAAMQIAADECQAAxAsAAMQMAADESwAAxE0AAMRPAADEUQAAxFQAAMRVAADEVgAAxFcAAMRYAADEWgAAxFwAAMRdAADEXgAAxGAAAMRhAADErAAAxM8AAMTvAADFDwAAxREAAMUTAADFFQAAxRcAAMUaAADFGwAAxRwAAMUfAADFIAAAxSIAAMUjAADFJQAAxSgAAMUpAADFKgAAxS0AAMUuAADFMwAAxUAAAMVFAADFRwAAxUkAAMVOAADFUQAAxVQAAMVWAADFewAAxZ8AAMXGAADF6gAAxe0AAMXvAADF8QAAxfMAAMX1AADF9wAAxfgAAMX7AADGCAAAxhkAAMYbAADGHQAAxh8AAMYhAADGIwAAxiUAAMYnAADGKQAAxjoAAMY9AADGQAAAxkMAAMZGAADGSQAAxkwAAMZPAADGUgAAxlQAAMaTAADGlQAAxpcAAMaZAADGnAAAxp0AAMaeAADGnwAAxqAAAMaiAADGpAAAxqUAAMamAADGqAAAxqkAAMboAADG6gAAxuwAAMbuAADG8QAAxvIAAMbzAADG9AAAxvUAAMb3AADG+QAAxvoAAMb7AADG/QAAxv4AAMc9AADHPwAAx0IAAMdEAADHRwAAx0gAAMdJAADHSgAAx0sAAMdNAADHTwAAx1AAAMdRAADHUwAAx1QAAMdhAADHYgAAx2MAAMdlAADHpAAAx6YAAMeoAADHqgAAx60AAMeuAADHrwAAx7AAAMexAADHswAAx7UAAMe2AADHtwAAx7kAAMe6AADH+QAAx/sAAMf9AADH/wAAyAIAAMgDAADIBAAAyAUAAMgGAADICAAAyAoAAMgLAADIDAAAyA4AAMgPAADITgAAyFAAAMhSAADIVAAAyFcAAMhYAADIWQAAyFoAAMhbAADIXQAAyF8AAMhgAADIYQAAyGMAAMhkAADIowAAyKUAAMinAADIqQAAyKwAAMitAADIrgAAyK8AAMiwAADIsgAAyLQAAMi1AADItgAAyLgAAMi5AADI+AAAyPoAAMj8AADI/gAAyQEAAMkCAADJAwAAyQQAAMkFAADJBwAAyQkAAMkKAADJCwAAyQ0AAMkOAADJMwAAyVcAAMl+AADJogAAyaUAAMmnAADJqQAAyasAAMmtAADJrwAAybAAAMmzAADJwAAAyc8AAMnRAADJ0wAAydUAAMnXAADJ2QAAydsAAMndAADJ7AAAye8AAMnyAADJ9QAAyfgAAMn7AADJ/gAAygEAAMoDAADKQgAAykQAAMpHAADKSQAAykwAAMpNAADKTgAAyk8AAMpQAADKUgAAylQAAMpVAADKVgAAylgAAMpZAADKmAAAypoAAMqcAADKngAAyqEAAMqiAADKowAAyqQAAMqlAADKpwAAyqkAAMqqAADKqwAAyq0AAMquAADK7QAAyu8AAMrxAADK8wAAyvYAAMr3AADK+AAAyvkAAMr6AADK/AAAyv4AAMr/AADLAAAAywIAAMsDAADLQgAAy0QAAMtHAADLSQAAy0wAAMtNAADLTgAAy08AAMtQAADLUgAAy1QAAMtVAADLVgAAy1gAAMtZAADLmAAAy5oAAMucAADLngAAy6EAAMuiAADLowAAy6QAAMulAADLpwAAy6kAAMuqAADLqwAAy60AAMuuAADL7QAAy+8AAMvxAADL8wAAy/YAAMv3AADL+AAAy/kAAMv6AADL/AAAy/4AAMv/AADMAAAAzAIAAMwDAADMQgAAzEQAAMxGAADMSAAAzEsAAMxMAADMTQAAzE4AAMxPAADMUQAAzFMAAMxUAADMVQAAzFcAAMxYAADMowAAzMYAAMzmAADNBgAAzQgAAM0KAADNDAAAzQ4AAM0RAADNEgAAzRMAAM0WAADNFwAAzRkAAM0aAADNHAAAzR8AAM0gAADNIQAAzSQAAM0lAADNKgAAzTcAAM08AADNPgAAzUAAAM1FAADNSAAAzUsAAM1NAADNcgAAzZYAAM29AADN4QAAzeQAAM3mAADN6AAAzeoAAM3sAADN7gAAze8AAM3yAADN/wAAzhAAAM4SAADOFAAAzhYAAM4YAADOGgAAzhwAAM4eAADOIAAAzjEAAM40AADONwAAzjoAAM49AADOQAAAzkMAAM5GAADOSQAAzksAAM6KAADOjAAAzo4AAM6QAADOkwAAzpQAAM6VAADOlgAAzpcAAM6ZAADOmwAAzpwAAM6dAADOnwAAzqAAAM7fAADO4QAAzuMAAM7lAADO6AAAzukAAM7qAADO6wAAzuwAAM7uAADO8AAAzvEAAM7yAADO9AAAzvUAAM80AADPNgAAzzkAAM87AADPPgAAzz8AAM9AAADPQQAAz0IAAM9EAADPRgAAz0cAAM9IAADPSgAAz0sAAM9YAADPWQAAz1oAAM9cAADPmwAAz50AAM+fAADPoQAAz6QAAM+lAADPpgAAz6cAAM+oAADPqgAAz6wAAM+tAADPrgAAz7AAAM+xAADP8AAAz/IAAM/0AADP9gAAz/kAAM/6AADP+wAAz/wAAM/9AADP/wAA0AEAANACAADQAwAA0AUAANAGAADQRQAA0EcAANBJAADQSwAA0E4AANBPAADQUAAA0FEAANBSAADQVAAA0FYAANBXAADQWAAA0FoAANBbAADQmgAA0JwAANCeAADQoAAA0KMAANCkAADQpQAA0KYAANCnAADQqQAA0KsAANCsAADQrQAA0K8AANCwAADQ7wAA0PEAANDzAADQ9QAA0PgAAND5AADQ+gAA0PsAAND8AADQ/gAA0QAAANEBAADRAgAA0QQAANEFAADRKgAA0U4AANF1AADRmQAA0ZwAANGeAADRoAAA0aIAANGkAADRpgAA0acAANGqAADRtwAA0cYAANHIAADRygAA0cwAANHOAADR0AAA0dIAANHUAADR4wAA0eYAANHpAADR7AAA0e8AANHyAADR9QAA0fgAANH6AADSOQAA0jsAANI9AADSPwAA0kIAANJDAADSRAAA0kUAANJGAADSSAAA0koAANJLAADSTAAA0k4AANJPAADSjgAA0pAAANKSAADSlAAA0pcAANKYAADSmQAA0poAANKbAADSnQAA0p8AANKgAADSoQAA0qMAANKkAADS4wAA0uUAANLnAADS6QAA0uwAANLtAADS7gAA0u8AANLwAADS8gAA0vQAANL1AADS9gAA0vgAANL5AADTOAAA0zoAANM8AADTPgAA00EAANNCAADTQwAA00QAANNFAADTRwAA00kAANNKAADTSwAA000AANNOAADTjQAA048AANORAADTkwAA05YAANOXAADTmAAA05kAANOaAADTnAAA054AANOfAADToAAA06IAANOjAADT4gAA0+QAANPmAADT6AAA0+sAANPsAADT7QAA0+4AANPvAADT8QAA0/MAANP0AADT9QAA0/cAANP4AADUNwAA1DkAANQ7AADUPQAA1EAAANRBAADUQgAA1EMAANREAADURgAA1EgAANRJAADUSgAA1EwAANRNAADUmAAA1LsAANTbAADU+wAA1P0AANT/AADVAQAA1QMAANUGAADVBwAA1QgAANULAADVDAAA1Q4AANUPAADVEQAA1RQAANUVAADVFgAA1RkAANUaAADVHwAA1SwAANUxAADVMwAA1TUAANU6AADVPQAA1UAAANVCAADVZwAA1YsAANWyAADV1gAA1dkAANXbAADV3QAA1d8AANXhAADV4wAA1eQAANXnAADV9AAA1gUAANYHAADWCQAA1gsAANYNAADWDwAA1hEAANYTAADWFQAA1iYAANYpAADWLAAA1i8AANYyAADWNQAA1jgAANY7AADWPgAA1kAAANZ/AADWgQAA1oMAANaFAADWiAAA1okAANaKAADWiwAA1owAANaOAADWkAAA1pEAANaSAADWlAAA1pUAANbUAADW1gAA1tgAANbaAADW3QAA1t4AANbfAADW4AAA1uEAANbjAADW5QAA1uYAANbnAADW6QAA1uoAANcpAADXKwAA1y4AANcwAADXMwAA1zQAANc1AADXNgAA1zcAANc5AADXOwAA1zwAANc9AADXPwAA10AAANdNAADXTgAA108AANdRAADXkAAA15IAANeUAADXlgAA15kAANeaAADXmwAA15wAANedAADXnwAA16EAANeiAADXowAA16UAANemAADX5QAA1+cAANfpAADX6wAA1+4AANfvAADX8AAA1/EAANfyAADX9AAA1/YAANf3AADX+AAA1/oAANf7AADYOgAA2DwAANg+AADYQAAA2EMAANhEAADYRQAA2EYAANhHAADYSQAA2EsAANhMAADYTQAA2E8AANhQAADYjwAA2JEAANiTAADYlQAA2JgAANiZAADYmgAA2JsAANicAADYngAA2KAAANihAADYogAA2KQAANilAADY5AAA2OYAANjoAADY6gAA2O0AANjuAADY7wAA2PAAANjxAADY8wAA2PUAANj2AADY9wAA2PkAANj6AADZHwAA2UMAANlqAADZjgAA2ZEAANmTAADZlQAA2ZcAANmZAADZmwAA2ZwAANmfAADZrAAA2bsAANm9AADZvwAA2cEAANnDAADZxQAA2ccAANnJAADZ2AAA2dsAANneAADZ4QAA2eQAANnnAADZ6gAA2e0AANnvAADaLgAA2jAAANoyAADaNAAA2jcAANo4AADaOQAA2joAANo7AADaPQAA2j8AANpAAADaQQAA2kMAANpEAADagwAA2oUAANqHAADaiQAA2owAANqNAADajgAA2o8AANqQAADakgAA2pQAANqVAADalgAA2pgAANqZAADa2AAA2toAANrcAADa3gAA2uEAANriAADa4wAA2uQAANrlAADa5wAA2ukAANrqAADa6wAA2u0AANruAADbLQAA2y8AANsxAADbMwAA2zYAANs3AADbOAAA2zkAANs6AADbPAAA2z4AANs/AADbQAAA20IAANtDAADbggAA24QAANuGAADbiAAA24sAANuMAADbjQAA244AANuPAADbkQAA25MAANuUAADblQAA25cAANuYAADb1wAA29kAANvbAADb3QAA2+AAANvhAADb4gAA2+MAANvkAADb5gAA2+gAANvpAADb6gAA2+wAANvtAADcLAAA3C4AANwwAADcMgAA3DUAANw2AADcNwAA3DgAANw5AADcOwAA3D0AANw+AADcPwAA3EEAANxCAADcjQAA3LAAANzQAADc8AAA3PIAANz0AADc9gAA3PgAANz7AADc/AAA3P0AAN0AAADdAQAA3QMAAN0EAADdBgAA3QkAAN0KAADdCwAA3Q4AAN0PAADdFAAA3SEAAN0mAADdKAAA3SoAAN0vAADdMgAA3TUAAN03AADdXAAA3YAAAN2nAADdywAA3c4AAN3QAADd0gAA3dQAAN3WAADd2AAA3dkAAN3cAADd6QAA3foAAN38AADd/gAA3gAAAN4CAADeBAAA3gYAAN4IAADeCgAA3hsAAN4eAADeIQAA3iQAAN4nAADeKgAA3i0AAN4wAADeMwAA3jUAAN50AADedgAA3ngAAN56AADefQAA3n4AAN5/AADegAAA3oEAAN6DAADehQAA3oYAAN6HAADeiQAA3ooAAN7JAADeywAA3s0AAN7PAADe0gAA3tMAAN7UAADe1QAA3tYAAN7YAADe2gAA3tsAAN7cAADe3gAA3t8AAN8eAADfIAAA3yMAAN8lAADfKAAA3ykAAN8qAADfKwAA3ywAAN8uAADfMAAA3zEAAN8yAADfNAAA3zUAAN9CAADfQwAA30QAAN9GAADfhQAA34cAAN+JAADfiwAA344AAN+PAADfkAAA35EAAN+SAADflAAA35YAAN+XAADfmAAA35oAAN+bAADf2gAA39wAAN/eAADf4AAA3+MAAN/kAADf5QAA3+YAAN/nAADf6QAA3+sAAN/sAADf7QAA3+8AAN/wAADgLwAA4DEAAOAzAADgNQAA4DgAAOA5AADgOgAA4DsAAOA8AADgPgAA4EAAAOBBAADgQgAA4EQAAOBFAADghAAA4IYAAOCIAADgigAA4I0AAOCOAADgjwAA4JAAAOCRAADgkwAA4JUAAOCWAADglwAA4JkAAOCaAADg2QAA4NsAAODdAADg3wAA4OIAAODjAADg5AAA4OUAAODmAADg6AAA4OoAAODrAADg7AAA4O4AAODvAADhFAAA4TgAAOFfAADhgwAA4YYAAOGIAADhigAA4YwAAOGOAADhkAAA4ZEAAOGUAADhoQAA4bAAAOGyAADhtAAA4bYAAOG4AADhugAA4bwAAOG+AADhzQAA4dAAAOHTAADh1gAA4dkAAOHcAADh3wAA4eIAAOHkAADiIwAA4iUAAOInAADiKQAA4iwAAOItAADiLgAA4i8AAOIwAADiMgAA4jQAAOI1AADiNgAA4jgAAOI5AADieAAA4noAAOJ8AADifgAA4oEAAOKCAADigwAA4oQAAOKFAADihwAA4okAAOKKAADiiwAA4o0AAOKOAADizQAA4s8AAOLRAADi0wAA4tYAAOLXAADi2AAA4tkAAOLaAADi3AAA4t4AAOLfAADi4AAA4uIAAOLjAADjIgAA4yQAAOMmAADjKAAA4ysAAOMsAADjLQAA4y4AAOMvAADjMQAA4zMAAOM0AADjNQAA4zcAAOM4AADjdwAA43kAAON7AADjfQAA44AAAOOBAADjggAA44MAAOOEAADjhgAA44gAAOOJAADjigAA44wAAOONAADjzAAA484AAOPQAADj0gAA49UAAOPWAADj1wAA49gAAOPZAADj2wAA490AAOPeAADj3wAA4+EAAOPiAADkIQAA5CMAAOQlAADkJwAA5CoAAOQrAADkLAAA5C0AAOQuAADkMAAA5DIAAOQzAADkNAAA5DYAAOQ3AADkggAA5KUAAOTFAADk5QAA5OcAAOTpAADk6wAA5O0AAOTwAADk8QAA5PIAAOT1AADk9gAA5PgAAOT5AADk+wAA5P4AAOT/AADlAAAA5QMAAOUEAADlCQAA5RYAAOUbAADlHQAA5R8AAOUkAADlJwAA5SoAAOUsAADlUQAA5XUAAOWcAADlwAAA5cMAAOXFAADlxwAA5ckAAOXLAADlzQAA5c4AAOXRAADl3gAA5e8AAOXxAADl8wAA5fUAAOX3AADl+QAA5fsAAOX9AADl/wAA5hAAAOYTAADmFgAA5hkAAOYcAADmHwAA5iIAAOYlAADmKAAA5ioAAOZpAADmawAA5m0AAOZvAADmcgAA5nMAAOZ0AADmdQAA5nYAAOZ4AADmegAA5nsAAOZ8AADmfgAA5n8AAOa+AADmwAAA5sIAAObEAADmxwAA5sgAAObJAADmygAA5ssAAObNAADmzwAA5tAAAObRAADm0wAA5tQAAOcTAADnFQAA5xgAAOcaAADnHQAA5x4AAOcfAADnIAAA5yEAAOcjAADnJQAA5yYAAOcnAADnKQAA5yoAAOc3AADnOAAA5zkAAOc7AADnegAA53wAAOd+AADngAAA54MAAOeEAADnhQAA54YAAOeHAADniQAA54sAAOeMAADnjQAA548AAOeQAADnzwAA59EAAOfTAADn1QAA59gAAOfZAADn2gAA59sAAOfcAADn3gAA5+AAAOfhAADn4gAA5+QAAOflAADoJAAA6CYAAOgoAADoKgAA6C0AAOguAADoLwAA6DAAAOgxAADoMwAA6DUAAOg2AADoNwAA6DkAAOg6AADoeQAA6HsAAOh9AADofwAA6IIAAOiDAADohAAA6IUAAOiGAADoiAAA6IoAAOiLAADojAAA6I4AAOiPAADozgAA6NAAAOjSAADo1AAA6NcAAOjYAADo2QAA6NoAAOjbAADo3QAA6N8AAOjgAADo4QAA6OMAAOjkAADpCQAA6S0AAOlUAADpeAAA6XsAAOl9AADpfwAA6YEAAOmDAADphQAA6YYAAOmJAADplgAA6aUAAOmnAADpqQAA6asAAOmtAADprwAA6bEAAOmzAADpwgAA6cUAAOnIAADpywAA6c4AAOnRAADp1AAA6dcAAOnZAADqGAAA6hoAAOocAADqHgAA6iEAAOoiAADqIwAA6iQAAOolAADqJwAA6ikAAOoqAADqKwAA6i0AAOouAADqbQAA6m8AAOpxAADqcwAA6nYAAOp3AADqeAAA6nkAAOp6AADqfAAA6n4AAOp/AADqgAAA6oIAAOqDAADqwgAA6sQAAOrGAADqyAAA6ssAAOrMAADqzQAA6s4AAOrPAADq0QAA6tMAAOrUAADq1QAA6tcAAOrYAADrFwAA6xkAAOscAADrHgAA6yEAAOsiAADrIwAA6yQAAOslAADrJwAA6ykAAOsqAADrKwAA6y0AAOsuAADrbQAA628AAOtxAADrcwAA63YAAOt3AADreAAA63kAAOt6AADrfAAA634AAOt/AADrgAAA64IAAOuDAADrwgAA68QAAOvGAADryAAA68sAAOvMAADrzQAA684AAOvPAADr0QAA69MAAOvUAADr1QAA69cAAOvYAADsFwAA7BkAAOwbAADsHQAA7CAAAOwhAADsIgAA7CMAAOwkAADsJgAA7CgAAOwpAADsKgAA7CwAAOwtAADseAAA7JsAAOy7AADs2wAA7N0AAOzfAADs4QAA7OMAAOzmAADs5wAA7OgAAOzrAADs7AAA7O4AAOzvAADs8QAA7PMAAOz0AADs9QAA7PgAAOz5AADs/gAA7QsAAO0QAADtEgAA7RQAAO0ZAADtHAAA7R8AAO0hAADtRgAA7WoAAO2RAADttQAA7bgAAO26AADtvAAA7b4AAO3AAADtwgAA7cMAAO3GAADt0wAA7eQAAO3mAADt6AAA7eoAAO3sAADt7gAA7fAAAO3yAADt9AAA7gUAAO4IAADuCwAA7g4AAO4RAADuFAAA7hcAAO4aAADuHQAA7h8AAO5eAADuYAAA7mIAAO5kAADuZwAA7mgAAO5pAADuagAA7msAAO5tAADubwAA7nAAAO5xAADucwAA7nQAAO6zAADutQAA7rcAAO65AADuvAAA7r0AAO6+AADuvwAA7sAAAO7CAADuxAAA7sUAAO7GAADuyAAA7skAAO8IAADvCgAA7w0AAO8PAADvEgAA7xMAAO8UAADvFQAA7xYAAO8YAADvGgAA7xsAAO8cAADvHgAA7x8AAO8sAADvLQAA7y4AAO8wAADvbwAA73EAAO9zAADvdQAA73gAAO95AADvegAA73sAAO98AADvfgAA74AAAO+BAADvggAA74QAAO+FAADvxAAA78YAAO/IAADvygAA780AAO/OAADvzwAA79AAAO/RAADv0wAA79UAAO/WAADv1wAA79kAAO/aAADwGQAA8BsAAPAdAADwHwAA8CIAAPAjAADwJAAA8CUAAPAmAADwKAAA8CoAAPArAADwLAAA8C4AAPAvAADwbgAA8HAAAPByAADwdAAA8HcAAPB4AADweQAA8HoAAPB7AADwfQAA8H8AAPCAAADwgQAA8IMAAPCEAADwwwAA8MUAAPDHAADwyQAA8MwAAPDNAADwzgAA8M8AAPDQAADw0gAA8NQAAPDVAADw1gAA8NgAAPDZAADw/gAA8SIAAPFJAADxbQAA8XAAAPF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nAAENjgABDbIAAQ21AAENtwABDbkAAQ27AAENvQABDb8AAQ3AAAENwwABDdAAAQ3hAAEN4wABDeUAAQ3nAAEN6QABDesAAQ3tAAEN7wABDfEAAQ4CAAEOBQABDggAAQ4LAAEODgABDhEAAQ4UAAEOFwABDhoAAQ4cAAEOWwABDl0AAQ5fAAEOYQABDmQAAQ5lAAEOZgABDmcAAQ5oAAEOagABDmwAAQ5tAAEObgABDnAAAQ5xAAEOsAABDrIAAQ60AAEOtgABDrkAAQ66AAEOuwABDrwAAQ69AAEOvwABDsEAAQ7CAAEOwwABDsUAAQ7GAAEPBQABDwcAAQ8KAAEPDAABDw8AAQ8QAAEPEQABDxIAAQ8TAAEPFQABDxcAAQ8YAAEPGQABDxsAAQ8cAAEPKQABDyoAAQ8rAAEPLQABD2wAAQ9uAAEPcAABD3IAAQ91AAEPdgABD3cAAQ94AAEPeQABD3sAAQ99AAEPfgABD38AAQ+BAAEPggABD8EAAQ/DAAEPxQABD8cAAQ/KAAEPywABD8wAAQ/NAAEPzgABD9AAAQ/SAAEP0wABD9QAAQ/WAAEP1wABEBYAARAYAAEQGgABEBwAARAfAAEQIAABECEAARAiAAEQIwABECUAARAnAAEQKAABECkAARArAAEQLAABEGsAARBtAAEQbwABEHEAARB0AAEQdQABEHYAARB3AAEQeAABEHoAARB8AAEQfQABEH4AARCAAAEQgQABEMAAARDCAAEQxAABEMYAARDJAAEQygABEMsAARDMAAEQzQABEM8AARDRAAEQ0gABENMAARDVAAEQ1gABEPsAAREfAAERRgABEWoAARFtAAERbwABEXEAARFzAAERdQABEXcAARF4AAERewABEYgAARGXAAERmQABEZsAARGdAAERnwABEaEAARGjAAERpQABEbQAARG3AAERugABEb0AARHAAAERwwABEcYAARHJAAERywABEgoAARIMAAESDgABEhAAARITAAESFAABEhUAARIWAAESFwABEhkAARIbAAESHAABEh0AARIfAAESIAABEl8AARJhAAESYwABEmUAARJoAAESaQABEmoAARJrAAESbAABEm4AARJwAAEScQABEnIAARJ0AAESdQABErQAARK2AAESuAABEroAARK9AAESvgABEr8AARLAAAESwQABEsMAARLFAAESxgABEscAARLJAAESygABEwkAARMLAAETDQABEw8AARMSAAETEwABExQAARMVAAETFgABExgAARMaAAETGwABExwAARMeAAETHwABE14AARNgAAETYgABE2QAARNnAAETaAABE2kAARNqAAETawABE20AARNvAAETcAABE3EAARNzAAETdAABE7MAARO1AAETtwABE7kAARO8AAETvQABE74AARO/AAETwAABE8IAARPEAAETxQABE8YAARPIAAETyQABFAgAARQKAAEUDAABFA4AARQRAAEUEgABFBMAARQUAAEUFQABFBcAARQZAAEUGgABFBsAARQdAAEUHgABFGkAARSMAAEUrAABFMwAARTOAAEU0AABFNIAARTUAAEU1wABFNgAARTZAAEU3AABFN0AARTfAAEU4AABFOIAARTlAAEU5gABFOcAARTqAAEU6wABFPAAART9AAEVAgABFQQAARUGAAEVCwABFQ4AARURAAEVEwABFTgAARVcAAEVgwABFacAARWqAAEVrAABFa4AARWwAAEVsgABFbQAARW1AAEVuAABFcUAARXWAAEV2AABFdoAARXcAAEV3gABFeAAARXiAAEV5AABFeYAARX3AAEV+gABFf0AARYAAAEWAwABFgYAARYJAAEWDAABFg8AARYRAAEWUAABFlIAARZUAAEWVgABFlkAARZaAAEWWwABFlwAARZdAAEWXwABFmEAARZiAAEWYwABFmUAARZmAAEWpQABFqcAARapAAEWqwABFq4AARavAAEWsAABFrEAARayAAEWtAABFrYAARa3AAEWuAABFroAARa7AAEW+gABFvwAARb/AAEXAQABFwQAARcFAAEXBgABFwcAARcIAAEXCgABFwwAARcNAAEXDgABFxAAARcRAAEXHgABFx8AARcgAAEXIgABF2EAARdjAAEXZQABF2cAARdqAAEXawABF2wAARdtAAEXbgABF3AAARdyAAEXcwABF3QAARd2AAEXdwABF7YAARe4AAEXugABF7wAARe/AAEXwAABF8EAARfCAAEXwwABF8UAARfHAAEXyAABF8kAARfLAAEXzAABGAsAARgNAAEYDwABGBEAARgUAAEYFQABGBYAARgXAAEYGAABGBoAARgcAAEYHQABGB4AARggAAEYIQABGGAAARhiAAEYZAABGGYAARhpAAEYagABGGsAARhsAAEYbQABGG8AARhxAAEYcgABGHMAARh1AAEYdgABGLUAARi3AAEYuQABGLsAARi+AAEYvwABGMAAARjBAAEYwgABGMQAARjGAAEYxwABGMgAARjKAAEYywABGPAAARkUAAEZOwABGV8AARliAAEZZAABGWYAARloAAEZagABGWwAARltAAEZcAABGX0AARmMAAEZjgABGZAAARmSAAEZlAABGZYAARmYAAEZmgABGakAARmsAAEZrwABGbIAARm1AAEZuAABGbsAARm+AAEZwAABGf8AARoBAAEaAwABGgUAARoIAAEaCQABGgoAARoLAAEaDAABGg4AARoQAAEaEQABGhIAARoUAAEaFQABGlQAARpWAAEaWAABGloAARpdAAEaXgABGl8AARpgAAEaYQABGmMAARplAAEaZgABGmcAARppAAEaagABGqkAARqrAAEarQABGq8AARqyAAEaswABGrQAARq1AAEatgABGrgAARq6AAEauwABGrwAARq+AAEavwABGv4AARsAAAEbAgABGwQAARsHAAEbCAABGwkAARsKAAEbCwABGw0AARsPAAEbEAABGxEAARsTAAEbFAABG1MAARtVAAEbVwABG1kAARtcAAEbXQABG14AARtfAAEbYAABG2IAARtkAAEbZQABG2YAARtoAAEbaQABG6gAARuqAAEbrAABG64AARuxAAEbsgABG7MAARu0AAEbtQABG7cAARu5AAEbugABG7sAARu9AAEbvgABG/0AARv/AAEcAQABHAMAARwGAAEcBwABHAgAARwJAAEcCgABHAwAARwOAAEcDwABHBAAARwSAAEcEwABHB4AARwnAAEcKAABHCoAARwzAAEcPgABHE0AARxYAAEcZgABHHsAARyPAAEcpgABHLgAARz3AAEc+QABHPsAARz9AAEdAAABHQEAAR0CAAEdAwABHQQAAR0GAAEdCAABHQkAAR0KAAEdDAABHQ0AAR1MAAEdTgABHVAAAR1SAAEdVQABHVYAAR1XAAEdWAABHVkAAR1bAAEdXQABHV4AAR1fAAEdYQABHWIAAR2hAAEdowABHaUAAR2nAAEdqgABHasAAR2sAAEdrQABHa4AAR2wAAEdsgABHbMAAR20AAEdtgABHbcAAR32AAEd+AABHfoAAR38AAEd/wABHgAAAR4BAAEeAgABHgMAAR4FAAEeBwABHggAAR4JAAEeCwABHgwAAR5LAAEeTQABHk8AAR5RAAEeVAABHlUAAR5WAAEeVwABHlgAAR5aAAEeXAABHl0AAR5eAAEeYAABHmEAAR6sAAEezwABHu8AAR8PAAEfEQABHxMAAR8VAAEfFwABHxkAAR8aAAEfGwABHx4AAR8fAAEfIQABHyIAAR8kAAEfJgABHycAAR8oAAEfKwABHywAAR8xAAEfPgABH0MAAR9FAAEfRwABH0wAAR9PAAEfUgABH1QAAR95AAEfnQABH8QAAR/oAAEf6wABH+0AAR/vAAEf8QABH/MAAR/1AAEf9gABH/kAASAGAAEgFwABIBkAASAbAAEgHQABIB8AASAhAAEgIwABICUAASAnAAEgOAABIDsAASA+AAEgQQABIEQAASBHAAEgSgABIE0AASBQAAEgUgABIJEAASCTAAEglQABIJcAASCaAAEgmwABIJwAASCdAAEgngABIKAAASCiAAEgowABIKQAASCmAAEgpwABIOYAASDoAAEg6gABIOwAASDvAAEg8AABIPEAASDyAAEg8wABIPUAASD3AAEg+AABIPkAASD7AAEg/AABITsAASE9AAEhQAABIUIAASFFAAEhRgABIUcAASFIAAEhSQABIUsAASFNAAEhTgABIU8AASFRAAEhUgABIV8AASFgAAEhYQABIWMAASGiAAEhpAABIaYAASGoAAEhqwABIawAASGtAAEhrgABIa8AASGxAAEhswABIbQAASG1AAEhtwABIbgAASH3AAEh+QABIfsAASH9AAEiAAABIgEAASICAAEiAwABIgQAASIGAAEiCAABIgkAASIKAAEiDAABIg0AASJMAAEiTgABIlAAASJSAAEiVQABIlYAASJXAAEiWAABIlkAASJbAAEiXQABIl4AASJfAAEiYQABImIAASKhAAEiowABIqUAASKnAAEiqgABIqsAASKsAAEirQABIq4AASKwAAEisgABIrMAASK0AAEitgABIrcAASL2AAEi+AABIvoAASL8AAEi/wABIwAAASMBAAEjAgABIwMAASMFAAEjBwABIwgAASMJAAEjCwABIwwAASMxAAEjVQABI3wAASOgAAEjowABI6UAASOnAAEjqQABI6sAASOtAAEjrgABI7EAASO+AAEjzQABI88AASPRAAEj0wABI9UAASPXAAEj2QABI9sAASPqAAEj7QABI/AAASPzAAEj9gABI/kAASP8AAEj/wABJAEAASRAAAEkQgABJEQAASRGAAEkSQABJEoAASRLAAEkTAABJE0AASRPAAEkUQABJFIAASRTAAEkVQABJFYAASSVAAEklwABJJkAASSbAAEkngABJJ8AASSgAAEkoQABJKIAASSkAAEkpgABJKcAASSoAAEkqgABJKsAASTqAAEk7AABJO4AASTwAAEk8wABJPQAAST1AAEk9gABJPcAAST5AAEk+wABJPwAAST9AAEk/wABJQAAASU/AAElQQABJUMAASVFAAElSAABJUkAASVKAAElSwABJUwAASVOAAElUAABJVEAASVSAAElVAABJVUAASWUAAEllgABJZgAASWaAAElnQABJZ4AASWfAAEloAABJaEAASWjAAElpQABJaYAASWnAAElqQABJaoAASXpAAEl6wABJe0AASXvAAEl8gABJfMAASX0AAEl9QABJfYAASX4AAEl+gABJfsAASX8AAEl/gABJf8AASY+AAEmQAABJkIAASZEAAEmRwABJkgAASZJAAEmSgABJksAASZNAAEmTwABJlAAASZRAAEmUwABJlQAASafAAEmwgABJuIAAScCAAEnBAABJwYAAScIAAEnCgABJwwAAScNAAEnDgABJxEAAScSAAEnFAABJxUAAScXAAEnGQABJxoAAScbAAEnHgABJx8AASckAAEnMQABJzYAASc4AAEnOgABJz8AASdCAAEnRQABJ0cAASdsAAEnkAABJ7cAASfbAAEn3gABJ+AAASfiAAEn5AABJ+YAASfoAAEn6QABJ+wAASf5AAEoCgABKAwAASgOAAEoEAABKBIAASgUAAEoFgABKBgAASgaAAEoKwABKC4AASgxAAEoNAABKDcAASg6AAEoPQABKEAAAShDAAEoRQABKIQAASiGAAEoiAABKIoAASiNAAEojgABKI8AASiQAAEokQABKJMAASiVAAEolgABKJcAASiZAAEomgABKNkAASjbAAEo3QABKN8AASjiAAEo4wABKOQAASjlAAEo5gABKOgAASjqAAEo6wABKOwAASjuAAEo7wABKS4AASkwAAEpMwABKTUAASk4AAEpOQABKToAASk7AAEpPAABKT4AASlAAAEpQQABKUIAASlEAAEpRQABKVIAASlTAAEpVAABKVYAASmVAAEplwABKZkAASmbAAEpngABKZ8AASmgAAEpoQABKaIAASmkAAEppgABKacAASmoAAEpqgABKasAASnqAAEp7AABKe4AASnwAAEp8wABKfQAASn1AAEp9gABKfcAASn5AAEp+wABKfwAASn9AAEp/wABKgAAASo/AAEqQQABKkMAASpFAAEqSAABKkkAASpKAAEqSwABKkwAASpOAAEqUAABKlEAASpSAAEqVAABKlUAASqUAAEqlgABKpgAASqaAAEqnQABKp4AASqfAAEqoAABKqEAASqjAAEqpQABKqYAASqnAAEqqQABKqoAASrpAAEq6wABKu0AASrvAAEq8gABKvMAASr0AAEq9QABKvYAASr4AAEq+gABKvsAASr8AAEq/gABKv8AASskAAErSAABK28AASuTAAErlgABK5gAASuaAAErnAABK54AASugAAEroQABK6QAASuxAAErwAABK8IAASvEAAErxgABK8gAASvKAAErzAABK84AASvdAAEr4AABK+MAASvmAAEr6QABK+wAASvvAAEr8gABK/QAASwzAAEsNQABLDcAASw5AAEsPAABLD0AASw+AAEsPwABLEAAASxCAAEsRAABLEUAASxGAAEsSAABLEkAASyIAAEsigABLIwAASyOAAEskQABLJIAASyTAAEslAABLJUAASyXAAEsmQABLJoAASybAAEsnQABLJ4AASzdAAEs3wABLOEAASzjAAEs5gABLOcAASzoAAEs6QABLOoAASzsAAEs7gABLO8AASzwAAEs8gABLPMAAS0yAAEtNAABLTcAAS05AAEtPAABLT0AAS0+AAEtPwABLUAAAS1CAAEtRAABLUUAAS1GAAEtSAABLUkAAS2IAAEtigABLYwAAS2OAAEtkQABLZIAAS2TAAEtlAABLZUAAS2XAAEtmQABLZoAAS2bAAEtnQABLZ4AAS3dAAEt3wABLeEAAS3jAAEt5gABLecAAS3oAAEt6QABLeoAAS3sAAEt7gABLe8AAS3wAAEt8gABLfMAAS4yAAEuNAABLjYAAS44AAEuOwABLjwAAS49AAEuPgABLj8AAS5BAAEuQwABLkQAAS5FAAEuRwABLkgAAS6TAAEutgABLtYAAS72AAEu+AABLvoAAS78AAEu/gABLwAAAS8BAAEvAgABLwUAAS8GAAEvCAABLwkAAS8LAAEvDQABLw4AAS8PAAEvEgABLxMAAS8YAAEvJQABLyoAAS8sAAEvLgABLzMAAS82AAEvOQABLzsAAS9gAAEvhAABL6sAAS/PAAEv0gABL9QAAS/WAAEv2AABL9oAAS/cAAEv3QABL+AAAS/tAAEv/gABMAAAATACAAEwBAABMAYAATAIAAEwCgABMAwAATAOAAEwHwABMCIAATAlAAEwKAABMCsAATAuAAEwMQABMDQAATA3AAEwOQABMHgAATB6AAEwfAABMH4AATCBAAEwggABMIMAATCEAAEwhQABMIcAATCJAAEwigABMIsAATCNAAEwjgABMM0AATDPAAEw0QABMNMAATDWAAEw1wABMNgAATDZAAEw2gABMNwAATDeAAEw3wABMOAAATDiAAEw4wABMSIAATEkAAExJwABMSkAATEsAAExLQABMS4AATEvAAExMAABMTIAATE0AAExNQABMTYAATE4AAExOQABMUYAATFHAAExSAABMUoAATGJAAExiwABMY0AATGPAAExkgABMZMAATGUAAExlQABMZYAATGYAAExmgABMZsAATGcAAExngABMZ8AATHeAAEx4AABMeIAATHkAAEx5wABMegAATHpAAEx6gABMesAATHtAAEx7wABMfAAATHxAAEx8wABMfQAATIzAAEyNQABMjcAATI5AAEyPAABMj0AATI+AAEyPwABMkAAATJCAAEyRAABMkUAATJGAAEySAABMkkAATKIAAEyigABMowAATKOAAEykQABMpIAATKTAAEylAABMpUAATKXAAEymQABMpoAATKbAAEynQABMp4AATLdAAEy3wABMuEAATLjAAEy5gABMucAATLoAAEy6QABMuoAATLsAAEy7gABMu8AATLwAAEy8gABMvMAATMYAAEzPAABM2MAATOHAAEzigABM4wAATOOAAEzkAABM5IAATOUAAEzlQABM5gAATOlAAEztAABM7YAATO4AAEzugABM7wAATO+AAEzwAABM8IAATPRAAEz1AABM9cAATPaAAEz3QABM+AAATPjAAEz5gABM+gAATQnAAE0KQABNCwAATQuAAE0MQABNDIAATQzAAE0NAABNDUAATQ3AAE0OQABNDoAATQ7AAE0PQABND4AATR9AAE0fwABNIEAATSDAAE0hgABNIcAATSIAAE0iQABNIoAATSMAAE0jgABNI8AATSQAAE0kgABNJMAATTSAAE01AABNNYAATTYAAE02wABNNwAATTdAAE03gABNN8AATThAAE04wABNOQAATTlAAE05wABNOgAATUnAAE1KQABNSwAATUuAAE1MQABNTIAATUzAAE1NAABNTUAATU3AAE1OQABNToAATU7AAE1PQABNT4AATV9AAE1fwABNYEAATWDAAE1hgABNYcAATWIAAE1iQABNYoAATWMAAE1jgABNY8AATWQAAE1kgABNZMAATXSAAE11AABNdYAATXYAAE12wABNdwAATXdAAE13gABNd8AATXhAAE14wABNeQAATXlAAE15wABNegAATYnAAE2KQABNisAATYtAAE2MAABNjEAATYyAAE2MwABNjQAATY2AAE2OAABNjkAATY6AAE2PAABNj0AATaIAAE2qwABNssAATbrAAE27QABNu8AATbxAAE28wABNvUAATb2AAE29wABNvoAATb7AAE2/QABNv4AATcAAAE3AgABNwMAATcEAAE3BwABNwgAATcNAAE3GgABNx8AATchAAE3IwABNygAATcrAAE3LgABNzAAATdVAAE3eQABN6AAATfEAAE3xwABN8kAATfLAAE3zQABN88AATfRAAE30gABN9UAATfiAAE38wABN/UAATf3AAE3+QABN/sAATf9AAE3/wABOAEAATgDAAE4FAABOBcAATgaAAE4HQABOCAAATgjAAE4JgABOCkAATgsAAE4LgABOG0AAThvAAE4cQABOHMAATh2AAE4dwABOHgAATh5AAE4egABOHwAATh+AAE4fwABOIAAATiCAAE4gwABOMIAATjEAAE4xgABOMgAATjLAAE4zAABOM0AATjOAAE4zwABONEAATjTAAE41AABONUAATjXAAE42AABORcAATkZAAE5HAABOR4AATkhAAE5IgABOSMAATkkAAE5JQABOScAATkpAAE5KgABOSsAATktAAE5LgABOTsAATk8AAE5PQABOT8AATl+AAE5gAABOYIAATmEAAE5hwABOYgAATmJAAE5igABOYsAATmNAAE5jwABOZAAATmRAAE5kwABOZQAATnTAAE51QABOdcAATnZAAE53AABOd0AATneAAE53wABOeAAATniAAE55AABOeUAATnmAAE56AABOekAATooAAE6KgABOiwAATouAAE6MQABOjIAATozAAE6NAABOjUAATo3AAE6OQABOjoAATo7AAE6PQABOj4AATp9AAE6fwABOoEAATqDAAE6hgABOocAATqIAAE6iQABOooAATqMAAE6jgABOo8AATqQAAE6kgABOpMAATrSAAE61AABOtYAATrYAAE62wABOtwAATrdAAE63gABOt8AATrhAAE64wABOuQAATrlAAE65wABOugAATsNAAE7MQABO1gAATt8AAE7fwABO4EAATuDAAE7hQABO4cAATuJAAE7igABO40AATuaAAE7qQABO6sAATutAAE7rwABO7EAATuzAAE7tQABO7cAATvGAAE7yQABO8wAATvPAAE70gABO9UAATvYAAE72wABO90AATwcAAE8HgABPCAAATwiAAE8JQABPCYAATwnAAE8KAABPCkAATwrAAE8LQABPC4AATwvAAE8MQABPDIAATxxAAE8cwABPHUAATx3AAE8egABPHsAATx8AAE8fQABPH4AATyAAAE8ggABPIMAATyEAAE8hgABPIcAATzGAAE8yAABPMoAATzMAAE8zwABPNAAATzRAAE80gABPNMAATzVAAE81wABPNgAATzZAAE82wABPNwAAT0bAAE9HQABPR8AAT0hAAE9JAABPSUAAT0mAAE9JwABPSgAAT0qAAE9LAABPS0AAT0uAAE9MAABPTEAAT1wAAE9cgABPXQAAT12AAE9eQABPXoAAT17AAE9fAABPX0AAT1/AAE9gQABPYIAAT2DAAE9hQABPYYAAT3FAAE9xwABPckAAT3LAAE9zgABPc8AAT3QAAE90QABPdIAAT3UAAE91gABPdcAAT3YAAE92gABPdsAAT4aAAE+HAABPh4AAT4gAAE+IwABPiQAAT4lAAE+JgABPicAAT4pAAE+KwABPiwAAT4tAAE+LwABPjAAAT57AAE+ngABPr4AAT7eAAE+4AABPuIAAT7kAAE+5gABPugAAT7pAAE+6gABPu0AAT7uAAE+8AABPvEAAT7zAAE+9QABPvYAAT73AAE++gABPvsAAT8AAAE/DQABPxIAAT8UAAE/FgABPxsAAT8eAAE/IQABPyMAAT9IAAE/bAABP5MAAT+3AAE/ugABP7wAAT++AAE/wAABP8IAAT/EAAE/xQABP8gAAT/VAAE/5gABP+gAAT/qAAE/7AABP+4AAT/wAAE/8gABP/QAAT/2AAFABwABQAoAAUANAAFAEAABQBMAAUAWAAFAGQABQBwAAUAfAAFAIQABQGAAAUBiAAFAZAABQGYAAUBpAAFAagABQGsAAUBsAAFAbQABQG8AAUBxAAFAcgABQHMAAUB1AAFAdgABQLUAAUC3AAFAuQABQLsAAUC+AAFAvwABQMAAAUDBAAFAwgABQMQAAUDGAAFAxwABQMgAAUDKAAFAywABQQoAAUEMAAFBDwABQREAAUEUAAFBFQABQRYAAUEXAAFBGAABQRoAAUEcAAFBHQABQR4AAUEgAAFBIQABQS4AAUEvAAFBMAABQTIAAUFxAAFBcwABQXUAAUF3AAFBegABQXsAAUF8AAFBfQABQX4AAUGAAAFBggABQYMAAUGEAAFBhgABQYcAAUHGAAFByAABQcoAAUHMAAFBzwABQdAAAUHRAAFB0gABQdMAAUHVAAFB1wABQdgAAUHZAAFB2wABQdwAAUIbAAFCHQABQh8AAUIhAAFCJAABQiUAAUImAAFCJwABQigAAUIqAAFCLAABQi0AAUIuAAFCMAABQjEAAUJwAAFCcgABQnQAAUJ2AAFCeQABQnoAAUJ7AAFCfAABQn0AAUJ/AAFCgQABQoIAAUKDAAFChQABQoYAAULFAAFCxwABQskAAULLAAFCzgABQs8AAULQAAFC0QABQtIAAULUAAFC1gABQtcAAULYAAFC2gABQtsAAUMAAAFDJAABQ0sAAUNvAAFDcgABQ3QAAUN2AAFDeAABQ3oAAUN8AAFDfQABQ4AAAUONAAFDnAABQ54AAUOgAAFDogABQ6QAAUOmAAFDqAABQ6oAAUO5AAFDvAABQ78AAUPCAAFDxQABQ8gAAUPLAAFDzgABQ9AAAUQPAAFEEQABRBMAAUQVAAFEGAABRBkAAUQaAAFEGwABRBwAAUQeAAFEIAABRCEAAUQiAAFEJAABRCUAAURkAAFEZgABRGkAAURrAAFEbgABRG8AAURwAAFEcQABRHIAAUR0AAFEdgABRHcAAUR4AAFEegABRHsAAUR9AAFEvAABRL4AAUTAAAFEwgABRMUAAUTGAAFExwABRMgAAUTJAAFEywABRM0AAUTOAAFEzwABRNEAAUTSAAFFEQABRRMAAUUWAAFFGAABRRsAAUUcAAFFHQABRR4AAUUfAAFFIQABRSMAAUUkAAFFJQABRScAAUUoAAFFawABRY8AAUWzAAFF1gABRf0AAUYdAAFGRAABRmsAAUaLAAFGrwABRtMAAUbVAAFG2AABRtoAAUbcAAFG3gABRuEAAUbkAAFG5gABRugAAUbrAAFG7QABRu8AAUbyAAFG9QABRvYAAUb7AAFHCAABRwsAAUcNAAFHEAABRxMAAUcVAAFHOgABR14AAUeFAAFHqQABR6wAAUeuAAFHsAABR7IAAUe0AAFHtgABR7cAAUe6AAFHxwABR9oAAUfcAAFH3gABR+AAAUfiAAFH5AABR+YAAUfoAAFH6gABR+wAAUf/AAFIAgABSAUAAUgIAAFICwABSA4AAUgRAAFIFAABSBcAAUgaAAFIHAABSFsAAUhdAAFIYAABSGIAAUhlAAFIZgABSGcAAUhoAAFIaQABSGsAAUhtAAFIbgABSG8AAUhxAAFIcgABSHsAAUh8AAFIfgABSL0AAUi/AAFIwQABSMMAAUjGAAFIxwABSMgAAUjJAAFIygABSMwAAUjOAAFIzwABSNAAAUjSAAFI0wABSRIAAUkUAAFJFwABSRkAAUkcAAFJHQABSR4AAUkfAAFJIAABSSIAAUkkAAFJJQABSSYAAUkoAAFJKQABSTIAAUk1AAFJOAABSToAAUlDAAFJRgABSUgAAUlKAAFJiQABSYsAAUmNAAFJjwABSZIAAUmTAAFJlAABSZUAAUmWAAFJmAABSZoAAUmbAAFJnAABSZ4AAUmfAAFJ3gABSeAAAUnjAAFJ5QABSegAAUnpAAFJ6gABSesAAUnsAAFJ7gABSfAAAUnxAAFJ8gABSfQAAUn1AAFJ/gABSf8AAUoBAAFKQAABSkIAAUpEAAFKRgABSkkAAUpKAAFKSwABSkwAAUpNAAFKTwABSlEAAUpSAAFKUwABSlUAAUpWAAFKlQABSpcAAUqaAAFKnAABSp8AAUqgAAFKoQABSqIAAUqjAAFKpQABSqcAAUqoAAFKqQABSqsAAUqsAAFKuQABSroAAUq7AAFKvQABSvwAAUr+AAFLAAABSwIAAUsFAAFLBgABSwcAAUsIAAFLCQABSwsAAUsNAAFLDgABSw8AAUsRAAFLEgABS1EAAUtTAAFLVgABS1gAAUtbAAFLXAABS10AAUteAAFLXwABS2EAAUtjAAFLZAABS2UAAUtnAAFLaAABS3QAAUuBAAFLjAABS44AAUuQAAFLkgABS5UAAUuYAAFLowABS6YAAUupAAFLrAABS68AAUuyAAFLtAABS78AAUvMAAFMFwABTDoAAUxaAAFMegABTHwAAUx+AAFMgAABTIIAAUyFAAFMhgABTIcAAUyKAAFMiwABTI0AAUyOAAFMkAABTJIAAUyTAAFMlAABTJcAAUyYAAFMnQABTKoAAUyvAAFMsQABTLMAAUy4AAFMuwABTL4AAUzAAAFM5QABTQkAAU0wAAFNVAABTVcAAU1ZAAFNWwABTV0AAU1fAAFNYQABTWIAAU1lAAFNcgABTYMAAU2FAAFNhwABTYkAAU2LAAFNjQABTY8AAU2RAAFNkwABTaQAAU2nAAFNqgABTa0AAU2wAAFNswABTbYAAU25AAFNvAABTb4AAU39AAFN/wABTgEAAU4DAAFOBgABTgcAAU4IAAFOCQABTgoAAU4MAAFODgABTg8AAU4QAAFOEgABThMAAU5SAAFOVAABTlYAAU5YAAFOWwABTlwAAU5dAAFOXgABTl8AAU5hAAFOYwABTmQAAU5lAAFOZwABTmgAAU6nAAFOqQABTqwAAU6uAAFOsQABTrIAAU6zAAFOtAABTrUAAU63AAFOuQABTroAAU67AAFOvQABTr4AAU7LAAFOzAABTs0AAU7PAAFPDgABTxAAAU8SAAFPFAABTxcAAU8YAAFPGQABTxoAAU8bAAFPHQABTx8AAU8gAAFPIQABTyMAAU8kAAFPYwABT2UAAU9nAAFPaQABT2wAAU9tAAFPbgABT28AAU9wAAFPcgABT3QAAU91AAFPdgABT3gAAU95AAFPuAABT7oAAU+8AAFPvgABT8EAAU/CAAFPwwABT8QAAU/FAAFPxwABT8kAAU/KAAFPywABT80AAU/OAAFQDQABUA8AAVARAAFQEwABUBYAAVAXAAFQGAABUBkAAVAaAAFQHAABUB4AAVAfAAFQIAABUCIAAVAjAAFQYgABUGQAAVBmAAFQaAABUGsAAVBsAAFQbQABUG4AAVBvAAFQcQABUHMAAVB0AAFQdQABUHcAAVB4AAFQnQABUMEAAVDoAAFRDAABUQ8AAVERAAFREwABURUAAVEXAAFRGQABURoAAVEdAAFRKgABUTkAAVE7AAFRPQABUT8AAVFBAAFRQwABUUUAAVFHAAFRVgABUVkAAVFcAAFRXwABUWIAAVFlAAFRaAABUWsAAVFtAAFRrAABUa4AAVGwAAFRsgABUbUAAVG2AAFRtwABUbgAAVG5AAFRuwABUb0AAVG+AAFRvwABUcEAAVHCAAFSAQABUgMAAVIFAAFSBwABUgoAAVILAAFSDAABUg0AAVIOAAFSEAABUhIAAVITAAFSFAABUhYAAVIXAAFSVgABUlgAAVJaAAFSXAABUl8AAVJgAAFSYQABUmIAAVJjAAFSZQABUmcAAVJoAAFSaQABUmsAAVJsAAFSqwABUq0AAVKvAAFSsQABUrQAAVK1AAFStgABUrcAAVK4AAFSugABUrwAAVK9AAFSvgABUsAAAVLBAAFTAAABUwIAAVMEAAFTBgABUwkAAVMKAAFTCwABUwwAAVMNAAFTDwABUxEAAVMSAAFTEwABUxUAAVMWAAFTVQABU1cAAVNZAAFTWwABU14AAVNfAAFTYAABU2EAAVNiAAFTZAABU2YAAVNnAAFTaAABU2oAAVNrAAFTqgABU6wAAVOuAAFTsAABU7MAAVO0AAFTtQABU7YAAVO3AAFTuQABU7sAAVO8AAFTvQABU78AAVPAAAFUCwABVC4AAVROAAFUbgABVHAAAVRyAAFUdAABVHYAAVR5AAFUegABVHsAAVR+AAFUfwABVIEAAVSCAAFUhAABVIYAAVSHAAFUiAABVIsAAVSMAAFUlQABVKIAAVSnAAFUqQABVKsAAVSwAAFUswABVLYAAVS4AAFU3QABVQEAAVUoAAFVTAABVU8AAVVRAAFVUwABVVUAAVVXAAFVWQABVVoAAVVdAAFVagABVXsAAVV9AAFVfwABVYEAAVWDAAFVhQABVYcAAVWJAAFViwABVZwAAVWfAAFVogABVaUAAVWoAAFVqwABVa4AAVWxAAFVtAABVbYAAVX1AAFV9wABVfkAAVX7AAFV/gABVf8AAVYAAAFWAQABVgIAAVYEAAFWBgABVgcAAVYIAAFWCgABVgsAAVZKAAFWTAABVk4AAVZQAAFWUwABVlQAAVZVAAFWVgABVlcAAVZZAAFWWwABVlwAAVZdAAFWXwABVmAAAVafAAFWoQABVqQAAVamAAFWqQABVqoAAVarAAFWrAABVq0AAVavAAFWsQABVrIAAVazAAFWtQABVrYAAVbDAAFWxAABVsUAAVbHAAFXBgABVwgAAVcKAAFXDAABVw8AAVcQAAFXEQABVxIAAVcTAAFXFQABVxcAAVcYAAFXGQABVxsAAVccAAFXWwABV10AAVdfAAFXYQABV2QAAVdlAAFXZgABV2cAAVdoAAFXagABV2wAAVdtAAFXbgABV3AAAVdxAAFXsAABV7IAAVe0AAFXtgABV7kAAVe6AAFXuwABV7wAAVe9AAFXvwABV8EAAVfCAAFXwwABV8UAAVfGAAFYBQABWAcAAVgJAAFYCwABWA4AAVgPAAFYEAABWBEAAVgSAAFYFAABWBYAAVgXAAFYGAABWBoAAVgbAAFYWgABWFwAAVheAAFYYAABWGMAAVhkAAFYZQABWGYAAVhnAAFYaQABWGsAAVhsAAFYbQABWG8AAVhwAAFYlQABWLkAAVjgAAFZBAABWQcAAVkJAAFZCwABWQ0AAVkPAAFZEQABWRIAAVkVAAFZIgABWTEAAVkzAAFZNQABWTcAAVk5AAFZOwABWT0AAVk/AAFZTgABWVEAAVlUAAFZVwABWVoAAVldAAFZYAABWWMAAVllAAFZpAABWaYAAVmoAAFZqgABWa0AAVmuAAFZrwABWbAAAVmxAAFZswABWbUAAVm2AAFZtwABWbkAAVm6AAFZ+QABWfsAAVn9AAFZ/wABWgIAAVoDAAFaBAABWgUAAVoGAAFaCAABWgoAAVoLAAFaDAABWg4AAVoPAAFaTgABWlAAAVpSAAFaVAABWlcAAVpYAAFaWQABWloAAVpbAAFaXQABWl8AAVpgAAFaYQABWmMAAVpkAAFaowABWqUAAVqnAAFaqQABWqwAAVqtAAFargABWq8AAVqwAAFasgABWrQAAVq1AAFatgABWrgAAVq5AAFa+AABWvoAAVr8AAFa/gABWwEAAVsCAAFbAwABWwQAAVsFAAFbBwABWwkAAVsKAAFbCwABWw0AAVsOAAFbTQABW08AAVtRAAFbUwABW1YAAVtXAAFbWAABW1kAAVtaAAFbXAABW14AAVtfAAFbYAABW2IAAVtjAAFbogABW6QAAVunAAFbqQABW6wAAVutAAFbrgABW68AAVuwAAFbsgABW7QAAVu1AAFbtgABW7gAAVu5AAFcBAABXCcAAVxHAAFcZwABXGkAAVxrAAFcbQABXG8AAVxyAAFccwABXHQAAVx3AAFceAABXHoAAVx7AAFcfQABXH8AAVyAAAFcgQABXIQAAVyFAAFcigABXJcAAVycAAFcngABXKAAAVylAAFcqAABXKsAAVytAAFc0gABXPYAAV0dAAFdQQABXUQAAV1GAAFdSAABXUoAAV1MAAFdTgABXU8AAV1SAAFdXwABXXAAAV1yAAFddAABXXYAAV14AAFdegABXXwAAV1+AAFdgAABXZEAAV2UAAFdlwABXZoAAV2dAAFdoAABXaMAAV2mAAFdqQABXasAAV3qAAFd7AABXe4AAV3wAAFd8wABXfQAAV31AAFd9gABXfcAAV35AAFd+wABXfwAAV39AAFd/wABXgAAAV4/AAFeQQABXkMAAV5FAAFeSAABXkkAAV5KAAFeSwABXkwAAV5OAAFeUAABXlEAAV5SAAFeVAABXlUAAV6UAAFelgABXpkAAV6bAAFengABXp8AAV6gAAFeoQABXqIAAV6kAAFepgABXqcAAV6oAAFeqgABXqsAAV64AAFeuQABXroAAV68AAFe+wABXv0AAV7/AAFfAQABXwQAAV8FAAFfBgABXwcAAV8IAAFfCgABXwwAAV8NAAFfDgABXxAAAV8RAAFfUAABX1IAAV9UAAFfVgABX1kAAV9aAAFfWwABX1wAAV9dAAFfXwABX2EAAV9iAAFfYwABX2UAAV9mAAFfpQABX6cAAV+pAAFfqwABX64AAV+vAAFfsAABX7EAAV+yAAFftAABX7YAAV+3AAFfuAABX7oAAV+7AAFf+gABX/wAAV/+AAFgAAABYAMAAWAEAAFgBQABYAYAAWAHAAFgCQABYAsAAWAMAAFgDQABYA8AAWAQAAFgTwABYFEAAWBTAAFgVQABYFgAAWBZAAFgWgABYFsAAWBcAAFgXgABYGAAAWBhAAFgYgABYGQAAWBlAAFgigABYK4AAWDVAAFg+QABYPwAAWD+AAFhAAABYQIAAWEEAAFhBgABYQcAAWEKAAFhFwABYSYAAWEoAAFhKgABYSwAAWEuAAFhMAABYTIAAWE0AAFhQwABYUYAAWFJAAFhTAABYU8AAWFSAAFhVQABYVgAAWFaAAFhmQABYZsAAWGeAAFhoAABYaMAAWGkAAFhpQABYaYAAWGnAAFhqQABYasAAWGsAAFhrQABYa8AAWGwAAFhsQABYfAAAWHyAAFh9AABYfYAAWH5AAFh+gABYfsAAWH8AAFh/QABYf8AAWIBAAFiAgABYgMAAWIFAAFiBgABYkUAAWJHAAFiSQABYksAAWJOAAFiTwABYlAAAWJRAAFiUgABYlQAAWJWAAFiVwABYlgAAWJaAAFiWwABYpoAAWKcAAFingABYqAAAWKjAAFipAABYqUAAWKmAAFipwABYqkAAWKrAAFirAABYq0AAWKvAAFisAABYu8AAWLxAAFi8wABYvUAAWL4AAFi+QABYvoAAWL7AAFi/AABYv4AAWMAAAFjAQABYwIAAWMEAAFjBQABY0QAAWNGAAFjSAABY0oAAWNNAAFjTgABY08AAWNQAAFjUQABY1MAAWNVAAFjVgABY1cAAWNZAAFjWgABY5kAAWObAAFjnQABY58AAWOiAAFjowABY6QAAWOlAAFjpgABY6gAAWOqAAFjqwABY6wAAWOuAAFjrwABY/oAAWQdAAFkPQABZF0AAWRfAAFkYQABZGMAAWRlAAFkaAABZGkAAWRqAAFkbQABZG4AAWRwAAFkcQABZHMAAWR2AAFkdwABZHgAAWR7AAFkfAABZIEAAWSOAAFkkwABZJUAAWSXAAFknAABZJ8AAWSiAAFkpAABZMkAAWTtAAFlFAABZTgAAWU7AAFlPQABZT8AAWVBAAFlQwABZUUAAWVGAAFlSQABZVYAAWVnAAFlaQABZWsAAWVtAAFlbwABZXEAAWVzAAFldQABZXcAAWWIAAFliwABZY4AAWWRAAFllAABZZcAAWWaAAFlnQABZaAAAWWiAAFl4QABZeMAAWXlAAFl5wABZeoAAWXrAAFl7AABZe0AAWXuAAFl8AABZfIAAWXzAAFl9AABZfYAAWX3AAFmNgABZjgAAWY6AAFmPAABZj8AAWZAAAFmQQABZkIAAWZDAAFmRQABZkcAAWZIAAFmSQABZksAAWZMAAFmiwABZo0AAWaQAAFmkgABZpUAAWaWAAFmlwABZpgAAWaZAAFmmwABZp0AAWaeAAFmnwABZqEAAWaiAAFmrwABZrAAAWaxAAFmswABZvIAAWb0AAFm9gABZvgAAWb7AAFm/AABZv0AAWb+AAFm/wABZwEAAWcDAAFnBAABZwUAAWcHAAFnCAABZ0cAAWdJAAFnSwABZ00AAWdQAAFnUQABZ1IAAWdTAAFnVAABZ1YAAWdYAAFnWQABZ1oAAWdcAAFnXQABZ5wAAWeeAAFnoAABZ6IAAWelAAFnpgABZ6cAAWeoAAFnqQABZ6sAAWetAAFnrgABZ68AAWexAAFnsgABZ/EAAWfzAAFn9QABZ/cAAWf6AAFn+wABZ/wAAWf9AAFn/gABaAAAAWgCAAFoAwABaAQAAWgGAAFoBwABaEYAAWhIAAFoSgABaEwAAWhPAAFoUAABaFEAAWhSAAFoUwABaFUAAWhXAAFoWAABaFkAAWhbAAFoXAABaIEAAWilAAFozAABaPAAAWjzAAFo9QABaPcAAWj5AAFo+wABaP0AAWj+AAFpAQABaQ4AAWkdAAFpHwABaSEAAWkjAAFpJQABaScAAWkpAAFpKwABaToAAWk9AAFpQAABaUMAAWlGAAFpSQABaUwAAWlPAAFpUQABaZAAAWmSAAFplAABaZYAAWmZAAFpmgABaZsAAWmcAAFpnQABaZ8AAWmhAAFpogABaaMAAWmlAAFppgABaeUAAWnnAAFp6QABaesAAWnuAAFp7wABafAAAWnxAAFp8gABafQAAWn2AAFp9wABafgAAWn6AAFp+wABajoAAWo8AAFqPgABakAAAWpDAAFqRAABakUAAWpGAAFqRwABakkAAWpLAAFqTAABak0AAWpPAAFqUAABao8AAWqRAAFqkwABapUAAWqYAAFqmQABapoAAWqbAAFqnAABap4AAWqgAAFqoQABaqIAAWqkAAFqpQABauQAAWrmAAFq6AABauoAAWrtAAFq7gABau8AAWrwAAFq8QABavMAAWr1AAFq9gABavcAAWr5AAFq+gABazkAAWs7AAFrPQABaz8AAWtCAAFrQwABa0QAAWtFAAFrRgABa0gAAWtKAAFrSwABa0wAAWtOAAFrTwABa44AAWuQAAFrkgABa5QAAWuXAAFrmAABa5kAAWuaAAFrmwABa50AAWufAAFroAABa6EAAWujAAFrpAABa+8AAWwSAAFsMgABbFIAAWxUAAFsVgABbFgAAWxaAAFsXQABbF4AAWxfAAFsYgABbGMAAWxlAAFsZgABbGgAAWxrAAFsbAABbG0AAWxwAAFscQABbHYAAWyDAAFsiAABbIoAAWyMAAFskQABbJQAAWyXAAFsmQABbL4AAWziAAFtCQABbS0AAW0wAAFtMgABbTQAAW02AAFtOAABbToAAW07AAFtPgABbUsAAW1cAAFtXgABbWAAAW1iAAFtZAABbWYAAW1oAAFtagABbWwAAW19AAFtgAABbYMAAW2GAAFtiQABbYwAAW2PAAFtkgABbZUAAW2XAAFt1gABbdgAAW3aAAFt3AABbd8AAW3gAAFt4QABbeIAAW3jAAFt5QABbecAAW3oAAFt6QABbesAAW3sAAFuKwABbi0AAW4vAAFuMQABbjQAAW41AAFuNgABbjcAAW44AAFuOgABbjwAAW49AAFuPgABbkAAAW5BAAFugAABboIAAW6FAAFuhwABbooAAW6LAAFujAABbo0AAW6OAAFukAABbpIAAW6TAAFulAABbpYAAW6XAAFupAABbqUAAW6mAAFuqAABbucAAW7pAAFu6wABbu0AAW7wAAFu8QABbvIAAW7zAAFu9AABbvYAAW74AAFu+QABbvoAAW78AAFu/QABbzwAAW8+AAFvQAABb0IAAW9FAAFvRgABb0cAAW9IAAFvSQABb0sAAW9NAAFvTgABb08AAW9RAAFvUgABb5EAAW+TAAFvlQABb5cAAW+aAAFvmwABb5wAAW+dAAFvngABb6AAAW+iAAFvowABb6QAAW+mAAFvpwABb+YAAW/oAAFv6gABb+wAAW/vAAFv8AABb/EAAW/yAAFv8wABb/UAAW/3AAFv+AABb/kAAW/7AAFv/AABcDsAAXA9AAFwPwABcEEAAXBEAAFwRQABcEYAAXBHAAFwSAABcEoAAXBMAAFwTQABcE4AAXBQAAFwUQABcHYAAXCaAAFwwQABcOUAAXDoAAFw6gABcOwAAXDuAAFw8AABcPIAAXDzAAFw9gABcQMAAXESAAFxFAABcRYAAXEYAAFxGgABcRwAAXEeAAFxIAABcS8AAXEyAAFxNQABcTgAAXE7AAFxPgABcUEAAXFEAAFxRgABcYUAAXGHAAFxiQABcYsAAXGOAAFxjwABcZAAAXGRAAFxkgABcZQAAXGWAAFxlwABcZgAAXGaAAFxmwABcdoAAXHcAAFx3gABceAAAXHjAAFx5AABceUAAXHmAAFx5wABcekAAXHrAAFx7AABce0AAXHvAAFx8AABci8AAXIxAAFyMwABcjUAAXI4AAFyOQABcjoAAXI7AAFyPAABcj4AAXJAAAFyQQABckIAAXJEAAFyRQABcoQAAXKGAAFyiAABcooAAXKNAAFyjgABco8AAXKQAAFykQABcpMAAXKVAAFylgABcpcAAXKZAAFymgABctkAAXLbAAFy3QABct8AAXLiAAFy4wABcuQAAXLlAAFy5gABcugAAXLqAAFy6wABcuwAAXLuAAFy7wABcy4AAXMwAAFzMgABczQAAXM3AAFzOAABczkAAXM6AAFzOwABcz0AAXM/AAFzQAABc0EAAXNDAAFzRAABc4MAAXOFAAFzhwABc4kAAXOMAAFzjQABc44AAXOPAAFzkAABc5IAAXOUAAFzlQABc5YAAXOYAAFzmQABc6IAAXOjAAFzpQABc+QAAXPmAAFz6AABc+oAAXPtAAFz7gABc+8AAXPwAAFz8QABc/MAAXP1AAFz9gABc/cAAXP5AAFz+gABdDkAAXQ7AAF0PQABdD8AAXRCAAF0QwABdEQAAXRFAAF0RgABdEgAAXRKAAF0SwABdEwAAXROAAF0TwABdI4AAXSQAAF0kwABdJUAAXSYAAF0mQABdJoAAXSbAAF0nAABdJ4AAXSgAAF0oQABdKIAAXSkAAF0pQABdPAAAXUTAAF1MwABdVMAAXVVAAF1VwABdVkAAXVbAAF1XQABdV4AAXVfAAF1YgABdWMAAXVlAAF1ZgABdWgAAXVqAAF1awABdWwAAXVvAAF1cAABdXUAAXWCAAF1hwABdYkAAXWLAAF1kAABdZMAAXWWAAF1mAABdb0AAXXhAAF2CAABdiwAAXYvAAF2MQABdjMAAXY1AAF2NwABdjkAAXY6AAF2PQABdkoAAXZbAAF2XQABdl8AAXZhAAF2YwABdmUAAXZnAAF2aQABdmsAAXZ8AAF2fwABdoIAAXaFAAF2iAABdosAAXaOAAF2kQABdpQAAXaWAAF21QABdtcAAXbZAAF22wABdt4AAXbfAAF24AABduEAAXbiAAF25AABduYAAXbnAAF26AABduoAAXbrAAF3KgABdywAAXcuAAF3MAABdzMAAXc0AAF3NQABdzYAAXc3AAF3OQABdzsAAXc8AAF3PQABdz8AAXdAAAF3fwABd4EAAXeEAAF3hgABd4kAAXeKAAF3iwABd4wAAXeNAAF3jwABd5EAAXeSAAF3kwABd5UAAXeWAAF3owABd6QAAXelAAF3pwABd+YAAXfoAAF36gABd+wAAXfvAAF38AABd/EAAXfyAAF38wABd/UAAXf3AAF3+AABd/kAAXf7AAF3/AABeDsAAXg9AAF4PwABeEEAAXhEAAF4RQABeEYAAXhHAAF4SAABeEoAAXhMAAF4TQABeE4AAXhQAAF4UQABeJAAAXiSAAF4lAABeJYAAXiZAAF4mgABeJsAAXicAAF4nQABeJ8AAXihAAF4ogABeKMAAXilAAF4pgABeOUAAXjnAAF46QABeOsAAXjuAAF47wABePAAAXjxAAF48gABePQAAXj2AAF49wABePgAAXj6AAF4+wABeToAAXk8AAF5PgABeUAAAXlDAAF5RAABeUUAAXlGAAF5RwABeUkAAXlLAAF5TAABeU0AAXlPAAF5UAABeXUAAXmZAAF5wAABeeQAAXnnAAF56QABeesAAXntAAF57wABefEAAXnyAAF59QABegIAAXoPAAF6EQABehMAAXoVAAF6FwABehkAAXobAAF6KAABeisAAXouAAF6MQABejQAAXo3AAF6OgABejwAAXp7AAF6fQABeoAAAXqCAAF6hQABeoYAAXqHAAF6iAABeokAAXqLAAF6jQABeo4AAXqPAAF6kQABepIAAXrRAAF60wABetUAAXrXAAF62gABetsAAXrcAAF63QABet4AAXrgAAF64gABeuMAAXrkAAF65gABeucAAXsmAAF7KAABeyoAAXssAAF7LwABezAAAXsxAAF7MgABezMAAXs1AAF7NwABezgAAXs5AAF7OwABezwAAXt7AAF7fQABe38AAXuBAAF7hAABe4UAAXuGAAF7hwABe4gAAXuKAAF7jAABe40AAXuOAAF7kAABe5EAAXvQAAF70gABe9QAAXvWAAF72QABe9oAAXvbAAF73AABe90AAXvfAAF74QABe+IAAXvjAAF75QABe+YAAXwlAAF8JwABfCkAAXwrAAF8LgABfC8AAXwwAAF8MQABfDIAAXw0AAF8NgABfDcAAXw4AAF8OgABfDsAAXyGAAF8qQABfMkAAXzpAAF86wABfO0AAXzvAAF88QABfPMAAXz0AAF89QABfPgAAXz5AAF8+wABfPwAAXz+AAF9AAABfQEAAX0CAAF9BQABfQYAAX0LAAF9GAABfR0AAX0fAAF9IQABfSYAAX0pAAF9LAABfS4AAX1TAAF9dwABfZ4AAX3CAAF9xQABfccAAX3JAAF9ywABfc0AAX3PAAF90AABfdMAAX3gAAF98QABffMAAX3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JAAGIzAABiM0AAYjOAAGIzwABiNAAAYjSAAGI1AABiNUAAYjWAAGI2AABiNkAAYj+AAGJIgABiUkAAYltAAGJcAABiXIAAYl0AAGJdgABiXgAAYl6AAGJewABiX4AAYmLAAGJmgABiZwAAYmeAAGJoAABiaIAAYmkAAGJpgABiagAAYm3AAGJugABib0AAYnAAAGJwwABicYAAYnJAAGJzAABic4AAYoNAAGKDwABihIAAYoUAAGKFwABihgAAYoZAAGKGgABihsAAYodAAGKHwABiiAAAYohAAGKIwABiiQAAYpjAAGKZQABimcAAYppAAGKbAABim0AAYpuAAGKbwABinAAAYpyAAGKdAABinUAAYp2AAGKeAABinkAAYq4AAGKugABirwAAYq+AAGKwQABisIAAYrDAAGKxAABisUAAYrHAAGKyQABisoAAYrLAAGKzQABis4AAYsNAAGLDwABixIAAYsUAAGLFwABixgAAYsZAAGLGgABixsAAYsdAAGLHwABiyAAAYshAAGLIwABiyQAAYtjAAGLZQABi2cAAYtpAAGLbAABi20AAYtuAAGLbwABi3AAAYtyAAGLdAABi3UAAYt2AAGLeAABi3kAAYu4AAGLugABi7wAAYu+AAGLwQABi8IAAYvDAAGLxAABi8UAAYvHAAGLyQABi8oAAYvLAAGLzQABi84AAYwNAAGMDwABjBEAAYwTAAGMFgABjBcAAYwYAAGMGQABjBoAAYwcAAGMHgABjB8AAYwgAAGMIgABjCMAAYxuAAGMkQABjLEAAYzRAAGM0wABjNUAAYzXAAGM2QABjNsAAYzcAAGM3QABjOAAAYzhAAGM4wABjOQAAYzmAAGM6AABjOkAAYzqAAGM7QABjO4AAYzzAAGNAAABjQUAAY0HAAGNCQABjQ4AAY0RAAGNFAABjRYAAY07AAGNXwABjYYAAY2qAAGNrQABja8AAY2xAAGNswABjbUAAY23AAGNuAABjbsAAY3IAAGN2QABjdsAAY3dAAGN3wABjeEAAY3jAAGN5QABjecAAY3pAAGN+gABjf0AAY4AAAGOAwABjgYAAY4JAAGODAABjg8AAY4SAAGOFAABjlMAAY5VAAGOVwABjlkAAY5cAAGOXQABjl4AAY5fAAGOYAABjmIAAY5kAAGOZQABjmYAAY5oAAGOaQABjqgAAY6qAAGOrAABjq4AAY6xAAGOsgABjrMAAY60AAGOtQABjrcAAY65AAGOugABjrsAAY69AAGOvgABjv0AAY7/AAGPAgABjwQAAY8HAAGPCAABjwkAAY8KAAGPCwABjw0AAY8PAAGPEAABjxEAAY8TAAGPFAABjyEAAY8iAAGPIwABjyUAAY9kAAGPZgABj2gAAY9qAAGPbQABj24AAY9vAAGPcAABj3EAAY9zAAGPdQABj3YAAY93AAGPeQABj3oAAY+5AAGPuwABj70AAY+/AAGPwgABj8MAAY/EAAGPxQABj8YAAY/IAAGPygABj8sAAY/MAAGPzgABj88AAZAOAAGQEAABkBIAAZAUAAGQFwABkBgAAZAZAAGQGgABkBsAAZAdAAGQHwABkCAAAZAhAAGQIwABkCQAAZBjAAGQZQABkGcAAZBpAAGQbAABkG0AAZBuAAGQbwABkHAAAZByAAGQdAABkHUAAZB2AAGQeAABkHkAAZC4AAGQugABkLwAAZC+AAGQwQABkMIAAZDDAAGQxAABkMUAAZDHAAGQyQABkMoAAZDLAAGQzQABkM4AAZDzAAGRFwABkT4AAZFiAAGRZQABkWcAAZFpAAGRawABkW0AAZFvAAGRcAABkXMAAZGAAAGRjwABkZEAAZGTAAGRlQABkZcAAZGZAAGRmwABkZ0AAZGsAAGRrwABkbIAAZG1AAGRuAABkbsAAZG+AAGRwQABkcMAAZICAAGSBAABkgYAAZIIAAGSCwABkgwAAZINAAGSDgABkg8AAZIRAAGSEwABkhQAAZIVAAGSFwABkhgAAZJXAAGSWQABklsAAZJdAAGSYAABkmEAAZJiAAGSYwABkmQAAZJmAAGSaAABkmkAAZJqAAGSbAABkm0AAZKsAAGSrgABkrAAAZKyAAGStQABkrYAAZK3AAGSuAABkrkAAZK7AAGSvQABkr4AAZK/AAGSwQABksIAAZMBAAGTAwABkwYAAZMIAAGTCwABkwwAAZMNAAGTDgABkw8AAZMRAAGTEwABkxQAAZMVAAGTFwABkxgAAZNXAAGTWQABk1sAAZNdAAGTYAABk2EAAZNiAAGTYwABk2QAAZNmAAGTaAABk2kAAZNqAAGTbAABk20AAZOsAAGTrgABk7AAAZOyAAGTtQABk7YAAZO3AAGTuAABk7kAAZO7AAGTvQABk74AAZO/AAGTwQABk8IAAZQBAAGUAwABlAUAAZQHAAGUCgABlAsAAZQMAAGUDQABlA4AAZQQAAGUEgABlBMAAZQUAAGUFgABlBcAAZRiAAGUhQABlKUAAZTFAAGUxwABlMkAAZTLAAGUzQABlM8AAZTQAAGU0QABlNQAAZTVAAGU1wABlNgAAZTaAAGU3AABlN0AAZTeAAGU4QABlOIAAZTrAAGU+AABlP0AAZT/AAGVAQABlQYAAZUJAAGVDAABlQ4AAZUzAAGVVwABlX4AAZWiAAGVpQABlacAAZWpAAGVqwABla0AAZWvAAGVsAABlbMAAZXAAAGV0QABldMAAZXVAAGV1wABldkAAZXbAAGV3QABld8AAZXhAAGV8gABlfUAAZX4AAGV+wABlf4AAZYBAAGWBAABlgcAAZYKAAGWDAABlksAAZZNAAGWTwABllEAAZZUAAGWVQABllYAAZZXAAGWWAABlloAAZZcAAGWXQABll4AAZZgAAGWYQABlqAAAZaiAAGWpAABlqYAAZapAAGWqgABlqsAAZasAAGWrQABlq8AAZaxAAGWsgABlrMAAZa1AAGWtgABlvUAAZb3AAGW+gABlvwAAZb/AAGXAAABlwEAAZcCAAGXAwABlwUAAZcHAAGXCAABlwkAAZcLAAGXDAABlxkAAZcaAAGXGwABlx0AAZdcAAGXXgABl2AAAZdiAAGXZQABl2YAAZdnAAGXaAABl2kAAZdrAAGXbQABl24AAZdvAAGXcQABl3IAAZexAAGXswABl7UAAZe3AAGXugABl7sAAZe8AAGXvQABl74AAZfAAAGXwgABl8MAAZfEAAGXxgABl8cAAZgGAAGYCAABmAoAAZgMAAGYDwABmBAAAZgRAAGYEgABmBMAAZgVAAGYFwABmBgAAZgZAAGYGwABmBwAAZhbAAGYXQABmF8AAZhhAAGYZAABmGUAAZhmAAGYZwABmGgAAZhqAAGYbAABmG0AAZhuAAGYcAABmHEAAZiwAAGYsgABmLQAAZi2AAGYuQABmLoAAZi7AAGYvAABmL0AAZi/AAGYwQABmMIAAZjDAAGYxQABmMYAAZjrAAGZDwABmTYAAZlaAAGZXQABmV8AAZlhAAGZYwABmWUAAZlnAAGZaAABmWsAAZl4AAGZhwABmYkAAZmLAAGZjQABmY8AAZmRAAGZkwABmZUAAZmkAAGZpwABmaoAAZmtAAGZsAABmbMAAZm2AAGZuQABmbsAAZn6AAGZ/AABmf4AAZoAAAGaAwABmgQAAZoFAAGaBgABmgcAAZoJAAGaCwABmgwAAZoNAAGaDwABmhAAAZpPAAGaUQABmlMAAZpVAAGaWAABmlkAAZpaAAGaWwABmlwAAZpeAAGaYAABmmEAAZpiAAGaZAABmmUAAZqkAAGapgABmqgAAZqqAAGarQABmq4AAZqvAAGasAABmrEAAZqzAAGatQABmrYAAZq3AAGauQABmroAAZr5AAGa+wABmv0AAZr/AAGbAgABmwMAAZsEAAGbBQABmwYAAZsIAAGbCgABmwsAAZsMAAGbDgABmw8AAZtOAAGbUAABm1IAAZtUAAGbVwABm1gAAZtZAAGbWgABm1sAAZtdAAGbXwABm2AAAZthAAGbYwABm2QAAZujAAGbpQABm6cAAZupAAGbrAABm60AAZuuAAGbrwABm7AAAZuyAAGbtAABm7UAAZu2AAGbuAABm7kAAZv4AAGb+gABm/wAAZv+AAGcAQABnAIAAZwDAAGcBAABnAUAAZwHAAGcCQABnAoAAZwLAAGcDQABnA4AAZxZAAGcfAABnJwAAZy8AAGcvgABnMAAAZzCAAGcxAABnMYAAZzHAAGcyAABnMsAAZzMAAGczgABnM8AAZzRAAGc0wABnNQAAZzVAAGc2AABnNkAAZziAAGc7wABnPQAAZz2AAGc+AABnP0AAZ0AAAGdAwABnQUAAZ0qAAGdTgABnXUAAZ2ZAAGdnAABnZ4AAZ2gAAGdogABnaQAAZ2mAAGdpwABnaoAAZ23AAGdyAABncoAAZ3MAAGdzgABndAAAZ3SAAGd1AABndYAAZ3YAAGd6QABnewAAZ3vAAGd8gABnfUAAZ34AAGd+wABnf4AAZ4BAAGeAwABnkIAAZ5EAAGeRgABnkgAAZ5LAAGeTAABnk0AAZ5OAAGeTwABnlEAAZ5TAAGeVAABnlUAAZ5XAAGeWAABnpcAAZ6ZAAGemwABnp0AAZ6gAAGeoQABnqIAAZ6jAAGepAABnqYAAZ6oAAGeqQABnqoAAZ6sAAGerQABnuwAAZ7uAAGe8QABnvMAAZ72AAGe9wABnvgAAZ75AAGe+gABnvwAAZ7+AAGe/wABnwAAAZ8CAAGfAwABnxAAAZ8RAAGfEgABnxQAAZ9TAAGfVQABn1cAAZ9ZAAGfXAABn10AAZ9eAAGfXwABn2AAAZ9iAAGfZAABn2UAAZ9mAAGfaAABn2kAAZ+oAAGfqgABn6wAAZ+uAAGfsQABn7IAAZ+zAAGftAABn7UAAZ+3AAGfuQABn7oAAZ+7AAGfvQABn74AAZ/9AAGf/wABoAEAAaADAAGgBgABoAcAAaAIAAGgCQABoAoAAaAMAAGgDgABoA8AAaAQAAGgEgABoBMAAaBSAAGgVAABoFYAAaBYAAGgWwABoFwAAaBdAAGgXgABoF8AAaBhAAGgYwABoGQAAaBlAAGgZwABoGgAAaCnAAGgqQABoKsAAaCtAAGgsAABoLEAAaCyAAGgswABoLQAAaC2AAGguAABoLkAAaC6AAGgvAABoL0AAaDiAAGhBgABoS0AAaFRAAGhVAABoVYAAaFYAAGhWgABoVwAAaFeAAGhXwABoWIAAaFvAAGhfgABoYAAAaGCAAGhhAABoYYAAaGIAAGhigABoYwAAaGbAAGhngABoaEAAaGkAAGhpwABoaoAAaGtAAGhsAABobIAAaHxAAGh8wABofUAAaH3AAGh+gABofsAAaH8AAGh/QABof4AAaIAAAGiAgABogMAAaIEAAGiBgABogcAAaJGAAGiSAABokoAAaJMAAGiTwABolAAAaJRAAGiUgABolMAAaJVAAGiVwABolgAAaJZAAGiWwABolwAAaKbAAGinQABop8AAaKhAAGipAABoqUAAaKmAAGipwABoqgAAaKqAAGirAABoq0AAaKuAAGisAABorEAAaLwAAGi8gABovQAAaL2AAGi+QABovoAAaL7AAGi/AABov0AAaL/AAGjAQABowIAAaMDAAGjBQABowYAAaNFAAGjRwABo0kAAaNLAAGjTgABo08AAaNQAAGjUQABo1IAAaNUAAGjVgABo1cAAaNYAAGjWgABo1sAAaOaAAGjnAABo54AAaOgAAGjowABo6QAAaOlAAGjpgABo6cAAaOpAAGjqwABo6wAAaOtAAGjrwABo7AAAaPvAAGj8QABo/MAAaP1AAGj+AABo/kAAaP6AAGj+wABo/wAAaP+AAGkAAABpAEAAaQCAAGkBAABpAUAAaRQAAGkcwABpJMAAaSzAAGktQABpLcAAaS5AAGkuwABpL0AAaS+AAGkvwABpMIAAaTDAAGkxQABpMYAAaTIAAGkygABpMsAAaTMAAGkzwABpNAAAaTVAAGk4gABpOcAAaTpAAGk6wABpPAAAaTzAAGk9gABpPgAAaUdAAGlQQABpWgAAaWMAAGljwABpZEAAaWTAAGllQABpZcAAaWZAAGlmgABpZ0AAaWqAAGluwABpb0AAaW/AAGlwQABpcMAAaXFAAGlxwABpckAAaXLAAGl3AABpd8AAaXiAAGl5QABpegAAaXrAAGl7gABpfEAAaX0AAGl9gABpjUAAaY3AAGmOQABpjsAAaY+AAGmPwABpkAAAaZBAAGmQgABpkQAAaZGAAGmRwABpkgAAaZKAAGmSwABpooAAaaMAAGmjgABppAAAaaTAAGmlAABppUAAaaWAAGmlwABppkAAaabAAGmnAABpp0AAaafAAGmoAABpt8AAabhAAGm5AABpuYAAabpAAGm6gABpusAAabsAAGm7QABpu8AAabxAAGm8gABpvMAAab1AAGm9gABpwMAAacEAAGnBQABpwcAAadGAAGnSAABp0oAAadMAAGnTwABp1AAAadRAAGnUgABp1MAAadVAAGnVwABp1gAAadZAAGnWwABp1wAAaebAAGnnQABp58AAaehAAGnpAABp6UAAaemAAGnpwABp6gAAaeqAAGnrAABp60AAaeuAAGnsAABp7EAAafwAAGn8gABp/QAAaf2AAGn+QABp/oAAaf7AAGn/AABp/0AAaf/AAGoAQABqAIAAagDAAGoBQABqAYAAahFAAGoRwABqEkAAahLAAGoTgABqE8AAahQAAGoUQABqFIAAahUAAGoVgABqFcAAahYAAGoWgABqFsAAaiaAAGonAABqJ4AAaigAAGoowABqKQAAailAAGopgABqKcAAaipAAGoqwABqKwAAaitAAGorwABqLAAAajVAAGo+QABqSAAAalEAAGpRwABqUkAAalLAAGpTQABqU8AAalRAAGpUgABqVUAAaliAAGpcQABqXMAAal1AAGpdwABqXkAAal7AAGpfQABqX8AAamOAAGpkQABqZQAAamXAAGpmgABqZ0AAamgAAGpowABqaUAAankAAGp5gABqegAAanqAAGp7QABqe4AAanvAAGp8AABqfEAAanzAAGp9QABqfYAAan3AAGp+QABqfoAAao5AAGqOwABqj0AAao/AAGqQgABqkMAAapEAAGqRQABqkYAAapIAAGqSgABqksAAapMAAGqTgABqk8AAaqOAAGqkAABqpIAAaqUAAGqlwABqpgAAaqZAAGqmgABqpsAAaqdAAGqnwABqqAAAaqhAAGqowABqqQAAarjAAGq5QABqugAAarqAAGq7QABqu4AAarvAAGq8AABqvEAAarzAAGq9QABqvYAAar3AAGq+QABqvoAAas9AAGrYQABq4UAAauoAAGrzwABq+8AAawWAAGsPQABrF0AAayBAAGspQABrKcAAayqAAGsrAABrK4AAaywAAGsswABrLYAAay4AAGsugABrL0AAay/AAGswQABrMQAAazHAAGsyAABrM0AAazaAAGs3QABrN8AAaziAAGs5QABrOcAAa0MAAGtMAABrVcAAa17AAGtfgABrYAAAa2CAAGthAABrYYAAa2IAAGtiQABrYwAAa2ZAAGtrAABra4AAa2wAAGtsgABrbQAAa22AAGtuAABrboAAa28AAGtvgABrdEAAa3UAAGt1wABrdoAAa3dAAGt4AABreMAAa3mAAGt6QABrewAAa3uAAGuLQABri8AAa4yAAGuNAABrjcAAa44AAGuOQABrjoAAa47AAGuPQABrj8AAa5AAAGuQQABrkMAAa5EAAGuTQABrk4AAa5QAAGujwABrpEAAa6TAAGulQABrpgAAa6ZAAGumgABrpsAAa6cAAGungABrqAAAa6hAAGuogABrqQAAa6lAAGu5AABruYAAa7pAAGu6wABru4AAa7vAAGu8AABrvEAAa7yAAGu9AABrvYAAa73AAGu+AABrvoAAa77AAGvBAABrwUAAa8HAAGvRgABr0gAAa9KAAGvTAABr08AAa9QAAGvUQABr1IAAa9TAAGvVQABr1cAAa9YAAGvWQABr1sAAa9cAAGvmwABr50AAa+gAAGvogABr6UAAa+mAAGvpwABr6gAAa+pAAGvqwABr60AAa+uAAGvrwABr7EAAa+yAAGvuwABr7wAAa++AAGv/QABr/8AAbABAAGwAwABsAYAAbAHAAGwCAABsAkAAbAKAAGwDAABsA4AAbAPAAGwEAABsBIAAbATAAGwUgABsFQAAbBXAAGwWQABsFwAAbBdAAGwXgABsF8AAbBgAAGwYgABsGQAAbBlAAGwZgABsGgAAbBpAAGwdgABsHcAAbB4AAGwegABsLkAAbC7AAGwvQABsL8AAbD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TAAHHVgABx1gAAceXAAHHmQABx5sAAcedAAHHoAABx6EAAceiAAHHowABx6QAAcemAAHHqAABx6kAAceqAAHHrAABx60AAcfsAAHH7gABx/AAAcfyAAHH9QABx/YAAcf3AAHH+AABx/kAAcf7AAHH/QABx/4AAcf/AAHIAQAByAIAAchBAAHIQwAByEUAAchHAAHISgAByEsAAchMAAHITQAByE4AAchQAAHIUgAByFMAAchUAAHIVgAByFcAAciWAAHImAAByJsAAcidAAHIoAAByKEAAciiAAHIowAByKQAAcimAAHIqAAByKkAAciqAAHIrAAByK0AAcjsAAHI7gAByPAAAcjyAAHI9QAByPYAAcj3AAHI+AAByPkAAcj7AAHI/QAByP4AAcj/AAHJAQAByQIAAclBAAHJQwAByUYAAclIAAHJSwAByUwAAclNAAHJTgAByU8AAclRAAHJUwAByVQAAclVAAHJVwAByVgAAcl/AAHJvgABycAAAcnCAAHJxAAByccAAcnIAAHJyQABycoAAcnLAAHJzQAByc8AAcnQAAHJ0QABydMAAcnUAAHKHwABykIAAcpiAAHKggAByoQAAcqGAAHKiAAByooAAcqNAAHKjgAByo8AAcqSAAHKkwABypUAAcqWAAHKmAABypsAAcqcAAHKnQAByqAAAcqhAAHKpgAByrMAAcq4AAHKugAByrwAAcrBAAHKxAAByscAAcrJAAHK7gAByxIAAcs5AAHLXQABy2AAActiAAHLZAABy2YAActoAAHLagABy2sAActuAAHLewABy4wAAcuOAAHLkAABy5IAAcuUAAHLlgABy5gAAcuaAAHLnAABy60AAcuwAAHLswABy7YAAcu5AAHLvAABy78AAcvCAAHLxQABy8cAAcwGAAHMCAABzAoAAcwMAAHMDwABzBAAAcwRAAHMEgABzBMAAcwVAAHMFwABzBgAAcwZAAHMGwABzBwAAcxbAAHMXQABzF8AAcxhAAHMZAABzGUAAcxmAAHMZwABzGgAAcxqAAHMbAABzG0AAcxuAAHMcAABzHEAAcywAAHMsgABzLUAAcy3AAHMugABzLsAAcy8AAHMvQABzL4AAczAAAHMwgABzMMAAczEAAHMxgABzMcAAczUAAHM1QABzNYAAczYAAHNFwABzRkAAc0bAAHNHQABzSAAAc0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VAAHYVAAB2FYAAdhYAAHYWgAB2F0AAdheAAHYXwAB2GAAAdhhAAHYYwAB2GUAAdhmAAHYZwAB2GkAAdhqAAHYqQAB2KsAAdiuAAHYsAAB2LMAAdi0AAHYtQAB2LYAAdi3AAHYuQAB2LsAAdi8AAHYvQAB2L8AAdjAAAHZAwAB2ScAAdlLAAHZbgAB2ZUAAdm1AAHZ3AAB2gMAAdojAAHaRwAB2msAAdptAAHacAAB2nIAAdp0AAHadgAB2nkAAdp8AAHafgAB2oAAAdqDAAHahQAB2ocAAdqKAAHajQAB2o4AAdqTAAHaoAAB2qMAAdqlAAHaqAAB2qsAAdqtAAHa0gAB2vYAAdsdAAHbQQAB20QAAdtGAAHbSAAB20oAAdtMAAHbTgAB208AAdtSAAHbXwAB23IAAdt0AAHbdgAB23gAAdt6AAHbfAAB234AAduAAAHbggAB24QAAduXAAHbmgAB250AAdugAAHbowAB26YAAdupAAHbrAAB268AAduyAAHbtAAB2/MAAdv1AAHb+AAB2/oAAdv9AAHb/gAB2/8AAdwAAAHcAQAB3AMAAdwFAAHcBgAB3AcAAdwJAAHcCgAB3BMAAdwUAAHcFgAB3FUAAdxXAAHcWQAB3FsAAdxeAAHcXwAB3GAAAdxhAAHcYgAB3GQAAdxmAAHcZwAB3GgAAdxqAAHcawAB3KoAAdysAAHcrwAB3LEAAdy0AAHctQAB3LYAAdy3AAHcuAAB3LoAAdy8AAHcvQAB3L4AAdzAAAHcwQAB3MoAAdzLAAHczQAB3QwAAd0OAAHdEAAB3RIAAd0VAAHdFgAB3RcAAd0YAAHdGQAB3RsAAd0dAAHdHgAB3R8AAd0hAAHdIgAB3WEAAd1jAAHdZgAB3WgAAd1rAAHdbAAB3W0AAd1uAAHdbwAB3XEAAd1zAAHddAAB3XUAAd13AAHdeAAB3YEAAd2CAAHdhAAB3cMAAd3FAAHdxwAB3ckAAd3MAAHdzQAB3c4AAd3PAAHd0AAB3dIAAd3UAAHd1QAB3dYAAd3YAAHd2QAB3hgAAd4aAAHeHQAB3h8AAd4iAAHeIwAB3iQAAd4lAAHeJgAB3igAAd4qAAHeKwAB3iwAAd4uAAHeLwAB3jwAAd49AAHePgAB3kAAAd5/AAHegQAB3oMAAd6FAAHeiAAB3okAAd6KAAHeiwAB3owAAd6OAAHekAAB3pEAAd6SAAHelAAB3pUAAd7UAAHe1gAB3tkAAd7bAAHe3gAB3t8AAd7gAAHe4QAB3uIAAd7kAAHe5gAB3ucAAd7oAAHe6gAB3usAAd8HAAHfFAAB3xsAAd8dAAHfHwAB3yIAAd8pAAHfLAAB3y8AAd8yAAHfNAAB3zsAAd+GAAHfqQAB38kAAd/pAAHf6wAB3+0AAd/vAAHf8QAB3/QAAd/1AAHf9gAB3/kAAd/6AAHf/AAB3/0AAd//AAHgAQAB4AIAAeADAAHgBgAB4AcAAeAMAAHgGQAB4B4AAeAgAAHgIgAB4CcAAeAqAAHgLQAB4C8AAeBUAAHgeAAB4J8AAeDDAAHgxgAB4MgAAeDKAAHgzAAB4M4AAeDQAAHg0QAB4NQAAeDhAAHg8gAB4PQAAeD2AAHg+AAB4PoAAeD8AAHg/gAB4QAAAeECAAHhEwAB4RYAAeEZAAHhHAAB4R8AAeEiAAHhJQAB4SgAAeErAAHhLQAB4WwAAeFuAAHhcAAB4XIAAeF1AAHhdgAB4XcAAeF4AAHheQAB4XsAAeF9AAHhfgAB4X8AAeGBAAHhggAB4cEAAeHDAAHhxQAB4ccAAeHKAAHhywAB4cwAAeHNAAHhzgAB4dAAAeHSAAHh0wAB4dQAAeHWAAHh1wAB4hYAAeIYAAHiGwAB4h0AAeIgAAHiIQAB4iIAAeIjAAHiJAAB4iYAAeIoAAHiKQAB4ioAAeIsAAHiLQAB4joAAeI7AAHiPAAB4j4AAeJ9AAHifwAB4oEAAeKDAAHihgAB4ocAAeKIAAHiiQAB4ooAAeKMAAHijgAB4o8AAeKQAAHikgAB4pMAAeLSAAHi1AAB4tYAAeLYAAHi2wAB4twAAeLdAAHi3gAB4t8AAeLhAAHi4wAB4uQAAeLlAAHi5wAB4ugAAeMnAAHjKQAB4ysAAeMtAAHjMAAB4zEAAeMyAAHjMwAB4zQAAeM2AAHjOAAB4zkAAeM6AAHjPAAB4z0AAeN8AAHjfgAB44AAAeOCAAHjhQAB44YAAeOHAAHjiAAB44kAAeOLAAHjjQAB444AAeOPAAHjkQAB45IAAePRAAHj0wAB49UAAePXAAHj2gAB49sAAePcAAHj3QAB494AAePgAAHj4gAB4+MAAePkAAHj5gAB4+cAAeQMAAHkMAAB5FcAAeR7AAHkfgAB5IAAAeSCAAHkhAAB5IYAAeSIAAHkiQAB5IwAAeSZAAHkqAAB5KoAAeSsAAHkrgAB5LAAAeSyAAHktAAB5LYAAeTFAAHkyAAB5MsAAeTOAAHk0QAB5NQAAeTXAAHk2gAB5NwAAeUbAAHlHQAB5R8AAeUhAAHlJAAB5SUAAeUmAAHlJwAB5SgAAeUqAAHlLAAB5S0AAeUuAAHlMAAB5TEAAeVwAAHlcgAB5XQAAeV2AAHleQAB5XoAAeV7AAHlfAAB5X0AAeV/AAHlgQAB5YIAAeWDAAHlhQAB5YYAAeXFAAHlxwAB5ckAAeXLAAHlzgAB5c8AAeXQAAHl0QAB5dIAAeXUAAHl1gAB5dcAAeXYAAHl2gAB5dsAAeYaAAHmHAAB5h8AAeYhAAHmJAAB5iUAAeYmAAHmJwAB5igAAeYqAAHmLAAB5i0AAeYuAAHmMAAB5jEAAeZwAAHmcgAB5nQAAeZ2AAHmeQAB5noAAeZ7AAHmfAAB5n0AAeZ/AAHmgQAB5oIAAeaDAAHmhQAB5oYAAebFAAHmxwAB5soAAebMAAHmzwAB5tAAAebRAAHm0gAB5tMAAebVAAHm1wAB5tgAAebZAAHm2wAB5twAAecDAAHnQgAB50QAAedGAAHnSAAB50sAAedMAAHnTQAB504AAedPAAHnUQAB51MAAedUAAHnVQAB51cAAedYAAHnowAB58YAAefmAAHoBgAB6AgAAegKAAHoDAAB6A4AAegRAAHoEgAB6BMAAegWAAHoFwAB6BkAAegaAAHoHAAB6B4AAegfAAHoIAAB6CMAAegkAAHoKQAB6DYAAeg7AAHoPQAB6D8AAehEAAHoRwAB6EoAAehMAAHocQAB6JUAAei8AAHo4AAB6OMAAejlAAHo5wAB6OkAAejrAAHo7QAB6O4AAejxAAHo/gAB6Q8AAekRAAHpEwAB6RUAAekXAAHpGQAB6RsAAekdAAHpHwAB6TAAAekzAAHpNgAB6TkAAek8AAHpPwAB6UIAAelFAAHpSAAB6UoAAemJAAHpiwAB6Y0AAemPAAHpkgAB6ZMAAemUAAHplQAB6ZYAAemYAAHpmgAB6ZsAAemcAAHpngAB6Z8AAeneAAHp4AAB6eIAAenkAAHp5wAB6egAAenpAAHp6gAB6esAAentAAHp7wAB6fAAAenxAAHp8wAB6fQAAeozAAHqNQAB6jgAAeo6AAHqPQAB6j4AAeo/AAHqQAAB6kEAAepDAAHqRQAB6kYAAepHAAHqSQAB6koAAepXAAHqWAAB6lkAAepbAAHqmgAB6pwAAeqeAAHqoAAB6qMAAeqkAAHqpQAB6qYAAeqnAAHqqQAB6qsAAeqsAAHqrQAB6q8AAeqwAAHq7wAB6vEAAerzAAHq9QAB6vgAAer5AAHq+gAB6vsAAer8AAHq/gAB6wAAAesBAAHrAgAB6wQAAesFAAHrRAAB60YAAetIAAHrSgAB600AAetOAAHrTwAB61AAAetRAAHrUwAB61UAAetWAAHrVwAB61kAAetaAAHrmQAB65sAAeudAAHrnwAB66IAAeujAAHrpAAB66UAAeumAAHrqAAB66oAAeurAAHrrAAB664AAeuvAAHr7gAB6/AAAevyAAHr9AAB6/cAAev4AAHr+QAB6/oAAev7AAHr/QAB6/8AAewAAAHsAQAB7AMAAewEAAHsKQAB7E0AAex0AAHsmAAB7JsAAeydAAHsnwAB7KEAAeyjAAHspQAB7KYAAeypAAHstgAB7MUAAezHAAHsyQAB7MsAAezNAAHszwAB7NEAAezTAAHs4gAB7OUAAezoAAHs6wAB7O4AAezxAAHs9AAB7PcAAez5AAHtOAAB7ToAAe08AAHtPgAB7UEAAe1CAAHtQwAB7UQAAe1FAAHtRwAB7UkAAe1KAAHtSwAB7U0AAe1OAAHtjQAB7Y8AAe2RAAHtkwAB7ZYAAe2XAAHtmAAB7ZkAAe2aAAHtnAAB7Z4AAe2fAAHtoAAB7aIAAe2jAAHt4gAB7eQAAe3mAAHt6AAB7esAAe3sAAHt7QAB7e4AAe3vAAHt8QAB7fMAAe30AAHt9QAB7fcAAe34AAHuNwAB7jkAAe47AAHuPQAB7kAAAe5BAAHuQgAB7kMAAe5EAAHuRgAB7kgAAe5JAAHuSgAB7kwAAe5NAAHujAAB7o4AAe6QAAHukgAB7pUAAe6WAAHulwAB7pgAAe6ZAAHumwAB7p0AAe6eAAHunwAB7qEAAe6iAAHu4QAB7uMAAe7lAAHu5wAB7uoAAe7rAAHu7AAB7u0AAe7uAAHu8AAB7vIAAe7zAAHu9AAB7vYAAe73AAHvNgAB7zgAAe86AAHvPAAB7z8AAe9AAAHvQQAB70IAAe9DAAHvRQAB70cAAe9IAAHvSQAB70sAAe9MAAHvlwAB77oAAe/aAAHv+gAB7/wAAe/+AAHwAAAB8AIAAfAFAAHwBgAB8AcAAfAKAAHwCwAB8A0AAfAOAAHwEAAB8BMAAfAUAAHwFQAB8BgAAfAZAAHwHgAB8CsAAfAwAAHwMgAB8DQAAfA5AAHwPAAB8D8AAfBBAAHwZgAB8IoAAfCxAAHw1QAB8NgAAfDaAAHw3AAB8N4AAfDgAAHw4gAB8OMAAfDmAAHw8wAB8QQAAfEGAAHxCAAB8QoAAfEMAAHxDgAB8RAAAfESAAHxFAAB8SUAAfEoAAHxKwAB8S4AAfExAAHxNAAB8TcAAfE6AAHxPQAB8T8AAfF+AAHxgAAB8YIAAfGEAAHxhwAB8YgAAfGJAAHxigAB8YsAAfGNAAHxjwAB8ZAAAfGRAAHxkwAB8ZQAAfHTAAHx1QAB8dcAAfHZAAHx3AAB8d0AAfHeAAHx3wAB8eAAAfHiAAHx5AAB8eUAAfHmAAHx6AAB8ekAAfIoAAHyKgAB8i0AAfIvAAHyMgAB8jMAAfI0AAHyNQAB8jYAAfI4AAHyOgAB8jsAAfI8AAHyPgAB8j8AAfJMAAHyTQAB8k4AAfJQAAHyjwAB8pEAAfKTAAHylQAB8pgAAfKZAAHymgAB8psAAfKcAAHyngAB8qAAAfKhAAHyogAB8qQAAfKlAAHy5AAB8uYAAfLoAAHy6gAB8u0AAfLuAAHy7wAB8vAAAfLxAAHy8wAB8vUAAfL2AAHy9wAB8vkAAfL6AAHzOQAB8zsAAfM9AAHzPwAB80IAAfNDAAHzRAAB80UAAfNGAAHzSAAB80oAAfNLAAHzTAAB804AAfNPAAHzjgAB85AAAfOSAAHzlAAB85cAAfOYAAHzmQAB85oAAfObAAHznQAB858AAfOgAAHzoQAB86MAAfOkAAHz4wAB8+UAAfPnAAHz6QAB8+wAAfPtAAHz7gAB8+8AAfPwAAHz8gAB8/QAAfP1AAHz9gAB8/gAAfP5AAH0HgAB9EIAAfRpAAH0jQAB9JAAAfSSAAH0lAAB9JYAAfSYAAH0mgAB9JsAAfSeAAH0qwAB9LoAAfS8AAH0vgAB9MAAAfTCAAH0xAAB9MYAAfTIAAH01wAB9NoAAfTdAAH04AAB9OMAAfTmAAH06QAB9OwAAfTuAAH1LQAB9S8AAfUxAAH1MwAB9TYAAfU3AAH1OAAB9TkAAfU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5AAILfAACC30AAgt+AAILfwACC4AAAguCAAILhAACC4UAAguGAAILiAACC4kAAgvIAAILygACC8wAAgvOAAIL0QACC9IAAgvTAAIL1AACC9UAAgvXAAIL2QACC9oAAgvbAAIL3QACC94AAgwdAAIMHwACDCIAAgwkAAIMJwACDCgAAgwpAAIMKgACDCsAAgwtAAIMLwACDDAAAgwxAAIMMwACDDQAAgxBAAIMQgACDEMAAgxFAAIMhAACDIYAAgyIAAIMigACDI0AAgyOAAIMjwACDJAAAgyRAAIMkwACDJUAAgyWAAIMlwACDJkAAgyaAAIM2QACDNsAAgzdAAIM3wACDOIAAgzjAAIM5AACDOUAAgzmAAIM6AACDOoAAgzrAAIM7AACDO4AAgzvAAINLgACDTAAAg0yAAINNAACDTcAAg04AAINOQACDToAAg07AAINPQACDT8AAg1AAAINQQACDUMAAg1EAAINgwACDYUAAg2HAAINiQACDYwAAg2NAAINjgACDY8AAg2QAAINkgACDZQAAg2VAAINlgACDZgAAg2ZAAIN2AACDdoAAg3cAAIN3gACDeEAAg3iAAIN4wACDeQAAg3lAAIN5wACDekAAg3qAAIN6wACDe0AAg3uAAIOEwACDjcAAg5eAAIOggACDoUAAg6HAAIOiQACDosAAg6NAAIOjwACDpAAAg6TAAIOoAACDq0AAg6vAAIOsQACDrMAAg61AAIOtwACDrkAAg7GAAIOyQACDswAAg7PAAIO0gACDtUAAg7YAAIO2gACDxkAAg8bAAIPHgACDyAAAg8jAAIPJAACDyUAAg8mAAIPJwACDykAAg8rAAIPLAACDy0AAg8vAAIPMAACD28AAg9xAAIPcwACD3UAAg94AAIPeQACD3oAAg97AAIPfAACD34AAg+AAAIPgQACD4IAAg+EAAIPhQACD8QAAg/GAAIPyAACD8oAAg/NAAIPzgACD88AAg/QAAIP0QACD9MAAg/VAAIP1gACD9cAAg/ZAAIP2gACEBkAAhAbAAIQHgACECAAAhAjAAIQJAACECUAAhAmAAIQJwACECkAAhArAAIQLAACEC0AAhAvAAIQMAACEG8AAhBxAAIQcwACEHUAAhB4AAIQeQACEHoAAhB7AAIQfAACEH4AAhCAAAIQgQACEIIAAhCEAAIQhQACEMQAAhDGAAIQyAACEMoAAhDNAAIQzgACEM8AAhDQAAIQ0QACENMAAhDVAAIQ1gACENcAAhDZAAIQ2gACEOMAAhDkAAIQ5gACESUAAhEnAAIRKQACESsAAhEtAAIRLgACES8AAhEwAAIRMQACETMAAhE1AAIRNgACETcAAhE5AAIROgACEXkAAhF7AAIRfQACEX8AAhGBAAIRggACEYMAAhGEAAIRhQACEYcAAhGJAAIRigACEYsAAhGNAAIRjgACEc0AAhHPAAIR0QACEdMAAhHVAAIR1gACEdcAAhHYAAIR2QACEdsAAhHdAAIR3gACEd8AAhHhAAIR4gACEi0AAhJQAAIScAACEpAAAhKSAAISlAACEpYAAhKYAAISmgACEpsAAhKcAAISnwACEqAAAhKiAAISowACEqUAAhKnAAISqAACEqkAAhKsAAISrQACErIAAhK/AAISxAACEsYAAhLIAAISzQACEtAAAhLTAAIS1QACEvoAAhMeAAITRQACE2kAAhNsAAITbgACE3AAAhNyAAITdAACE3YAAhN3AAITegACE4cAAhOYAAITmgACE5wAAhOeAAIToAACE6IAAhOkAAITpgACE6gAAhO5AAITvAACE78AAhPCAAITxQACE8gAAhPLAAITzgACE9EAAhPTAAIUEgACFBQAAhQWAAIUGAACFBsAAhQcAAIUHQACFB4AAhQfAAIUIQACFCMAAhQkAAIUJQACFCcAAhQoAAIUZwACFGkAAhRrAAIUbQACFHAAAhRxAAIUcgACFHMAAhR0AAIUdgACFHgAAhR5AAIUegACFHwAAhR9AAIUvAACFL4AAhTBAAIUwwACFMYAAhTHAAIUyAACFMkAAhTKAAIUzAACFM4AAhTPAAIU0AACFNIAAhTTAAIU4AACFOEAAhTiAAIU5AACFSMAAhUlAAIVJwACFSkAAhUsAAIVLQACFS4AAhUvAAIVMAACFTIAAhU0AAIVNQACFTYAAhU4AAIVOQACFXgAAhV6AAIVfAACFX4AAhWBAAIVggACFYMAAhWEAAIVhQACFYcAAhWJAAIVigACFYsAAhWNAAIVjgACFc0AAhXPAAIV0QACFdMAAhXWAAIV1wACFdgAAhXZAAIV2gACFdwAAhXeAAIV3wACFeAAAhXiAAIV4wACFiIAAhYkAAIWJgACFigAAhYrAAIWLAACFi0AAhYuAAIWLwACFjEAAhYzAAIWNAACFjUAAhY3AAIWOAACFncAAhZ5AAIWewACFn0AAhaAAAIWgQACFoIAAhaDAAIWhAACFoYAAhaIAAIWiQACFooAAhaMAAIWjQACFrIAAhbWAAIW/QACFyEAAhckAAIXJgACFygAAhcqAAIXLAACFy4AAhcvAAIXMgACFz8AAhdOAAIXUAACF1IAAhdUAAIXVgACF1gAAhdaAAIXXAACF2sAAhduAAIXcQACF3QAAhd3AAIXegACF30AAheAAAIXggACF8EAAhfDAAIXxQACF8cAAhfKAAIXywACF8wAAhfNAAIXzgACF9AAAhfSAAIX0wACF9QAAhfWAAIX1wACGBYAAhgYAAIYGgACGBwAAhgfAAIYIAACGCEAAhgiAAIYIwACGCUAAhgnAAIYKAACGCkAAhgrAAIYLAACGGsAAhhtAAIYbwACGHEAAhh0AAIYdQACGHYAAhh3AAIYeAACGHoAAhh8AAIYfQACGH4AAhiAAAIYgQACGMAAAhjCAAIYxQACGMcAAhjKAAIYywACGMwAAhjNAAIYzgACGNAAAhjSAAIY0wACGNQAAhjWAAIY1wACGRYAAhkYAAIZGgACGRwAAhkfAAIZIAACGSEAAhkiAAIZIwACGSUAAhknAAIZKAACGSkAAhkrAAIZLAACGWsAAhltAAIZcAACGXIAAhl1AAIZdgACGXcAAhl4AAIZeQACGXsAAhl9AAIZfgACGX8AAhmBAAIZggACGZ4AAhndAAIZ3wACGeEAAhnjAAIZ5gACGecAAhnoAAIZ6QACGeoAAhnsAAIZ7gACGe8AAhnwAAIZ8gACGfMAAho+AAIaYQACGoEAAhqhAAIaowACGqUAAhqnAAIaqQACGqsAAhqsAAIarQACGrAAAhqxAAIaswACGrQAAhq2AAIauAACGrkAAhq6AAIavQACGr4AAhrDAAIa0AACGtUAAhrXAAIa2QACGt4AAhrhAAIa5AACGuYAAhsLAAIbLwACG1YAAht6AAIbfQACG38AAhuBAAIbgwACG4UAAhuHAAIbiAACG4sAAhuYAAIbqQACG6sAAhutAAIbrwACG7EAAhuzAAIbtQACG7cAAhu5AAIbygACG80AAhvQAAIb0wACG9YAAhvZAAIb3AACG98AAhviAAIb5AACHCMAAhwlAAIcJwACHCkAAhwsAAIcLQACHC4AAhwvAAIcMAACHDIAAhw0AAIcNQACHDYAAhw4AAIcOQACHHgAAhx6AAIcfAACHH4AAhyBAAIcggACHIMAAhyEAAIchQACHIcAAhyJAAIcigACHIsAAhyNAAIcjgACHM0AAhzPAAIc0gACHNQAAhzXAAIc2AACHNkAAhzaAAIc2wACHN0AAhzfAAIc4AACHOEAAhzjAAIc5AACHPEAAhzyAAIc8wACHPUAAh00AAIdNgACHTgAAh06AAIdPQACHT4AAh0/AAIdQAACHUEAAh1DAAIdRQACHUYAAh1HAAIdSQACHUoAAh2JAAIdiwACHY0AAh2PAAIdkgACHZMAAh2UAAIdlQACHZYAAh2YAAIdmgACHZsAAh2cAAIdngACHZ8AAh3eAAId4AACHeIAAh3kAAId5wACHegAAh3pAAId6gACHesAAh3tAAId7wACHfAAAh3xAAId8wACHfQAAh4zAAIeNQACHjcAAh45AAIePAACHj0AAh4+AAIePwACHkAAAh5CAAIeRAACHkUAAh5GAAIeSAACHkkAAh6IAAIeigACHowAAh6OAAIekQACHpIAAh6TAAIelAACHpUAAh6XAAIemQACHpoAAh6bAAIenQACHp4AAh7DAAIe5wACHw4AAh8yAAIfNQACHzcAAh85AAIfOwACHz0AAh8/AAIfQAACH0MAAh9QAAIfXwACH2EAAh9jAAIfZQACH2cAAh9pAAIfawACH20AAh98AAIffwACH4IAAh+FAAIfiAACH4sAAh+OAAIfkQACH5MAAh/SAAIf1AACH9YAAh/YAAIf2wACH9wAAh/dAAIf3gACH98AAh/hAAIf4wACH+QAAh/lAAIf5wACH+gAAiAnAAIgKQACICsAAiAtAAIgMAACIDEAAiAyAAIgMwACIDQAAiA2AAIgOAACIDkAAiA6AAIgPAACID0AAiB8AAIgfgACIIAAAiCCAAIghQACIIYAAiCHAAIgiAACIIkAAiCLAAIgjQACII4AAiCPAAIgkQACIJIAAiDRAAIg0wACINUAAiDXAAIg2gACINsAAiDcAAIg3QACIN4AAiDgAAIg4gACIOMAAiDkAAIg5gACIOcAAiEmAAIhKAACISoAAiEsAAIhLwACITAAAiExAAIhMgACITMAAiE1AAIhNwACITgAAiE5AAIhOwACITwAAiF7AAIhfQACIX8AAiGBAAIhhAACIYUAAiGGAAIhhwACIYgAAiGKAAIhjAACIY0AAiGOAAIhkAACIZEAAiHQAAIh0gACIdQAAiHWAAIh2QACIdoAAiHbAAIh3AACId0AAiHfAAIh4QACIeIAAiHjAAIh5QACIeYAAiIxAAIiVAACInQAAiKUAAIilgACIpgAAiKaAAIinAACIp4AAiKfAAIioAACIqMAAiKkAAIipgACIqcAAiKpAAIiqwACIqwAAiKtAAIisAACIrEAAiK6AAIixwACIswAAiLOAAIi0AACItUAAiLYAAIi2wACIt0AAiMCAAIjJgACI00AAiNxAAIjdAACI3YAAiN4AAIjegACI3wAAiN+AAIjfwACI4IAAiOPAAIjoAACI6IAAiOkAAIjpgACI6gAAiOqAAIjrAACI64AAiOwAAIjwQACI8QAAiPHAAIjygACI80AAiPQAAIj0wACI9YAAiPZAAIj2wACJBoAAiQcAAIkHgACJCAAAiQjAAIkJAACJCUAAiQmAAIkJwACJCkAAiQrAAIkLAACJC0AAiQvAAIkMAACJG8AAiRxAAIkcwACJHUAAiR4AAIkeQACJHoAAiR7AAIkfAACJH4AAiSAAAIkgQACJIIAAiSEAAIkhQACJMQAAiTGAAIkyQACJMsAAiTOAAIkzwACJNAAAiTRAAIk0gACJNQAAiTWAAIk1wACJNgAAiTaAAIk2wACJOgAAiTpAAIk6gACJOwAAiUrAAIlLQACJS8AAiUxAAIlNAACJTUAAiU2AAIlNwACJTgAAiU6AAIlPAACJT0AAiU+AAIlQAACJUEAAiWAAAIlggACJYQAAiWGAAIliQACJYoAAiWLAAIljAACJY0AAiWPAAIlkQACJZIAAiWTAAIllQACJZYAAiXVAAIl1wACJdkAAiXbAAIl3gACJd8AAiXgAAIl4QACJeIAAiXkAAIl5gACJecAAiXoAAIl6gACJesAAiYqAAImLAACJi4AAiYwAAImMwACJjQAAiY1AAImNgACJjcAAiY5AAImOwACJjwAAiY9AAImPwACJkAAAiZ/AAImgQACJoMAAiaFAAImiAACJokAAiaKAAImiwACJowAAiaOAAImkAACJpEAAiaSAAImlAACJpUAAia6AAIm3gACJwUAAicpAAInLAACJy4AAicwAAInMgACJzQAAic2AAInNwACJzoAAidHAAInVgACJ1gAAidaAAInXAACJ14AAidgAAInYgACJ2QAAidzAAIndgACJ3kAAid8AAInfwACJ4IAAieFAAIniAACJ4oAAifJAAInywACJ80AAifPAAIn0gACJ9MAAifUAAIn1QACJ9YAAifYAAIn2gACJ9sAAifcAAIn3gACJ98AAigeAAIoIAACKCIAAigkAAIoJwACKCgAAigpAAIoKgACKCsAAigtAAIoLwACKDAAAigxAAIoMwACKDQAAihzAAIodQACKHcAAih5AAIofAACKH0AAih+AAIofwACKIAAAiiCAAIohAACKIUAAiiGAAIoiAACKIkAAijIAAIoygACKMwAAijOAAIo0QACKNIAAijTAAIo1AACKNUAAijXAAIo2QACKNoAAijbAAIo3QACKN4AAikdAAIpHwACKSEAAikjAAIpJgACKScAAikoAAIpKQACKSoAAiksAAIpLgACKS8AAikwAAIpMgACKTMAAilyAAIpdAACKXYAAil4AAIpewACKXwAAil9AAIpfgACKX8AAimBAAIpgwACKYQAAimFAAIphwACKYgAAinHAAIpyQACKcsAAinNAAIp0AACKdEAAinSAAIp0wACKdQAAinWAAIp2AACKdkAAinaAAIp3AACKd0AAinmAAIp5wACKekAAiosAAIqUAACKnQAAiqXAAIqvgACKt4AAisFAAIrLAACK0wAAitwAAIrlAACK5YAAiuZAAIrmwACK50AAiufAAIrogACK6UAAiunAAIrqQACK6wAAiuuAAIrsAACK7MAAiu2AAIrtwACK7wAAivJAAIrzAACK84AAivRAAIr1AACK9YAAiv7AAIsHwACLEYAAixqAAIsbQACLG8AAixxAAIscwACLHUAAix3AAIseAACLHsAAiyIAAIsmwACLJ0AAiyfAAIsoQACLKMAAiylAAIspwACLKkAAiyrAAIsrQACLMAAAizDAAIsxgACLMkAAizMAAIszwACLNIAAizVAAIs2AACLNsAAizdAAItHAACLR4AAi0hAAItIwACLSYAAi0nAAItKAACLSkAAi0qAAItLAACLS4AAi0vAAItMAACLTIAAi0zAAItPAACLT0AAi0/AAItfgACLYAAAi2CAAIthAACLYcAAi2IAAItiQACLYoAAi2LAAItjQACLY8AAi2QAAItkQACLZMAAi2UAAIt0wACLdUAAi3YAAIt2gACLd0AAi3eAAIt3wACLeAAAi3hAAIt4wACLeUAAi3mAAIt5wACLekAAi3qAAIt8wACLfQAAi32AAIuNQACLjcAAi45AAIuOwACLj4AAi4/AAIuQAACLkEAAi5CAAIuRAACLkYAAi5HAAIuSAACLkoAAi5LAAIuigACLowAAi6PAAIukQACLpQAAi6VAAIulgACLpcAAi6YAAIumgACLpwAAi6dAAIungACLqAAAi6hAAIuqgACLqsAAi6tAAIu7AACLu4AAi7wAAIu8gACLvUAAi72AAIu9wACLvgAAi75AAIu+wACLv0AAi7+AAIu/wACLwEAAi8CAAIvQQACL0MAAi9GAAIvSAACL0sAAi9MAAIvTQACL04AAi9PAAIvUQACL1MAAi9UAAIvVQACL1cAAi9YAAIvZQACL2YAAi9nAAIvaQACL6gAAi+qAAIvrAACL64AAi+xAAIvsgACL7MAAi+0AAIvtQACL7cAAi+5AAIvugACL7sAAi+9AAIvvgACL/0AAi//AAIwAgACMAQAAjAHAAIwCAACMAkAAjAKAAIwCwACMA0AAjAPAAIwEAACMBEAAjATAAIwFAACMCIAAjAvAAIwNAACMDcAAjA6AAIwPwACMEIAAjBFAAIwRwACME8AAjBaAAIwpQACMMgAAjDoAAIxCAACMQoAAjEMAAIxDgACMRAAAjETAAIxFAACMRUAAjEYAAIxGQACMRsAAjEcAAIxHgACMSEAAjEiAAIxIwACMSYAAjEnAAIxMAACMT0AAjFCAAIxRAACMUYAAjFLAAIxTgACMVEAAjFTAAIxeAACMZwAAjHDAAIx5wACMeoAAjHsAAIx7gACMfAAAjHyAAIx9AACMfUAAjH4AAIyBQACMhYAAjIYAAIyGgACMhwAAjIeAAIyIAACMiIAAjIkAAIyJgACMjcAAjI6AAIyPQACMkAAAjJDAAIyRgACMkkAAjJMAAIyTwACMlEAAjKQAAIykgACMpQAAjKWAAIymQACMpoAAjKbAAIynAACMp0AAjKfAAIyoQACMqIAAjKjAAIypQACMqYAAjLlAAIy5wACMukAAjLrAAIy7gACMu8AAjLwAAIy8QACMvIAAjL0AAIy9gACMvcAAjL4AAIy+gACMvsAAjM6AAIzPAACMz8AAjNBAAIzRAACM0UAAjNGAAIzRwACM0gAAjNKAAIzTAACM00AAjNOAAIzUAACM1EAAjNeAAIzXwACM2AAAjNiAAIzoQACM6MAAjOlAAIzpwACM6oAAjOrAAIzrAACM60AAjOuAAIzsAACM7IAAjOzAAIztAACM7YAAjO3AAIz9gACM/gAAjP6AAIz/AACM/8AAjQAAAI0AQACNAIAAjQDAAI0BQACNAcAAjQIAAI0CQACNAsAAjQMAAI0SwACNE0AAjRPAAI0UQACNFQAAjRVAAI0VgACNFcAAjRYAAI0WgACNFwAAjRdAAI0XgACNGAAAjRhAAI0oAACNKIAAjSkAAI0pgACNKkAAjSqAAI0qwACNKwAAjStAAI0rwACNLEAAjSyAAI0swACNLUAAjS2AAI09QACNPcAAjT5AAI0+wACNP4AAjT/AAI1AAACNQEAAjUCAAI1BAACNQYAAjUHAAI1CAACNQoAAjULAAI1MAACNVQAAjV7AAI1nwACNaIAAjWkAAI1pgACNagAAjWqAAI1rAACNa0AAjWwAAI1vQACNcwAAjXOAAI10AACNdIAAjXUAAI11gACNdgAAjXaAAI16QACNewAAjXvAAI18gACNfUAAjX4AAI1+wACNf4AAjYAAAI2PwACNkEAAjZDAAI2RQACNkgAAjZJAAI2SgACNksAAjZMAAI2TgACNlAAAjZRAAI2UgACNlQAAjZVAAI2lAACNpYAAjaYAAI2mgACNp0AAjaeAAI2nwACNqAAAjahAAI2owACNqUAAjamAAI2pwACNqkAAjaqAAI26QACNusAAjbtAAI27wACNvIAAjbzAAI29AACNvUAAjb2AAI2+AACNvoAAjb7AAI2/AACNv4AAjb/AAI3PgACN0AAAjdDAAI3RQACN0gAAjdJAAI3SgACN0sAAjdMAAI3TgACN1AAAjdRAAI3UgACN1QAAjdVAAI3WAACN5cAAjeZAAI3mwACN50AAjegAAI3oQACN6IAAjejAAI3pAACN6YAAjeoAAI3qQACN6oAAjesAAI3rQACN+wAAjfuAAI38AACN/IAAjf1AAI39gACN/cAAjf4AAI3+QACN/sAAjf9AAI3/gACN/8AAjgBAAI4AgACOEEAAjhDAAI4RQACOEcAAjhKAAI4SwACOEwAAjhNAAI4TgACOFAAAjhSAAI4UwACOFQAAjhWAAI4VwACOKIAAjjFAAI45QACOQUAAjkHAAI5CQACOQsAAjkNAAI5EAACOREAAjkSAAI5FQACORYAAjkYAAI5GQACORsAAjkeAAI5HwACOSAAAjkjAAI5JAACOSkAAjk2AAI5OwACOT0AAjk/AAI5RAACOUcAAjlKAAI5TAACOXEAAjmVAAI5vAACOeAAAjnjAAI55QACOecAAjnpAAI56wACOe0AAjnuAAI58QACOf4AAjoPAAI6EQACOhMAAjoVAAI6FwACOhkAAjobAAI6HQACOh8AAjowAAI6MwACOjYAAjo5AAI6PAACOj8AAjpCAAI6RQACOkgAAjpKAAI6iQACOosAAjqNAAI6jwACOpIAAjqTAAI6lAACOpUAAjqWAAI6mAACOpoAAjqbAAI6nAACOp4AAjqfAAI63gACOuAAAjriAAI65AACOucAAjroAAI66QACOuoAAjrrAAI67QACOu8AAjrwAAI68QACOvMAAjr0AAI7MwACOzUAAjs4AAI7OgACOz0AAjs+AAI7PwACO0AAAjtBAAI7QwACO0UAAjtGAAI7RwACO0kAAjtKAAI7VwACO1gAAjtZAAI7WwACO5oAAjucAAI7ngACO6AAAjujAAI7pAACO6UAAjumAAI7pwACO6kAAjurAAI7rAACO60AAjuvAAI7sAACO+8AAjvxAAI78wACO/UAAjv4AAI7+QACO/oAAjv7AAI7/AACO/4AAjwAAAI8AQACPAIAAjwEAAI8BQACPEQAAjxGAAI8SAACPEoAAjxNAAI8TgACPE8AAjxQAAI8UQACPFMAAjxVAAI8VgACPFcAAjxZAAI8WgACPJkAAjybAAI8nQACPJ8AAjyiAAI8owACPKQAAjylAAI8pgACPKgAAjyqAAI8qwACPKwAAjyuAAI8rwACPO4AAjzwAAI88gACPPQAAjz3AAI8+AACPPkAAjz6AAI8+wACPP0AAjz/AAI9AAACPQEAAj0DAAI9BAACPSkAAj1NAAI9dAACPZgAAj2bAAI9nQACPZ8AAj2hAAI9owACPaUAAj2mAAI9qQACPbYAAj3FAAI9xwACPckAAj3LAAI9zQACPc8AAj3RAAI90wACPeIAAj3lAAI96AACPesAAj3uAAI98QACPfQAAj33AAI9+QACPjgAAj46AAI+PAACPj4AAj5BAAI+QgACPkMAAj5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FAAJVRgACVYUAAlWHAAJViQACVYsAAlWOAAJVjwACVZAAAlWRAAJVkgACVZQAAlWWAAJVlwACVZgAAlWaAAJVmwACVdoAAlXcAAJV3gACVeAAAlXjAAJV5AACVeUAAlXmAAJV5wACVekAAlXrAAJV7AACVe0AAlXvAAJV8AACVi8AAlYxAAJWMwACVjUAAlY4AAJWOQACVjoAAlY7AAJWPAACVj4AAlZAAAJWQQACVkIAAlZEAAJWRQACVoQAAlaGAAJWiAACVooAAlaNAAJWjgACVo8AAlaQAAJWkQACVpMAAlaVAAJWlgACVpcAAlaZAAJWmgACVtkAAlbbAAJW3QACVt8AAlbiAAJW4wACVuQAAlblAAJW5gACVugAAlbqAAJW6wACVuwAAlbuAAJW7wACVzoAAlddAAJXfQACV50AAlefAAJXoQACV6MAAlelAAJXqAACV6kAAleqAAJXrQACV64AAlewAAJXsQACV7MAAle2AAJXtwACV7gAAle7AAJXvAACV8EAAlfOAAJX0wACV9UAAlfXAAJX3AACV98AAlfiAAJX5AACWAkAAlgtAAJYVAACWHgAAlh7AAJYfQACWH8AAliBAAJYgwACWIUAAliGAAJYiQACWJYAAlinAAJYqQACWKsAAlitAAJYrwACWLEAAlizAAJYtQACWLcAAljIAAJYywACWM4AAljRAAJY1AACWNcAAljaAAJY3QACWOAAAljiAAJZIQACWSMAAlklAAJZJwACWSoAAlkrAAJZLAACWS0AAlkuAAJZMAACWTIAAlkzAAJZNAACWTYAAlk3AAJZdgACWXgAAll6AAJZfAACWX8AAlmAAAJZgQACWYIAAlmDAAJZhQACWYcAAlmIAAJZiQACWYsAAlmMAAJZywACWc0AAlnQAAJZ0gACWdUAAlnWAAJZ1wACWdgAAlnZAAJZ2wACWd0AAlneAAJZ3wACWeEAAlniAAJZ7wACWfAAAlnxAAJZ8wACWjIAAlo0AAJaNgACWjgAAlo7AAJaPAACWj0AAlo+AAJaPwACWkEAAlpDAAJaRAACWkUAAlpHAAJaSAACWocAAlqJAAJaiwACWo0AAlqQAAJakQACWpIAAlqTAAJalAACWpYAAlqYAAJamQACWpoAAlqcAAJanQACWtwAAlreAAJa4AACWuIAAlrlAAJa5gACWucAAlroAAJa6QACWusAAlrtAAJa7gACWu8AAlrxAAJa8gACWzEAAlszAAJbNQACWzcAAls6AAJbOwACWzwAAls9AAJbPgACW0AAAltCAAJbQwACW0QAAltGAAJbRwACW4YAAluIAAJbigACW4wAAluPAAJbkAACW5EAAluSAAJbkwACW5UAAluXAAJbmAACW5kAAlubAAJbnAACW8EAAlvlAAJcDAACXDAAAlwzAAJcNQACXDcAAlw5AAJcOwACXD0AAlw+AAJcQQACXE4AAlxdAAJcXwACXGEAAlxjAAJcZQACXGcAAlxpAAJcawACXHoAAlx9AAJcgAACXIMAAlyGAAJciQACXIwAAlyPAAJckQACXNAAAlzSAAJc1AACXNYAAlzZAAJc2gACXNsAAlzcAAJc3QACXN8AAlzhAAJc4gACXOMAAlzlAAJc5gACXSUAAl0nAAJdKQACXSsAAl0uAAJdLwACXTAAAl0xAAJdMgACXTQAAl02AAJdNwACXTgAAl06AAJdOwACXXoAAl18AAJdfgACXYAAAl2DAAJdhAACXYUAAl2GAAJdhwACXYkAAl2LAAJdjAACXY0AAl2PAAJdkAACXc8AAl3RAAJd1AACXdYAAl3ZAAJd2gACXdsAAl3cAAJd3QACXd8AAl3hAAJd4gACXeMAAl3lAAJd5gACXekAAl4oAAJeKgACXiwAAl4uAAJeMQACXjIAAl4zAAJeNAACXjUAAl43AAJeOQACXjoAAl47AAJePQACXj4AAl59AAJefwACXoEAAl6DAAJehgACXocAAl6IAAJeiQACXooAAl6MAAJejgACXo8AAl6QAAJekgACXpMAAl7SAAJe1AACXtYAAl7YAAJe2wACXtwAAl7dAAJe3gACXt8AAl7hAAJe4wACXuQAAl7lAAJe5wACXugAAl8zAAJfVgACX3YAAl+WAAJfmAACX5oAAl+cAAJfngACX6EAAl+iAAJfowACX6YAAl+nAAJfqQACX6oAAl+sAAJfrwACX7AAAl+xAAJftAACX7UAAl+6AAJfxwACX8wAAl/OAAJf0AACX9UAAl/YAAJf2wACX90AAmACAAJgJgACYE0AAmBxAAJgdAACYHYAAmB4AAJgegACYHwAAmB+AAJgfwACYIIAAmCPAAJgoAACYKIAAmCkAAJgpgACYKgAAmCqAAJgrAACYK4AAmCwAAJgwQACYMQAAmDHAAJgygACYM0AAmDQAAJg0wACYNYAAmDZAAJg2wACYRoAAmEcAAJhHgACYSAAAmEjAAJhJAACYSUAAmEmAAJhJwACYSkAAmErAAJhLAACYS0AAmEvAAJhMAACYW8AAmFxAAJhcwACYXUAAmF4AAJheQACYXoAAmF7AAJhfAACYX4AAmGAAAJhgQACYYIAAmGEAAJhhQACYcQAAmHGAAJhyQACYcsAAmHOAAJhzwACYdAAAmHRAAJh0gACYdQAAmHWAAJh1wACYdgAAmHaAAJh2wACYegAAmHpAAJh6gACYewAAmIrAAJiLQACYi8AAmIxAAJiNAACYjUAAmI2AAJiNwACYjgAAmI6AAJiPAACYj0AAmI+AAJiQAACYkEAAmKAAAJiggACYoQAAmKGAAJiiQACYooAAmKLAAJijAACYo0AAmKPAAJikQACYpIAAmKTAAJilQACYpYAAmLVAAJi1wACYtkAAmLbAAJi3gACYt8AAmLgAAJi4QACYuIAAmLkAAJi5gACYucAAmLoAAJi6gACYusAAmMqAAJjLAACYy4AAmMwAAJjMwACYzQAAmM1AAJjNgACYzcAAmM5AAJjOwACYzwAAmM9AAJjPwACY0AAAmN/AAJjgQACY4MAAmOFAAJjiAACY4kAAmOKAAJjiwACY4wAAmOOAAJjkAACY5EAAmOSAAJjlAACY5UAAmO6AAJj3gACZAUAAmQpAAJkLAACZC4AAmQwAAJkMgACZDQAAmQ2AAJkNwACZDoAAmRHAAJkVgACZFgAAmRaAAJkXAACZF4AAmRgAAJkYgACZGQAAmRzAAJkdgACZHkAAmR8AAJkfwACZIIAAmSFAAJkiAACZIoAAmTJAAJkywACZM0AAmTPAAJk0gACZNMAAmTUAAJk1QACZNYAAmTYAAJk2gACZNsAAmTcAAJk3gACZN8AAmUeAAJlIAACZSIAAmUkAAJlJwACZSgAAmUpAAJlKgACZSsAAmUtAAJlLwACZTAAAmUxAAJlMwACZTQAAmVzAAJldQACZXcAAmV5AAJlfAACZX0AAmV+AAJlfwACZYAAAmWCAAJlhAACZYUAAmWGAAJliAACZYkAAmXIAAJlygACZcwAAmXOAAJl0QACZdIAAmXTAAJl1AACZdUAAmXXAAJl2QACZdoAAmXbAAJl3QACZd4AAmYdAAJmHwACZiEAAmYjAAJmJgACZicAAmYoAAJmKQACZioAAmYsAAJmLgACZi8AAmYwAAJmMgACZjMAAmZyAAJmdAACZnYAAmZ4AAJmewACZnwAAmZ9AAJmfgACZn8AAmaBAAJmgwACZoQAAmaFAAJmhwACZogAAmbHAAJmyQACZssAAmbNAAJm0AACZtEAAmbSAAJm0wACZtQAAmbWAAJm2AACZtkAAmbaAAJm3AACZt0AAmcoAAJnSwACZ2sAAmeLAAJnjQACZ48AAmeRAAJnkwACZ5YAAmeXAAJnmAACZ5sAAmecAAJnngACZ58AAmehAAJnpAACZ6UAAmemAAJnqQACZ6oAAmezAAJnwAACZ8UAAmfHAAJnyQACZ84AAmfRAAJn1AACZ9YAAmf7AAJoHwACaEYAAmhqAAJobQACaG8AAmhxAAJocwACaHUAAmh3AAJoeAACaHsAAmiIAAJomQACaJsAAmidAAJonwACaKEAAmijAAJopQACaKcAAmipAAJougACaL0AAmjAAAJowwACaMYAAmjJAAJozAACaM8AAmjSAAJo1AACaRMAAmkVAAJpFwACaRkAAmkcAAJpHQACaR4AAmkfAAJpIAACaSIAAmkkAAJpJQACaSYAAmkoAAJpKQACaWgAAmlqAAJpbAACaW4AAmlxAAJpcgACaXMAAml0AAJpdQACaXcAAml5AAJpegACaXsAAml9AAJpfgACab0AAmm/AAJpwgACacQAAmnHAAJpyAACackAAmnKAAJpywACac0AAmnPAAJp0AACadEAAmnTAAJp1AACaeEAAmniAAJp4wACaeUAAmokAAJqJgACaigAAmoqAAJqLQACai4AAmovAAJqMAACajEAAmozAAJqNQACajYAAmo3AAJqOQACajoAAmp5AAJqewACan0AAmp/AAJqggACaoMAAmqEAAJqhQACaoYAAmqIAAJqigACaosAAmqMAAJqjgACao8AAmrOAAJq0AACatIAAmrUAAJq1wACatgAAmrZAAJq2gACatsAAmrdAAJq3wACauAAAmrhAAJq4wACauQAAmsjAAJrJQACaycAAmspAAJrLAACay0AAmsuAAJrLwACazAAAmsyAAJrNAACazUAAms2AAJrOAACazkAAmt4AAJregACa3wAAmt+AAJrgQACa4IAAmuDAAJrhAACa4UAAmuHAAJriQACa4oAAmuLAAJrjQACa44AAmuzAAJr1wACa/4AAmwiAAJsJQACbCcAAmwpAAJsKwACbC0AAmwvAAJsMAACbDMAAmxAAAJsTwACbFEAAmxTAAJsVQACbFcAAmxZAAJsWwACbF0AAmxsAAJsbwACbHIAAmx1AAJseAACbHsAAmx+AAJsgQACbIMAAmzCAAJsxAACbMYAAmzIAAJsywACbMwAAmzNAAJszgACbM8AAmzRAAJs0wACbNQAAmzVAAJs1wACbNgAAm0XAAJtGQACbRsAAm0dAAJtIAACbSEAAm0iAAJtIwACbSQAAm0mAAJtKAACbSkAAm0qAAJtLAACbS0AAm1sAAJtbgACbXAAAm1yAAJtdQACbXYAAm13AAJteAACbXkAAm17AAJtfQACbX4AAm1/AAJtgQACbYIAAm3BAAJtwwACbcUAAm3HAAJtygACbcsAAm3MAAJtzQACbc4AAm3QAAJt0gACbdMAAm3UAAJt1gACbdcAAm4WAAJuGAACbhoAAm4cAAJuHwACbiAAAm4hAAJuIgACbiMAAm4lAAJuJwACbigAAm4pAAJuKwACbiwAAm5rAAJubQACbm8AAm5xAAJudAACbnUAAm52AAJudwACbngAAm56AAJufAACbn0AAm5+AAJugAACboEAAm7AAAJuwgACbsQAAm7GAAJuyQACbsoAAm7LAAJuzAACbs0AAm7PAAJu0QACbtIAAm7TAAJu1QACbtYAAm7fAAJu4AACbuIAAm8lAAJvSQACb20AAm+QAAJvtwACb9cAAm/+AAJwJQACcEUAAnBpAAJwjQACcI8AAnCSAAJwlAACcJYAAnCYAAJwmwACcJ4AAnCgAAJwogACcKUAAnCnAAJwqQACcKwAAnCvAAJwsAACcLUAAnDCAAJwxQACcMcAAnDKAAJwzQACcM8AAnD0AAJxGAACcT8AAnFjAAJxZgACcWgAAnFqAAJxbAACcW4AAnFwAAJxcQACcXQAAnGBAAJxlAACcZYAAnGYAAJxmgACcZwAAnGeAAJxoAACcaIAAnGkAAJxpgACcbkAAnG8AAJxvwACccIAAnHFAAJxyAACccsAAnHOAAJx0QACcdQAAnHWAAJyFQACchcAAnIaAAJyHAACch8AAnIgAAJyIQACciIAAnIjAAJyJQACcicAAnIoAAJyKQACcisAAnI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8AAKDPgACg0AAAoNCAAKDRAACg0YAAoNIAAKDSgACg1kAAoNcAAKDXwACg2IAAoNlAAKDaAACg2sAAoNuAAKDcAACg68AAoOxAAKDswACg7UAAoO4AAKDuQACg7oAAoO7AAKDvAACg74AAoPAAAKDwQACg8IAAoPEAAKDxQAChAQAAoQGAAKECAAChAoAAoQNAAKEDgAChA8AAoQQAAKEEQAChBMAAoQVAAKEFgAChBcAAoQZAAKEGgAChFkAAoRbAAKEXQAChF8AAoRiAAKEYwAChGQAAoRlAAKEZgAChGgAAoRqAAKEawAChGwAAoRuAAKEbwAChK4AAoSwAAKEswAChLUAAoS4AAKEuQAChLoAAoS7AAKEvAAChL4AAoTAAAKEwQAChMIAAoTEAAKExQAChQQAAoUGAAKFCAAChQoAAoUNAAKFDgAChQ8AAoUQAAKFEQAChRMAAoUVAAKFFgAChRcAAoUZAAKFGgAChVkAAoVbAAKFXgAChWAAAoVjAAKFZAAChWUAAoVmAAKFZwAChWkAAoVrAAKFbAAChW0AAoVvAAKFcAAChZcAAoXWAAKF2AAChdoAAoXcAAKF3wACheAAAoXhAAKF4gACheMAAoXlAAKF5wAChegAAoXpAAKF6wAChewAAoY3AAKGWgAChnoAAoaaAAKGnAAChp4AAoagAAKGogAChqUAAoamAAKGpwAChqoAAoarAAKGrQAChq4AAoawAAKGswAChrQAAoa1AAKGuAAChrkAAoa+AAKGywAChtAAAobSAAKG1AAChtkAAobcAAKG3wAChuEAAocGAAKHKgACh1EAAod1AAKHeAACh3oAAod8AAKHfgACh4AAAoeCAAKHgwACh4YAAoeTAAKHpAACh6YAAoeoAAKHqgACh6wAAoeuAAKHsAACh7IAAoe0AAKHxQACh8gAAofLAAKHzgACh9EAAofUAAKH1wACh9oAAofdAAKH3wACiB4AAoggAAKIIgACiCQAAognAAKIKAACiCkAAogqAAKIKwACiC0AAogvAAKIMAACiDEAAogzAAKINAACiHMAAoh1AAKIdwACiHkAAoh8AAKIfQACiH4AAoh/AAKIgAACiIIAAoiEAAKIhQACiIYAAoiIAAKIiQACiMgAAojKAAKIzQACiM8AAojSAAKI0wACiNQAAojVAAKI1gACiNgAAojaAAKI2wACiNwAAojeAAKI3wACiOwAAojtAAKI7gACiPAAAokvAAKJMQACiTMAAok1AAKJOAACiTkAAok6AAKJOwACiTwAAok+AAKJQAACiUEAAolCAAKJRAACiUUAAomEAAKJhgACiYgAAomKAAKJjQACiY4AAomPAAKJkAACiZEAAomTAAKJlQACiZYAAomXAAKJmQACiZoAAonZAAKJ2wACid0AAonfAAKJ4gACieMAAonkAAKJ5QACieYAAonoAAKJ6gACiesAAonsAAKJ7gACie8AAoouAAKKMAACijIAAoo0AAKKNwACijgAAoo5AAKKOgACijsAAoo9AAKKPwACikAAAopBAAKKQwACikQAAoqDAAKKhQACiocAAoqJAAKKjAACio0AAoqOAAKKjwACipAAAoqSAAKKlAACipUAAoqWAAKKmAACipkAAoq+AAKK4gACiwkAAostAAKLMAACizIAAos0AAKLNgACizgAAos6AAKLOwACiz4AAotLAAKLWgACi1wAAoteAAKLYAACi2IAAotkAAKLZgACi2gAAot3AAKLegACi30AAouAAAKLgwACi4YAAouJAAKLjAACi44AAovNAAKLzwACi9EAAovTAAKL1gACi9cAAovYAAKL2QACi9oAAovcAAKL3gACi98AAovgAAKL4gACi+MAAowiAAKMJAACjCYAAowoAAKMKwACjCwAAowtAAKMLgACjC8AAowxAAKMMwACjDQAAow1AAKMNwACjDgAAox3AAKMeQACjHsAAox9AAKMgAACjIEAAoyCAAKMgwACjIQAAoyGAAKMiAACjIkAAoyKAAKMjAACjI0AAozMAAKMzgACjNAAAozSAAKM1QACjNYAAozXAAKM2AACjNkAAozbAAKM3QACjN4AAozfAAKM4QACjOIAAo0hAAKNIwACjSUAAo0nAAKNKgACjSsAAo0sAAKNLQACjS4AAo0wAAKNMgACjTMAAo00AAKNNgACjTcAAo12AAKNeAACjXoAAo18AAKNfwACjYAAAo2BAAKNggACjYMAAo2FAAKNhwACjYgAAo2JAAKNiwACjYwAAo3LAAKNzQACjc8AAo3RAAKN1AACjdUAAo3WAAKN1wACjdgAAo3aAAKN3AACjd0AAo3eAAKN4AACjeEAAo4sAAKOTwACjm8AAo6PAAKOkQACjpMAAo6VAAKOlwACjpoAAo6bAAKOnAACjp8AAo6gAAKOogACjqMAAo6lAAKOqAACjqkAAo6qAAKOrQACjq4AAo6zAAKOwAACjsUAAo7HAAKOyQACjs4AAo7RAAKO1AACjtYAAo77AAKPHwACj0YAAo9qAAKPbQACj28AAo9xAAKPcwACj3UAAo93AAKPeAACj3sAAo+IAAKPmQACj5sAAo+dAAKPnwACj6EAAo+jAAKPpQACj6cAAo+pAAKPugACj70AAo/AAAKPwwACj8YAAo/JAAKPzAACj88AAo/SAAKP1AACkBMAApAVAAKQFwACkBkAApAcAAKQHQACkB4AApAfAAKQIAACkCIAApAkAAKQJQACkCYAApAoAAKQKQACkGgAApBqAAKQbAACkG4AApBxAAKQcgACkHMAApB0AAKQdQACkHcAApB5AAKQegACkHsAApB9AAKQfgACkL0AApC/AAKQwgACkMQAApDHAAKQyAACkMkAApDKAAKQywACkM0AApDPAAKQ0AACkNEAApDTAAKQ1AACkOEAApDiAAKQ4wACkOUAApEkAAKRJgACkSgAApEqAAKRLQACkS4AApEvAAKRMAACkTEAApEzAAKRNQACkTYAApE3AAKROQACkToAApF5AAKRewACkX0AApF/AAKRggACkYMAApGEAAKRhQACkYYAApGIAAKRigACkYsAApGMAAKRjgACkY8AApHOAAKR0AACkdIAApHUAAKR1wACkdgAApHZAAKR2gACkdsAApHdAAKR3wACkeAAApHhAAKR4wACkeQAApIjAAKSJQACkicAApIpAAKSLAACki0AApIuAAKSLwACkjAAApIyAAKSNAACkjUAApI2AAKSOAACkjkAApJ4AAKSegACknwAApJ+AAKSgQACkoIAApKDAAKShAACkoUAApKHAAKSiQACkooAApKLAAKSjQACko4AApKzAAKS1wACkv4AApMiAAKTJQACkycAApMpAAKTKwACky0AApMvAAKTMAACkzMAApNAAAKTTQACk08AApNRAAKTUwACk1UAApNXAAKTWQACk2YAApNpAAKTbAACk28AApNyAAKTdQACk3gAApN6AAKTuQACk7sAApO+AAKTwAACk8MAApPEAAKTxQACk8YAApPHAAKTyQACk8sAApPMAAKTzQACk88AApPQAAKUEwAClDcAApRbAAKUfgAClKUAApTFAAKU7AAClRMAApUzAAKVVwAClXsAApV9AAKVgAAClYIAApWEAAKVhgAClYkAApWMAAKVjgAClZAAApWTAAKVlQAClZcAApWaAAKVnQAClZ4AApWjAAKVsAAClbMAApW1AAKVuAAClbsAApW9AAKV4gAClgYAApYtAAKWUQACllQAApZWAAKWWAAClloAApZcAAKWXgACll8AApZiAAKWbwACloIAApaEAAKWhgAClogAApaKAAKWjAAClo4AApaQAAKWkgAClpQAApanAAKWqgAClq0AApawAAKWswAClrYAApa5AAKWvAAClr8AApbCAAKWxAAClwMAApcFAAKXCAAClwoAApcNAAKXDgAClw8AApcQAAKXEQAClxMAApcVAAKXFgAClxcAApcZAAKXGgAClyMAApckAAKXJgACl2UAApdnAAKXaQACl2sAApduAAKXbwACl3AAApdxAAKXcgACl3QAApd2AAKXdwACl3gAApd6AAKXewACl7oAApe8AAKXvwACl8EAApfEAAKXxQACl8YAApfHAAKXyAACl8oAApfMAAKXzQACl84AApfQAAKX0QACl9oAApfbAAKX3QACmBwAApgeAAKYIAACmCIAApglAAKYJgACmCcAApgoAAKYKQACmCsAApgtAAKYLgACmC8AApgxAAKYMgACmHEAAphzAAKYdgACmHgAAph7AAKYfAACmH0AAph+AAKYfwACmIEAApiDAAKYhAACmIUAApiHAAKYiAACmJEAApiSAAKYlAACmNMAApjVAAKY1wACmNkAApjcAAKY3QACmN4AApjfAAKY4AACmOIAApjkAAKY5QACmOYAApjoAAKY6QACmSgAApkqAAKZLQACmS8AApkyAAKZMwACmTQAApk1AAKZNgACmTgAApk6AAKZOwACmTwAApk+AAKZPwACmUwAAplNAAKZTgACmVAAApmPAAKZkQACmZMAApmVAAKZmAACmZkAApmaAAKZmwACmZwAApmeAAKZoAACmaEAApmiAAKZpAACmaUAApnkAAKZ5gACmekAApnrAAKZ7gACme8AApnwAAKZ8QACmfIAApn0AAKZ9gACmfcAApn4AAKZ+gACmfsAApoKAAKaFwACmh4AApohAAKaIwACmiYAApotAAKaMAACmjMAApo2AAKaOAACmkAAAppFAAKakAACmrMAAprTAAKa8wACmvUAApr3AAKa+QACmvsAApr+AAKa/wACmwAAApsDAAKbBAACmwYAApsHAAKbCQACmwwAApsNAAKbDgACmxEAApsSAAKbFwACmyQAApspAAKbKwACmy0AApsyAAKbNQACmzgAAps6AAKbXwACm4MAApuqAAKbzgACm9EAApvTAAKb1QACm9cAApvZAAKb2wACm9wAApvfAAKb7AACm/0AApv/AAKcAQACnAMAApwFAAKcBwACnAkAApwLAAKcDQACnB4AApwhAAKcJAACnCcAApwqAAKcLQACnDAAApwzAAKcNgACnDgAApx3AAKceQACnHsAApx9AAKcgAACnIEAApyCAAKcgwACnIQAApyGAAKciAACnIkAApyKAAKcjAACnI0AApzMAAKczgACnNAAApzSAAKc1QACnNYAApzXAAKc2AACnNkAApzbAAKc3QACnN4AApzfAAKc4QACnOIAAp0hAAKdIwACnSYAAp0oAAKdKwACnSwAAp0tAAKdLgACnS8AAp0xAAKdMwACnTQAAp01AAKdNwACnTgAAp1FAAKdRgACnUcAAp1JAAKdiAACnYoAAp2MAAKdjgACnZEAAp2SAAKdkwACnZQAAp2VAAKdlwACnZkAAp2aAAKdmwACnZ0AAp2eAAKd3QACnd8AAp3hAAKd4wACneYAAp3nAAKd6AACnekAAp3qAAKd7AACne4AAp3vAAKd8AACnfIAAp3zAAKeMgACnjQAAp42AAKeOAACnjsAAp48AAKePQACnj4AAp4/AAKeQQACnkMAAp5EAAKeRQACnkcAAp5IAAKehwACnokAAp6LAAKejQACnpAAAp6RAAKekgACnpMAAp6UAAKelgACnpgAAp6ZAAKemgACnpwAAp6dAAKe3AACnt4AAp7gAAKe4gACnuUAAp7mAAKe5wACnugAAp7pAAKe6wACnu0AAp7uAAKe7wACnvEAAp7yAAKfFwACnzsAAp9iAAKfhgACn4kAAp+LAAKfjQACn48AAp+RAAKfkwACn5QAAp+XAAKfpAACn7MAAp+1AAKftwACn7kAAp+7AAKfvQACn78AAp/BAAKf0AACn9MAAp/WAAKf2QACn9wAAp/fAAKf4gACn+UAAp/nAAKgJgACoCgAAqAqAAKgLAACoC8AAqAwAAKgMQACoDIAAqAzAAKgNQACoDcAAqA4AAKgOQACoDsAAqA8AAKgewACoH0AAqB/AAKggQACoIQAAqCFAAKghgACoIcAAqCIAAKgigACoIwAAqCNAAKgjgACoJAAAqCRAAKg0AACoNIAAqDUAAKg1gACoNkAAqDaAAKg2wACoNwAAqDdAAKg3wACoOEAAqDiAAKg4wACoOUAAqDmAAKhJQACoScAAqEpAAKhKwACoS4AAqEvAAKhMAACoTEAAqEyAAKhNAACoTYAAqE3AAKhOAACoToAAqE7AAKhegACoXwAAqF+AAKhgAACoYMAAqGEAAKhhQACoYYAAqGHAAKhiQACoYsAAqGMAAKhjQACoY8AAqGQAAKhzwACodEAAqHTAAKh1QACodgAAqHZAAKh2gACodsAAqHcAAKh3gACoeAAAqHhAAKh4gACoeQAAqHlAAKiJAACoiYAAqIoAAKiKgACoi0AAqIuAAKiLwACojAAAqIxAAKiMwACojUAAqI2AAKiNwACojkAAqI6AAKihQACoqgAAqLIAAKi6AACouoAAqLsAAKi7gACovAAAqLzAAKi9AACovUAAqL4AAKi+QACovsAAqL8AAKi/gACowAAAqMBAAKjAgACowUAAqMGAAKjCwACoxgAAqMdAAKjHwACoyEAAqMmAAKjKQACoywAAqMuAAKjUwACo3cAAqOeAAKjwgACo8UAAqPHAAKjyQACo8sAAqPNAAKjzwACo9AAAqPTAAKj4AACo/EAAqPzAAKj9QACo/cAAqP5AAKj+wACo/0AAqP/AAKkAQACpBIAAqQVAAKkGAACpBsAAqQeAAKkIQACpCQAAqQnAAKkKgACpCwAAqRrAAKkbQACpG8AAqRxAAKkdAACpHUAAqR2AAKkdwACpHgAAqR6AAKkfAACpH0AAqR+AAKkgAACpIEAAqTAAAKkwgACpMQAAqTGAAKkyQACpMoAAqTLAAKkzAACpM0AAqTPAAKk0QACpNIAAqTTAAKk1QACpNYAAqUVAAKlFwACpRoAAqUcAAKlHwACpSAAAqUhAAKlIgACpSMAAqUlAAKlJwACpSgAAqUpAAKlKwACpSwAAqU5AAKlOgACpTsAAqU9AAKlfAACpX4AAqWAAAKlggACpYUAAqWGAAKlhwACpYgAAqWJAAKliwACpY0AAqWOAAKljwACpZEAAqWSAAKl0QACpdMAAqXVAAKl1wACpdoAAqXbAAKl3AACpd0AAqXeAAKl4AACpeIAAqXjAAKl5AACpeYAAqXnAAKmJgACpigAAqYqAAKmLAACpi8AAqYwAAKmMQACpjIAAqYzAAKmNQACpjcAAqY4AAKmOQACpjsAAqY8AAKmewACpn0AAqZ/AAKmgQACpoQAAqaFAAKmhgACpocAAqaIAAKmigACpowAAqaNAAKmjgACppAAAqaRAAKm0AACptIAAqbUAAKm1gACptkAAqbaAAKm2wACptwAAqbdAAKm3wACpuEAAqbiAAKm4wACpuUAAqbmAAKnCwACpy8AAqdWAAKnegACp30AAqd/AAKngQACp4MAAqeFAAKnhwACp4gAAqeLAAKnmAACp6cAAqepAAKnqwACp60AAqevAAKnsQACp7MAAqe1AAKnxAACp8cAAqfKAAKnzQACp9AAAqfTAAKn1gACp9kAAqfbAAKoGgACqBwAAqgeAAKoIAACqCMAAqgkAAKoJQACqCYAAqgnAAKoKQACqCsAAqgsAAKoLQACqC8AAqgwAAKobwACqHEAAqhzAAKodQACqHgAAqh5AAKoegACqHsAAqh8AAKofgACqIAAAqiBAAKoggACqIQAAqiFAAKoxAACqMYAAqjIAAKoygACqM0AAqjOAAKozwACqNAAAqjRAAKo0wACqNUAAqjWAAKo1wACqNkAAqjaAAKpGQACqRsAAqkdAAKpHwACqSIAAqkjAAKpJAACqSUAAqkmAAKpKAACqSoAAqkrAAKpLAACqS4AAqkvAAKpbgACqXAAAqlyAAKpdAACqXcAAql4AAKpeQACqXoAAql7AAKpfQACqX8AAqmAAAKpgQACqYMAAqmEAAKpwwACqcUAAqnHAAKpyQACqcwAAqnNAAKpzgACqc8AAqnQAAKp0gACqdQAAqnVAAKp1gACqdgAAqnZAAKqGAACqhoAAqocAAKqHgACqiEAAqoiAAKqIwACqiQAAqolAAKqJwACqikAAqoqAAKqKwACqi0AAqouAAKqeQACqpwAAqq8AAKq3AACqt4AAqrgAAKq4gACquQAAqrnAAKq6AACqukAAqrsAAKq7QACqu8AAqrwAAKq8gACqvUAAqr2AAKq9wACqvoAAqr7AAKrAAACqw0AAqsSAAKrFAACqxYAAqsbAAKrHgACqyEAAqsjAAKrSAACq2wAAquTAAKrtwACq7oAAqu8AAKrvgACq8AAAqvCAAKrxAACq8UAAqvIAAKr1QACq+YAAqvoAAKr6gACq+wAAqvuAAKr8AACq/IAAqv0AAKr9gACrAcAAqwKAAKsDQACrBAAAqwTAAKsFgACrBkAAqwcAAKsHwACrCEAAqxgAAKsYgACrGQAAqxmAAKsaQACrGoAAqxrAAKsbAACrG0AAqxvAAKscQACrHIAAqxzAAKsdQACrHYAAqy1AAKstwACrLkAAqy7AAKsvgACrL8AAqzAAAKswQACrMIAAqzEAAKsxgACrMcAAqzIAAKsygACrMsAAq0KAAKtDAACrQ8AAq0RAAKtFAACrRUAAq0WAAKtFwACrRgAAq0aAAKtHAACrR0AAq0eAAKtIAACrSEAAq0uAAKtLwACrTAAAq0yAAKtcQACrXMAAq11AAKtdwACrXoAAq17AAKtfAACrX0AAq1+AAKtgAACrYIAAq2DAAKthAACrYYAAq2HAAKtxgACrcgAAq3KAAKtzAACrc8AAq3QAAKt0QACrdIAAq3TAAKt1QACrdcAAq3YAAKt2QACrdsAAq3cAAKuGwACrh0AAq4fAAKuIQACriQAAq4lAAKuJgACricAAq4oAAKuKgACriwAAq4tAAKuLgACrjAAAq4xAAKucAACrnIAAq50AAKudgACrnkAAq56AAKuewACrnwAAq59AAKufwACroEAAq6CAAKugwACroUAAq6GAAKuxQACrscAAq7JAAKuywACrs4AAq7PAAKu0AACrtEAAq7SAAKu1AACrtYAAq7XAAKu2AACrtoAAq7bAAKvAAACryQAAq9LAAKvbwACr3IAAq90AAKvdgACr3gAAq96AAKvfAACr30AAq+AAAKvjQACr5wAAq+eAAKvoAACr6IAAq+kAAKvpgACr6gAAq+qAAKvuQACr7wAAq+/AAKvwgACr8UAAq/IAAKvywACr84AAq/QAAKwDwACsBEAArATAAKwFQACsBgAArAZAAKwGgACsBsAArAcAAKwHgACsCAAArAhAAKwIgACsCQAArAlAAKwZAACsGYAArBoAAKwagACsG0AArBuAAKwbwACsHAAArBxAAKwcwACsHUAArB2AAKwdwACsHkAArB6AAKwuQACsLsAArC9AAKwvwACsMIAArDDAAKwxAACsMUAArDGAAKwyAACsMoAArDLAAKwzAACsM4AArDPAAKxDgACsRAAArETAAKxFQACsRgAArEZAAKxGgACsRsAArEcAAKxHgACsSAAArEhAAKxIgACsSQAArElAAKxJwACsWYAArFoAAKxagACsWwAArFvAAKxcAACsXEAArFyAAKxcwACsXUAArF3AAKxeAACsXkAArF7AAKxfAACsbsAArG9AAKxvwACscEAArHEAAKxxQACscYAArHHAAKxyAACscoAArHMAAKxzQACsc4AArHQAAKx0QACshAAArISAAKyFAACshYAArIZAAKyGgACshsAArIcAAKyHQACsh8AArIhAAKyIgACsiMAArIlAAKyJgACsi8AArIwAAKyMgACsnEAArJzAAKydQACsncAArJ6AAKyewACsnwAArJ9AAKyfgACsoAAArKCAAKygwACsoQAArKGAAKyhwACssYAArLIAAKyygACsswAArLPAAKy0AACstEAArLSAAKy0wACstUAArLXAAKy2AACstkAArLbAAKy3AACsxsAArMdAAKzHwACsyEAArMkAAKzJQACsyYAArMnAAKzKAACsyoAArMsAAKzLQACsy4AArMwAAKzMQACs3AAArNyAAKzdAACs3YAArN5AAKzegACs3sAArN8AAKzfQACs38AArOBAAKzggACs4MAArOFAAKzhgACs8UAArPHAAKzyQACs8sAArPOAAKzzwACs9AAArPRAAKz0gACs9QAArPWAAKz1wACs9gAArPaAAKz2wACtCYAArRJAAK0aQACtIkAArSLAAK0jQACtI8AArSRAAK0lAACtJUAArSWAAK0mQACtJoAArScAAK0nQACtJ8AArSiAAK0owACtKQAArSnAAK0qAACtLEAArS+AAK0wwACtMUAArTHAAK0zAACtM8AArTSAAK01AACtPkAArUdAAK1RAACtWgAArVrAAK1bQACtW8AArVxAAK1cwACtXUAArV2AAK1eQACtYYAArWXAAK1mQACtZsAArWdAAK1nwACtaEAArWjAAK1pQACtacAArW4AAK1uwACtb4AArXBAAK1xAACtccAArXKAAK1zQACtdAAArXSAAK2EQACthMAArYVAAK2FwACthoAArYbAAK2HAACth0AArYeAAK2IAACtiIAArYjAAK2JAACtiYAArYnAAK2ZgACtmgAArZqAAK2bAACtm8AArZwAAK2cQACtnIAArZzAAK2dQACtncAArZ4AAK2eQACtnsAArZ8AAK2uwACtr0AArbAAAK2wgACtsUAArbGAAK2xwACtsgAArbJAAK2ywACts0AArbOAAK2zwACttEAArbSAAK23wACtuAAArbhAAK24wACtyIAArckAAK3JgACtygAArcrAAK3LAACty0AArcuAAK3LwACtzEAArczAAK3NAACtzUAArc3AAK3OAACt3cAArd5AAK3ewACt30AAreAAAK3gQACt4IAAreDAAK3hAACt4YAAreIAAK3iQACt4oAAreMAAK3jQACt8wAArfOAAK30AACt9IAArfVAAK31gACt9cAArfYAAK32QACt9sAArfdAAK33gACt98AArfhAAK34gACuCEAArgjAAK4JQACuCcAArgqAAK4KwACuCwAArgtAAK4LgACuDAAArgyAAK4MwACuDQAArg2AAK4NwACuHYAArh4AAK4egACuHwAArh/AAK4gAACuIEAAriCAAK4gwACuIUAAriHAAK4iAACuIkAAriLAAK4jAACuLEAArjVAAK4/AACuSAAArkjAAK5JQACuScAArkpAAK5KwACuS0AArkuAAK5MQACuT4AArlNAAK5TwACuVEAArlTAAK5VQACuVcAArlZAAK5WwACuWoAArltAAK5cAACuXMAArl2AAK5eQACuXwAArl/AAK5gQACucAAArnCAAK5xAACucYAArnJAAK5ygACucsAArnMAAK5zQACuc8AArnRAAK50gACudMAArnVAAK51gACuhUAAroXAAK6GQACuhsAAroeAAK6HwACuiAAArohAAK6IgACuiQAAromAAK6JwACuigAAroqAAK6KwACumoAArpsAAK6bgACunAAArpzAAK6dAACunUAArp2AAK6dwACunkAArp7AAK6fAACun0AArp/AAK6gAACur8AArrBAAK6wwACusUAArrIAAK6yQACusoAArrLAAK6zAACus4AArrQAAK60QACutIAArrUAAK61QACuxQAArsWAAK7GAACuxoAArsdAAK7HgACux8AArsgAAK7IQACuyMAArslAAK7JgACuycAArspAAK7KgACu2kAArtrAAK7bQACu28AArtyAAK7cwACu3QAArt1AAK7dgACu3gAArt6AAK7ewACu3wAArt+AAK7fwACu74AArvAAAK7wgACu8QAArvHAAK7yAACu8kAArvKAAK7ywACu80AArvPAAK70AACu9EAArvTAAK71AACu90AArveAAK74AACvCMAArxHAAK8awACvI4AAry1AAK81QACvPwAAr0jAAK9QwACvWcAAr2LAAK9jQACvZAAAr2SAAK9lAACvZYAAr2ZAAK9nAACvZ4AAr2gAAK9owACvaUAAr2nAAK9qgACva0AAr2uAAK9swACvcAAAr3DAAK9xQACvcgAAr3LAAK9zQACvfIAAr4WAAK+PQACvmEAAr5kAAK+ZgACvmgAAr5qAAK+bAACvm4AAr5vAAK+cgACvn8AAr6SAAK+lAACvpYAAr6YAAK+mgACvpwAAr6eAAK+oAACvqIAAr6kAAK+twACvroAAr69AAK+wAACvsMAAr7GAAK+yQACvswAAr7PAAK+0gACvtQAAr8TAAK/FQACvxgAAr8aAAK/HQACvx4AAr8fAAK/IAACvyEAAr8jAAK/JQACvyYAAr8nAAK/KQACvyoAAr8zAAK/NAACvzYAAr91AAK/dwACv3kAAr97AAK/fgACv38AAr+AAAK/gQACv4IAAr+EAAK/hgACv4cAAr+IAAK/igACv4sAAr/KAAK/zAACv88AAr/RAAK/1AACv9UAAr/WAAK/1wACv9gAAr/aAAK/3AACv90AAr/eAAK/4AACv+EAAr/qAAK/6wACv+0AAsAsAALALgACwDAAAsAyAALANQACwDYAAsA3AALAOAACwDkAAsA7AALAPQACwD4AAsA/AALAQQACwEIAAsCBAALAgwACwIYAAsCIAALAiwACwIwAAsCNAALAjgACwI8AAsCRAALAkwACwJQAAsCVAALAlwACwJgAAsChAALAogACwKQAAsDjAALA5QACwOcAAsDpAALA7AACwO0AAsDuAALA7wACwPAAAsDyAALA9AACwPUAAsD2AALA+AACwPkAAsE4AALBOgACwT0AAsE/AALBQgACwUMAAsFEAALBRQACwUYAAsFIAALBSgACwUsAAsFMAALBTgACwU8AAsFcAALBXQACwV4AAsFgAALBnwACwaEAAsGjAALBpQACwagAAsGpAALBqgACwasAAsGsAALBrgACwbAAAsGxAALBsgACwbQAAsG1AALB9AACwfYAAsH5AALB+wACwf4AAsH/AALCAAACwgEAAsICAALCBAACwgYAAsIHAALCCAACwgoAAsILAALCFwACwiQAAsIpAALCLAACwi8AAsI0AALCNwACwjoAAsI8AALCQgACwk0AAsKYAALCuwACwtsAAsL7AALC/QACwv8AAsMBAALDAwACwwYAAsMHAALDCAACwwsAAsMMAALDDgACww8AAsMRAALDFAACwxUAAsMWAALDGQACwxoAAsMfAALDLAACwzEAAsMzAALDNQACwzoAAsM9AALDQAACw0IAAsNnAALDiwACw7IAAsPWAALD2QACw9sAAsPdAALD3wACw+EAAsPjAALD5AACw+cAAsP0AALEBQACxAcAAsQJAALECwACxA0AAsQPAALEEQACxBMAAsQVAALEJgACxCkAAsQsAALELwACxDIAAsQ1AALEOAACxDsAAsQ+AALEQAACxH8AAsSBAALEgwACxIUAAsSIAALEiQACxIoAAsSLAALEjAACxI4AAsSQAALEkQACxJIAAsSUAALElQACxNQAAsTWAALE2AACxNoAAsTdAALE3gACxN8AAsTgAALE4QACxOMAAsTlAALE5gACxOcAAsTpAALE6gACxSkAAsUrAALFLgACxTAAAsUzAALFNAACxTUAAsU2AALFNwACxTkAAsU7AALFPAACxT0AAsU/AALFQAACxU0AAsVOAALFTwACxVEAAsWQAALFkgACxZQAAsWWAALFmQACxZoAAsWbAALFnAACxZ0AAsWfAALFoQACxaIAAsWjAALFpQACxaYAAsXlAALF5wACxekAAsXrAALF7gACxe8AAsXwAALF8QACxfIAAsX0AALF9gACxfcAAsX4AALF+gACxfsAAsY6AALGPAACxj4AAsZAAALGQwACxkQAAsZFAALGRgACxkcAAsZJAALGSwACxkwAAsZNAALGTwACxlAAAsaPAALGkQACxpMAAsaVAALGmAACxpkAAsaaAALGmwACxpwAAsaeAALGoAACxqEAAsaiAALGpAACxqUAAsbkAALG5gACxugAAsbqAALG7QACxu4AAsbvAALG8AACxvEAAsbzAALG9QACxvYAAsb3AALG+QACxvoAAscfAALHQwACx2oAAseOAALHkQACx5MAAseVAALHlwACx5kAAsebAALHnAACx58AAsesAALHuwACx70AAse/AALHwQACx8MAAsfFAALHxwACx8kAAsfYAALH2wACx94AAsfhAALH5AACx+cAAsfqAALH7QACx+8AAsguAALIMAACyDIAAsg0AALINwACyDgAAsg5AALIOgACyDsAAsg9AALIPwACyEAAAshBAALIQwACyEQAAsiDAALIhQACyIcAAsiJAALIjAACyI0AAsiOAALIjwACyJAAAsiSAALIlAACyJUAAsiWAALImAACyJkAAsjYAALI2gACyNwAAsjeAALI4QACyOIAAsjjAALI5AACyOUAAsjnAALI6QACyOoAAsjrAALI7QACyO4AAsktAALJLwACyTEAAskzAALJNgACyTcAAsk4AALJOQACyToAAsk8AALJPgACyT8AAslAAALJQgACyUMAAsmCAALJhAACyYYAAsmIAALJiwACyYwAAsmNAALJjgACyY8AAsmRAALJkwACyZQAAsmVAALJlwACyZgAAsnXAALJ2QACydsAAsndAALJ4AACyeEAAsniAALJ4wACyeQAAsnmAALJ6AACyekAAsnqAALJ7AACye0AAsosAALKLgACyjAAAsoyAALKNQACyjYAAso3AALKOAACyjkAAso7AALKPQACyj4AAso/AALKQQACykIAAsqNAALKsAACytAAAsrwAALK8gACyvQAAsr2AALK+AACyvsAAsr8AALK/QACywAAAssBAALLAwACywQAAssGAALLCQACywoAAssLAALLDgACyw8AAssUAALLIQACyyYAAssoAALLKgACyy8AAssyAALLNQACyzcAAstcAALLgAACy6cAAsvLAALLzgACy9AAAsvSAALL1AACy9YAAsvYAALL2QACy9wAAsvpAALL+gACy/wAAsv+AALMAAACzAIAAswEAALMBgACzAgAAswKAALMGwACzB4AAswhAALMJAACzCcAAswqAALMLQACzDAAAswzAALMNQACzHQAAsx2AALMeAACzHoAAsx9AALMfgACzH8AAsyAAALMgQACzIMAAsyFAALMhgACzIcAAsyJAALMigACzMkAAszLAALMzQACzM8AAszSAALM0wACzNQAAszVAALM1gACzNgAAszaAALM2wACzNwAAszeAALM3wACzR4AAs0gAALNIwACzSUAAs0oAALNKQACzSoAAs0rAALNLAACzS4AAs0wAALNMQACzTIAAs00AALNNQACzUIAAs1DAALNRAACzUYAAs2FAALNhwACzYkAAs2LAALNjgACzY8AAs2QAALNkQACzZIAAs2UAALNlgACzZcAAs2YAALNmgACzZsAAs3aAALN3AACzd4AAs3gAALN4wACzeQAAs3lAALN5gACzecAAs3pAALN6wACzewAAs3tAALN7wACzfAAAs4vAALOMQACzjMAAs41AALOOAACzjkAAs46AALOOwACzjwAAs4+AALOQAACzkEAAs5CAALORAACzkUAAs6EAALOhgACzogAAs6KAALOjQACzo4AAs6PAALOkAACzpEAAs6TAALOlQACzpYAAs6XAALOmQACzpoAAs7ZAALO2wACzt0AAs7fAALO4gACzuMAAs7kAALO5QACzuYAAs7oAALO6gACzusAAs7sAALO7gACzu8AAs8UAALPOAACz18AAs+DAALPhgACz4gAAs+KAALPjAACz44AAs+QAALPkQACz5QAAs+hAALPsAACz7IAAs+0AALPtgACz7gAAs+6AALPvAACz74AAs/NAALP0AACz9MAAs/WAALP2QACz9wAAs/fAALP4gACz+QAAtAjAALQJQAC0CcAAtApAALQLAAC0C0AAtAuAALQLwAC0DAAAtAyAALQNAAC0DUAAtA2AALQOAAC0DkAAtB4AALQegAC0HwAAtB+AALQgQAC0IIAAtCDAALQhAAC0IUAAtCHAALQiQAC0IoAAtCLAALQjQAC0I4AAtDNAALQzwAC0NEAAtDTAALQ1gAC0NcAAtDYAALQ2QAC0NoAAtDcAALQ3gAC0N8AAtDgAALQ4gAC0OMAAtEiAALRJAAC0SYAAtEoAALRKwAC0SwAAtEtAALRLgAC0S8AAtExAALRMwAC0TQAAtE1AALRNwAC0TgAAtF3AALReQAC0XsAAtF9AALRgAAC0YEAAtGCAALRgwAC0YQAAtGGAALRiAAC0YkAAtGKAALRjAAC0Y0AAtHMAALRzgAC0dAAAtHSAALR1QAC0dYAAtHXAALR2AAC0dkAAtHbAALR3QAC0d4AAtHfAALR4QAC0eIAAtIhAALSIwAC0iUAAtInAALSKgAC0isAAtIsAALSLQAC0i4AAtIwAALSMgAC0jMAAtI0AALSNgAC0jcAAtJAAALSQQAC0kMAAtKGAALSqgAC0s4AAtLxAALTGAAC0zgAAtNfAALThgAC06YAAtPKAALT7gAC0/AAAtPzAALT9QAC0/cAAtP5AALT/AAC0/8AAtQBAALUAwAC1AYAAtQIAALUCgAC1A0AAtQQAALUEQAC1BYAAtQjAALUJgAC1CgAAtQrAALULgAC1DAAAtRVAALUeQAC1KAAAtTEAALUxwAC1MkAAtTLAALUzQAC1M8AAtTRAALU0gAC1NUAAtTiAALU9QAC1PcAAtT5AALU+wAC1P0AAtT/AALVAQAC1QMAAtUFAALVBwAC1RoAAtUdAALVIAAC1SMAAtUmAALVKQAC1SwAAtUvAALVMgAC1TUAAtU3AALVdgAC1XgAAtV7AALVfQAC1YAAAtWBAALVggAC1YMAAtWEAALVhgAC1YgAAtWJAALVigAC1YwAAtWNAALVlgAC1ZcAAtWZAALV2AAC1doAAtXcAALV3gAC1eEAAtXiAALV4wAC1eQAAtXlAALV5wAC1ekAAtXqAALV6wAC1e0AAtXuAALWLQAC1i8AAtYyAALWNAAC1jcAAtY4AALWOQAC1joAAtY7AALWPQAC1j8AAtZAAALWQQAC1kMAAtZEAALWTQAC1k4AAtZQAALWjwAC1pEAAtaTAALWlQAC1pgAAtaZAALWmgAC1psAAtacAALWngAC1qAAAtahAALWogAC1qQAAtalAALW5AAC1uYAAtbpAALW6wAC1u4AAtbvAALW8AAC1vEAAtbyAALW9AAC1vYAAtb3AALW+AAC1voAAtb7AALXBAAC1wUAAtcHAALXRgAC10gAAtdKAALXTAAC108AAtdQAALXUQAC11IAAtdTAALXVQAC11cAAtdYAALXWQAC11sAAtdcAALXmwAC150AAtegAALXogAC16UAAtemAALXpwAC16gAAtepAALXqwAC160AAteuAALXrwAC17EAAteyAALXvwAC18AAAtfBAALXwwAC2AIAAtgEAALYBgAC2AgAAtgLAALYDAAC2A0AAtgOAALYDwAC2BEAAtgTAALYFAAC2BUAAtgXAALYGAAC2FcAAthZAALYXAAC2F4AAthhAALYYgAC2GMAAthkAALYZQAC2GcAAthpAALYagAC2GsAAthtAALYbgAC2IYAAtiTAALYngAC2KEAAtikAALYpwAC2KoAAtitAALYuAAC2LsAAti+AALYwQAC2MQAAtjHAALYyQAC2NIAAtjbAALY5QAC2TAAAtlTAALZcwAC2ZMAAtmVAALZlwAC2ZkAAtmbAALZngAC2Z8AAtmgAALZowAC2aQAAtmmAALZpwAC2akAAtmsAALZrQAC2a4AAtmxAALZsgAC2bsAAtnIAALZzQAC2c8AAtnRAALZ1gAC2dkAAtncAALZ3gAC2gMAAtonAALaTgAC2nIAAtp1AALadwAC2nkAAtp7AALafQAC2n8AAtqAAALagwAC2pAAAtqhAALaowAC2qUAAtqnAALaqQAC2qsAAtqtAALarwAC2rEAAtrCAALaxQAC2sgAAtrLAALazgAC2tEAAtrUAALa1wAC2toAAtrcAALbGwAC2x0AAtsfAALbIQAC2yQAAtslAALbJgAC2ycAAtsoAALbKgAC2ywAAtstAALbLgAC2zAAAtsxAALbcAAC23IAAtt0AALbdgAC23kAAtt6AALbewAC23wAAtt9AALbfwAC24EAAtuCAALbgwAC24UAAtuGAALbxQAC28cAAtvKAALbzAAC288AAtvQAALb0QAC29IAAtvTAALb1QAC29cAAtvYAALb2QAC29sAAtvcAALb6QAC2+oAAtvrAALb7QAC3CwAAtwuAALcMAAC3DIAAtw1AALcNgAC3DcAAtw4AALcOQAC3DsAAtw9AALcPgAC3D8AAtxBAALcQgAC3IEAAtyDAALchQAC3IcAAtyKAALciwAC3IwAAtyNAALcjgAC3JAAAtySAALckwAC3JQAAtyWAALclwAC3NYAAtzYAALc2gAC3NwAAtzfAALc4AAC3OEAAtziAALc4wAC3OUAAtznAALc6AAC3OkAAtzrAALc7AAC3SsAAt0tAALdLwAC3TEAAt00AALdNQAC3TYAAt03AALdOAAC3ToAAt08AALdPQAC3T4AAt1AAALdQQAC3YAAAt2CAALdhAAC3YYAAt2JAALdigAC3YsAAt2MAALdjQAC3Y8AAt2RAALdkgAC3ZMAAt2VAALdlgAC3bsAAt3fAALeBgAC3ioAAt4tAALeLwAC3jEAAt4zAALeNQAC3jcAAt44AALeOwAC3kgAAt5XAALeWQAC3lsAAt5dAALeXwAC3mEAAt5jAALeZQAC3nQAAt53AALeegAC3n0AAt6AAALegwAC3oYAAt6JAALeiwAC3soAAt7MAALezgAC3tAAAt7TAALe1AAC3tUAAt7WAALe1wAC3tkAAt7bAALe3AAC3t0AAt7fAALe4AAC3x8AAt8hAALfIwAC3yUAAt8oAALfKQAC3yoAAt8rAALfLAAC3y4AAt8wAALfMQAC3zIAAt80AALfNQAC33QAAt92AALfeAAC33oAAt99AALffgAC338AAt+AAALfgQAC34MAAt+FAALfhgAC34cAAt+JAALfigAC38kAAt/LAALfzgAC39AAAt/TAALf1AAC39UAAt/WAALf1wAC39kAAt/bAALf3AAC390AAt/fAALf4AAC4B8AAuAhAALgIwAC4CUAAuAoAALgKQAC4CoAAuArAALgLAAC4C4AAuAwAALgMQAC4DIAAuA0AALgNQAC4HQAAuB2AALgeAAC4HoAAuB9AALgfgAC4H8AAuCAAALggQAC4IMAAuCFAALghgAC4IcAAuCJAALgigAC4MkAAuDLAALgzQAC4M8AAuDSAALg0wAC4NQAAuDVAALg1gAC4NgAAuDaAALg2wAC4NwAAuDeAALg3wAC4SoAAuFNAALhbQAC4Y0AAuGPAALhkQAC4ZMAAuGVAALhmAAC4ZkAAuGaAALhnQAC4Z4AAuGgAALhoQAC4aMAAuGmAALhpwAC4agAAuGrAALhrAAC4bEAAuG+AALhwwAC4cUAAuHHAALhzAAC4c8AAuHSAALh1AAC4fkAAuIdAALiRAAC4mgAAuJrAALibQAC4m8AAuJxAALicwAC4nUAAuJ2AALieQAC4oYAAuKXAALimQAC4psAAuKdAALinwAC4qEAAuKjAALipQAC4qcAAuK4AALiuwAC4r4AAuLBAALixAAC4scAAuLKAALizQAC4tAAAuLSAALjEQAC4xMAAuMVAALjFwAC4xoAAuMbAALjHAAC4x0AAuMeAALjIAAC4yIAAuMjAALjJAAC4yYAAuMnAALjZgAC42gAAuNqAALjbAAC428AAuNwAALjcQAC43IAAuNzAALjdQAC43cAAuN4AALjeQAC43sAAuN8AALjuwAC470AAuPAAALjwgAC48UAAuPGAALjxwAC48gAAuPJAALjywAC480AAuPOAALjzwAC49EAAuPSAALj3wAC4+AAAuPhAALj4wAC5CIAAuQkAALkJgAC5CgAAuQrAALkLAAC5C0AAuQuAALkLwAC5DEAAuQzAALkNAAC5DUAAuQ3AALkOAAC5HcAAuR5AALkewAC5H0AAuSAAALkgQAC5IIAAuSDAALkhAAC5IYAAuSIAALkiQAC5IoAAuSMAALkjQAC5MwAAuTOAALk0AAC5NIAAuTVAALk1gAC5NcAAuTYAALk2QAC5NsAAuTdAALk3gAC5N8AAuThAALk4gAC5SEAAuUjAALlJQAC5ScAAuUqAALlKwAC5SwAAuUtAALlLgAC5TAAAuUyAALlMwAC5TQAAuU2AALlNwAC5XYAAuV4AALlegAC5XwAAuV/AALlgAAC5YEAAuWCAALlgwAC5YUAAuWHAALliAAC5YkAAuWLAALljAAC5bEAAuXVAALl/AAC5iAAAuYjAALmJQAC5icAAuYpAALmKwAC5i0AAuYuAALmMQAC5j4AAuZNAALmTwAC5lEAAuZTAALmVQAC5lcAAuZZAALmWwAC5moAAuZtAALmcAAC5nMAAuZ2AALmeQAC5nwAAuZ/AALmgQAC5sAAAubCAALmxAAC5sYAAubJAALmygAC5ssAAubMAALmzQAC5s8AAubRAALm0gAC5tMAAubVAALm1gAC5xUAAucXAALnGQAC5xsAAuceAALnHwAC5yAAAuchAALnIgAC5yQAAucmAALnJwAC5ygAAucqAALnKwAC52oAAudsAALnbgAC53AAAudzAALndAAC53UAAud2AALndwAC53kAAud7AALnfAAC530AAud/AALngAAC578AAufBAALnxAAC58YAAufJAALnygAC58sAAufMAALnzQAC588AAufRAALn0gAC59MAAufVAALn1gAC6BUAAugXAALoGQAC6BsAAugeAALoHwAC6CAAAughAALoIgAC6CQAAugmAALoJwAC6CgAAugqAALoKwAC6GoAAuhsAALobgAC6HAAAuhzAALodAAC6HUAAuh2AALodwAC6HkAAuh7AALofAAC6H0AAuh/AALogAAC6L8AAujBAALowwAC6MUAAujIAALoyQAC6MoAAujLAALozAAC6M4AAujQAALo0QAC6NIAAujUAALo1QAC6SAAAulDAALpYwAC6YMAAumFAALphwAC6YkAAumLAALpjgAC6Y8AAumQAALpkwAC6ZQAAumWAALplwAC6ZkAAumcAALpnQAC6Z4AAumhAALpogAC6acAAum0AALpuQAC6bsAAum9AALpwgAC6cUAAunIAALpygAC6e8AAuoTAALqOgAC6l4AAuphAALqYwAC6mUAAupnAALqaQAC6msAAupsAALqbwAC6nwAAuqNAALqjwAC6pEAAuqTAALqlQAC6pcAAuqZAALqmwAC6p0AAuquAALqsQAC6rQAAuq3AALqugAC6r0AAurAAALqwwAC6sYAAurIAALrBwAC6wkAAusLAALrDQAC6xAAAusRAALrEgAC6xMAAusUAALrFgAC6xgAAusZAALrGgAC6xwAAusdAALrXAAC614AAutgAALrYgAC62UAAutmAALrZwAC62gAAutpAALrawAC620AAutuAALrbwAC63EAAutyAALrsQAC67MAAuu2AALruAAC67sAAuu8AALrvQAC674AAuu/AALrwQAC68MAAuvEAALrxQAC68cAAuvIAALr1QAC69YAAuvXAALr2QAC7BgAAuwaAALsHAAC7B4AAuwhAALsIgAC7CMAAuwkAALsJQAC7CcAAuwpAALsKgAC7CsAAuwtAALsLgAC7G0AAuxvAALscQAC7HMAAux2AALsdwAC7HgAAux5AALsegAC7HwAAux+AALsfwAC7IAAAuyCAALsgwAC7MIAAuzEAALsxgAC7MgAAuzLAALszAAC7M0AAuzOAALszwAC7NEAAuzTAALs1AAC7NUAAuzXAALs2AAC7RcAAu0ZAALtGwAC7R0AAu0gAALtIQAC7SIAAu0jAALtJAAC7SYAAu0oAALtKQAC7SoAAu0sAALtLQAC7WwAAu1uAALtcAAC7XIAAu11AALtdgAC7XcAAu14AALteQAC7XsAAu19AALtfgAC7X8AAu2BAALtggAC7acAAu3LAALt8gAC7hYAAu4ZAALuGwAC7h0AAu4fAALuIQAC7iMAAu4kAALuJwAC7jQAAu5DAALuRQAC7kcAAu5JAALuSwAC7k0AAu5PAALuUQAC7mAAAu5jAALuZgAC7mkAAu5sAALubwAC7nIAAu51AALudwAC7rYAAu64AALuugAC7rwAAu6/AALuwAAC7sEAAu7CAALuwwAC7sUAAu7HAALuyAAC7skAAu7LAALuzAAC7wsAAu8NAALvDwAC7xEAAu8UAALvFQAC7xYAAu8XAALvGAAC7xoAAu8cAALvHQAC7x4AAu8gAALvIQAC72AAAu9iAALvZAAC72YAAu9pAALvagAC72sAAu9sAALvbQAC728AAu9xAALvcgAC73MAAu91AALvdgAC77UAAu+3AALvuQAC77sAAu++AALvvwAC78AAAu/BAALvwgAC78QAAu/GAALvxwAC78gAAu/KAALvywAC8AoAAvAMAALwDgAC8BAAAvATAALwFAAC8BUAAvAWAALwFwAC8BkAAvAbAALwHAAC8B0AAvAfAALwIAAC8F8AAvBhAALwYwAC8GUAAvBoAALwaQAC8GoAAvBrAALwbAAC8G4AAvBwAALwcQAC8HIAAvB0AALwdQAC8LQAAvC2AALwuAAC8LoAAvC9AALwvgAC8L8AAvDAAALwwQAC8MMAAvDFAALwxgAC8McAAvDJAALwygAC8RUAAvE4AALxWAAC8XgAAvF6AALxfAAC8X4AAvGAAALxgwAC8YQAAvGFAALxiAAC8YkAAvGLAALxjAAC8Y4AAvGRAALxkgAC8ZMAAvGWAALxlwAC8ZwAAvGpAALxrgAC8bAAAvGyAALxtwAC8boAAvG9AALxvwAC8eQAAvIIAALyLwAC8lMAAvJWAALyWAAC8loAAvJcAALyXgAC8mAAAvJhAALyZAAC8nEAAvKCAALyhAAC8oYAAvKIAALyigAC8owAAvKOAALykAAC8pIAAvKjAALypgAC8qkAAvKsAALyrwAC8rIAAvK1AALyuAAC8rsAAvK9AALy/AAC8v4AAvMAAALzAgAC8wUAAvMGAALzBwAC8wgAAvMJAALzCwAC8w0AAvMOAALzDwAC8xEAAvMSAALzUQAC81MAAvNVAALzVwAC81oAAvNbAALzXAAC810AAvNeAALzYAAC82IAAvNjAALzZAAC82YAAvNnAALzpgAC86gAAvOrAALzrQAC87AAAvOxAALzsgAC87MAAvO0AALztgAC87gAAvO5AALzugAC87wAAvO9AALzygAC88sAAvPMAALzzgAC9A0AAvQPAAL0EQAC9BMAAvQWAAL0FwAC9BgAAvQZAAL0GgAC9BwAAvQeAAL0HwAC9CAAAvQiAAL0IwAC9GIAAvRkAAL0ZgAC9GgAAvRrAAL0bAAC9G0AAvRuAAL0bwAC9HEAAvRzAAL0dAAC9HUAAvR3AAL0eAAC9LcAAvS5AAL0uwAC9L0AAvTAAAL0wQAC9MIAAvTDAAL0xAAC9MYAAvTIAAL0yQAC9MoAAvTMAAL0zQAC9QwAAvUOAAL1EAAC9RIAAvUVAAL1FgAC9RcAAvUYAAL1GQAC9RsAAvU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rAAMXdgADF5kAAxe5AAMX2QADF9sAAxfdAAMX3wADF+EAAxfkAAMX5QADF+YAAxfpAAMX6gADF+wAAxftAAMX7wADF/IAAxfzAAMX9AADF/cAAxf4AAMX/QADGAoAAxgPAAMYEQADGBMAAxgYAAMYGwADGB4AAxggAAMYRQADGGkAAxiQAAMYtAADGLcAAxi5AAMYuwADGL0AAxi/AAMYwQADGMIAAxjFAAMY0gADGOMAAxjlAAMY5wADGOkAAxjrAAMY7QADGO8AAxjxAAMY8wADGQQAAxkHAAMZCgADGQ0AAxkQAAMZEwADGRYAAxkZAAMZHAADGR4AAxldAAMZXwADGWEAAxljAAMZZgADGWcAAxloAAMZaQADGWoAAxlsAAMZbgADGW8AAxlwAAMZcgADGXMAAxmyAAMZtAADGbYAAxm4AAMZuwADGbwAAxm9AAMZvgADGb8AAxnBAAMZwwADGcQAAxnFAAMZxwADGcgAAxoHAAMaCQADGgwAAxoOAAMaEQADGhIAAxoTAAMaFAADGhUAAxoXAAMaGQADGhoAAxobAAMaHQADGh4AAxorAAMaLAADGi0AAxovAAMabgADGnAAAxpyAAMadAADGncAAxp4AAMaeQADGnoAAxp7AAMafQADGn8AAxqAAAMagQADGoMAAxqEAAMawwADGsUAAxrHAAMayQADGswAAxrNAAMazgADGs8AAxrQAAMa0gADGtQAAxrVAAMa1gADGtgAAxrZAAMbGAADGxoAAxscAAMbHgADGyEAAxsiAAMbIwADGyQAAxslAAMbJwADGykAAxsqAAMbKwADGy0AAxsuAAMbbQADG28AAxtxAAMbcwADG3YAAxt3AAMbeAADG3kAAxt6AAMbfAADG34AAxt/AAMbgAADG4IAAxuDAAMbwgADG8QAAxvGAAMbyAADG8sAAxvMAAMbzQADG84AAxvPAAMb0QADG9MAAxvUAAMb1QADG9cAAxvYAAMb/QADHCEAAxxIAAMcbAADHG8AAxxxAAMccwADHHUAAxx3AAMceQADHHoAAxx9AAMcigADHJkAAxybAAMcnQADHJ8AAxyhAAMcowADHKUAAxynAAMctgADHLkAAxy8AAMcvwADHMIAAxzFAAMcyAADHMsAAxzNAAMdDAADHQ4AAx0QAAMdEgADHRUAAx0WAAMdFwADHRgAAx0ZAAMdGwADHR0AAx0eAAMdHwADHSEAAx0iAAMdYQADHWMAAx1lAAMdZwADHWoAAx1rAAMdbAADHW0AAx1uAAMdcAADHXIAAx1zAAMddAADHXYAAx13AAMdtgADHbgAAx26AAMdvAADHb8AAx3AAAMdwQADHcIAAx3DAAMdxQADHccAAx3IAAMdyQADHcsAAx3MAAMeCwADHg0AAx4PAAMeEQADHhQAAx4VAAMeFgADHhcAAx4YAAMeGgADHhwAAx4dAAMeHgADHiAAAx4hAAMeYAADHmIAAx5kAAMeZgADHmkAAx5qAAMeawADHmwAAx5tAAMebwADHnEAAx5yAAMecwADHnUAAx52AAMetQADHrcAAx65AAMeuwADHr4AAx6/AAMewAADHsEAAx7CAAMexAADHsYAAx7HAAMeyAADHsoAAx7LAAMfCgADHwwAAx8OAAMfEAADHxMAAx8UAAMfFQADHxYAAx8XAAMfGQADHxsAAx8cAAMfHQADHx8AAx8gAAMfawADH44AAx+uAAMfzgADH9AAAx/SAAMf1AADH9YAAx/ZAAMf2gADH9sAAx/eAAMf3wADH+EAAx/iAAMf5AADH+cAAx/oAAMf6QADH+wAAx/tAAMf8gADH/8AAyAEAAMgBgADIAgAAyANAAMgEAADIBMAAyAVAAMgOgADIF4AAyCFAAMgqQADIKwAAyCuAAMgsAADILIAAyC0AAMgtgADILcAAyC6AAMgxwADINgAAyDaAAMg3AADIN4AAyDgAAMg4gADIOQAAyDmAAMg6AADIPkAAyD8AAMg/wADIQIAAyEFAAMhCAADIQsAAyEOAAMhEQADIRMAAyFSAAMhVAADIVYAAyFYAAMhWwADIVwAAyFdAAMhXgADIV8AAyFhAAMhYwADIWQAAyFlAAMhZwADIWgAAyGnAAMhqQADIasAAyGtAAMhsAADIbEAAyGyAAMhswADIbQAAyG2AAMhuAADIbkAAyG6AAMhvAADIb0AAyH8AAMh/gADIgEAAyIDAAMiBgADIgcAAyIIAAMiCQADIgoAAyIMAAMiDgADIg8AAyIQAAMiEgADIhMAAyIgAAMiIQADIiIAAyIkAAMiYwADImUAAyJnAAMiaQADImwAAyJtAAMibgADIm8AAyJwAAMicgADInQAAyJ1AAMidgADIngAAyJ5AAMiuAADIroAAyK8AAMivgADIsEAAyLCAAMiwwADIsQAAyLFAAMixwADIskAAyLKAAMiywADIs0AAyLOAAMjDQADIw8AAyMRAAMjEwADIxYAAyMXAAMjGAADIxkAAyMaAAMjHAADIx4AAyMfAAMjIAADIyIAAyMjAAMjYgADI2QAAyNmAAMjaAADI2sAAyNsAAMjbQADI24AAyNvAAMjcQADI3MAAyN0AAMjdQADI3cAAyN4AAMjtwADI7kAAyO7AAMjvQADI8AAAyPBAAMjwgADI8MAAyPEAAMjxgADI8gAAyPJAAMjygADI8wAAyPNAAMj8gADJBYAAyQ9AAMkYQADJGQAAyRmAAMkaAADJGoAAyRsAAMkbgADJG8AAyRyAAMkfwADJI4AAySQAAMkkgADJJQAAySWAAMkmAADJJoAAyScAAMkqwADJK4AAySxAAMktAADJLcAAyS6AAMkvQADJMAAAyTCAAMlAQADJQMAAyUFAAMlBwADJQoAAyULAAMlDAADJQ0AAyUOAAMlEAADJRIAAyUTAAMlFAADJRYAAyUXAAMlVgADJVgAAyVaAAMlXAADJV8AAyVgAAMlYQADJWIAAyVjAAMlZQADJWcAAyVoAAMlaQADJWsAAyVsAAMlqwADJa0AAyWvAAMlsQADJbQAAyW1AAMltgADJbcAAyW4AAMlugADJbwAAyW9AAMlvgADJcAAAyXBAAMmAAADJgIAAyYEAAMmBgADJgkAAyYKAAMmCwADJgwAAyYNAAMmDwADJhEAAyYSAAMmEwADJhUAAyYWAAMmVQADJlcAAyZZAAMmWwADJl4AAyZfAAMmYAADJmEAAyZiAAMmZAADJmYAAyZnAAMmaAADJmoAAyZrAAMmqgADJqwAAyauAAMmsAADJrMAAya0AAMmtQADJrYAAya3AAMmuQADJrsAAya8AAMmvQADJr8AAybAAAMm/wADJwEAAycDAAMnBQADJwgAAycJAAMnCgADJwsAAycMAAMnDgADJxAAAycRAAMnEgADJxQAAycVAAMnHgADJx8AAychAAMnZAADJ4gAAyesAAMnzwADJ/YAAygWAAMoPQADKGQAAyiEAAMoqAADKMwAAyjOAAMo0QADKNMAAyjVAAMo1wADKNoAAyjdAAMo3wADKOEAAyjkAAMo5gADKOgAAyjrAAMo7gADKO8AAyj0AAMpAQADKQQAAykGAAMpCQADKQwAAykOAAMpMwADKVcAAyl+AAMpogADKaUAAymnAAMpqQADKasAAymtAAMprwADKbAAAymzAAMpwAADKdMAAynVAAMp1wADKdkAAynbAAMp3QADKd8AAynhAAMp4wADKeUAAyn4AAMp+wADKf4AAyoBAAMqBAADKgcAAyoKAAMqDQADKhAAAyoTAAMqFQADKlQAAypWAAMqWQADKlsAAypeAAMqXwADKmAAAyphAAMqYgADKmQAAypmAAMqZwADKmgAAypqAAMqawADKnQAAyp1AAMqdwADKrYAAyq4AAMqugADKrwAAyq/AAMqwAADKsEAAyrCAAMqwwADKsUAAyrHAAMqyAADKskAAyrLAAMqzAADKwsAAysNAAMrEAADKxIAAysVAAMrFgADKxcAAysYAAMrGQADKxsAAysdAAMrHgADKx8AAyshAAMrIgADKysAAyssAAMrLgADK20AAytvAAMrcQADK3MAAyt2AAMrdwADK3gAAyt5AAMregADK3wAAyt+AAMrfwADK4AAAyuCAAMrgwADK8IAAyvEAAMrxwADK8kAAyvMAAMrzQADK84AAyvPAAMr0AADK9IAAyvUAAMr1QADK9YAAyvYAAMr2QADK+IAAyvjAAMr5QADLCQAAywmAAMsKAADLCoAAywtAAMsLgADLC8AAywwAAMsMQADLDMAAyw1AAMsNgADLDcAAyw5AAMsOgADLHkAAyx7AAMsfgADLIAAAyyDAAMshAADLIUAAyyGAAMshwADLIkAAyyLAAMsjAADLI0AAyyPAAMskAADLJ0AAyyeAAMsnwADLKEAAyzgAAMs4gADLOQAAyzmAAMs6QADLOoAAyzrAAMs7AADLO0AAyzvAAMs8QADLPIAAyzzAAMs9QADLPYAAy01AAMtNwADLToAAy08AAMtPwADLUAAAy1BAAMtQgADLUMAAy1FAAMtRwADLUgAAy1JAAMtSwADLUwAAy1nAAMtdAADLYsAAy2OAAMtkQADLZQAAy2XAAMtmgADLZ0AAy2gAAMtowADLaYAAy2pAAMtrAADLcMAAy3GAAMtyQADLcwAAy3PAAMt0gADLdUAAy3YAAMt2wADLd4AAy3hAAMt5AADLeYAAy3tAAMt9AADLf0AAy4CAAMuDQADLhkAAy4iAAMuJgADLjAAAy44AAMugwADLqYAAy7GAAMu5gADLugAAy7qAAMu7AADLu4AAy7xAAMu8gADLvMAAy72AAMu9wADLvkAAy76AAMu/AADLv8AAy8AAAMvAQADLwQAAy8FAAMvCgADLxcAAy8cAAMvHgADLyAAAy8lAAMvKAADLysAAy8tAAMvUgADL3YAAy+dAAMvwQADL8QAAy/GAAMvyAADL8oAAy/MAAMvzgADL88AAy/SAAMv3wADL/AAAy/yAAMv9AADL/YAAy/4AAMv+gADL/wAAy/+AAMwAAADMBEAAzAUAAMwFwADMBoAAzAdAAMwIAADMCMAAzAmAAMwKQADMCsAAzBqAAMwbAADMG4AAzBwAAMwcwADMHQAAzB1AAMwdgADMHcAAzB5AAMwewADMHwAAzB9AAMwfwADMIAAAzC/AAMwwQADMMMAAzDFAAMwyAADMMkAAzDKAAMwywADMMwAAzDOAAMw0AADMNEAAzDSAAMw1AADMNUAAzEUAAMxFgADMRkAAzEbAAMxHgADMR8AAzEgAAMxIQADMSIAAzEkAAMxJgADMScAAzEoAAMxKgADMSsAAzE4AAMxOQADMToAAzE8AAMxewADMX0AAzF/AAMxgQADMYQAAzGFAAMxhgADMYcAAzGIAAMxigADMYwAAzGNAAMxjgADMZAAAzGRAAMx0AADMdIAAzHUAAMx1gADMdkAAzHaAAMx2wADMdwAAzHdAAMx3wADMeEAAzHiAAMx4wADMeUAAzHmAAMyJQADMicAAzIpAAMyKwADMi4AAzIvAAMyMAADMjEAAzIyAAMyNAADMjYAAzI3AAMyOAADMjoAAzI7AAMyegADMnwAAzJ+AAMygAADMoMAAzKEAAMyhQADMoYAAzKHAAMyiQADMosAAzKMAAMyjQADMo8AAzKQAAMyzwADMtEAAzLTAAMy1QADMtgAAzLZAAMy2gADMtsAAzLcAAMy3gADMuAAAzLhAAMy4gADMuQAAzLlAAMzCgADMy4AAzNVAAMzeQADM3wAAzN+AAMzgAADM4IAAzOEAAMzhgADM4cAAzOKAAMzlwADM6YAAzOoAAMzqgADM6wAAzOuAAMzsAADM7IAAzO0AAMzwwADM8YAAzPJAAMzzAADM88AAzPSAAMz1QADM9gAAzPaAAM0GQADNBsAAzQdAAM0HwADNCIAAzQjAAM0JAADNCUAAzQmAAM0KAADNCoAAzQ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4AAM/ugADP7wAAz++AAM/wAADP8EAAz/EAAM/0QADP+IAAz/kAAM/5gADP+gAAz/qAAM/7AADP+4AAz/wAAM/8gADQAMAA0AGAANACQADQAwAA0APAANAEgADQBUAA0AYAANAGwADQB0AA0BcAANAXgADQGAAA0BiAANAZQADQGYAA0BnAANAaAADQGkAA0BrAANAbQADQG4AA0BvAANAcQADQHIAA0CxAANAswADQLUAA0C3AANAugADQLsAA0C8AANAvQADQL4AA0DAAANAwgADQMMAA0DEAANAxgADQMcAA0EGAANBCAADQQsAA0ENAANBEAADQREAA0ESAANBEwADQRQAA0EWAANBGAADQRkAA0EaAANBHAADQR0AA0EqAANBKwADQSwAA0EuAANBbQADQW8AA0FxAANBcwADQXYAA0F3AANBeAADQXkAA0F6AANBfAADQX4AA0F/AANBgAADQYIAA0GDAANBwgADQcQAA0HGAANByAADQcsAA0HMAANBzQADQc4AA0HPAANB0QADQdMAA0HUAANB1QADQdcAA0HYAANCFwADQhkAA0IbAANCHQADQiAAA0IhAANCIgADQiMAA0IkAANCJgADQigAA0IpAANCKgADQiwAA0ItAANCbAADQm4AA0JwAANCcgADQnUAA0J2AANCdwADQngAA0J5AANCewADQn0AA0J+AANCfwADQoEAA0KCAANCwQADQsMAA0LFAANCxwADQsoAA0LLAANCzAADQs0AA0LOAANC0AADQtIAA0LTAANC1AADQtYAA0LXAANC/AADQyAAA0NHAANDawADQ24AA0NwAANDcgADQ3QAA0N2AANDeAADQ3kAA0N8AANDiQADQ5gAA0OaAANDnAADQ54AA0OgAANDogADQ6QAA0OmAANDtQADQ7gAA0O7AANDvgADQ8EAA0PEAANDxwADQ8oAA0PMAANECwADRA0AA0QPAANEEQADRBQAA0QVAANEFgADRBcAA0QYAANEGgADRBwAA0QdAANEHgADRCAAA0QhAANEYAADRGIAA0RkAANEZgADRGkAA0RqAANEawADRGwAA0RtAANEbwADRHEAA0RyAANEcwADRHUAA0R2AANEtQADRLcAA0S5AANEuwADRL4AA0S/AANEwAADRMEAA0TCAANExAADRMYAA0THAANEyAADRMoAA0TLAANFCgADRQwAA0UOAANFEAADRRMAA0UUAANFFQADRRYAA0UXAANFGQADRRsAA0UcAANFHQADRR8AA0UgAANFXwADRWEAA0VjAANFZQADRWgAA0VpAANFagADRWsAA0VsAANFbgADRXAAA0VxAANFcgADRXQAA0V1AANFtAADRbYAA0W4AANFugADRb0AA0W+AANFvwADRcAAA0XBAANFwwADRcUAA0XGAANFxwADRckAA0XKAANGCQADRgsAA0YNAANGDwADRhIAA0YTAANGFAADRhUAA0YWAANGGAADRhoAA0YbAANGHAADRh4AA0YfAANGagADRo0AA0atAANGzQADRs8AA0bRAANG0wADRtUAA0bYAANG2QADRtoAA0bdAANG3gADRuAAA0bhAANG4wADRuYAA0bnAANG6AADRusAA0bsAANG8QADRv4AA0cDAANHBQADRwcAA0cMAANHDwADRxIAA0cUAANHOQADR10AA0eEAANHqAADR6sAA0etAANHrwADR7EAA0ezAANHtQADR7YAA0e5AANHxgADR9cAA0fZAANH2wADR90AA0ffAANH4QADR+MAA0flAANH5wADR/gAA0f7AANH/gADSAEAA0gEAANIBwADSAoAA0gNAANIEAADSBIAA0hRAANIUwADSFUAA0hXAANIWgADSFsAA0hcAANIXQADSF4AA0hgAANIYgADSGMAA0hkAANIZgADSGcAA0imAANIqAADSKoAA0isAANIrwADSLAAA0ixAANIsgADSLMAA0i1AANItwADSLgAA0i5AANIuwADSLwAA0j7AANI/QADSQAAA0kCAANJBQADSQYAA0kHAANJCAADSQkAA0kLAANJDQADSQ4AA0kPAANJEQADSRIAA0kfAANJIAADSSEAA0kjAANJYgADSWQAA0lmAANJaAADSWsAA0lsAANJbQADSW4AA0lvAANJcQADSXMAA0l0AANJdQADSXcAA0l4AANJtwADSbkAA0m7AANJvQADScAAA0nBAANJwgADScMAA0nEAANJxgADScgAA0nJAANJygADScwAA0nNAANKDAADSg4AA0oQAANKEgADShUAA0oWAANKFwADShgAA0oZAANKGwADSh0AA0oeAANKHwADSiEAA0oiAANKYQADSmMAA0plAANKZwADSmoAA0prAANKbAADSm0AA0puAANKcAADSnIAA0pzAANKdAADSnYAA0p3AANKtgADSrgAA0q6AANKvAADSr8AA0rAAANKwQADSsIAA0rDAANKxQADSscAA0rIAANKyQADSssAA0rMAANK8QADSxUAA0s8AANLYAADS2MAA0tlAANLZwADS2kAA0trAANLbQADS24AA0txAANLfgADS40AA0uPAANLkQADS5MAA0uVAANLlwADS5kAA0ubAANLqgADS60AA0uwAANLswADS7YAA0u5AANLvAADS78AA0vBAANMAAADTAIAA0wEAANMBgADTAkAA0wKAANMCwADTAwAA0wNAANMDwADTBEAA0wSAANMEwADTBUAA0wWAANMVQADTFcAA0xZAANMWwADTF4AA0xfAANMYAADTGEAA0xiAANMZAADTGYAA0xnAANMaAADTGoAA0xrAANMqgADTKwAA0yuAANMsAADTLMAA0y0AANMtQADTLYAA0y3AANMuQADTLsAA0y8AANMvQADTL8AA0zAAANM/wADTQEAA00EAANNBgADTQkAA00KAANNCwADTQwAA00NAANNDwADTREAA00SAANNEwADTRUAA00WAANNVQADTVcAA01ZAANNWwADTV4AA01fAANNYAADTWEAA01iAANNZAADTWYAA01nAANNaAADTWoAA01rAANNqgADTawAA02uAANNsAADTbMAA020AANNtQADTbYAA023AANNuQADTbsAA028AANNvQADTb8AA03AAANN/wADTgEAA04DAANOBQADTggAA04JAANOCgADTgsAA04MAANODgADThAAA04RAANOEgADThQAA04VAANOYAADToMAA06jAANOwwADTsUAA07HAANOyQADTssAA07OAANOzwADTtAAA07TAANO1AADTtYAA07XAANO2QADTtwAA07dAANO3gADTuEAA07iAANO5wADTvQAA075AANO+wADTv0AA08CAANPBQADTwgAA08KAANPLwADT1MAA096AANPngADT6EAA0+jAANPpQADT6cAA0+pAANPqwADT6wAA0+vAANPvAADT80AA0/PAANP0QADT9MAA0/VAANP1wADT9kAA0/bAANP3QADT+4AA0/xAANP9AADT/cAA0/6AANP/QADUAAAA1ADAANQBgADUAgAA1BHAANQSQADUEsAA1BNAANQUAADUFEAA1BSAANQUwADUFQAA1BWAANQWAADUFkAA1BaAANQXAADUF0AA1CcAANQngADUKAAA1CiAANQpQADUKYAA1CnAANQqAADUKkAA1CrAANQrQADUK4AA1CvAANQsQADULIAA1DxAANQ8wADUPYAA1D4AANQ+wADUPwAA1D9AANQ/gADUP8AA1EBAANRAwADUQQAA1EFAANRBwADUQgAA1EVAANRFgADURcAA1EZAANRWAADUVoAA1FcAANRXgADUWEAA1FiAANRYwADUWQAA1FlAANRZwADUWkAA1FqAANRawADUW0AA1FuAANRrQADUa8AA1GxAANRswADUbYAA1G3AANRuAADUbkAA1G6AANRvAADUb4AA1G/AANRwAADUcIAA1HDAANSAgADUgQAA1IGAANSCAADUgsAA1IMAANSDQADUg4AA1IPAANSEQADUhMAA1IUAANSFQADUhcAA1IYAANSVwADUlkAA1JbAANSXQADUmAAA1JhAANSYgADUmMAA1JkAANSZgADUmgAA1JpAANSagADUmwAA1JtAANSrAADUq4AA1KwAANSsgADUrUAA1K2AANStwADUrgAA1K5AANSuwADUr0AA1K+AANSvwADUsEAA1LCAANS5wADUwsAA1MyAANTVgADU1kAA1NbAANTXQADU18AA1NhAANTYwADU2QAA1NnAANTdAADU4MAA1OFAANThwADU4kAA1OLAANTjQADU48AA1ORAANToAADU6MAA1OmAANTqQADU6wAA1OvAANTsgADU7UAA1O3AANT9gADU/gAA1P6AANT/AADU/8AA1QAAANUAQADVAIAA1QDAANUBQADVAcAA1QIAANUCQADVAsAA1QMAANUSwADVE0AA1RPAANUUQADVFQAA1RVAANUVgADVFcAA1RYAANUWgADVFwAA1RdAANUXgADVGAAA1RhAANUoAADVKIAA1SkAANUpgADVKkAA1SqAANUqwADVKwAA1StAANUrwADVLEAA1SyAANUswADVLUAA1S2AANU9QADVPcAA1T5AANU+wADVP4AA1T/AANVAAADVQEAA1UCAANVBAADVQYAA1UHAANVCAADVQoAA1ULAANVSgADVUwAA1VOAANVUAADVVMAA1VUAANVVQADVVYAA1VXAANVWQADVVsAA1VcAANVXQADVV8AA1VgAANVnwADVaEAA1WjAANVpQADVagAA1WpAANVqgADVasAA1WsAANVrgADVbAAA1WxAANVsgADVbQAA1W1AANV9AADVfYAA1X4AANV+gADVf0AA1X+AANV/wADVgAAA1YBAANWAwADVgUAA1YGAANWBwADVgkAA1YKAANWVQADVngAA1aYAANWuAADVroAA1a8AANWvgADVsAAA1bDAANWxAADVsUAA1bIAANWyQADVssAA1bMAANWzgADVtEAA1bSAANW0wADVtYAA1bXAANW3AADVukAA1buAANW8AADVvIAA1b3AANW+gADVv0AA1b/AANXJAADV0gAA1dvAANXkwADV5YAA1eYAANXmgADV5wAA1eeAANXoAADV6EAA1ekAANXsQADV8IAA1fEAANXxgADV8gAA1fKAANXzAADV84AA1fQAANX0gADV+MAA1fmAANX6QADV+wAA1fvAANX8gADV/UAA1f4AANX+wADV/0AA1g8AANYPgADWEAAA1hCAANYRQADWEYAA1hHAANYSAADWEkAA1hLAANYTQADWE4AA1hPAANYUQADWFIAA1iRAANYkwADWJUAA1iXAANYmgADWJsAA1icAANYnQADWJ4AA1igAANYogADWKMAA1ikAANYpgADWKcAA1jmAANY6AADWOsAA1jtAANY8AADWPEAA1jyAANY8wADWPQAA1j2AANY+AADWPkAA1j6AANY/AADWP0AA1kKAANZCwADWQwAA1kOAANZTQADWU8AA1lRAANZUwADWVYAA1lXAANZWAADWVkAA1laAANZXAADWV4AA1lfAANZYAADWWIAA1ljAANZogADWaQAA1mmAANZqAADWasAA1msAANZrQADWa4AA1mvAANZsQADWbMAA1m0AANZtQADWbcAA1m4AANZ9wADWfkAA1n7AANZ/QADWgAAA1oBAANaAgADWgMAA1oEAANaBgADWggAA1oJAANaCgADWgwAA1oNAANaTAADWk4AA1pQAANaUgADWlUAA1pWAANaVwADWlgAA1pZAANaWwADWl0AA1peAANaXwADWmEAA1piAANaoQADWqMAA1qlAANapwADWqoAA1qrAANarAADWq0AA1quAANasAADWrIAA1qzAANatAADWrYAA1q3AANa3AADWwAAA1snAANbSwADW04AA1tQAANbUgADW1QAA1tWAANbWAADW1kAA1tcAANbaQADW3gAA1t6AANbfAADW34AA1uAAANbggADW4QAA1uGAANblQADW5gAA1ubAANbngADW6EAA1ukAANbpwADW6oAA1usAANb6wADW+0AA1vvAANb8QADW/QAA1v1AANb9gADW/cAA1v4AANb+gADW/wAA1v9AANb/gADXAAAA1wBAANcQAADXEIAA1xEAANcRgADXEkAA1xKAANcSwADXEwAA1xNAANcTwADXFEAA1xSAANcUwADXFUAA1xWAANclQADXJcAA1yZAANcmwADXJ4AA1yfAANcoAADXKEAA1yiAANcpAADXKYAA1ynAANcqAADXKoAA1yrAANc6gADXOwAA1zvAANc8QADXPQAA1z1AANc9gADXPcAA1z4AANc+gADXPwAA1z9AANc/gADXQAAA10BAANdQAADXUIAA11EAANdRgADXUkAA11KAANdSwADXUwAA11NAANdTwADXVEAA11SAANdUwADXVUAA11WAANdlQADXZcAA12ZAANdmwADXZ4AA12fAANdoAADXaEAA12iAANdpAADXaYAA12nAANdqAADXaoAA12rAANd6gADXewAA13uAANd8AADXfMAA130AANd9QADXfYAA133AANd+QADXfsAA138AANd/QADXf8AA14AAANeSwADXm4AA16OAANergADXrAAA16yAANetAADXrYAA165AANeugADXrsAA16+AANevwADXsEAA17CAANexAADXscAA17IAANeyQADXswAA17NAANe0gADXt8AA17kAANe5gADXugAA17tAANe8AADXvMAA171AANfGgADXz4AA19lAANfiQADX4wAA1+OAANfkAADX5IAA1+UAANflgADX5cAA1+aAANfpwADX7gAA1+6AANfvAADX74AA1/AAANfwgADX8QAA1/GAANfyAADX9kAA1/cAANf3wADX+IAA1/lAANf6AADX+sAA1/uAANf8QADX/MAA2AyAANgNAADYDYAA2A4AANgOwADYDwAA2A9AANgPgADYD8AA2BBAANgQwADYEQAA2BFAANgRwADYEgAA2CHAANgiQADYIsAA2CNAANgkAADYJEAA2CSAANgkwADYJQAA2CWAANgmAADYJkAA2CaAANgnAADYJ0AA2DcAANg3gADYOEAA2DjAANg5gADYOcAA2DoAANg6QADYOoAA2DsAANg7gADYO8AA2DwAANg8gADYPMAA2EAAANhAQADYQIAA2EEAANhQwADYUUAA2FHAANhSQADYUwAA2FNAANhTgADYU8AA2FQAANhUgADYVQAA2FVAANhVgADYVgAA2FZAANhmAADYZoAA2GcAANhngADYaEAA2GiAANhowADYaQAA2GlAANhpwADYakAA2GqAANhqwADYa0AA2GuAANh7QADYe8AA2HxAANh8wADYfYAA2H3AANh+AADYfkAA2H6AANh/AADYf4AA2H/AANiAAADYgIAA2IDAANiQgADYkQAA2JGAANiSAADYksAA2JMAANiTQADYk4AA2JPAANiUQADYlMAA2JUAANiVQADYlcAA2JYAANilwADYpkAA2KbAANinQADYqAAA2KhAANiogADYqMAA2KkAANipgADYqgAA2KpAANiqgADYqwAA2KtAANi0gADYvYAA2MdAANjQQADY0QAA2NGAANjSAADY0oAA2NMAANjTgADY08AA2NSAANjXwADY24AA2NwAANjcgADY3QAA2N2AANjeAADY3oAA2N8AANjiwADY44AA2ORAANjlAADY5cAA2OaAANjnQADY6AAA2OiAANj4QADY+MAA2PlAANj5wADY+oAA2PrAANj7AADY+0AA2PuAANj8AADY/IAA2PzAANj9AADY/YAA2P3AANkNgADZDgAA2Q6AANkPAADZD8AA2RAAANkQQADZEIAA2RDAANkRQADZEcAA2RIAANkSQADZEsAA2RMAANkiwADZI0AA2SPAANkkQADZJQAA2SVAANklgADZJcAA2SYAANkmgADZJwAA2SdAANkngADZKAAA2ShAANk4AADZOIAA2TkAANk5gADZOkAA2TqAANk6wADZOwAA2TtAANk7wADZPEAA2TyAANk8wADZPUAA2T2AANlNQADZTcAA2U5AANlOwADZT4AA2U/AANlQAADZUEAA2VCAANlRAADZUYAA2VHAANlSAADZUoAA2VLAANligADZYwAA2WOAANlkAADZZMAA2WUAANllQADZZYAA2WXAANlmQADZZsAA2WcAANlnQADZZ8AA2WgAANl3wADZeEAA2XjAANl5QADZegAA2XpAANl6gADZesAA2XsAANl7gADZfAAA2XxAANl8gADZfQAA2X1AANmQAADZmMAA2aDAANmowADZqUAA2anAANmqQADZqsAA2auAANmrwADZrAAA2azAANmtAADZrYAA2a3AANmuQADZrwAA2a9AANmvgADZsEAA2bCAANmxwADZtQAA2bZAANm2wADZt0AA2biAANm5QADZugAA2bqAANnDwADZzMAA2daAANnfgADZ4EAA2eDAANnhQADZ4cAA2eJAANniwADZ4wAA2ePAANnnAADZ60AA2evAANnsQADZ7MAA2e1AANntwADZ7kAA2e7AANnvQADZ84AA2fRAANn1AADZ9cAA2faAANn3QADZ+AAA2fjAANn5gADZ+gAA2gnAANoKQADaCsAA2gtAANoMAADaDEAA2gyAANoMwADaDQAA2g2AANoOAADaDkAA2g6AANoPAADaD0AA2h8AANofgADaIAAA2iCAANohQADaIYAA2iHAANoiAADaIkAA2iLAANojQADaI4AA2iPAANokQADaJIAA2jRAANo0wADaNYAA2jYAANo2wADaNwAA2jdAANo3gADaN8AA2jhAANo4wADaOQAA2jlAANo5wADaOgAA2j1AANo9gADaPcAA2j5AANpOAADaToAA2k8AANpPgADaUEAA2lCAANpQwADaUQAA2lFAANpRwADaUkAA2lKAANpSwADaU0AA2lOAANpjQADaY8AA2mRAANpkwADaZYAA2mXAANpmAADaZkAA2maAANpnAADaZ4AA2mfAANpoAADaaIAA2mjAANp4gADaeQAA2nmAANp6AADaesAA2nsAANp7QADae4AA2nvAANp8QADafMAA2n0AANp9QADafcAA2n4AANqNwADajkAA2o7AANqPQADakAAA2pBAANqQgADakMAA2pEAANqRgADakgAA2pJAANqSgADakwAA2pNAANqjAADao4AA2qQAANqkgADapUAA2qWAANqlwADapgAA2qZAANqmwADap0AA2qeAANqnwADaqEAA2qiAANqxwADausAA2sSAANrNgADazkAA2s7AANrPQADaz8AA2tBAANrQwADa0QAA2tHAANrVAADa2MAA2tlAANrZwADa2kAA2trAANrbQADa28AA2txAANrgAADa4MAA2uGAANriQADa4wAA2uPAANrkgADa5UAA2uXAANr1gADa9gAA2vaAANr3AADa98AA2vgAANr4QADa+IAA2vjAANr5QADa+cAA2voAANr6QADa+sAA2vsAANsKwADbC0AA2wvAANsMQADbDQAA2w1AANsNgADbDcAA2w4AANsOgADbDwAA2w9AANsPgADbEAAA2xBAANsgAADbIIAA2yEAANshgADbIkAA2yKAANsiwADbIwAA2yNAANsjwADbJEAA2ySAANskwADbJUAA2yWAANs1QADbNcAA2zZAANs2wADbN4AA2zfAANs4AADbOEAA2ziAANs5AADbOYAA2znAANs6AADbOoAA2zrAANtKgADbSwAA20uAANtMAADbTMAA200AANtNQADbTYAA203AANtOQADbTsAA208AANtPQADbT8AA21AAANtfwADbYEAA22DAANthQADbYgAA22JAANtigADbYsAA22MAANtjgADbZAAA22RAANtkgADbZQAA22VAANt1AADbdYAA23YAANt2gADbd0AA23eAANt3wADbeAAA23hAANt4wADbeUAA23mAANt5wADbekAA23qAANuNQADblgAA254AANumAADbpoAA26cAANungADbqAAA26jAANupAADbqUAA26oAANuqQADbqsAA26sAANurgADbrEAA26yAANuswADbrYAA263AANuvAADbskAA27OAANu0AADbtIAA27XAANu2gADbt0AA27fAANvBAADbygAA29PAANvcwADb3YAA294AANvegADb3wAA29+AANvgAADb4EAA2+EAANvkQADb6IAA2+kAANvpgADb6gAA2+qAANvrAADb64AA2+wAANvsgADb8MAA2/GAANvyQADb8wAA2/PAANv0gADb9UAA2/YAANv2wADb90AA3AcAANwHgADcCAAA3AiAANwJQADcCYAA3AnAANwKAADcCkAA3ArAANwLQADcC4AA3AvAANwMQADcDIAA3BxAANwcwADcHUAA3B3AANwegADcHsAA3B8AANwfQADcH4AA3CAAANwggADcIMAA3CEAANwhgADcIcAA3DGAANwyAADcMsAA3DNAANw0AADcNEAA3DSAANw0wADcNQAA3DWAANw2AADcNkAA3DaAANw3AADcN0AA3DqAANw6wADcOwAA3DuAANxLQADcS8AA3ExAANxMwADcTYAA3E3AANxOAADcTkAA3E6AANxPAADcT4AA3E/AANxQAADcUIAA3FDAANxggADcYQAA3GGAANxiAADcYsAA3GMAANxjQADcY4AA3GPAANxkQADcZMAA3GUAANxlQADcZcAA3GYAANx1wADcdkAA3HbAANx3QADceAAA3HhAANx4gADceMAA3HkAANx5gADcegAA3HpAANx6gADcewAA3HtAANyLAADci4AA3IwAANyMgADcjUAA3I2AANyNwADcjgAA3I5AANyOwADcj0AA3I+AANyPwADckEAA3JCAANygQADcoMAA3KFAANyhwADcooAA3KLAANyjAADco0AA3KOAANykAADcpIAA3KTAANylAADcpYAA3KXAANyvAADcuAAA3MHAANzKwADcy4AA3MwAANzMgADczQAA3M2AANzOAADczkAA3M8AANzSQADc1gAA3NaAANzXAADc14AA3NgAANzYgADc2QAA3NmAANzdQADc3gAA3N7AANzfgADc4EAA3OEAANzhwADc4oAA3OMAANzywADc80AA3PPAANz0QADc9QAA3PVAANz1gADc9cAA3PYAANz2gADc9wAA3PdAANz3gADc+AAA3PhAAN0IAADdCIAA3QkAAN0JgADdCkAA3QqAAN0KwADdCwAA3QtAAN0LwADdDEAA3QyAAN0MwADdDUAA3Q2AAN0dQADdHcAA3R5AAN0ewADdH4AA3R/AAN0gAADdIEAA3SCAAN0hAADdIYAA3SHAAN0iAADdIoAA3SLAAN0ygADdMwAA3TOAAN00AADdNMAA3TUAAN01QADdNYAA3TXAAN02QADdNsAA3TcAAN03QADdN8AA3TgAAN1HwADdSEAA3UjAAN1JQADdSgAA3UpAAN1KgADdSsAA3UsAAN1LgADdTAAA3UxAAN1MgADdTQAA3U1AAN1dAADdXYAA3V4AAN1egADdX0AA3V+AAN1fwADdYAAA3WBAAN1gwADdYUAA3WGAAN1hwADdYkAA3WKAAN1yQADdcsAA3XNAAN1zwADddIAA3XTAAN11AADddUAA3XWAAN12AADddoAA3XbAAN13AADdd4AA3XfAAN2KgADdk0AA3ZtAAN2jQADdo8AA3aRAAN2kwADdpUAA3aYAAN2mQADdpoAA3adAAN2ngADdqAAA3ahAAN2owADdqYAA3anAAN2qAADdqsAA3asAAN2sQADdr4AA3bDAAN2xQADdscAA3bMAAN2zwADdtIAA3bUAAN2+QADdx0AA3dEAAN3aAADd2sAA3dtAAN3bwADd3EAA3dzAAN3dQADd3YAA3d5AAN3hgADd5cAA3eZAAN3mwADd50AA3efAAN3oQADd6MAA3elAAN3pwADd7gAA3e7AAN3vgADd8EAA3fEAAN3xwADd8oAA3fNAAN30AADd9IAA3gRAAN4EwADeBUAA3gXAAN4GgADeBsAA3gcAAN4HQADeB4AA3ggAAN4IgADeCMAA3gkAAN4JgADeCcAA3hmAAN4aAADeGoAA3hsAAN4bwADeHAAA3hxAAN4cgADeHMAA3h1AAN4dwADeHgAA3h5AAN4ewADeHwAA3i7AAN4vQADeMAAA3jCAAN4xQADeMYAA3jHAAN4yAADeMkAA3jLAAN4zQADeM4AA3jPAAN40QADeNIAA3jfAAN44AADeOEAA3jjAAN5IgADeSQAA3kmAAN5KAADeSsAA3ksAAN5LQADeS4AA3kvAAN5MQADeTMAA3k0AAN5NQADeTcAA3k4AAN5dwADeXkAA3l7AAN5fQADeYAAA3mBAAN5ggADeYMAA3mEAAN5hgADeYgAA3mJAAN5igADeYwAA3mNAAN5zAADec4AA3nQAAN50gADedUAA3nWAAN51wADedgAA3nZAAN52wADed0AA3neAAN53wADeeEAA3niAAN6IQADeiMAA3olAAN6JwADeioAA3orAAN6LAADei0AA3ouAAN6MAADejIAA3ozAAN6NAADejYAA3o3AAN6dgADengAA3p6AAN6fAADen8AA3qAAAN6gQADeoIAA3qDAAN6hQADeocAA3qIAAN6iQADeosAA3qMAAN6sQADetUAA3r8AAN7IAADeyMAA3slAAN7JwADeykAA3srAAN7LQADey4AA3sxAAN7PgADe00AA3tPAAN7UQADe1MAA3tVAAN7VwADe1kAA3tbAAN7agADe20AA3twAAN7cwADe3YAA3t5AAN7fAADe38AA3uBAAN7wAADe8IAA3vEAAN7xgADe8kAA3vKAAN7ywADe8wAA3vNAAN7zwADe9EAA3vSAAN70wADe9UAA3vWAAN8FQADfBcAA3wZAAN8GwADfB4AA3wfAAN8IAADfCEAA3wiAAN8JAADfCYAA3wnAAN8KAADfCoAA3wrAAN8agADfGwAA3xuAAN8cAADfHMAA3x0AAN8dQADfHYAA3x3AAN8eQADfHsAA3x8AAN8fQADfH8AA3yAAAN8vwADfMEAA3zEAAN8xgADfMkAA3zKAAN8ywADfMwAA3zNAAN8zwADfNEAA3zSAAN80wADfNUAA3zWAAN9FQADfRcAA30ZAAN9GwADfR4AA30fAAN9IAADfSEAA30iAAN9JAADfSYAA30nAAN9KAADfSoAA30rAAN9agADfWwAA31uAAN9cAADfXMAA310AAN9dQADfXYAA313AAN9eQADfXsAA318AAN9fQADfX8AA32AAAN9vwADfcEAA33DAAN9xQADfcgAA33JAAN9ygADfcsAA33MAAN9zgADfdAAA33RAAN90gADfdQAA33VAAN+IAADfkMAA35jAAN+gwADfoUAA36HAAN+iQADfosAA36OAAN+jwADfpAAA36TAAN+lAADfpYAA36XAAN+mQADfpwAA36dAAN+ngADfqEAA36iAAN+pwADfrQAA365AAN+uwADfr0AA37CAAN+xQADfsgAA37KAAN+7wADfxMAA386AAN/XgADf2EAA39jAAN/ZQADf2cAA39pAAN/awADf2wAA39vAAN/fAADf40AA3+PAAN/kQADf5MAA3+VAAN/lwADf5kAA3+bAAN/nQADf64AA3+xAAN/tAADf7cAA3+6AAN/vQADf8AAA3/DAAN/xgADf8gAA4AHAAOACQADgAsAA4ANAAOAEAADgBEAA4ASAAOAEwADgBQAA4AWAAOAGAADgBkAA4AaAAOAHAADgB0AA4BcAAOAXgADgGAAA4BiAAOAZQADgGYAA4BnAAOAaAADgGkAA4BrAAOAbQADgG4AA4BvAAOAcQADgHIAA4CxAAOAswADgLYAA4C4AAOAuwADgLwAA4C9AAOAvgADgL8AA4DBAAOAwwADgMQAA4DFAAOAxwADgMgAA4DVAAOA1gADgNcAA4DZAAOBGAADgRoAA4EcAAOBHgADgSEAA4EiAAOBIwADgSQAA4ElAAOBJwADgSkAA4EqAAOBKwADgS0AA4EuAAOBbQADgW8AA4FxAAOBcwADgXYAA4F3AAOBeAADgXkAA4F6AAOBfAADgX4AA4F/AAOBgAADgYIAA4GDAAOBwgADgcQAA4HGAAOByAADgcsAA4HMAAOBzQADgc4AA4HPAAOB0QADgdMAA4HUAAOB1QADgdcAA4HYAAOCFwADghkAA4IbAAOCHQADgiAAA4IhAAOCIgADgiMAA4IkAAOCJgADgigAA4IpAAOCKgADgiwAA4ItAAOCbAADgm4AA4JwAAOCcgADgnUAA4J2AAOCdwADgngAA4J5AAOCewADgn0AA4J+AAOCfwADgoEAA4KCAAOCpwADgssAA4LyAAODFgADgxkAA4MbAAODHQADgx8AA4MhAAODIwADgyQAA4MnAAODNAADg0MAA4NFAAODRwADg0kAA4NLAAODTQADg08AA4NRAAODYAADg2MAA4NmAAODaQADg2wAA4NvAAODcgADg3UAA4N3AAODtgADg7gAA4O6AAODvAADg78AA4PAAAODwQADg8IAA4PDAAODxQADg8cAA4PIAAODyQADg8sAA4PMAAOECwADhA0AA4QPAAOEEQADhBQAA4QVAAOEFgADhBcAA4QYAAOEGgADhBwAA4QdAAOEHgADhCAAA4QhAAOEYAADhGIAA4RkAAOEZgADhGkAA4RqAAOEawADhGwAA4RtAAOEbwADhHEAA4RyAAOEcwADhHUAA4R2AAOEtQADhLcAA4S5AAOEuwADhL4AA4S/AAOEwAADhMEAA4TCAAOExAADhMYAA4THAAOEyAADhMoAA4TLAAOFCgADhQwAA4UOAAOFEAADhRMAA4UUAAOFFQADhRYAA4UXAAOFGQADhRsAA4UcAAOFHQADhR8AA4UgAAOFXwADhWEAA4VjAAOFZQADhWgAA4VpAAOFagADhWsAA4VsAAOFbgADhXAAA4VxAAOFcgADhXQAA4V1AAOFtAADhbYAA4W4AAOFugADhb0AA4W+AAOFvwADhcAAA4XBAAOFwwADhcUAA4XGAAOFxwADhckAA4XKAAOF0wADhdQAA4XWAAOGGQADhj0AA4ZhAAOGhAADhqsAA4bLAAOG8gADhxkAA4c5AAOHXQADh4EAA4eDAAOHhgADh4gAA4eKAAOHjAADh48AA4eSAAOHlAADh5YAA4eZAAOHmwADh50AA4egAAOHowADh6QAA4epAAOHtgADh7kAA4e7AAOHvgADh8EAA4fDAAOH6AADiAwAA4gzAAOIVwADiFoAA4hcAAOIXgADiGAAA4hiAAOIZAADiGUAA4hoAAOIdQADiIgAA4iKAAOIjAADiI4AA4iQAAOIkgADiJQAA4iWAAOImAADiJoAA4itAAOIsAADiLMAA4i2AAOIuQADiLwAA4i/AAOIwgADiMUAA4jIAAOIygADiQkAA4kLAAOJDgADiRAAA4kTAAOJFAADiRUAA4kWAAOJFwADiRkAA4kbAAOJHAADiR0AA4kfAAOJIAADiSkAA4kqAAOJLAADiWsAA4ltAAOJbwADiXEAA4l0AAOJdQADiXYAA4l3AAOJeAADiXoAA4l8AAOJfQADiX4AA4mAAAOJgQADicAAA4nCAAOJxQADiccAA4nKAAOJywADicwAA4nNAAOJzgADidAAA4nSAAOJ0wADidQAA4nWAAOJ1wADieAAA4nhAAOJ4wADiiIAA4okAAOKJgADiigAA4orAAOKLAADii0AA4ouAAOKLwADijEAA4ozAAOKNAADijUAA4o3AAOKOAADincAA4p5AAOKfAADin4AA4qBAAOKggADioMAA4qEAAOKhQADiocAA4qJAAOKigADiosAA4qNAAOKjgADipcAA4qYAAOKmgADitkAA4rbAAOK3QADit8AA4riAAOK4wADiuQAA4rlAAOK5gADiugAA4rqAAOK6wADiuwAA4ruAAOK7wADiy4AA4swAAOLMwADizUAA4s4AAOLOQADizoAA4s7AAOLPAADiz4AA4tAAAOLQQADi0IAA4tEAAOLRQADi1IAA4tTAAOLVAADi1YAA4uVAAOLlwADi5kAA4ubAAOLngADi58AA4ugAAOLoQADi6IAA4ukAAOLpgADi6cAA4uoAAOLqgADi6sAA4vqAAOL7AADi+4AA4vwAAOL8wADi/QAA4v1AAOL9gADi/cAA4v5AAOL+wADi/wAA4v9AAOL/wADjAAAA4wNAAOMFAADjBcAA4wZAAOMGwADjCIAA4wlAAOMKAADjCsAA4wtAAOMeAADjJsAA4y7AAOM2wADjN0AA4zfAAOM4QADjOMAA4zmAAOM5wADjOgAA4zrAAOM7AADjO4AA4zvAAOM8QADjPQAA4z1AAOM9gADjPkAA4z6AAONAwADjRAAA40VAAONFwADjRkAA40eAAONIQADjSQAA40mAAONSwADjW8AA42WAAONugADjb0AA42/AAONwQADjcMAA43FAAONxwADjcgAA43LAAON2AADjekAA43rAAON7QADje8AA43xAAON8wADjfUAA433AAON+QADjgoAA44NAAOOEAADjhMAA44WAAOOGQADjhwAA44fAAOOIgADjiQAA45jAAOOZQADjmcAA45pAAOObAADjm0AA45uAAOObwADjnAAA45yAAOOdAADjnUAA452AAOOeAADjnkAA464AAOOugADjrwAA46+AAOOwQADjsIAA47DAAOOxAADjsUAA47HAAOOyQADjsoAA47LAAOOzQADjs4AA48NAAOPDwADjxIAA48UAAOPFwADjxgAA48ZAAOPGgADjxsAA48dAAOPHwADjyAAA48hAAOPIwADjyQAA48xAAOPMgADjzMAA481AAOPdAADj3YAA494AAOPegADj30AA49+AAOPfwADj4AAA4+BAAOPgwADj4UAA4+GAAOPhwADj4kAA4+KAAOPyQADj8sAA4/NAAOPzwADj9IAA4/TAAOP1AADj9UAA4/WAAOP2AADj9oAA4/bAAOP3AADj94AA4/fAAOQHgADkCAAA5AiAAOQJAADkCcAA5AoAAOQKQADkCoAA5ArAAOQLQADkC8AA5AwAAOQMQADkDMAA5A0AAOQcwADkHUAA5B3AAOQeQADkHwAA5B9AAOQfgADkH8AA5CAAAOQggADkIQAA5CFAAOQhgADkIgAA5CJAAOQyAADkMoAA5DMAAOQzgADkNEAA5DSAAOQ0wADkNQAA5DVAAOQ1wADkNkAA5DaAAOQ2wADkN0AA5DeAAORAwADkScAA5FOAAORcgADkXUAA5F3AAOReQADkXsAA5F9AAORfwADkYAAA5GDAAORkAADkZ8AA5GhAAORowADkaUAA5GnAAORqQADkasAA5GtAAORvAADkb8AA5HCAAORxQADkcgAA5HLAAORzgADkdEAA5HTAAOSEgADkhQAA5IWAAOSGAADkhsAA5IcAAOSHQADkh4AA5IfAAOSIQADkiMAA5IkAAOSJQADkicAA5IoAAOSZwADkmkAA5JrAAOSbQADknAAA5JxAAOScgADknMAA5J0AAOSdgADkngAA5J5AAOSegADknwAA5J9AAOSvAADkr4AA5LAAAOSwgADksUAA5LGAAOSxwADksgAA5LJAAOSywADks0AA5LOAAOSzwADktEAA5LSAAOTEQADkxMAA5MVAAOTFwADkxoAA5MbAAOTHAADkx0AA5MeAAOTIAADkyIAA5MjAAOTJAADkyYAA5MnAAOTZgADk2gAA5NqAAOTbAADk28AA5NwAAOTcQADk3IAA5NzAAOTdQADk3cAA5N4AAOTeQADk3sAA5N8AAOTuwADk70AA5O/AAOTwQADk8QAA5PFAAOTxgADk8cAA5PIAAOTygADk8wAA5PNAAOTzgADk9AAA5PRAAOUEAADlBIAA5QUAAOUFgADlBkAA5QaAAOUGwADlBwAA5QdAAOUHwADlCEAA5QiAAOUIwADlCUAA5QmAAOUcQADlJQAA5S0AAOU1AADlNYAA5TYAAOU2gADlNwAA5TfAAOU4AADlOEAA5TkAAOU5QADlOcAA5ToAAOU6gADlOwAA5TtAAOU7gADlPEAA5TyAAOU9wADlQQAA5UJAAOVCwADlQ0AA5USAAOVFQADlRgAA5UaAAOVPwADlWMAA5WKAAOVrgADlbEAA5WzAAOVtQADlbcAA5W5AAOVuwADlbwAA5W/AAOVzAADld0AA5XfAAOV4QADleMAA5XlAAOV5wADlekAA5XrAAOV7QADlf4AA5YBAAOWBAADlgcAA5YKAAOWDQADlhAAA5YTAAOWFgADlhgAA5ZXAAOWWQADllsAA5ZdAAOWYAADlmEAA5ZiAAOWYwADlmQAA5ZmAAOWaAADlmkAA5ZqAAOWbAADlm0AA5asAAOWrgADlrAAA5ayAAOWtQADlrYAA5a3AAOWuAADlrkAA5a7AAOWvQADlr4AA5a/AAOWwQADlsIAA5cBAAOXAwADlwYAA5cIAAOXCwADlwwAA5cNAAOXDgADlw8AA5cRAAOXEwADlxQAA5cVAAOXFwADlxgAA5clAAOXJgADlycAA5cpAAOXaAADl2oAA5dsAAOXbgADl3EAA5dyAAOXcwADl3QAA5d1AAOXdwADl3kAA5d6AAOXewADl30AA5d+AAOXvQADl78AA5fBAAOXwwADl8YAA5fHAAOXyAADl8kAA5fKAAOXzAADl84AA5fPAAOX0AADl9IAA5fTAAOYEgADmBQAA5gWAAOYGAADmBsAA5gcAAOYHQADmB4AA5gfAAOYIQADmCMAA5gkAAOYJQADmCcAA5goAAOYZwADmGkAA5hrAAOYbQADmHAAA5hxAAOYcgADmHMAA5h0AAOYdgADmHgAA5h5AAOYegADmHwAA5h9AAOYvAADmL4AA5jAAAOYwgADmMUAA5jGAAOYxwADmMgAA5jJAAOYywADmM0AA5jOAAOYzwADmNEAA5jSAAOY9wADmRsAA5lCAAOZZgADmWkAA5lrAAOZbQADmW8AA5lxAAOZcwADmXQAA5l3AAOZhAADmZMAA5mVAAOZlwADmZkAA5mbAAOZnQADmZ8AA5mhAAOZsAADmbMAA5m2AAOZuQADmbwAA5m/AAOZwgADmcUAA5nHAAOaBgADmggAA5oKAAOaDAADmg8AA5oQAAOaEQADmhIAA5oTAAOaFQADmhcAA5oYAAOaGQADmhsAA5ocAAOaWwADml0AA5pfAAOaYQADmmQAA5plAAOaZgADmmcAA5poAAOaagADmmwAA5ptAAOabgADmnAAA5pxAAOasAADmrIAA5q0AAOatgADmrkAA5q6AAOauwADmrwAA5q9AAOavwADmsEAA5rCAAOawwADmsUAA5rGAAObBQADmwcAA5sJAAObCwADmw4AA5sPAAObEAADmxEAA5sSAAObFAADmxYAA5sXAAObGAADmxoAA5sbAAObWgADm1wAA5teAAObYAADm2MAA5tkAAObZQADm2YAA5tnAAObaQADm2sAA5tsAAObbQADm28AA5twAAObrwADm7EAA5uzAAObtQADm7gAA5u5AAObugADm7sAA5u8AAObvgADm8AAA5vBAAObwgADm8QAA5vFAAOcBAADnAYAA5wIAAOcCgADnA0AA5wOAAOcDwADnBAAA5wRAAOcEwADnBUAA5wWAAOcFwADnBkAA5waAAOcZQADnIgAA5yoAAOcyAADnMoAA5zMAAOczgADnNAAA5zTAAOc1AADnNUAA5zYAAOc2QADnNsAA5zcAAOc3gADnOAAA5zhAAOc4gADnOUAA5zmAAOc7wADnPwAA50BAAOdAwADnQUAA50KAAOdDQADnRAAA50SAAOdNwADnVsAA52CAAOdpgADnakAA52rAAOdrQADna8AA52xAAOdswADnbQAA523AAOdxAADndUAA53XAAOd2QADndsAA53dAAOd3wADneEAA53jAAOd5QADnfYAA535AAOd/AADnf8AA54CAAOeBQADnggAA54LAAOeDgADnhAAA55PAAOeUQADnlMAA55VAAOeWAADnlkAA55aAAOeWwADnlwAA55eAAOeYAADnmEAA55iAAOeZAADnmUAA56kAAOepgADnqgAA56qAAOerQADnq4AA56vAAOesAADnrEAA56zAAOetQADnrYAA563AAOeuQADnroAA575AAOe+wADnv4AA58AAAOfAwADnwQAA58FAAOfBgADnwcAA58JAAOfCwADnwwAA58NAAOfDwADnxAAA58dAAOfHgADnx8AA58hAAOfYAADn2IAA59kAAOfZgADn2kAA59qAAOfawADn2wAA59tAAOfbwADn3EAA59yAAOfcwADn3UAA592AAOftQADn7cAA5+5AAOfuwADn74AA5+/AAOfwAADn8EAA5/CAAOfxAADn8YAA5/HAAOfyAADn8oAA5/LAAOgCgADoAwAA6AOAAOgEAADoBMAA6AUAAOgFQADoBYAA6AXAAOgGQADoBsAA6AcAAOgHQADoB8AA6AgAAOgXwADoGEAA6BjAAOgZQADoGgAA6BpAAOgagADoGsAA6BsAAOgbgADoHAAA6BxAAOgcgADoHQAA6B1AAOgtAADoLYAA6C4AAOgugADoL0AA6C+AAOgvwADoMAAA6DBAAOgwwADoMUAA6DGAAOgxwADoMkAA6DKAAOg7wADoRMAA6E6AAOhXgADoWEAA6FjAAOhZQADoWcAA6FpAAOhawADoWwAA6FvAAOhfAADoYsAA6GNAAOhjwADoZEAA6GTAAOhlQADoZcAA6GZAAOhqAADoasAA6GuAAOhsQADobQAA6G3AAOhugADob0AA6G/AAOh/gADogAAA6ICAAOiBAADogcAA6IIAAOiCQADogoAA6ILAAOiDQADog8AA6IQAAOiEQADohMAA6IUAAOiUwADolUAA6JXAAOiWQADolwAA6JdAAOiXgADol8AA6JgAAOiYgADomQAA6JlAAOiZgADomgAA6JpAAOiqAADoqoAA6KsAAOirgADorEAA6KyAAOiswADorQAA6K1AAOitwADorkAA6K6AAOiuwADor0AA6K+AAOi/QADov8AA6MBAAOjAwADowYAA6MHAAOjCAADowkAA6MKAAOjDAADow4AA6MPAAOjEAADoxIAA6MTAAOjUgADo1QAA6NWAAOjWAADo1sAA6NcAAOjXQADo14AA6NfAAOjYQADo2MAA6NkAAOjZQADo2cAA6NoAAOjpwADo6kAA6OrAAOjrQADo7AAA6OxAAOjsgADo7MAA6O0AAOjtgADo7gAA6O5AAOjugADo7wAA6O9AAOj/AADo/4AA6QAAAOkAgADpAUAA6QGAAOkBwADpAgAA6QJAAOkCwADpA0AA6QOAAOkDwADpBEAA6QSAAOkGwADpBwAA6QeAAOkYQADpIUAA6SpAAOkzAADpPMAA6UTAAOlOgADpWEAA6WBAAOlpQADpckAA6XLAAOlzgADpdAAA6XSAAOl1AADpdcAA6XaAAOl3AADpd4AA6XhAAOl4wADpeUAA6XoAAOl6wADpewAA6XxAAOl/gADpgEAA6YDAAOmBgADpgkAA6YLAAOmMAADplQAA6Z7AAOmnwADpqIAA6akAAOmpgADpqgAA6aqAAOmrAADpq0AA6awAAOmvQADptAAA6bSAAOm1AADptYAA6bYAAOm2gADptwAA6beAAOm4AADpuIAA6b1AAOm+AADpvsAA6b+AAOnAQADpwQAA6cHAAOnCgADpw0AA6cQAAOnEgADp1EAA6dTAAOnVgADp1gAA6dbAAOnXAADp10AA6deAAOnXwADp2EAA6djAAOnZAADp2UAA6dnAAOnaAADp3EAA6dyAAOndAADp7MAA6e1AAOntwADp7kAA6e8AAOnvQADp74AA6e/AAOnwAADp8IAA6fEAAOnxQADp8YAA6fIAAOnyQADqAgAA6gKAAOoDQADqA8AA6gSAAOoEwADqBQAA6gVAAOoFgADqBgAA6gaAAOoGwADqBwAA6geAAOoHwADqCgAA6gpAAOoKwADqGoAA6hsAAOobgADqHAAA6hzAAOodAADqHUAA6h2AAOodwADqHkAA6h7AAOofAADqH0AA6h/AAOogAADqL8AA6jBAAOoxAADqMYAA6jJAAOoygADqMsAA6jMAAOozQADqM8AA6jRAAOo0gADqNMAA6jVAAOo1gADqN8AA6jgAAOo4gADqSEAA6kjAAOpJQADqScAA6kqAAOpKwADqSwAA6ktAAOpLgADqTAAA6kyAAOpMwADqTQAA6k2AAOpNwADqXYAA6l4AAOpewADqX0AA6mAAAOpgQADqYIAA6mDAAOphAADqYYAA6mIAAOpiQADqYoAA6mMAAOpjQADqZoAA6mbAAOpnAADqZ4AA6ndAAOp3wADqeEAA6njAAOp5gADqecAA6noAAOp6QADqeoAA6nsAAOp7gADqe8AA6nwAAOp8gADqfMAA6oyAAOqNAADqjcAA6o5AAOqPAADqj0AA6o+AAOqPwADqkAAA6pCAAOqRAADqkUAA6pGAAOqSAADqkkAA6pYAAOqZQADqmwAA6pvAAOqcgADqnUAA6p8AAOqfwADqoIAA6qFAAOqhwADqo4AA6qYAAOq4wADqwYAA6smAAOrRgADq0gAA6tKAAOrTAADq04AA6tRAAOrUgADq1MAA6tWAAOrVwADq1kAA6taAAOrXAADq18AA6tgAAOrYQADq2QAA6tlAAOragADq3cAA6t8AAOrfgADq4AAA6uFAAOriAADq4sAA6uNAAOrsgADq9YAA6v9AAOsIQADrCQAA6wmAAOsKAADrCoAA6wsAAOsLgADrC8AA6wyAAOsPwADrFAAA6xSAAOsVAADrFYAA6xYAAOsWgADrFwAA6xeAAOsYAADrHEAA6x0AAOsdwADrHoAA6x9AAOsgAADrIMAA6yGAAOsiQADrIsAA6zKAAOszAADrM4AA6zQAAOs0wADrNQAA6zVAAOs1gADrNcAA6zZAAOs2wADrNwAA6zdAAOs3wADrOAAA60fAAOtIQADrSMAA60lAAOtKAADrSkAA60qAAOtKwADrSwAA60uAAOtMAADrTEAA60yAAOtNAADrTUAA610AAOtdgADrXkAA617AAOtfgADrX8AA62AAAOtgQADrYIAA62EAAOthgADrYcAA62IAAOtigADrYsAA62YAAOtmQADrZoAA62cAAOt2wADrd0AA63fAAOt4QADreQAA63lAAOt5gADrecAA63oAAOt6gADrewAA63tAAOt7gADrfAAA63xAAOuMAADrjIAA640AAOuNgADrjkAA646AAOuOwADrjwAA649AAOuPwADrkEAA65CAAOuQwADrkUAA65GAAOuhQADrocAA66JAAOuiwADro4AA66PAAOukAADrpEAA66SAAOulAADrpYAA66XAAOumAADrpoAA66bAAOu2gADrtwAA67eAAOu4AADruMAA67kAAOu5QADruYAA67nAAOu6QADrusAA67sAAOu7QADru8AA67wAAOvLwADrzEAA68zAAOvNQADrzgAA685AAOvOgADrzsAA688AAOvPgADr0AAA69BAAOvQgADr0QAA69FAAOvagADr44AA6+1AAOv2QADr9wAA6/eAAOv4AADr+IAA6/kAAOv5gADr+cAA6/qAAOv9wADsAYAA7AIAAOwCgADsAwAA7AOAAOwEAADsBIAA7AUAAOwIwADsCYAA7ApAAOwLAADsC8AA7AyAAOwNQADsDgAA7A6AAOweQADsHsAA7B9AAOwfwADsIIAA7CDAAOwhAADsIUAA7CGAAOwiAADsIoAA7CLAAOwjAADsI4AA7CPAAOwzgADsNAAA7DSAAOw1AADsNcAA7DYAAOw2QADsNoAA7DbAAOw3QADsN8AA7DgAAOw4QADsOMAA7DkAAOxIwADsSUAA7EnAAOxKQADsSwAA7EtAAOxLgADsS8AA7EwAAOxMgADsTQAA7E1AAOxNgADsTgAA7E5AAOxeAADsXoAA7F8AAOxfgADsYEAA7GCAAOxgwADsYQAA7GFAAOxhwADsYkAA7GKAAOxiwADsY0AA7GOAAOxzQADsc8AA7HRAAOx0wADsdYAA7HXAAOx2AADsdkAA7HaAAOx3AADsd4AA7HfAAOx4AADseIAA7HjAAOyIgADsiQAA7ImAAOyKAADsisAA7IsAAOyLQADsi4AA7IvAAOyMQADsjMAA7I0AAOyNQADsjcAA7I4AAOydwADsnkAA7J7AAOyfQADsoAAA7KBAAOyggADsoMAA7KEAAOyhgADsogAA7KJAAOyigADsowAA7KNAAOy2AADsvsAA7MbAAOzOwADsz0AA7M/AAOzQQADs0MAA7NGAAOzRwADs0gAA7NLAAOzTAADs04AA7NPAAOzUQADs1QAA7NVAAOzVgADs1kAA7NaAAOzXwADs2wAA7NxAAOzcwADs3UAA7N6AAOzfQADs4AAA7OCAAOzpwADs8sAA7PyAAO0FgADtBkAA7QbAAO0HQADtB8AA7QhAAO0IwADtCQAA7QnAAO0NAADtEUAA7RHAAO0SQADtEsAA7RNAAO0TwADtFEAA7RTAAO0VQADtGYAA7RpAAO0bAADtG8AA7RyAAO0dQADtHgAA7R7AAO0fgADtIAAA7S/AAO0wQADtMMAA7TFAAO0yAADtMkAA7TKAAO0ywADtMwAA7TOAAO00AADtNEAA7TSAAO01AADtNUAA7UUAAO1FgADtRgAA7UaAAO1HQADtR4AA7UfAAO1IAADtSEAA7UjAAO1JQADtSYAA7UnAAO1KQADtSoAA7VpAAO1awADtW4AA7VwAAO1cwADtXQAA7V1AAO1dgADtXcAA7V5AAO1ewADtXwAA7V9AAO1fwADtYAAA7WNAAO1jgADtY8AA7WRAAO10AADtdIAA7XUAAO11gADtdkAA7XaAAO12wADtdwAA7XdAAO13wADteEAA7XiAAO14wADteUAA7XmAAO2JQADticAA7YpAAO2KwADti4AA7YvAAO2MAADtjEAA7YyAAO2NAADtjYAA7Y3AAO2OAADtjoAA7Y7AAO2egADtnwAA7Z+AAO2gAADtoMAA7aEAAO2hQADtoYAA7aHAAO2iQADtosAA7aMAAO2jQADto8AA7aQAAO2zwADttEAA7bTAAO21QADttgAA7bZAAO22gADttsAA7bcAAO23gADtuAAA7bhAAO24gADtuQAA7blAAO3JAADtyYAA7coAAO3KgADty0AA7cuAAO3LwADtzAAA7cxAAO3MwADtzUAA7c2AAO3NwADtzkAA7c6AAO3XwADt4MAA7eqAAO3zgADt9EAA7fTAAO31QADt9cAA7fZAAO32wADt9wAA7ffAAO37AADt/sAA7f9AAO3/wADuAEAA7gDAAO4BQADuAcAA7gJAAO4GAADuBsAA7geAAO4IQADuCQAA7gnAAO4KgADuC0AA7gvAAO4bgADuHAAA7hyAAO4dAADuHcAA7h4AAO4eQADuHoAA7h7AAO4fQADuH8AA7iAAAO4gQADuIMAA7iEAAO4wwADuMUAA7jHAAO4yQADuMwAA7jNAAO4zgADuM8AA7jQAAO40gADuNQAA7jVAAO41gADuNgAA7jZAAO5GAADuRoAA7kcAAO5HgADuSEAA7kiAAO5IwADuSQAA7klAAO5JwADuSkAA7kqAAO5KwADuS0AA7kuAAO5bQADuW8AA7lxAAO5cwADuXYAA7l3AAO5eAADuXkAA7l6AAO5fAADuX4AA7l/AAO5gAADuYIAA7mDAAO5wgADucQAA7nGAAO5yAADucsAA7nMAAO5zQADuc4AA7nPAAO50QADudMAA7nUAAO51QADudcAA7nYAAO6FwADuhkAA7obAAO6HQADuiAAA7ohAAO6IgADuiMAA7okAAO6JgADuigAA7opAAO6KgADuiwAA7otAAO6bAADum4AA7pwAAO6cgADunUAA7p2AAO6dwADungAA7p5AAO6ewADun0AA7p+AAO6fwADuoEAA7qCAAO6zQADuvAAA7sQAAO7MAADuzIAA7s0AAO7NgADuzgAA7s7AAO7PAADuz0AA7tAAAO7QQADu0MAA7tEAAO7RgADu0kAA7tKAAO7SwADu04AA7tPAAO7VAADu2EAA7tmAAO7aAADu2oAA7tvAAO7cgADu3UAA7t3AAO7nAADu8AAA7vnAAO8CwADvA4AA7wQAAO8EgADvBQAA7wWAAO8GAADvBkAA7wcAAO8KQADvDoAA7w8AAO8PgADvEAAA7xCAAO8RAADvEYAA7xIAAO8SgADvFsAA7xeAAO8YQADvGQAA7xnAAO8agADvG0AA7xwAAO8cwADvHUAA7y0AAO8tgADvLgAA7y6AAO8vQADvL4AA7y/AAO8wAADvMEAA7zDAAO8xQADvMYAA7zHAAO8yQADvMoAA70JAAO9CwADvQ0AA70PAAO9EgADvRMAA70UAAO9FQADvRYAA70YAAO9GgADvRsAA70cAAO9HgADvR8AA71eAAO9YAADvWMAA71lAAO9aAADvWkAA71qAAO9awADvWwAA71uAAO9cAADvXEAA71yAAO9dAADvXUAA72CAAO9gwADvYQAA72GAAO9xQADvccAA73JAAO9ywADvc4AA73PAAO90AADvdEAA73SAAO91AADvdYAA73XAAO92AADvdoAA73bAAO+GgADvhwAA74eAAO+IAADviMAA74kAAO+JQADviYAA74nAAO+KQADvisAA74sAAO+LQADvi8AA74wAAO+bwADvnEAA75zAAO+dQADvngAA755AAO+egADvnsAA758AAO+fgADvoAAA76BAAO+ggADvoQAA76FAAO+xAADvsYAA77IAAO+ygADvs0AA77OAAO+zwADvtAAA77RAAO+0wADvtUAA77WAAO+1wADvtkAA77aAAO/GQADvxsAA78dAAO/HwADvyIAA78jAAO/JAADvyUAA78mAAO/KAADvyoAA78rAAO/LAADvy4AA78vAAO/VAADv3gAA7+fAAO/wwADv8YAA7/IAAO/ygADv8wAA7/OAAO/0AADv9EAA7/UAAO/4QADv/AAA7/yAAO/9AADv/YAA7/4AAO/+gADv/wAA7/+AAPADQADwBAAA8ATAAPAFgADwBkAA8AcAAPAHwADwCIAA8AkAAPAYwADwGUAA8BnAAPAaQADwGwAA8BtAAPAbgADwG8AA8BwAAPAcgADwHQAA8B1AAPAdgADwHgAA8B5AAPAuAADwLoAA8C8AAPAvgADwMEAA8DCAAPAwwADwMQAA8DFAAPAxwADwMkAA8DKAAPAywADwM0AA8DOAAPBDQADwQ8AA8ERAAPBEwADwRYAA8EXAAPBGAADwRkAA8EaAAPBHAADwR4AA8E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 diff --git a/fearless/Common/Storage/PersistentStoreCoordinator+Extensions.swift b/fearless/Common/Storage/PersistentStoreCoordinator+Extensions.swift index ef831071ee..bc587836ef 100644 --- a/fearless/Common/Storage/PersistentStoreCoordinator+Extensions.swift +++ b/fearless/Common/Storage/PersistentStoreCoordinator+Extensions.swift @@ -1,5 +1,2437 @@ import Foundation import CoreData +import CryptoKit +import Darwin + +enum CrashConsistentStoreReplacementBoundary: Equatable { + case preparingMarkerPersisted + case backupFileCopied(String) + case committingMarkerPersisted + case replacementReturned + case destinationValidated + case destinationFamilySynced + case committedMarkerPersisted + case rollbackMarkerPersisted + case liveFileRemoved(String) + case rollbackTemporaryFileCopied(String) + case rollbackFileInstalled(String) + case rollbackFamilyVerified + case cleanupBackupFileRemoved(String) + case cleanupBackupDirectoryRemoved + case cleanupMarkerTemporaryRemoved + case cleanupMarkerRemoved + case cleanupTransactionDirectoryRemoved + case cleanupRecoveryRootRemoved + case transactionCleaned +} + +enum CrashConsistentStoreReplacementInterruption: Error { + /// Test-only fault used to emulate a process disappearing without running + /// Swift unwinding, rollback, or defer blocks. + case simulatedProcessDeath +} + +enum CrashConsistentStoreReplacementError: LocalizedError { + case sourceStoreMissing + case unsafeFile(URL) + case unsafeDirectory(URL) + case storeFamilySizeOverflow + case storeFamilyTooLarge( + actualByteCount: UInt64, + maximumByteCount: UInt64 + ) + case insufficientStorageCapacity( + requiredByteCount: UInt64, + availableByteCount: UInt64 + ) + case markerMissingForInterruptedStore + case markerTooLarge + case invalidMarker + case familyMismatch + case backupUnavailable + case destinationValidationFailed(Error) + case rollbackFailed(Error, Error) + case fileSynchronizationFailed(URL, Error) + case directorySynchronizationFailed(URL, Error) + + var errorDescription: String? { + switch self { + case .sourceStoreMissing: + return "The SQLite source store is missing" + case .unsafeFile: + return "The SQLite replacement transaction contains an unsafe file" + case .unsafeDirectory: + return "The SQLite replacement transaction contains an unsafe directory" + case .storeFamilySizeOverflow: + return "The SQLite store family size overflowed its bounded counter" + case let .storeFamilyTooLarge(actualByteCount, maximumByteCount): + return """ + The SQLite store family uses \(actualByteCount) bytes, exceeding the \ + \(maximumByteCount)-byte migration limit + """ + case let .insufficientStorageCapacity( + requiredByteCount, + availableByteCount + ): + return """ + SQLite replacement requires \(requiredByteCount) free bytes, but only \ + \(availableByteCount) bytes are available + """ + case .markerMissingForInterruptedStore: + return "An interrupted SQLite replacement is missing its recovery marker" + case .markerTooLarge: + return "The SQLite replacement recovery marker is too large" + case .invalidMarker: + return "The SQLite replacement recovery marker is invalid" + case .familyMismatch: + return "The SQLite store family does not match its durable manifest" + case .backupUnavailable: + return "The SQLite rollback family is incomplete or damaged" + case let .destinationValidationFailed(error): + return "The replaced SQLite store failed validation: \(error.localizedDescription)" + case let .rollbackFailed(replacementError, rollbackError): + return """ + SQLite replacement failed with \(replacementError.localizedDescription), and rollback \ + failed with \(rollbackError.localizedDescription) + """ + case let .fileSynchronizationFailed(_, error): + return "Unable to synchronize a SQLite replacement file: \(error.localizedDescription)" + case let .directorySynchronizationFailed(_, error): + return "Unable to synchronize a SQLite replacement directory: \(error.localizedDescription)" + } + } +} + +struct SQLiteStoreFamilyCopyLimits: Equatable { + static let userStorageProduction = SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: 512 * 1024 * 1024, + minimumFreeStorageReserveByteCount: 64 * 1024 * 1024 + ) + static let substrateStorageProduction = SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: 4 * 1024 * 1024 * 1024, + minimumFreeStorageReserveByteCount: 128 * 1024 * 1024 + ) + + let maximumFamilyByteCount: UInt64 + let minimumFreeStorageReserveByteCount: UInt64 + + init( + maximumFamilyByteCount: UInt64, + minimumFreeStorageReserveByteCount: UInt64 + ) { + self.maximumFamilyByteCount = maximumFamilyByteCount + self.minimumFreeStorageReserveByteCount = + minimumFreeStorageReserveByteCount + } +} + +/// Makes a bounded private SQLite-family copy without following sidecar +/// symlinks. Migration callers use the copy as disposable input, so all size +/// and capacity checks happen before the first destination member is created. +enum SQLiteStoreFamilyCopier { + static let storeFamilySuffixes = ["", "-wal", "-shm", "-journal"] + + private struct SourceMember { + let sourceURL: URL + let destinationURL: URL + let byteCount: UInt64 + let deviceID: UInt64 + let inode: UInt64 + } + + static func copy( + from sourceStoreURL: URL, + to destinationStoreURL: URL, + includingSharedMemory: Bool, + fileManager: FileManager, + limits: SQLiteStoreFamilyCopyLimits, + availableCapacityProvider: + ((URL) throws -> UInt64)? = nil + ) throws { + let sourceStoreURL = sourceStoreURL.standardizedFileURL + let destinationStoreURL = + destinationStoreURL.standardizedFileURL + let destinationDirectoryURL = + destinationStoreURL.deletingLastPathComponent() + + try requireDirectory(destinationDirectoryURL) + + let capacityProvider = + availableCapacityProvider ?? { directoryURL in + try availableCapacity( + at: directoryURL, + fileManager: fileManager + ) + } + var sourceMembers: [SourceMember] = [] + var aggregateByteCount: UInt64 = 0 + + for suffix in storeFamilySuffixes { + let sourceURL = familyURL( + sourceStoreURL, + suffix: suffix + ) + let destinationURL = familyURL( + destinationStoreURL, + suffix: suffix + ) + + // Reject stale destination sidecars even when the corresponding + // source member is absent. Otherwise SQLite could attach data that + // was never part of the bounded source snapshot. + guard pathKind(at: destinationURL) == .missing else { + throw CrashConsistentStoreReplacementError + .unsafeFile(destinationURL) + } + + if suffix == "-shm", !includingSharedMemory { + continue + } + + switch pathKind(at: sourceURL) { + case .missing: + if suffix.isEmpty { + throw CrashConsistentStoreReplacementError + .sourceStoreMissing + } + continue + case .regularFile: + break + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeFile(sourceURL) + } + + let values = try lstatValues(at: sourceURL) + let addition = + aggregateByteCount.addingReportingOverflow( + values.byteCount + ) + guard !addition.overflow else { + throw CrashConsistentStoreReplacementError + .storeFamilySizeOverflow + } + aggregateByteCount = addition.partialValue + guard + aggregateByteCount <= + limits.maximumFamilyByteCount + else { + throw CrashConsistentStoreReplacementError + .storeFamilyTooLarge( + actualByteCount: aggregateByteCount, + maximumByteCount: + limits.maximumFamilyByteCount + ) + } + + sourceMembers.append( + SourceMember( + sourceURL: sourceURL, + destinationURL: destinationURL, + byteCount: values.byteCount, + deviceID: values.deviceID, + inode: values.inode + ) + ) + } + + let requiredCapacity = + aggregateByteCount.addingReportingOverflow( + limits.minimumFreeStorageReserveByteCount + ) + guard !requiredCapacity.overflow else { + throw CrashConsistentStoreReplacementError + .storeFamilySizeOverflow + } + let availableByteCount = try capacityProvider( + destinationDirectoryURL + ) + guard + availableByteCount >= requiredCapacity.partialValue + else { + throw CrashConsistentStoreReplacementError + .insufficientStorageCapacity( + requiredByteCount: + requiredCapacity.partialValue, + availableByteCount: availableByteCount + ) + } + + for member in sourceMembers { + let sourceBeforeCopy = try lstatValues( + at: member.sourceURL + ) + guard + sourceBeforeCopy.byteCount == member.byteCount, + sourceBeforeCopy.deviceID == member.deviceID, + sourceBeforeCopy.inode == member.inode, + pathKind(at: member.destinationURL) == .missing + else { + throw CrashConsistentStoreReplacementError + .familyMismatch + } + + try fileManager.copyItem( + at: member.sourceURL, + to: member.destinationURL + ) + + let sourceAfterCopy = try lstatValues( + at: member.sourceURL + ) + let destinationValues = try lstatValues( + at: member.destinationURL + ) + guard + pathKind(at: member.destinationURL) == + .regularFile, + sourceAfterCopy.byteCount == member.byteCount, + sourceAfterCopy.deviceID == member.deviceID, + sourceAfterCopy.inode == member.inode, + destinationValues.byteCount == member.byteCount + else { + throw CrashConsistentStoreReplacementError + .familyMismatch + } + } + } + + private enum PathKind: Equatable { + case missing + case regularFile + case directory + case symbolicLink + case other + } + + private static func availableCapacity( + at directoryURL: URL, + fileManager: FileManager + ) throws -> UInt64 { + let keys: Set = [ + .volumeAvailableCapacityForImportantUsageKey, + .volumeAvailableCapacityKey + ] + if let values = try? directoryURL.resourceValues(forKeys: keys) { + if + let capacity = + values.volumeAvailableCapacityForImportantUsage, + capacity >= 0 { + return UInt64(capacity) + } + if + let capacity = values.volumeAvailableCapacity, + capacity >= 0 { + return UInt64(capacity) + } + } + + let attributes = try fileManager.attributesOfFileSystem( + forPath: directoryURL.path + ) + if + let freeSize = attributes[.systemFreeSize] as? NSNumber, + freeSize.int64Value >= 0 { + return freeSize.uint64Value + } + + throw CocoaError(.fileReadUnknown) + } + + private static func requireDirectory(_ url: URL) throws { + guard pathKind(at: url) == .directory else { + throw CrashConsistentStoreReplacementError + .unsafeDirectory(url) + } + } + + private static func familyURL( + _ storeURL: URL, + suffix: String + ) -> URL { + URL(fileURLWithPath: storeURL.path + suffix) + } + + private static func pathKind(at url: URL) -> PathKind { + var fileStatus = stat() + guard Darwin.lstat(url.path, &fileStatus) == 0 else { + return errno == ENOENT ? .missing : .other + } + + switch fileStatus.st_mode & S_IFMT { + case S_IFREG: + return .regularFile + case S_IFDIR: + return .directory + case S_IFLNK: + return .symbolicLink + default: + return .other + } + } + + private static func lstatValues( + at url: URL + ) throws -> ( + byteCount: UInt64, + deviceID: UInt64, + inode: UInt64 + ) { + var fileStatus = stat() + guard Darwin.lstat(url.path, &fileStatus) == 0 else { + throw POSIXError( + POSIXErrorCode(rawValue: errno) ?? .EIO + ) + } + guard + fileStatus.st_size >= 0, + fileStatus.st_mode & S_IFMT == S_IFREG + else { + throw CrashConsistentStoreReplacementError + .unsafeFile(url) + } + + return ( + byteCount: UInt64(fileStatus.st_size), + deviceID: UInt64(truncatingIfNeeded: fileStatus.st_dev), + inode: UInt64(truncatingIfNeeded: fileStatus.st_ino) + ) + } +} + +/// Replaces a closed SQLite store family while retaining a bounded, durable +/// rollback transaction beside the database. The transaction is deliberately +/// independent of the application's temporary directory so an iOS process +/// termination cannot discard the sole recovery copy. +final class CrashConsistentStoreReplacer { + private enum TransactionState: String, Codable { + case preparing + case committing + case rollingBack + case committed + } + + private struct FamilyMember: Codable, Equatable { + let suffix: String + let byteCount: UInt64 + let sha256: String + } + + private struct Marker: Codable { + let schemaVersion: Int + let storeFileName: String + var state: TransactionState + let originalFamily: [FamilyMember] + var committedFamily: [FamilyMember]? + } + + private enum PathKind { + case missing + case regularFile + case directory + case symbolicLink + case other + } + + private struct FileIdentity: Hashable { + let deviceID: UInt64 + let inode: UInt64 + } + + private struct StrictJSONField { + let key: String + let keyUsedEscape: Bool + let value: StrictJSONValue + } + + private indirect enum StrictJSONValue { + case object([StrictJSONField]) + case array([StrictJSONValue]) + case string(String) + case number(String) + case boolean(Bool) + case null + } + + private struct StrictJSONParser { + private static let maximumDepth = 8 + private static let maximumCollectionCount = 32 + + private let bytes: [UInt8] + private var index = 0 + + init(data: Data) { + bytes = Array(data) + } + + mutating func parse() throws -> StrictJSONValue { + skipWhitespace() + let value = try parseValue(depth: 0) + skipWhitespace() + guard index == bytes.count else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + return value + } + + private mutating func parseValue( + depth: Int + ) throws -> StrictJSONValue { + guard + depth <= Self.maximumDepth, + let byte = currentByte + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + + switch byte { + case 0x7B: + return .object(try parseObject(depth: depth + 1)) + case 0x5B: + return .array(try parseArray(depth: depth + 1)) + case 0x22: + return .string(try parseString().value) + case 0x2D, 0x30 ... 0x39: + return .number(try parseNumber()) + case 0x74: + try consumeLiteral([0x74, 0x72, 0x75, 0x65]) + return .boolean(true) + case 0x66: + try consumeLiteral([ + 0x66, 0x61, 0x6C, 0x73, 0x65 + ]) + return .boolean(false) + case 0x6E: + try consumeLiteral([0x6E, 0x75, 0x6C, 0x6C]) + return .null + default: + throw CrashConsistentStoreReplacementError.invalidMarker + } + } + + private mutating func parseObject( + depth: Int + ) throws -> [StrictJSONField] { + try consume(0x7B) + skipWhitespace() + if consumeIfPresent(0x7D) { + return [] + } + + var fields: [StrictJSONField] = [] + while true { + guard fields.count < Self.maximumCollectionCount else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + + let key = try parseString() + skipWhitespace() + try consume(0x3A) + skipWhitespace() + let value = try parseValue(depth: depth) + fields.append( + StrictJSONField( + key: key.value, + keyUsedEscape: key.usedEscape, + value: value + ) + ) + + skipWhitespace() + if consumeIfPresent(0x7D) { + return fields + } + + try consume(0x2C) + skipWhitespace() + } + } + + private mutating func parseArray( + depth: Int + ) throws -> [StrictJSONValue] { + try consume(0x5B) + skipWhitespace() + if consumeIfPresent(0x5D) { + return [] + } + + var values: [StrictJSONValue] = [] + while true { + guard values.count < Self.maximumCollectionCount else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + + values.append(try parseValue(depth: depth)) + skipWhitespace() + if consumeIfPresent(0x5D) { + return values + } + + try consume(0x2C) + skipWhitespace() + } + } + + private mutating func parseString() throws -> ( + value: String, + usedEscape: Bool + ) { + guard currentByte == 0x22 else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + + let startIndex = index + index += 1 + var usedEscape = false + + while let byte = currentByte { + switch byte { + case 0x22: + index += 1 + let token = Data(bytes[startIndex ..< index]) + do { + return ( + try JSONDecoder().decode( + String.self, + from: token + ), + usedEscape + ) + } catch { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + case 0x5C: + usedEscape = true + index += 1 + guard let escapedByte = currentByte else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + + switch escapedByte { + case 0x22, 0x2F, 0x5C, 0x62, 0x66, 0x6E, + 0x72, 0x74: + index += 1 + case 0x75: + index += 1 + guard index + 4 <= bytes.count else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + for hexByte in bytes[index ..< index + 4] { + guard Self.isHexadecimal(hexByte) else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + } + index += 4 + default: + throw CrashConsistentStoreReplacementError + .invalidMarker + } + case 0x00 ... 0x1F: + throw CrashConsistentStoreReplacementError + .invalidMarker + default: + index += 1 + } + } + + throw CrashConsistentStoreReplacementError.invalidMarker + } + + private mutating func parseNumber() throws -> String { + let startIndex = index + + if consumeIfPresent(0x2D) { + guard currentByte != nil else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + } + + if consumeIfPresent(0x30) { + if + let byte = currentByte, + Self.isDigit(byte) { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + } else { + guard + let byte = currentByte, + (0x31 ... 0x39).contains(byte) + else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + index += 1 + while + let byte = currentByte, + Self.isDigit(byte) { + index += 1 + } + } + + if consumeIfPresent(0x2E) { + guard + let byte = currentByte, + Self.isDigit(byte) + else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + while + let byte = currentByte, + Self.isDigit(byte) { + index += 1 + } + } + + if + currentByte == 0x65 || + currentByte == 0x45 { + index += 1 + if currentByte == 0x2B || currentByte == 0x2D { + index += 1 + } + guard + let byte = currentByte, + Self.isDigit(byte) + else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + while + let byte = currentByte, + Self.isDigit(byte) { + index += 1 + } + } + + return String( + decoding: bytes[startIndex ..< index], + as: UTF8.self + ) + } + + private mutating func consumeLiteral( + _ literal: [UInt8] + ) throws { + guard + index + literal.count <= bytes.count, + Array(bytes[index ..< index + literal.count]) == + literal + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + index += literal.count + } + + private mutating func consume(_ byte: UInt8) throws { + guard consumeIfPresent(byte) else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + } + + private mutating func consumeIfPresent( + _ byte: UInt8 + ) -> Bool { + guard currentByte == byte else { + return false + } + index += 1 + return true + } + + private mutating func skipWhitespace() { + while + let byte = currentByte, + byte == 0x20 || + byte == 0x09 || + byte == 0x0A || + byte == 0x0D { + index += 1 + } + } + + private var currentByte: UInt8? { + index < bytes.count ? bytes[index] : nil + } + + private static func isDigit(_ byte: UInt8) -> Bool { + (0x30 ... 0x39).contains(byte) + } + + private static func isHexadecimal(_ byte: UInt8) -> Bool { + (0x30 ... 0x39).contains(byte) || + (0x41 ... 0x46).contains(byte) || + (0x61 ... 0x66).contains(byte) + } + } + + static let storeFamilySuffixes = ["", "-wal", "-shm", "-journal"] + static let defaultMaximumStoreFamilyByteCount: UInt64 = + 4 * 1024 * 1024 * 1024 + static let defaultMinimumFreeStorageReserveByteCount: UInt64 = + 64 * 1024 * 1024 + + private static let markerSchemaVersion = 1 + private static let maximumMarkerByteCount: UInt64 = 64 * 1024 + private static let digestChunkByteCount = 1024 * 1024 + private static let recoveryRootName = ".FearlessStoreReplacement" + + let storeURL: URL + let transactionDirectoryURL: URL + + private let fileManager: FileManager + private let storeReplacer: (URL, URL) throws -> Void + private let boundaryHook: (CrashConsistentStoreReplacementBoundary) throws -> Void + private let maximumStoreFamilyByteCount: UInt64 + private let minimumFreeStorageReserveByteCount: UInt64 + private let availableCapacityProvider: (URL) throws -> UInt64 + + private var databaseDirectoryURL: URL { + storeURL.deletingLastPathComponent() + } + + private var recoveryRootURL: URL { + transactionDirectoryURL.deletingLastPathComponent() + } + + private var backupDirectoryURL: URL { + transactionDirectoryURL.appendingPathComponent( + "OriginalStoreFamily", + isDirectory: true + ) + } + + private var markerURL: URL { + transactionDirectoryURL.appendingPathComponent("transaction.json") + } + + private var markerTemporaryURL: URL { + transactionDirectoryURL.appendingPathComponent( + "transaction.json.pending" + ) + } + + var hasPendingTransaction: Bool { + pathKind(at: transactionDirectoryURL) != .missing + } + + init( + storeURL: URL, + fileManager: FileManager, + storeReplacer: @escaping (URL, URL) throws -> Void, + boundaryHook: @escaping ( + CrashConsistentStoreReplacementBoundary + ) throws -> Void = { _ in }, + maximumStoreFamilyByteCount: UInt64 = + CrashConsistentStoreReplacer + .defaultMaximumStoreFamilyByteCount, + minimumFreeStorageReserveByteCount: UInt64 = + CrashConsistentStoreReplacer + .defaultMinimumFreeStorageReserveByteCount, + availableCapacityProvider: ((URL) throws -> UInt64)? = nil + ) { + self.storeURL = storeURL.standardizedFileURL + self.fileManager = fileManager + self.storeReplacer = storeReplacer + self.boundaryHook = boundaryHook + self.maximumStoreFamilyByteCount = + maximumStoreFamilyByteCount + self.minimumFreeStorageReserveByteCount = + minimumFreeStorageReserveByteCount + self.availableCapacityProvider = + availableCapacityProvider ?? { directoryURL in + let keys: Set = [ + .volumeAvailableCapacityForImportantUsageKey, + .volumeAvailableCapacityKey + ] + if + let values = try? directoryURL.resourceValues( + forKeys: keys + ) { + if + let capacity = + values + .volumeAvailableCapacityForImportantUsage, + capacity >= 0 { + return UInt64(capacity) + } + + if + let capacity = + values.volumeAvailableCapacity, + capacity >= 0 { + return UInt64(capacity) + } + } + + let attributes = try fileManager + .attributesOfFileSystem( + forPath: directoryURL.path + ) + if + let freeSize = + attributes[.systemFreeSize] as? NSNumber, + freeSize.int64Value >= 0 { + return freeSize.uint64Value + } + + throw CocoaError(.fileReadUnknown) + } + + let pathDigest = SHA256.hash( + data: Data(self.storeURL.path.utf8) + ).prefix(12).map { + String(format: "%02x", $0) + }.joined() + let safeStoreName = self.storeURL.lastPathComponent.map { + $0.isLetter || $0.isNumber || $0 == "." || $0 == "-" || $0 == "_" + ? String($0) + : "_" + }.joined() + let boundedStoreName = String(safeStoreName.prefix(80)) + transactionDirectoryURL = self.storeURL + .deletingLastPathComponent() + .appendingPathComponent(Self.recoveryRootName, isDirectory: true) + .appendingPathComponent( + "\(boundedStoreName)-\(pathDigest)", + isDirectory: true + ) + } + + func liveStoreExistsSafely() throws -> Bool { + try requireSafeDatabaseDirectory() + + switch pathKind(at: storeURL) { + case .regularFile: + for suffix in Self.storeFamilySuffixes.dropFirst() { + let sidecarURL = familyURL( + storeURL: storeURL, + suffix: suffix + ) + + switch pathKind(at: sidecarURL) { + case .missing, .regularFile: + continue + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeFile(sidecarURL) + } + } + + return true + case .missing: + let hasOrphanSidecar = Self.storeFamilySuffixes + .dropFirst() + .contains { + pathKind( + at: familyURL( + storeURL: storeURL, + suffix: $0 + ) + ) != .missing + } + + guard !hasOrphanSidecar else { + throw CrashConsistentStoreReplacementError + .markerMissingForInterruptedStore + } + + return false + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeFile(storeURL) + } + } + + func reconcile( + validateCommittedStore: (URL) throws -> Void + ) throws { + try requireSafeDatabaseDirectory() + + switch pathKind(at: transactionDirectoryURL) { + case .missing: + try removeRecoveryRootIfEmpty() + return + case .directory: + break + case .regularFile, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeDirectory(transactionDirectoryURL) + } + + guard pathKind(at: markerURL) != .missing else { + try reconcileMarkerlessTransaction() + return + } + + let marker = try readMarker() + try requireSafeTransactionTree( + for: marker, + verifyBackupContents: false + ) + try removeMarkerTemporaryIfPresent() + + switch marker.state { + case .preparing: + if try family(at: storeURL, matches: marker.originalFamily) { + try removeTransaction( + using: marker, + verifyBackupContents: false + ) + } else { + try restoreOriginalFamily(using: marker) + } + case .committing: + try restoreOriginalFamily(using: marker) + case .rollingBack: + if try family(at: storeURL, matches: marker.originalFamily) { + try removeTransaction( + using: marker, + verifyBackupContents: false + ) + } else { + try restoreOriginalFamily(using: marker) + } + case .committed: + do { + guard + let committedFamily = marker.committedFamily, + try family(at: storeURL, matches: committedFamily) + else { + throw CrashConsistentStoreReplacementError.familyMismatch + } + + try validateCommittedStoreUsingPrivateCopy( + committedFamily, + validateCommittedStore: validateCommittedStore + ) + } catch is CrashConsistentStoreReplacementInterruption { + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } catch { + if Self.isRetryableCapacityError(error) { + // A committed live family and its rollback copy are both + // still durable. Leave the transaction intact so a later + // launch can validate it after the user frees space. + throw error + } + + try restoreOriginalFamily(using: marker) + return + } + + try removeTransaction(using: marker) + } + } + + func replaceStore( + with stagedStoreURL: URL, + validateDestination: (URL) throws -> Void + ) throws { + let stagedStoreURL = stagedStoreURL.standardizedFileURL + try reconcile(validateCommittedStore: validateDestination) + try requireSafeDatabaseDirectory() + let stagedFamily = try validateStagedStoreFamily( + at: stagedStoreURL + ) + + let originalFamily = try manifest( + for: storeURL, + requiringMainStore: true + ) + try requireCapacity( + forAdditionalByteCount: + try aggregateByteCount(of: originalFamily), + at: databaseDirectoryURL + ) + var marker = Marker( + schemaVersion: Self.markerSchemaVersion, + storeFileName: storeURL.lastPathComponent, + state: .preparing, + originalFamily: originalFamily, + committedFamily: nil + ) + var commitDurablyRecorded = false + + try createTransactionDirectory() + try persist(marker) + try boundaryHook(.preparingMarkerPersisted) + try createBackupDirectory() + + do { + try copyOriginalFamily(originalFamily) + + guard try family(at: backupStoreURL, matches: originalFamily) else { + throw CrashConsistentStoreReplacementError.backupUnavailable + } + + marker.state = .committing + try persist(marker) + try boundaryHook(.committingMarkerPersisted) + + guard + try validateStagedStoreFamily( + at: stagedStoreURL + ) == stagedFamily + else { + throw CrashConsistentStoreReplacementError + .familyMismatch + } + try storeReplacer(storeURL, stagedStoreURL) + try boundaryHook(.replacementReturned) + + do { + try validateDestination(storeURL) + } catch { + throw CrashConsistentStoreReplacementError + .destinationValidationFailed(error) + } + try boundaryHook(.destinationValidated) + + try synchronizeFamily(at: storeURL) + try boundaryHook(.destinationFamilySynced) + + marker.state = .committed + marker.committedFamily = try manifest( + for: storeURL, + requiringMainStore: true + ) + try persist(marker) + commitDurablyRecorded = true + try boundaryHook(.committedMarkerPersisted) + + try removeTransaction(using: marker) + } catch is CrashConsistentStoreReplacementInterruption { + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } catch { + let replacementError = error + + guard !commitDurablyRecorded else { + throw replacementError + } + + do { + if try family(at: backupStoreURL, matches: originalFamily) { + try restoreOriginalFamily(using: marker) + } else if try family(at: storeURL, matches: originalFamily) { + try removeTransaction( + using: marker, + verifyBackupContents: false + ) + } else { + throw CrashConsistentStoreReplacementError.backupUnavailable + } + } catch is CrashConsistentStoreReplacementInterruption { + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } catch { + throw CrashConsistentStoreReplacementError.rollbackFailed( + replacementError, + error + ) + } + + throw replacementError + } + } + + private var backupStoreURL: URL { + backupDirectoryURL.appendingPathComponent(storeURL.lastPathComponent) + } + + private func createTransactionDirectory() throws { + switch pathKind(at: recoveryRootURL) { + case .missing: + try fileManager.createDirectory( + at: recoveryRootURL, + withIntermediateDirectories: false + ) + try synchronizeDirectory(databaseDirectoryURL) + case .directory: + break + case .regularFile, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeDirectory(recoveryRootURL) + } + + guard pathKind(at: transactionDirectoryURL) == .missing else { + throw CrashConsistentStoreReplacementError + .unsafeDirectory(transactionDirectoryURL) + } + + try fileManager.createDirectory( + at: transactionDirectoryURL, + withIntermediateDirectories: false + ) + try synchronizeDirectory(recoveryRootURL) + } + + private func createBackupDirectory() throws { + guard pathKind(at: backupDirectoryURL) == .missing else { + throw CrashConsistentStoreReplacementError + .unsafeDirectory(backupDirectoryURL) + } + try fileManager.createDirectory( + at: backupDirectoryURL, + withIntermediateDirectories: false + ) + try synchronizeDirectory(transactionDirectoryURL) + } + + private func copyOriginalFamily( + _ originalFamily: [FamilyMember] + ) throws { + for member in originalFamily { + let sourceURL = familyURL( + storeURL: storeURL, + suffix: member.suffix + ) + let destinationURL = familyURL( + storeURL: backupStoreURL, + suffix: member.suffix + ) + + try requireRegularFile(sourceURL) + guard pathKind(at: destinationURL) == .missing else { + throw CrashConsistentStoreReplacementError + .unsafeFile(destinationURL) + } + + try fileManager.copyItem(at: sourceURL, to: destinationURL) + try synchronizeFile(destinationURL) + try synchronizeDirectory(backupDirectoryURL) + + guard + try familyMember( + at: destinationURL, + suffix: member.suffix, + expectedByteCount: member.byteCount + ) == member + else { + throw CrashConsistentStoreReplacementError.familyMismatch + } + + try boundaryHook(.backupFileCopied(member.suffix)) + } + } + + private func restoreOriginalFamily( + using originalMarker: Marker + ) throws { + guard + try family( + at: backupStoreURL, + matches: originalMarker.originalFamily + ) + else { + throw CrashConsistentStoreReplacementError.backupUnavailable + } + + var marker = originalMarker + marker.state = .rollingBack + marker.committedFamily = nil + try persist(marker) + try boundaryHook(.rollbackMarkerPersisted) + + for suffix in Self.storeFamilySuffixes { + let liveURL = familyURL(storeURL: storeURL, suffix: suffix) + + switch pathKind(at: liveURL) { + case .missing: + continue + case .regularFile: + try fileManager.removeItem(at: liveURL) + try synchronizeDirectory(databaseDirectoryURL) + try boundaryHook(.liveFileRemoved(suffix)) + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeFile(liveURL) + } + } + + for member in marker.originalFamily { + let backupURL = familyURL( + storeURL: backupStoreURL, + suffix: member.suffix + ) + let liveURL = familyURL( + storeURL: storeURL, + suffix: member.suffix + ) + let temporaryURL = databaseDirectoryURL.appendingPathComponent( + ".\(liveURL.lastPathComponent).fearless-rollback" + ) + + try removeSafeTemporaryFileIfPresent(at: temporaryURL) + try fileManager.copyItem(at: backupURL, to: temporaryURL) + try synchronizeFile(temporaryURL) + guard + try familyMember( + at: temporaryURL, + suffix: member.suffix, + expectedByteCount: member.byteCount + ) == member + else { + throw CrashConsistentStoreReplacementError.familyMismatch + } + try synchronizeDirectory(databaseDirectoryURL) + try boundaryHook( + .rollbackTemporaryFileCopied(member.suffix) + ) + + try fileManager.moveItem(at: temporaryURL, to: liveURL) + try synchronizeDirectory(databaseDirectoryURL) + try boundaryHook(.rollbackFileInstalled(member.suffix)) + } + + guard try family(at: storeURL, matches: marker.originalFamily) else { + throw CrashConsistentStoreReplacementError.familyMismatch + } + try boundaryHook(.rollbackFamilyVerified) + + try removeTransaction(using: marker) + } + + private func removeSafeTemporaryFileIfPresent(at url: URL) throws { + switch pathKind(at: url) { + case .missing: + return + case .regularFile: + try fileManager.removeItem(at: url) + try synchronizeDirectory(databaseDirectoryURL) + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError.unsafeFile(url) + } + } + + private func removeTransaction( + using marker: Marker, + verifyBackupContents: Bool = true + ) throws { + try requireSafeTransactionTree( + for: marker, + verifyBackupContents: verifyBackupContents + ) + + if pathKind(at: backupDirectoryURL) == .directory { + for member in marker.originalFamily { + let backupURL = familyURL( + storeURL: backupStoreURL, + suffix: member.suffix + ) + + switch pathKind(at: backupURL) { + case .missing: + continue + case .regularFile: + if verifyBackupContents { + guard + try familyMember( + at: backupURL, + suffix: member.suffix, + expectedByteCount: + member.byteCount + ) == member + else { + throw CrashConsistentStoreReplacementError + .familyMismatch + } + } + try fileManager.removeItem(at: backupURL) + try synchronizeDirectory(backupDirectoryURL) + try boundaryHook( + .cleanupBackupFileRemoved(member.suffix) + ) + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeFile(backupURL) + } + } + + guard + try fileManager.contentsOfDirectory( + at: backupDirectoryURL, + includingPropertiesForKeys: nil, + options: [] + ).isEmpty + else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + try fileManager.removeItem(at: backupDirectoryURL) + try synchronizeDirectory(transactionDirectoryURL) + try boundaryHook(.cleanupBackupDirectoryRemoved) + } + + try removeMarkerTemporaryIfPresent() + + try requireRegularFile(markerURL) + try fileManager.removeItem(at: markerURL) + try synchronizeDirectory(transactionDirectoryURL) + try boundaryHook(.cleanupMarkerRemoved) + + guard + try fileManager.contentsOfDirectory( + at: transactionDirectoryURL, + includingPropertiesForKeys: nil, + options: [] + ).isEmpty + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + try removeEmptyTransactionDirectory() + } + + private func removeMarkerTemporaryIfPresent() throws { + switch pathKind(at: markerTemporaryURL) { + case .missing: + return + case .regularFile: + let values = try lstatValues(at: markerTemporaryURL) + guard + values.byteCount <= Self.maximumMarkerByteCount + else { + throw CrashConsistentStoreReplacementError.markerTooLarge + } + try fileManager.removeItem(at: markerTemporaryURL) + try synchronizeDirectory(transactionDirectoryURL) + try boundaryHook(.cleanupMarkerTemporaryRemoved) + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeFile(markerTemporaryURL) + } + } + + private func reconcileMarkerlessTransaction() throws { + let transactionContents = try fileManager.contentsOfDirectory( + at: transactionDirectoryURL, + includingPropertiesForKeys: nil, + options: [] + ) + + guard try liveStoreExistsSafely() else { + throw CrashConsistentStoreReplacementError + .markerMissingForInterruptedStore + } + + if transactionContents.isEmpty { + try removeEmptyTransactionDirectory() + return + } + + guard + transactionContents.count == 1, + transactionContents[0].lastPathComponent == + markerTemporaryURL.lastPathComponent + else { + throw CrashConsistentStoreReplacementError + .markerMissingForInterruptedStore + } + + switch pathKind(at: markerTemporaryURL) { + case .regularFile: + let values = try lstatValues(at: markerTemporaryURL) + guard + values.byteCount <= Self.maximumMarkerByteCount + else { + throw CrashConsistentStoreReplacementError.markerTooLarge + } + case .missing: + throw CrashConsistentStoreReplacementError + .markerMissingForInterruptedStore + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeFile(markerTemporaryURL) + } + + try removeMarkerTemporaryIfPresent() + try removeEmptyTransactionDirectory() + } + + private func removeEmptyTransactionDirectory() throws { + guard pathKind(at: transactionDirectoryURL) == .directory else { + throw CrashConsistentStoreReplacementError + .unsafeDirectory(transactionDirectoryURL) + } + + guard + try fileManager.contentsOfDirectory( + at: transactionDirectoryURL, + includingPropertiesForKeys: nil, + options: [] + ).isEmpty + else { + throw CrashConsistentStoreReplacementError + .markerMissingForInterruptedStore + } + + try fileManager.removeItem(at: transactionDirectoryURL) + try synchronizeDirectory(recoveryRootURL) + try boundaryHook(.cleanupTransactionDirectoryRemoved) + try removeRecoveryRootIfEmpty() + try boundaryHook(.transactionCleaned) + } + + private func removeRecoveryRootIfEmpty() throws { + switch pathKind(at: recoveryRootURL) { + case .missing: + return + case .directory: + guard + try fileManager.contentsOfDirectory( + at: recoveryRootURL, + includingPropertiesForKeys: nil, + options: [] + ).isEmpty + else { + return + } + + try fileManager.removeItem(at: recoveryRootURL) + try synchronizeDirectory(databaseDirectoryURL) + try boundaryHook(.cleanupRecoveryRootRemoved) + case .regularFile, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeDirectory(recoveryRootURL) + } + } + + private func requireSafeTransactionTree( + for marker: Marker, + verifyBackupContents: Bool = true + ) throws { + guard pathKind(at: transactionDirectoryURL) == .directory else { + throw CrashConsistentStoreReplacementError + .unsafeDirectory(transactionDirectoryURL) + } + + let contents = try fileManager.contentsOfDirectory( + at: transactionDirectoryURL, + includingPropertiesForKeys: nil, + options: [] + ) + let allowedTopLevelNames: Set = [ + backupDirectoryURL.lastPathComponent, + markerURL.lastPathComponent, + markerTemporaryURL.lastPathComponent + ] + guard + contents.allSatisfy({ + allowedTopLevelNames.contains($0.lastPathComponent) + }), + contents.contains(where: { + $0.lastPathComponent == markerURL.lastPathComponent + }) + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + + for url in contents { + switch url.lastPathComponent { + case backupDirectoryURL.lastPathComponent: + guard pathKind(at: url) == .directory else { + throw CrashConsistentStoreReplacementError + .unsafeDirectory(url) + } + try requireSafeBackupTree( + for: marker, + verifyContents: verifyBackupContents + ) + case markerURL.lastPathComponent: + try requireRegularFile(url) + case markerTemporaryURL.lastPathComponent: + try requireRegularFile(url) + let values = try lstatValues(at: url) + guard + values.byteCount <= + Self.maximumMarkerByteCount + else { + throw CrashConsistentStoreReplacementError + .markerTooLarge + } + default: + throw CrashConsistentStoreReplacementError + .invalidMarker + } + } + } + + private func requireSafeBackupTree( + for marker: Marker, + verifyContents: Bool + ) throws { + let expectedMembers = Dictionary( + uniqueKeysWithValues: marker.originalFamily.map { + ( + storeURL.lastPathComponent + $0.suffix, + $0 + ) + } + ) + let contents = try fileManager.contentsOfDirectory( + at: backupDirectoryURL, + includingPropertiesForKeys: nil, + options: [] + ) + + for url in contents { + guard + let expectedMember = + expectedMembers[url.lastPathComponent] + else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + try requireRegularFile(url) + if verifyContents { + guard + try familyMember( + at: url, + suffix: expectedMember.suffix, + expectedByteCount: + expectedMember.byteCount + ) == expectedMember + else { + throw CrashConsistentStoreReplacementError + .familyMismatch + } + } + } + } + + private func persist(_ marker: Marker) throws { + try validate(marker) + + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys] + let data = try encoder.encode(marker) + guard data.count <= Self.maximumMarkerByteCount else { + throw CrashConsistentStoreReplacementError.markerTooLarge + } + try validateRawMarkerJSON(data) + + switch pathKind(at: markerURL) { + case .missing, .regularFile: + break + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError.unsafeFile(markerURL) + } + + guard pathKind(at: markerTemporaryURL) == .missing else { + throw CrashConsistentStoreReplacementError + .unsafeFile(markerTemporaryURL) + } + try data.write(to: markerTemporaryURL) + try synchronizeFile(markerTemporaryURL) + + guard + Darwin.rename( + markerTemporaryURL.path, + markerURL.path + ) == 0 + else { + throw CrashConsistentStoreReplacementError + .fileSynchronizationFailed( + markerURL, + POSIXError( + POSIXErrorCode(rawValue: errno) ?? .EIO + ) + ) + } + try synchronizeFile(markerURL) + try synchronizeDirectory(transactionDirectoryURL) + } + + private func readMarker() throws -> Marker { + try requireRegularFile(markerURL) + let values = try lstatValues(at: markerURL) + guard + values.byteCount <= Self.maximumMarkerByteCount + else { + throw CrashConsistentStoreReplacementError.markerTooLarge + } + + let data = try Data(contentsOf: markerURL, options: [.mappedIfSafe]) + try validateRawMarkerJSON(data) + let marker: Marker + do { + marker = try JSONDecoder().decode(Marker.self, from: data) + } catch { + throw CrashConsistentStoreReplacementError.invalidMarker + } + + try validate(marker) + return marker + } + + private func validateRawMarkerJSON(_ data: Data) throws { + var parser = StrictJSONParser(data: data) + let value = try parser.parse() + guard case let .object(fields) = value else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + + let requiredKeys: Set = [ + "schemaVersion", + "storeFileName", + "state", + "originalFamily" + ] + let allowedKeys = requiredKeys.union(["committedFamily"]) + let fieldMap = try exactFieldMap( + fields, + allowedKeys: allowedKeys + ) + guard requiredKeys.isSubset(of: Set(fieldMap.keys)) else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + + guard + let schemaValue = fieldMap["schemaVersion"], + case let .number(schemaVersion) = schemaValue, + Int(schemaVersion) != nil, + let storeFileNameValue = fieldMap["storeFileName"], + case .string = storeFileNameValue, + let stateValue = fieldMap["state"], + case .string = stateValue, + let originalFamilyValue = fieldMap["originalFamily"], + case let .array(originalFamily) = originalFamilyValue + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + try validateRawFamily(originalFamily) + + if let committedFamily = fieldMap["committedFamily"] { + guard case let .array(members) = committedFamily else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + try validateRawFamily(members) + } + } + + private func validateRawFamily( + _ values: [StrictJSONValue] + ) throws { + guard + !values.isEmpty, + values.count <= Self.storeFamilySuffixes.count + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + + for value in values { + guard case let .object(fields) = value else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + let fieldMap = try exactFieldMap( + fields, + allowedKeys: ["suffix", "byteCount", "sha256"] + ) + guard + fieldMap.count == 3, + let suffixValue = fieldMap["suffix"], + case .string = suffixValue, + let byteCountValue = fieldMap["byteCount"], + case let .number(byteCount) = byteCountValue, + UInt64(byteCount) != nil, + let digestValue = fieldMap["sha256"], + case .string = digestValue + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + } + } + + private func exactFieldMap( + _ fields: [StrictJSONField], + allowedKeys: Set + ) throws -> [String: StrictJSONValue] { + guard + fields.allSatisfy({ + !$0.keyUsedEscape && + allowedKeys.contains($0.key) + }) + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + + var result: [String: StrictJSONValue] = [:] + for field in fields { + guard result.updateValue( + field.value, + forKey: field.key + ) == nil else { + throw CrashConsistentStoreReplacementError + .invalidMarker + } + } + return result + } + + private func validate(_ marker: Marker) throws { + guard + marker.schemaVersion == Self.markerSchemaVersion, + marker.storeFileName == storeURL.lastPathComponent + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + + try validate(marker.originalFamily) + + switch marker.state { + case .preparing, .committing, .rollingBack: + guard marker.committedFamily == nil else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + case .committed: + guard let committedFamily = marker.committedFamily else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + try validate(committedFamily) + } + } + + private func validate(_ family: [FamilyMember]) throws { + let allowedSuffixes = Set(Self.storeFamilySuffixes) + let suffixes = family.map(\.suffix) + let canonicalSuffixes = Self.storeFamilySuffixes.filter { + suffixes.contains($0) + } + var aggregateByteCount: UInt64 = 0 + var aggregateOverflowed = false + for member in family { + let addition = aggregateByteCount.addingReportingOverflow( + member.byteCount + ) + aggregateByteCount = addition.partialValue + aggregateOverflowed = aggregateOverflowed || addition.overflow + } + guard + family.count <= Self.storeFamilySuffixes.count, + !family.isEmpty, + suffixes.contains(""), + suffixes == canonicalSuffixes, + Set(suffixes).count == suffixes.count, + suffixes.allSatisfy(allowedSuffixes.contains), + !aggregateOverflowed, + aggregateByteCount <= maximumStoreFamilyByteCount, + family.allSatisfy({ + $0.sha256.count == 64 && + $0.sha256.allSatisfy { + $0.isHexDigit && !$0.isUppercase + } + }) + else { + throw CrashConsistentStoreReplacementError.invalidMarker + } + } + + private func validateStagedStoreFamily( + at stagedStoreURL: URL + ) throws -> [FamilyMember] { + let standardizedStagedURL = + stagedStoreURL.standardizedFileURL + let stagedFamily = try manifest( + for: standardizedStagedURL, + requiringMainStore: true + ) + let forbiddenDirectories = [ + recoveryRootURL, + transactionDirectoryURL, + backupDirectoryURL + ] + let forbiddenFiles = Self.storeFamilySuffixes.flatMap { + suffix in + + [ + familyURL(storeURL: storeURL, suffix: suffix), + familyURL( + storeURL: backupStoreURL, + suffix: suffix + ) + ] + } + [markerURL, markerTemporaryURL] + var stagedIdentities = Set() + + for forbiddenDirectory in forbiddenDirectories { + guard + !isWithin( + standardizedStagedURL, + directory: forbiddenDirectory + ), + !isWithin( + standardizedStagedURL + .resolvingSymlinksInPath(), + directory: forbiddenDirectory + .resolvingSymlinksInPath() + ) + else { + throw CrashConsistentStoreReplacementError + .unsafeFile(standardizedStagedURL) + } + } + + for member in stagedFamily { + let stagedMemberURL = familyURL( + storeURL: standardizedStagedURL, + suffix: member.suffix + ) + let stagedIdentity = try lstatValues( + at: stagedMemberURL + ) + guard + stagedIdentities.insert( + FileIdentity( + deviceID: stagedIdentity.deviceID, + inode: stagedIdentity.inode + ) + ).inserted + else { + throw CrashConsistentStoreReplacementError + .unsafeFile(stagedMemberURL) + } + + for forbiddenURL in forbiddenFiles { + guard + !urlsAlias(stagedMemberURL, forbiddenURL) + else { + throw CrashConsistentStoreReplacementError + .unsafeFile(stagedMemberURL) + } + + guard pathKind(at: forbiddenURL) == .regularFile else { + continue + } + let forbiddenIdentity = try lstatValues( + at: forbiddenURL + ) + guard + stagedIdentity.deviceID != + forbiddenIdentity.deviceID || + stagedIdentity.inode != + forbiddenIdentity.inode + else { + throw CrashConsistentStoreReplacementError + .unsafeFile(stagedMemberURL) + } + } + } + + return stagedFamily + } + + private func validateCommittedStoreUsingPrivateCopy( + _ committedFamily: [FamilyMember], + validateCommittedStore: (URL) throws -> Void + ) throws { + try requireCapacity( + forAdditionalByteCount: + try aggregateByteCount(of: committedFamily), + at: fileManager.temporaryDirectory + ) + + let validationDirectoryURL = fileManager.temporaryDirectory + .appendingPathComponent( + "FearlessCommittedStoreValidation-\(UUID().uuidString)", + isDirectory: true + ) + guard pathKind(at: validationDirectoryURL) == .missing else { + throw CrashConsistentStoreReplacementError + .unsafeDirectory(validationDirectoryURL) + } + + try fileManager.createDirectory( + at: validationDirectoryURL, + withIntermediateDirectories: false + ) + defer { + try? fileManager.removeItem(at: validationDirectoryURL) + } + + let validationStoreURL = validationDirectoryURL + .appendingPathComponent(storeURL.lastPathComponent) + for member in committedFamily { + let sourceURL = familyURL( + storeURL: storeURL, + suffix: member.suffix + ) + let destinationURL = familyURL( + storeURL: validationStoreURL, + suffix: member.suffix + ) + + try requireRegularFile(sourceURL) + guard pathKind(at: destinationURL) == .missing else { + throw CrashConsistentStoreReplacementError + .unsafeFile(destinationURL) + } + try fileManager.copyItem( + at: sourceURL, + to: destinationURL + ) + } + + guard + try family( + at: validationStoreURL, + matches: committedFamily + ) + else { + throw CrashConsistentStoreReplacementError.familyMismatch + } + + try validateCommittedStore(validationStoreURL) + + guard + try family( + at: storeURL, + matches: committedFamily + ) + else { + throw CrashConsistentStoreReplacementError.familyMismatch + } + } + + private func urlsAlias(_ lhs: URL, _ rhs: URL) -> Bool { + let standardizedLHS = lhs.standardizedFileURL + let standardizedRHS = rhs.standardizedFileURL + if standardizedLHS == standardizedRHS { + return true + } + + return standardizedLHS + .resolvingSymlinksInPath() + .standardizedFileURL == + standardizedRHS + .resolvingSymlinksInPath() + .standardizedFileURL + } + + private func isWithin( + _ candidate: URL, + directory: URL + ) -> Bool { + let candidateComponents = + candidate.standardizedFileURL.pathComponents + let directoryComponents = + directory.standardizedFileURL.pathComponents + + guard + candidateComponents.count >= + directoryComponents.count + else { + return false + } + + return Array( + candidateComponents.prefix(directoryComponents.count) + ) == directoryComponents + } + + private static func isRetryableCapacityError( + _ error: Error + ) -> Bool { + guard + let replacementError = + error as? CrashConsistentStoreReplacementError + else { + return false + } + + if case .insufficientStorageCapacity = replacementError { + return true + } + + return false + } + + private func aggregateByteCount( + of family: [FamilyMember] + ) throws -> UInt64 { + var result: UInt64 = 0 + + for member in family { + let addition = result.addingReportingOverflow( + member.byteCount + ) + guard !addition.overflow else { + throw CrashConsistentStoreReplacementError + .storeFamilySizeOverflow + } + result = addition.partialValue + guard result <= maximumStoreFamilyByteCount else { + throw CrashConsistentStoreReplacementError + .storeFamilyTooLarge( + actualByteCount: result, + maximumByteCount: + maximumStoreFamilyByteCount + ) + } + } + + return result + } + + private func requireCapacity( + forAdditionalByteCount additionalByteCount: UInt64, + at directoryURL: URL + ) throws { + let requirement = + additionalByteCount.addingReportingOverflow( + minimumFreeStorageReserveByteCount + ) + guard !requirement.overflow else { + throw CrashConsistentStoreReplacementError + .storeFamilySizeOverflow + } + + let availableByteCount = try availableCapacityProvider( + directoryURL + ) + guard availableByteCount >= requirement.partialValue else { + throw CrashConsistentStoreReplacementError + .insufficientStorageCapacity( + requiredByteCount: requirement.partialValue, + availableByteCount: availableByteCount + ) + } + } + + private func manifest( + for familyStoreURL: URL, + requiringMainStore: Bool + ) throws -> [FamilyMember] { + var memberSources: [ + ( + url: URL, + suffix: String, + byteCount: UInt64 + ) + ] = [] + var aggregateByteCount: UInt64 = 0 + + for suffix in Self.storeFamilySuffixes { + let url = familyURL( + storeURL: familyStoreURL, + suffix: suffix + ) + + switch pathKind(at: url) { + case .missing: + if suffix.isEmpty, requiringMainStore { + throw CrashConsistentStoreReplacementError + .sourceStoreMissing + } + case .regularFile: + let values = try lstatValues(at: url) + let addition = + aggregateByteCount.addingReportingOverflow( + values.byteCount + ) + guard !addition.overflow else { + throw CrashConsistentStoreReplacementError + .storeFamilySizeOverflow + } + aggregateByteCount = addition.partialValue + guard + aggregateByteCount <= + maximumStoreFamilyByteCount + else { + throw CrashConsistentStoreReplacementError + .storeFamilyTooLarge( + actualByteCount: + aggregateByteCount, + maximumByteCount: + maximumStoreFamilyByteCount + ) + } + memberSources.append( + ( + url: url, + suffix: suffix, + byteCount: values.byteCount + ) + ) + case .directory, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError.unsafeFile(url) + } + } + + if + requiringMainStore, + !memberSources.contains(where: { + $0.suffix.isEmpty + }) + { + throw CrashConsistentStoreReplacementError.sourceStoreMissing + } + + // Size every member before hashing any of them. A sparse or corrupt + // family is therefore rejected in constant memory and without + // spending unbounded startup time in SHA-256. + return try memberSources.map { + try familyMember( + at: $0.url, + suffix: $0.suffix, + expectedByteCount: $0.byteCount + ) + } + } + + private func family( + at familyStoreURL: URL, + matches expectedFamily: [FamilyMember] + ) throws -> Bool { + do { + let actualFamily = try manifest( + for: familyStoreURL, + requiringMainStore: true + ) + return actualFamily == expectedFamily + } catch CrashConsistentStoreReplacementError.sourceStoreMissing { + return false + } + } + + private func familyMember( + at url: URL, + suffix: String, + expectedByteCount: UInt64? = nil + ) throws -> FamilyMember { + try requireRegularFile(url) + let valuesBeforeDigest = try lstatValues(at: url) + guard + valuesBeforeDigest.byteCount <= + maximumStoreFamilyByteCount + else { + throw CrashConsistentStoreReplacementError + .storeFamilyTooLarge( + actualByteCount: + valuesBeforeDigest.byteCount, + maximumByteCount: + maximumStoreFamilyByteCount + ) + } + if let expectedByteCount { + guard + valuesBeforeDigest.byteCount == expectedByteCount + else { + throw CrashConsistentStoreReplacementError + .familyMismatch + } + } + + let sha256 = try digest( + at: url, + expectedByteCount: valuesBeforeDigest.byteCount + ) + let valuesAfterDigest = try lstatValues(at: url) + guard + valuesAfterDigest.byteCount == + valuesBeforeDigest.byteCount, + valuesAfterDigest.deviceID == + valuesBeforeDigest.deviceID, + valuesAfterDigest.inode == + valuesBeforeDigest.inode + else { + throw CrashConsistentStoreReplacementError.familyMismatch + } + + return FamilyMember( + suffix: suffix, + byteCount: valuesBeforeDigest.byteCount, + sha256: sha256 + ) + } + + private func digest( + at url: URL, + expectedByteCount: UInt64 + ) throws -> String { + let handle = try FileHandle(forReadingFrom: url) + defer { + try? handle.close() + } + + var hasher = SHA256() + var remainingByteCount = expectedByteCount + while remainingByteCount > 0 { + let readByteCount = Int( + min( + remainingByteCount, + UInt64(Self.digestChunkByteCount) + ) + ) + let data = try handle.read( + upToCount: readByteCount + ) ?? Data() + guard !data.isEmpty else { + throw CrashConsistentStoreReplacementError.familyMismatch + } + + hasher.update(data: data) + remainingByteCount -= UInt64(data.count) + } + + let unexpectedByte = try handle.read(upToCount: 1) ?? Data() + guard unexpectedByte.isEmpty else { + throw CrashConsistentStoreReplacementError.familyMismatch + } + + return hasher.finalize().map { + String(format: "%02x", $0) + }.joined() + } + + private func synchronizeFamily(at familyStoreURL: URL) throws { + let family = try manifest( + for: familyStoreURL, + requiringMainStore: true + ) + + for member in family { + try synchronizeFile( + familyURL( + storeURL: familyStoreURL, + suffix: member.suffix + ) + ) + } + + try synchronizeDirectory( + familyStoreURL.deletingLastPathComponent() + ) + } + + private func synchronizeFile(_ url: URL) throws { + do { + try requireRegularFile(url) + let handle = try FileHandle(forUpdating: url) + defer { + try? handle.close() + } + try handle.synchronize() + } catch { + throw CrashConsistentStoreReplacementError + .fileSynchronizationFailed(url, error) + } + } + + private func synchronizeDirectory(_ url: URL) throws { + do { + guard pathKind(at: url) == .directory else { + throw CrashConsistentStoreReplacementError + .unsafeDirectory(url) + } + + let descriptor = Darwin.open(url.path, O_RDONLY) + guard descriptor >= 0 else { + throw POSIXError( + POSIXErrorCode(rawValue: errno) ?? .EIO + ) + } + defer { + _ = Darwin.close(descriptor) + } + + guard Darwin.fsync(descriptor) == 0 else { + throw POSIXError( + POSIXErrorCode(rawValue: errno) ?? .EIO + ) + } + } catch { + throw CrashConsistentStoreReplacementError + .directorySynchronizationFailed(url, error) + } + } + + private func requireSafeDatabaseDirectory() throws { + guard pathKind(at: databaseDirectoryURL) == .directory else { + throw CrashConsistentStoreReplacementError + .unsafeDirectory(databaseDirectoryURL) + } + + switch pathKind(at: recoveryRootURL) { + case .missing, .directory: + return + case .regularFile, .symbolicLink, .other: + throw CrashConsistentStoreReplacementError + .unsafeDirectory(recoveryRootURL) + } + } + + private func requireRegularFile(_ url: URL) throws { + guard pathKind(at: url) == .regularFile else { + throw CrashConsistentStoreReplacementError.unsafeFile(url) + } + } + + private func pathKind(at url: URL) -> PathKind { + var fileStatus = stat() + guard Darwin.lstat(url.path, &fileStatus) == 0 else { + return errno == ENOENT ? .missing : .other + } + + switch fileStatus.st_mode & S_IFMT { + case S_IFREG: + return .regularFile + case S_IFDIR: + return .directory + case S_IFLNK: + return .symbolicLink + default: + return .other + } + } + + private func lstatValues( + at url: URL + ) throws -> ( + byteCount: UInt64, + mode: mode_t, + deviceID: UInt64, + inode: UInt64 + ) { + var fileStatus = stat() + guard Darwin.lstat(url.path, &fileStatus) == 0 else { + throw POSIXError( + POSIXErrorCode(rawValue: errno) ?? .EIO + ) + } + + guard fileStatus.st_size >= 0 else { + throw CrashConsistentStoreReplacementError.unsafeFile(url) + } + + return ( + byteCount: UInt64(fileStatus.st_size), + mode: fileStatus.st_mode, + deviceID: UInt64( + truncatingIfNeeded: fileStatus.st_dev + ), + inode: UInt64( + truncatingIfNeeded: fileStatus.st_ino + ) + ) + } + + private func familyURL( + storeURL: URL, + suffix: String + ) -> URL { + URL(fileURLWithPath: storeURL.path + suffix) + } +} extension NSPersistentStoreCoordinator { static func destroyStore(at storeURL: URL) throws { diff --git a/fearless/Common/Storage/PersistentValueSettings.swift b/fearless/Common/Storage/PersistentValueSettings.swift index 658c57106d..449c58e42a 100644 --- a/fearless/Common/Storage/PersistentValueSettings.swift +++ b/fearless/Common/Storage/PersistentValueSettings.swift @@ -5,6 +5,11 @@ enum PersistentValueSettingsError: Error { } class PersistentValueSettings { + private struct PendingSave { + let value: T + let completion: (Result) -> Void + } + let storageFacade: StorageFacadeProtocol init(storageFacade: StorageFacadeProtocol) { @@ -14,6 +19,10 @@ class PersistentValueSettings { private let mutex = NSLock() var internalValue: T? + private var committedValue: T? + private var pendingSaves: [PendingSave] = [] + private var isPerformingSave = false + private var actionsWaitingForSaves: [() -> Void] = [] var value: T? { mutex.lock() @@ -26,6 +35,76 @@ class PersistentValueSettings { var hasValue: Bool { value != nil } + @discardableResult + func applySetupResult( + _ result: Result, + when shouldApply: () -> Bool, + commit: () -> Void = {} + ) -> Bool { + applySetupResultAtomically(result) { applyValue in + guard shouldApply() else { + return false + } + + applyValue() + commit() + + return true + } + } + + /// Executes `commitIfCurrent` with `mutex` held. The supplied `applyValue` + /// closure updates both the visible and committed values and must be called + /// exactly once when `commitIfCurrent` returns `true`. + @discardableResult + func applySetupResultAtomically( + _ result: Result, + commitIfCurrent: (_ applyValue: () -> Void) -> Bool + ) -> Bool { + mutex.lock() + + guard + pendingSaves.isEmpty, + !isPerformingSave + else { + mutex.unlock() + return false + } + + let applyValue = { + if case let .success(newValue) = result { + self.internalValue = newValue + self.committedValue = newValue + } + } + let didCommit = commitIfCurrent(applyValue) + + mutex.unlock() + + return didCommit + } + + func applySetupResult(_ result: Result) { + applySetupResult(result, when: { true }) + } + + /// Called with `mutex` held immediately before the save is registered. + /// Implementations must not re-enter `PersistentValueSettings`. + func prepareForSaveInvocation() {} + + func performAfterPendingSaves(_ action: @escaping () -> Void) { + mutex.lock() + let shouldPerformImmediately = pendingSaves.isEmpty && !isPerformingSave + if !shouldPerformImmediately { + actionsWaitingForSaves.append(action) + } + mutex.unlock() + + if shouldPerformImmediately { + action() + } + } + func performSetup(completionClosure _: @escaping (Result) -> Void) { fatalError("Function must be implemented in subclass") } @@ -38,16 +117,14 @@ class PersistentValueSettings { runningCompletionIn queue: DispatchQueue?, completionClosure: ((Result) -> Void)? ) { - performSetup { result in - self.mutex.lock() - if case let .success(newValue) = result { - self.internalValue = newValue - } - self.mutex.unlock() - - if let closure = completionClosure { - dispatchInQueueWhenPossible(queue) { - closure(result) + performAfterPendingSaves { + self.performSetup { result in + self.applySetupResult(result) + + if let closure = completionClosure { + dispatchInQueueWhenPossible(queue) { + closure(result) + } } } } @@ -63,25 +140,72 @@ class PersistentValueSettings { completionClosure: ((Result) -> Void)? ) { mutex.lock() - let previousValue = internalValue + prepareForSaveInvocation() internalValue = value + pendingSaves.append( + PendingSave(value: value) { result in + if let completionClosure { + dispatchInQueueWhenPossible(queue) { + completionClosure(result) + } + } + } + ) + let shouldStartSave = !isPerformingSave + if shouldStartSave { + isPerformingSave = true + } mutex.unlock() - performSave(value: value) { result in - self.mutex.lock() - switch result { - case let .success(newValue): - self.internalValue = newValue - case .failure: - self.internalValue = previousValue - } - self.mutex.unlock() + if shouldStartSave { + performNextSave() + } + } - if let closure = completionClosure { - dispatchInQueueWhenPossible(queue) { - closure(result) - } - } + private func performNextSave() { + mutex.lock() + guard let pendingSave = pendingSaves.first else { + isPerformingSave = false + mutex.unlock() + return + } + mutex.unlock() + + performSave(value: pendingSave.value) { result in + self.completeCurrentSave(result) + } + } + + private func completeCurrentSave(_ result: Result) { + mutex.lock() + guard !pendingSaves.isEmpty else { + isPerformingSave = false + mutex.unlock() + return + } + + let completedSave = pendingSaves.removeFirst() + if case let .success(newValue) = result { + committedValue = newValue + } + + internalValue = pendingSaves.last?.value ?? committedValue + let hasNextSave = !pendingSaves.isEmpty + let waitingActions = hasNextSave ? [] : actionsWaitingForSaves + if !hasNextSave { + actionsWaitingForSaves.removeAll() + } + if !hasNextSave { + isPerformingSave = false + } + mutex.unlock() + + completedSave.completion(result) + + if hasNextSave { + performNextSave() + } else { + waitingActions.forEach { $0() } } } diff --git a/fearless/Common/Storage/SelectedWalletSettings.swift b/fearless/Common/Storage/SelectedWalletSettings.swift index d8212db3ba..f97c5a580f 100644 --- a/fearless/Common/Storage/SelectedWalletSettings.swift +++ b/fearless/Common/Storage/SelectedWalletSettings.swift @@ -1,82 +1,311 @@ import Foundation import RobinHood +enum SelectedWalletStoreState: Equatable { + case unresolved + case empty + case ready + case unsupportedOnly + case unavailable +} + +enum SelectedWalletSettingsError: LocalizedError { + case duplicateWalletIdentifier + case unsupportedWalletIdentifierConflict + + var errorDescription: String? { + switch self { + case .duplicateWalletIdentifier: + return "The wallet store contains duplicate identifiers" + case .unsupportedWalletIdentifierConflict: + return "A supported wallet conflicts with an unsupported stored wallet" + } + } +} + final class SelectedWalletSettings: PersistentValueSettings { + private typealias SetupOutcome = ( + selectedWallet: MetaAccountModel?, + repairedAccounts: [MetaAccountSelectionModel], + storeState: SelectedWalletStoreState + ) + static let shared = SelectedWalletSettings( storageFacade: UserDataStorageFacade.shared, operationQueue: OperationManagerFacade.persistentQueue ) let operationQueue: OperationQueue - let mapper = ManagedMetaAccountMapper() - lazy var repository = storageFacade.createRepository(mapper: AnyCoreDataMapper(mapper)) + private let storeStateLock = NSLock() + private var internalStoreState = SelectedWalletStoreState.unresolved + private let setupGenerationLock = NSLock() + private var setupGeneration = UUID() + private let savePreparationHook: (() -> Void)? + private let setupPreparationHook: (() -> Void)? + private let setupCommitHook: (() -> Void)? + + var storeState: SelectedWalletStoreState { + storeStateLock.lock() + defer { storeStateLock.unlock() } + + return internalStoreState + } - init(storageFacade: StorageFacadeProtocol, operationQueue: OperationQueue) { + init( + storageFacade: StorageFacadeProtocol, + operationQueue: OperationQueue, + savePreparationHook: (() -> Void)? = nil, + setupPreparationHook: (() -> Void)? = nil, + setupCommitHook: (() -> Void)? = nil + ) { self.operationQueue = operationQueue + self.savePreparationHook = savePreparationHook + self.setupPreparationHook = setupPreparationHook + self.setupCommitHook = setupCommitHook super.init(storageFacade: storageFacade) } + override func prepareForSaveInvocation() { + _ = replaceSetupGeneration() + savePreparationHook?() + } + + override func setup( + runningCompletionIn queue: DispatchQueue?, + completionClosure: ((Result) -> Void)? + ) { + let generation = replaceSetupGeneration() + setupPreparationHook?() + + performAfterPendingSaves { + self.performSetupOutcome(generation: generation) { result in + let publicResult = result.map(\.selectedWallet) + self.commitSetupOutcomeIfCurrent(result, generation: generation) + + if let completionClosure { + dispatchInQueueWhenPossible(queue) { + completionClosure(publicResult) + } + } + } + } + } + override func performSetup(completionClosure: @escaping (Result) -> Void) { - let mapper = MetaAccountMapper() + performSetupOutcome(generation: nil) { result in + completionClosure(result.map(\.selectedWallet)) + } + } + + private func performSetupOutcome( + generation: UUID?, + completionClosure: @escaping (Result) -> Void + ) { + let selectionMapper = MetaAccountSelectionMapper() let repository = storageFacade.createRepository( - filter: NSPredicate.selectedMetaAccount(), - sortDescriptors: [], - mapper: AnyCoreDataMapper(mapper) + mapper: AnyCoreDataMapper(selectionMapper) ) - let options = RepositoryFetchOptions(includesProperties: true, includesSubentities: true) - let operation = repository.fetchAllOperation(with: options) + let fetchOperation = repository.fetchAllOperation(with: options) + let selectionOperation: BaseOperation = ClosureOperation { + let accounts = try fetchOperation.extractNoCancellableResultData() + + guard Set(accounts.map(\.identifier)).count == accounts.count else { + throw SelectedWalletSettingsError.duplicateWalletIdentifier + } - operation.completionBlock = { + guard !accounts.isEmpty else { + return (nil, [], .empty) + } + + let supportedAccounts = accounts.filter { $0.wallet != nil } + guard !supportedAccounts.isEmpty else { + let containsStructurallyValidUnsupportedWallet = accounts.contains { + $0.recordState == .unsupported + } + let state: SelectedWalletStoreState = + containsStructurallyValidUnsupportedWallet + ? .unsupportedOnly + : .unavailable + + return (nil, [], state) + } + + let selectedSupportedAccounts = supportedAccounts.filter(\.isSelected) + let selectionPool = selectedSupportedAccounts.isEmpty + ? supportedAccounts + : selectedSupportedAccounts + guard + let selectedAccount = selectionPool.min(by: Self.precedesForSelection), + let selectedWallet = selectedAccount.wallet + else { + throw MetaAccountMapperError.invalidWalletRecord + } + + let repairedAccounts: [MetaAccountSelectionModel] = accounts.compactMap { account in + guard account.recordState.allowsStoredRecordUpdates else { + return nil + } + + let shouldBeSelected = account.identifier == selectedAccount.identifier + return account.isSelected == shouldBeSelected + ? nil + : account.replacingSelection(shouldBeSelected) + } + + return (selectedWallet, repairedAccounts, .ready) + } + let repairOperation: BaseOperation = ClosureOperation { + let repairedAccounts = try selectionOperation + .extractNoCancellableResultData() + .repairedAccounts + + guard !repairedAccounts.isEmpty else { + return + } + + let repair = { + let saveOperation = repository.saveOperation( + { repairedAccounts }, + { [] } + ) + let queue = OperationQueue() + queue.addOperations([saveOperation], waitUntilFinished: true) + _ = try saveOperation.extractNoCancellableResultData() + } + + if let generation { + try self.performRepairIfCurrent( + generation: generation, + repair: repair + ) + } else { + try repair() + } + } + + selectionOperation.addDependency(fetchOperation) + repairOperation.addDependency(selectionOperation) + + repairOperation.completionBlock = { do { - let result = try operation.extractNoCancellableResultData().first + _ = try repairOperation.extractNoCancellableResultData() + let result = try selectionOperation.extractNoCancellableResultData() completionClosure(.success(result)) } catch { completionClosure(.failure(error)) } } - operationQueue.addOperation(operation) + operationQueue.addOperations( + [fetchOperation, selectionOperation, repairOperation], + waitUntilFinished: false + ) + } + + private func replaceSetupGeneration() -> UUID { + let generation = UUID() + + setupGenerationLock.lock() + setupGeneration = generation + setupGenerationLock.unlock() + + return generation + } + + private func commitSetupOutcomeIfCurrent( + _ result: Result, + generation: UUID + ) { + let publicResult = result.map(\.selectedWallet) + let storeState: SelectedWalletStoreState + switch result { + case let .success(outcome): + storeState = outcome.storeState + case .failure: + storeState = .unavailable + } + + applySetupResultAtomically(publicResult) { applyValue in + self.setupGenerationLock.lock() + defer { self.setupGenerationLock.unlock() } + + guard self.setupGeneration == generation else { + return false + } + + applyValue() + self.setupCommitHook?() + self.updateStoreState(storeState) + + return true + } + } + + private func performRepairIfCurrent( + generation: UUID, + repair: () throws -> Void + ) throws { + setupGenerationLock.lock() + defer { setupGenerationLock.unlock() } + + guard setupGeneration == generation else { + return + } + + try repair() } override func performSave( value: MetaAccountModel, completionClosure: @escaping (Result) -> Void ) { + let selectionMapper = MetaAccountSelectionMapper() + let repository = storageFacade.createRepository( + mapper: AnyCoreDataMapper(selectionMapper) + ) let options = RepositoryFetchOptions(includesProperties: true, includesSubentities: true) let allAccountsOperation = repository.fetchAllOperation(with: options) let saveOperation = repository.saveOperation({ let existingAccounts = try allAccountsOperation.extractNoCancellableResultData() - var accountsById = existingAccounts.reduce(into: [String: ManagedMetaAccountModel]()) { result, account in - result[account.identifier] = account + guard Set(existingAccounts.map(\.identifier)).count == existingAccounts.count else { + throw SelectedWalletSettingsError.duplicateWalletIdentifier } - if let currentAccount = existingAccounts.first(where: \.isSelected), - currentAccount.identifier != value.identifier { - accountsById[currentAccount.identifier] = ManagedMetaAccountModel( - info: currentAccount.info, - isSelected: false, - order: currentAccount.order - ) + let existingTarget = existingAccounts.first { + $0.identifier == value.identifier + } + + if let existingTarget, existingTarget.wallet == nil { + throw SelectedWalletSettingsError.unsupportedWalletIdentifierConflict + } + + var accountsToSave: [MetaAccountSelectionModel] = existingAccounts.compactMap { account in + guard + account.recordState.allowsStoredRecordUpdates, + account.identifier != value.identifier, + account.isSelected + else { + return nil + } + + return account.replacingSelection(false) } - if let existingAccount = accountsById[value.identifier] { - accountsById[value.identifier] = ManagedMetaAccountModel( - info: value, + accountsToSave.append( + MetaAccountSelectionModel( + identifier: value.identifier, + wallet: value, isSelected: true, - order: existingAccount.order - ) - } else { - accountsById[value.identifier] = ManagedMetaAccountModel( - info: value, - isSelected: true + order: existingTarget?.order ?? ManagedMetaAccountModel.noOrder, + updatesWalletPayload: true ) - } + ) - return Array(accountsById.values) + return accountsToSave }, { [] }) saveOperation.addDependency(allAccountsOperation) @@ -84,7 +313,7 @@ final class SelectedWalletSettings: PersistentValueSettings { saveOperation.completionBlock = { [weak self] in do { _ = try saveOperation.extractNoCancellableResultData() - self?.internalValue = value + self?.updateStoreState(.ready) completionClosure(.success(value)) } catch { completionClosure(.failure(error)) @@ -93,4 +322,24 @@ final class SelectedWalletSettings: PersistentValueSettings { operationQueue.addOperations([allAccountsOperation, saveOperation], waitUntilFinished: false) } + + private static func precedesForSelection( + _ lhs: MetaAccountSelectionModel, + _ rhs: MetaAccountSelectionModel + ) -> Bool { + let lhsOrder = lhs.order == ManagedMetaAccountModel.noOrder ? UInt32.max : lhs.order + let rhsOrder = rhs.order == ManagedMetaAccountModel.noOrder ? UInt32.max : rhs.order + + if lhsOrder != rhsOrder { + return lhsOrder < rhsOrder + } + + return lhs.identifier < rhs.identifier + } + + private func updateStoreState(_ state: SelectedWalletStoreState) { + storeStateLock.lock() + internalStoreState = state + storeStateLock.unlock() + } } diff --git a/fearless/Common/Storage/SubstrateDataStorageFacade.swift b/fearless/Common/Storage/SubstrateDataStorageFacade.swift index 508cc1a071..cdd83d1202 100644 --- a/fearless/Common/Storage/SubstrateDataStorageFacade.swift +++ b/fearless/Common/Storage/SubstrateDataStorageFacade.swift @@ -25,30 +25,53 @@ class SubstrateDataStorageFacade: StorageFacadeProtocol { let databaseService: CoreDataServiceProtocol - private init() { + private convenience init() { let modelName = "SubstrateDataModel" let modelURL = Bundle.main.url(forResource: modelName, withExtension: "momd") - let databaseName = "\(modelName).sqlite" let baseURL = FileManager.default.urls( for: .documentDirectory, in: .userDomainMask ).first?.appendingPathComponent("CoreData") + self.init( + modelURL: modelURL, + databaseDirectory: baseURL!, + databaseName: "\(modelName).sqlite" + ) + } + + init( + modelURL: URL?, + databaseDirectory: URL, + databaseName: String = SubstrateStorageParams.databaseName + ) { + let resolvedModelURL: URL + if let modelURL { + resolvedModelURL = modelURL + } else { + Logger.shared.error( + "Required Substrate Core Data model resource is unavailable" + ) + resolvedModelURL = Bundle.main.bundleURL.appendingPathComponent( + "__fearless_missing_substrate_model_\(UUID().uuidString).momd" + ) + } + let options = [ NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true ] let persistentSettings = CoreDataPersistentSettings( - databaseDirectory: baseURL!, + databaseDirectory: databaseDirectory, databaseName: databaseName, incompatibleModelStrategy: .ignore, options: options ) let configuration = CoreDataServiceConfiguration( - modelURL: modelURL!, + modelURL: resolvedModelURL, storageType: .persistent(settings: persistentSettings) ) diff --git a/fearless/Common/Storage/UserDataStorageFacade.swift b/fearless/Common/Storage/UserDataStorageFacade.swift index 18d1db64b3..1003cc6759 100644 --- a/fearless/Common/Storage/UserDataStorageFacade.swift +++ b/fearless/Common/Storage/UserDataStorageFacade.swift @@ -3,7 +3,7 @@ import RobinHood import CoreData enum UserStorageParams { - static let modelVersion: UserStorageVersion = .version12 + static let modelVersion: UserStorageVersion = .version14 static let modelDirectory: String = "Modules_SSFAccountManagmentStorage.bundle//UserDataModel.momd" static let databaseName = "UserDataModel.sqlite" @@ -26,32 +26,44 @@ class UserDataStorageFacade: StorageFacadeProtocol { let databaseService: CoreDataServiceProtocol - private init() { - let modelName = UserStorageParams.modelVersion.rawValue + private convenience init() { let bundle = Bundle.main - let omoURL = bundle.url( - forResource: modelName, - withExtension: "omo", - subdirectory: UserStorageParams.modelDirectory + let modelURL = UserStorageParams.modelVersion.modelURL( + in: bundle, + legacyModelDirectory: UserStorageParams.modelDirectory ) - let momURL = bundle.url( - forResource: modelName, - withExtension: "mom", - subdirectory: UserStorageParams.modelDirectory + self.init( + modelURL: modelURL, + databaseDirectory: UserStorageParams.storageDirectoryURL ) + } - let modelURL = omoURL ?? momURL + init( + modelURL: URL?, + databaseDirectory: URL + ) { + let resolvedModelURL: URL + if let modelURL { + resolvedModelURL = modelURL + } else { + Logger.shared.error( + "Required User Core Data model resource is unavailable" + ) + resolvedModelURL = Bundle.main.bundleURL.appendingPathComponent( + "__fearless_missing_user_model_\(UUID().uuidString).mom" + ) + } let persistentSettings = CoreDataPersistentSettings( - databaseDirectory: UserStorageParams.storageDirectoryURL, + databaseDirectory: databaseDirectory, databaseName: UserStorageParams.databaseName, incompatibleModelStrategy: .ignore ) let configuration = CoreDataServiceConfiguration( - modelURL: modelURL!, + modelURL: resolvedModelURL, storageType: .persistent(settings: persistentSettings) ) diff --git a/fearless/Info.plist b/fearless/Info.plist index 36375a7e4d..b46c19644a 100644 --- a/fearless/Info.plist +++ b/fearless/Info.plist @@ -53,7 +53,15 @@ CFBundleVersion - 1 + $(CURRENT_PROJECT_VERSION) + FearlessBuildConfiguration + $(CONFIGURATION) + FearlessEnableTestability + $(ENABLE_TESTABILITY) + FearlessGitCommit + $(FEARLESS_GIT_COMMIT) + FearlessSwiftOptimizationLevel + $(SWIFT_OPTIMIZATION_LEVEL) GIDClientID ITSAppUsesNonExemptEncryption diff --git a/fearless/Modules/Onboarding/OnboardingPresenter.swift b/fearless/Modules/Onboarding/OnboardingPresenter.swift index 8f9c085de0..c1dae508ef 100644 --- a/fearless/Modules/Onboarding/OnboardingPresenter.swift +++ b/fearless/Modules/Onboarding/OnboardingPresenter.swift @@ -51,7 +51,7 @@ final class OnboardingPresenter { router.showPincodeSetup() case .login: router.showLogin() - case .onboarding, .broken: + case .onboarding, .broken, .unsupportedWallet: break } } diff --git a/fearless/Modules/Root/RootInteractor.swift b/fearless/Modules/Root/RootInteractor.swift index 1a9be4b79b..828a8ad34d 100644 --- a/fearless/Modules/Root/RootInteractor.swift +++ b/fearless/Modules/Root/RootInteractor.swift @@ -1,39 +1,455 @@ import Foundation +import CoreData import SoraKeystore import IrohaCrypto import RobinHood import SoraFoundation +enum RootStoragePreflightError: LocalizedError { + case contextUnavailable + case persistentStoreCoordinatorUnavailable + case entityNameUnavailable + case managedObjectClassNameUnavailable(entityName: String) + case managedObjectClassUnavailable(entityName: String, className: String) + case invocationCapacityExhausted + case unexpectedManagedObjectClassIdentity( + entityName: String, + expectedClassName: String, + actualClassName: String + ) + + var errorDescription: String? { + switch self { + case .contextUnavailable: + return "Substrate storage opened without a managed object context" + case .persistentStoreCoordinatorUnavailable: + return "Substrate storage opened without a persistent store coordinator" + case .entityNameUnavailable: + return "Substrate storage contains an unnamed entity" + case let .managedObjectClassNameUnavailable(entityName): + return "Substrate storage entity \(entityName) has no managed object class" + case let .managedObjectClassUnavailable(entityName, className): + return "Substrate storage entity \(entityName) cannot resolve class \(className)" + case .invocationCapacityExhausted: + return "Substrate storage preflight is still blocked; retry after the current checks finish" + case let .unexpectedManagedObjectClassIdentity( + entityName, + expectedClassName, + actualClassName + ): + return "Substrate storage entity \(entityName) resolves as \(actualClassName), expected \(expectedClassName)" + } + } +} + +enum RootSetupDeadlineError: LocalizedError { + case migrationTimedOut + case migrationStillRunning + case storagePreflightTimedOut + case selectedWalletSetupTimedOut + + var errorDescription: String? { + switch self { + case .migrationTimedOut: + return "Wallet storage migration timed out" + case .migrationStillRunning: + return "Wallet storage migration is still running" + case .storagePreflightTimedOut: + return "Substrate storage preflight timed out" + case .selectedWalletSetupTimedOut: + return "Selected wallet storage setup timed out" + } + } +} + +protocol RootStoragePreflighting: AnyObject { + func preflight( + completion: @escaping (Result) -> Void + ) +} + +typealias RootStoragePreflightProvider = () -> RootStoragePreflighting +typealias RootSetupDeadlineScheduler = ( + TimeInterval, + @escaping () -> Void +) -> Void + +private final class RootSetupCompletionGate { + private let lock = NSLock() + private var isCompleted = false + + func hasClaimedCompletion() -> Bool { + lock.lock() + defer { lock.unlock() } + + return isCompleted + } + + func claimCompletion() -> Bool { + lock.lock() + defer { lock.unlock() } + + guard !isCompleted else { + return false + } + + isCompleted = true + return true + } +} + +private final class RootStoragePreflightInvocation { + private let lock = NSLock() + private let finishAction: () -> Void + private var hasReturned = false + private var hasDeliveredCompletion = false + private var isFinished = false + + init(finishAction: @escaping () -> Void) { + self.finishAction = finishAction + } + + deinit { + finish(returned: false, deliveredCompletion: false, force: true) + } + + func markReturned() { + finish(returned: true, deliveredCompletion: false, force: false) + } + + func markCompletionDelivered() { + finish(returned: false, deliveredCompletion: true, force: false) + } + + func markSkipped() { + finish(returned: false, deliveredCompletion: false, force: true) + } + + private func finish( + returned: Bool, + deliveredCompletion: Bool, + force: Bool + ) { + lock.lock() + + hasReturned = hasReturned || returned + hasDeliveredCompletion = + hasDeliveredCompletion || deliveredCompletion + + let shouldFinish = + !isFinished && + (force || (hasReturned && hasDeliveredCompletion)) + + if shouldFinish { + isFinished = true + } + + lock.unlock() + + if shouldFinish { + finishAction() + } + } +} + +private final class RootStoragePreflightInvocationLimiter { + private let lock = NSLock() + private let maximumInvocationCount: Int + private var activeInvocationCount = 0 + + init(maximumInvocationCount: Int) { + self.maximumInvocationCount = maximumInvocationCount + } + + func acquire() -> RootStoragePreflightInvocation? { + lock.lock() + defer { lock.unlock() } + + guard activeInvocationCount < maximumInvocationCount else { + return nil + } + + activeInvocationCount += 1 + + return RootStoragePreflightInvocation { [weak self] in + self?.release() + } + } + + private func release() { + lock.lock() + activeInvocationCount = max(0, activeInvocationCount - 1) + lock.unlock() + } +} + +final class RootCoreDataStoragePreflight: RootStoragePreflighting { + private let databaseService: CoreDataServiceProtocol + + init(databaseService: CoreDataServiceProtocol) { + self.databaseService = databaseService + } + + func preflight( + completion: @escaping (Result) -> Void + ) { + databaseService.performAsync { [self] context, error in + completion( + Result { + try validate(context: context, serviceError: error) + } + ) + } + } + + private func validate( + context: NSManagedObjectContext?, + serviceError: Error? + ) throws { + if let serviceError { + throw serviceError + } + + guard let context else { + throw RootStoragePreflightError.contextUnavailable + } + + guard let persistentStoreCoordinator = context.persistentStoreCoordinator else { + throw RootStoragePreflightError.persistentStoreCoordinatorUnavailable + } + + let entities = persistentStoreCoordinator.managedObjectModel.entities.sorted { + ($0.name ?? "") < ($1.name ?? "") + } + + for entity in entities { + try validate(entity: entity, in: context) + } + } + + private func validate( + entity: NSEntityDescription, + in context: NSManagedObjectContext + ) throws { + guard let entityName = entity.name else { + throw RootStoragePreflightError.entityNameUnavailable + } + + guard let expectedClassName = entity.managedObjectClassName else { + throw RootStoragePreflightError.managedObjectClassNameUnavailable( + entityName: entityName + ) + } + + guard let expectedClass = ManagedObjectRuntimeClassRegistry.resolve( + className: expectedClassName + ) else { + throw RootStoragePreflightError.managedObjectClassUnavailable( + entityName: entityName, + className: expectedClassName + ) + } + + let resolvedClassName = NSStringFromClass(expectedClass) + guard resolvedClassName == expectedClassName else { + throw RootStoragePreflightError.unexpectedManagedObjectClassIdentity( + entityName: entityName, + expectedClassName: expectedClassName, + actualClassName: resolvedClassName + ) + } + + guard !entity.isAbstract else { + return + } + + // Fetch only an object ID. Instantiating managed objects or touching their + // attributes here can decode transformable archives and raise an Objective-C + // exception that Swift cannot catch. Startup content mapping remains owned by + // the repositories; this preflight is deliberately limited to store/query and + // runtime-class availability. + let request = NSFetchRequest(entityName: entityName) + request.resultType = .managedObjectIDResultType + request.fetchLimit = 1 + request.includesPendingChanges = false + request.includesSubentities = false + _ = try context.fetch(request) + } +} + +protocol RootSelectedWalletSettingsProtocol: AnyObject { + func setup( + runningCompletionIn queue: DispatchQueue?, + completionClosure: ((Result) -> Void)? + ) +} + +extension SelectedWalletSettings: RootSelectedWalletSettingsProtocol {} + final class RootInteractor { + private static let setupDeadlineQueue = DispatchQueue( + label: "jp.co.soramitsu.fearlesswallet.root-setup-deadline", + qos: .userInitiated + ) + + private enum MigrationBarrierState { + case notRequested + case inProgress + case completed + case failed(Error) + } + + private struct MigrationWaiter { + let generation: UUID + let completionGate: RootSetupCompletionGate + } + weak var presenter: RootInteractorOutputProtocol? - private let chainRegistry: ChainRegistryProtocol - private let settings: SelectedWalletSettings + private let chainRegistryProvider: () -> ChainRegistryProtocol + private lazy var chainRegistry = chainRegistryProvider() + private let storagePreflightProvider: RootStoragePreflightProvider + private let settingsProvider: () -> RootSelectedWalletSettingsProtocol + private lazy var settings = settingsProvider() private let applicationConfig: ApplicationConfigProtocol private let eventCenter: EventCenterProtocol private let migrators: [Migrating] private let logger: LoggerProtocol? private let onboardingService: OnboardingServiceProtocol private let onboardingConfigResolver: OnboardingConfigVersionResolver + private let migrationDeadline: TimeInterval + private let setupDeadline: TimeInterval + private let setupDeadlineScheduler: RootSetupDeadlineScheduler? + private let setupQueue = DispatchQueue( + label: "jp.co.soramitsu.fearlesswallet.root-setup", + qos: .userInitiated + ) + // Core Data migration APIs are synchronous and cannot be cancelled safely. + // Keep exactly one migration worker alive after a presentation deadline so + // a retry can wait for that same attempt instead of racing a second writer. + private let migrationInvocationQueue: OperationQueue = { + let queue = OperationQueue() + queue.name = "jp.co.soramitsu.fearlesswallet.root-migration" + queue.qualityOfService = .userInitiated + queue.maxConcurrentOperationCount = 1 + return queue + }() + + // A Core Data store open cannot be cancelled and may block before + // `performAsync` returns. Keep one recovery lane, but account for an + // invocation until both the call returns and its terminal callback arrives. + // If both lanes stall, retries fail immediately instead of accumulating + // queued work or opening an unbounded number of concurrent stores. These + // lanes only perform the read-only preflight; migration writers stay behind + // the single-worker migration barrier above. + private let storagePreflightInvocationQueue = DispatchQueue( + label: "jp.co.soramitsu.fearlesswallet.root-storage-preflight", + qos: .userInitiated, + attributes: .concurrent + ) + private let storagePreflightInvocationLimiter = + RootStoragePreflightInvocationLimiter(maximumInvocationCount: 2) + + private let setupGenerationLock = NSLock() + private var setupGeneration = UUID() + // Accessed only on setupQueue. A no-migration reload is an assertion that + // migrations already completed earlier in this process. Once either path + // seals the barrier, shared Core Data services may open and migrations must + // not run again. A required migration failure remains fail-closed until a + // required retry succeeds. + private var migrationBarrierState = MigrationBarrierState.notRequested + private var migrationWaiter: MigrationWaiter? init( - chainRegistry: ChainRegistryProtocol, - settings: SelectedWalletSettings, + chainRegistryProvider: @escaping () -> ChainRegistryProtocol, + storagePreflightProvider: @escaping RootStoragePreflightProvider, + settingsProvider: @escaping () -> RootSelectedWalletSettingsProtocol, applicationConfig: ApplicationConfigProtocol, eventCenter: EventCenterProtocol, migrators: [Migrating], logger: LoggerProtocol? = nil, onboardingService: OnboardingServiceProtocol, - onboardingConfigResolver: OnboardingConfigVersionResolver + onboardingConfigResolver: OnboardingConfigVersionResolver, + migrationDeadline: TimeInterval = 60, + setupDeadline: TimeInterval = 15, + setupDeadlineScheduler: RootSetupDeadlineScheduler? = nil ) { - self.chainRegistry = chainRegistry - self.settings = settings + self.chainRegistryProvider = chainRegistryProvider + self.storagePreflightProvider = storagePreflightProvider + self.settingsProvider = settingsProvider self.applicationConfig = applicationConfig self.eventCenter = eventCenter self.migrators = migrators self.logger = logger self.onboardingService = onboardingService self.onboardingConfigResolver = onboardingConfigResolver + self.migrationDeadline = max(0.001, migrationDeadline) + self.setupDeadline = max(0.001, setupDeadline) + self.setupDeadlineScheduler = setupDeadlineScheduler + } + + deinit { + migrationInvocationQueue.cancelAllOperations() + } + + convenience init( + chainRegistryProvider: @escaping () -> ChainRegistryProtocol, + storagePreflightProvider: @escaping RootStoragePreflightProvider, + settings: RootSelectedWalletSettingsProtocol, + applicationConfig: ApplicationConfigProtocol, + eventCenter: EventCenterProtocol, + migrators: [Migrating], + logger: LoggerProtocol? = nil, + onboardingService: OnboardingServiceProtocol, + onboardingConfigResolver: OnboardingConfigVersionResolver, + migrationDeadline: TimeInterval = 60, + setupDeadline: TimeInterval = 15, + setupDeadlineScheduler: RootSetupDeadlineScheduler? = nil + ) { + self.init( + chainRegistryProvider: chainRegistryProvider, + storagePreflightProvider: storagePreflightProvider, + settingsProvider: { settings }, + applicationConfig: applicationConfig, + eventCenter: eventCenter, + migrators: migrators, + logger: logger, + onboardingService: onboardingService, + onboardingConfigResolver: onboardingConfigResolver, + migrationDeadline: migrationDeadline, + setupDeadline: setupDeadline, + setupDeadlineScheduler: setupDeadlineScheduler + ) + } + + convenience init( + chainRegistry: ChainRegistryProtocol, + storagePreflightProvider: @escaping RootStoragePreflightProvider, + settings: RootSelectedWalletSettingsProtocol, + applicationConfig: ApplicationConfigProtocol, + eventCenter: EventCenterProtocol, + migrators: [Migrating], + logger: LoggerProtocol? = nil, + onboardingService: OnboardingServiceProtocol, + onboardingConfigResolver: OnboardingConfigVersionResolver, + migrationDeadline: TimeInterval = 60, + setupDeadline: TimeInterval = 15, + setupDeadlineScheduler: RootSetupDeadlineScheduler? = nil + ) { + self.init( + chainRegistryProvider: { chainRegistry }, + storagePreflightProvider: storagePreflightProvider, + settings: settings, + applicationConfig: applicationConfig, + eventCenter: eventCenter, + migrators: migrators, + logger: logger, + onboardingService: onboardingService, + onboardingConfigResolver: onboardingConfigResolver, + migrationDeadline: migrationDeadline, + setupDeadline: setupDeadline, + setupDeadlineScheduler: setupDeadlineScheduler + ) } private func setupURLHandlingService() { @@ -48,13 +464,307 @@ final class RootInteractor { URLHandlingService.shared.setup(children: [purchaseHandler, keystoreImportService]) } - private func runMigrators() { - migrators.forEach { migrator in - do { - try migrator.migrate() - } catch { - logger?.error(error.localizedDescription) + private func runMigrators() throws { + for migrator in migrators { + try migrator.migrate() + } + } + + private func enforceMigrationBarrier( + runMigrations: Bool, + generation: UUID + ) { + if runMigrations { + switch migrationBarrierState { + case .completed: + preflightStorage(generation: generation) + case .notRequested, .failed: + startMigration(generation: generation) + case .inProgress: + waitForRunningMigration(generation: generation) + } + } else { + switch migrationBarrierState { + case .notRequested: + migrationBarrierState = .completed + preflightStorage(generation: generation) + case .completed: + preflightStorage(generation: generation) + case .inProgress: + failSetup( + with: RootSetupDeadlineError.migrationStillRunning, + generation: generation + ) + case let .failed(error): + failSetup(with: error, generation: generation) + } + } + } + + private func startMigration(generation: UUID) { + migrationBarrierState = .inProgress + waitForRunningMigration(generation: generation) + + migrationInvocationQueue.addOperation { [weak self] in + guard let self else { + return + } + + let result = Result { + try self.runMigrators() + } + + setupQueue.async { [weak self] in + self?.finishMigration(with: result) + } + } + } + + private func waitForRunningMigration(generation: UUID) { + let completionGate = RootSetupCompletionGate() + migrationWaiter = MigrationWaiter( + generation: generation, + completionGate: completionGate + ) + scheduleSetupDeadline( + after: migrationDeadline, + generation: generation, + completionGate: completionGate, + error: .migrationTimedOut + ) + } + + private func finishMigration(with result: Result) { + let waiter = migrationWaiter + migrationWaiter = nil + + switch result { + case .success: + migrationBarrierState = .completed + case let .failure(error): + migrationBarrierState = .failed(error) + } + + guard + let waiter, + waiter.completionGate.claimCompletion(), + isCurrentSetupGeneration(waiter.generation) + else { + return + } + + switch result { + case .success: + preflightStorage(generation: waiter.generation) + case let .failure(error): + failSetup(with: error, generation: waiter.generation) + } + } + + private func replaceSetupGeneration() -> UUID { + let generation = UUID() + + setupGenerationLock.lock() + setupGeneration = generation + setupGenerationLock.unlock() + + return generation + } + + private func isCurrentSetupGeneration(_ generation: UUID) -> Bool { + setupGenerationLock.lock() + defer { setupGenerationLock.unlock() } + + return setupGeneration == generation + } + + private func completeSetup(generation: UUID) { + guard isCurrentSetupGeneration(generation) else { + return + } + + DispatchQueue.main.async { [weak self] in + guard self?.isCurrentSetupGeneration(generation) == true else { + return + } + + self?.presenter?.didCompleteSetup() + } + } + + private func failSetup(with error: Error, generation: UUID) { + logger?.error(error.localizedDescription) + + guard isCurrentSetupGeneration(generation) else { + return + } + + DispatchQueue.main.async { [weak self] in + guard self?.isCurrentSetupGeneration(generation) == true else { + return + } + + self?.presenter?.didFailSetup() + } + } + + private func scheduleSetupDeadline( + after delay: TimeInterval, + generation: UUID, + completionGate: RootSetupCompletionGate, + error: RootSetupDeadlineError + ) { + let deadlineAction = { [weak self] in + guard + completionGate.claimCompletion(), + let self, + isCurrentSetupGeneration(generation) + else { + return } + + failSetup(with: error, generation: generation) + } + + if let setupDeadlineScheduler { + setupDeadlineScheduler(delay, deadlineAction) + } else { + Self.setupDeadlineQueue.asyncAfter( + deadline: .now() + delay, + execute: deadlineAction + ) + } + } + + private func setupSelectedWallet( + generation: UUID, + chainRegistry: ChainRegistryProtocol + ) { + guard isCurrentSetupGeneration(generation) else { + return + } + + let completionGate = RootSetupCompletionGate() + scheduleSetupDeadline( + after: setupDeadline, + generation: generation, + completionGate: completionGate, + error: .selectedWalletSetupTimedOut + ) + settings.setup(runningCompletionIn: .global()) { [weak self] result in + guard completionGate.claimCompletion() else { + return + } + + guard + let self, + isCurrentSetupGeneration(generation) + else { + return + } + + setupQueue.async { [weak self] in + guard + let self, + isCurrentSetupGeneration(generation) + else { + return + } + + switch result { + case let .success(wallet): + if let wallet { + chainRegistry.performHotBoot() + logger?.debug("Selected account: \(wallet.metaId)") + } else { + chainRegistry.performColdBoot() + logger?.debug("No selected account") + } + + completeSetup(generation: generation) + case let .failure(error): + failSetup(with: error, generation: generation) + } + } + } + } + + private func preflightStorage(generation: UUID) { + guard isCurrentSetupGeneration(generation) else { + return + } + + guard + let invocation = storagePreflightInvocationLimiter.acquire() + else { + failSetup( + with: RootStoragePreflightError.invocationCapacityExhausted, + generation: generation + ) + return + } + + let completionGate = RootSetupCompletionGate() + scheduleSetupDeadline( + after: setupDeadline, + generation: generation, + completionGate: completionGate, + error: .storagePreflightTimedOut + ) + let preflightProvider = storagePreflightProvider + storagePreflightInvocationQueue.async { [weak self, invocation] in + guard + self?.isCurrentSetupGeneration(generation) == true, + !completionGate.hasClaimedCompletion() + else { + invocation.markSkipped() + return + } + + let preflight = preflightProvider() + + guard + self?.isCurrentSetupGeneration(generation) == true, + !completionGate.hasClaimedCompletion() + else { + invocation.markSkipped() + return + } + + preflight.preflight { [weak self] result in + invocation.markCompletionDelivered() + + guard completionGate.claimCompletion() else { + return + } + + guard let self else { + return + } + + setupQueue.async { [weak self] in + guard + let self, + isCurrentSetupGeneration(generation) + else { + return + } + + switch result { + case .success: + let registry = chainRegistry + + setupSelectedWallet( + generation: generation, + chainRegistry: registry + ) + case let .failure(error): + failSetup(with: error, generation: generation) + } + } + } + + invocation.markReturned() } } } @@ -63,23 +773,21 @@ extension RootInteractor: RootInteractorInputProtocol { func setup(runMigrations: Bool) { setupURLHandlingService() - settings.setup(runningCompletionIn: .global()) { result in - if runMigrations { - self.runMigrators() + let generation = replaceSetupGeneration() + + setupQueue.async { [weak self] in + guard let self else { + return } - switch result { - case let .success(wallet): - if let wallet = wallet { - self.chainRegistry.performHotBoot() - self.logger?.debug("Selected account: \(wallet.metaId)") - } else { - self.chainRegistry.performColdBoot() - self.logger?.debug("No selected account") - } - case let .failure(error): - self.logger?.error("Selected account setup failed: \(error)") + guard isCurrentSetupGeneration(generation) else { + return } + + enforceMigrationBarrier( + runMigrations: runMigrations, + generation: generation + ) } } diff --git a/fearless/Modules/Root/RootPresenter.swift b/fearless/Modules/Root/RootPresenter.swift index 4e9b276fd0..748cb0029c 100644 --- a/fearless/Modules/Root/RootPresenter.swift +++ b/fearless/Modules/Root/RootPresenter.swift @@ -1,20 +1,72 @@ import UIKit import SoraFoundation +import os.log + +protocol RootStartupReadinessReporting: AnyObject { + func reportReady() + func reportFailure() +} + +final class RootStartupReadinessReporter: RootStartupReadinessReporting { + static let shared = RootStartupReadinessReporter() + + private let log = OSLog( + subsystem: Bundle.main.bundleIdentifier ?? "jp.co.soramitsu.fearlesswallet", + category: "startup-readiness" + ) + + private init() {} + + func reportReady() { + os_log("FEARLESS_STARTUP_READY", log: log, type: .default) + } + + func reportFailure() { + os_log("FEARLESS_STARTUP_FAILED", log: log, type: .error) + } +} final class RootPresenter { + private enum SetupPurpose { + case launch + case reload + } + + private enum LoadError: LocalizedError { + case missingInteractor + case onboardingConfigTimedOut + + var errorDescription: String? { + switch self { + case .missingInteractor: + return "Root interactor is unavailable" + case .onboardingConfigTimedOut: + return "Onboarding configuration request timed out" + } + } + } + var view: ControllerBackedProtocol? var window: UIWindow! var wireframe: RootWireframeProtocol! var interactor: RootInteractorInputProtocol! private let startViewHelper: StartViewHelperProtocol + private let onboardingConfigTimeoutNanoseconds: UInt64 + private let startupReadinessReporter: RootStartupReadinessReporting private var loadTask: Task? + private var setupPurpose: SetupPurpose? init( localizationManager: LocalizationManagerProtocol, - startViewHelper: StartViewHelperProtocol + startViewHelper: StartViewHelperProtocol, + onboardingConfigTimeoutNanoseconds: UInt64 = 5_000_000_000, + startupReadinessReporter: RootStartupReadinessReporting = + RootStartupReadinessReporter.shared ) { self.startViewHelper = startViewHelper + self.onboardingConfigTimeoutNanoseconds = max(1, onboardingConfigTimeoutNanoseconds) + self.startupReadinessReporter = startupReadinessReporter self.localizationManager = localizationManager } @@ -27,52 +79,255 @@ final class RootPresenter { switch startView { case .pin: wireframe.showLocalAuthentication(on: window) + startupReadinessReporter.reportReady() case .pinSetup: wireframe.showPincodeSetup(on: window) + startupReadinessReporter.reportReady() case .login: wireframe.showMain(on: window) + startupReadinessReporter.reportReady() case .broken: wireframe.showBroken(on: window) + startupReadinessReporter.reportFailure() + showProtectedDataFailure() + case .unsupportedWallet: + wireframe.showBroken(on: window) + startupReadinessReporter.reportFailure() + showUnsupportedWalletFailure() case let .onboarding(config): wireframe.showOnboarding(on: window, with: config) + startupReadinessReporter.reportReady() } } -} -extension RootPresenter: RootPresenterProtocol { - func loadOnLaunch() { - wireframe.showSplash(splashView: view, on: window) + private func fetchOnboardingConfigWithTimeout() async throws -> OnboardingConfigWrapper? { + try Task.checkCancellation() - interactor.setup(runMigrations: true) + let raceState = RootAsyncRaceState() + let timeout = onboardingConfigTimeoutNanoseconds + + guard let interactor else { + throw LoadError.missingInteractor + } + + return try await withTaskCancellationHandler( + operation: { + try await withCheckedThrowingContinuation { continuation in + guard raceState.install(continuation), !Task.isCancelled else { + raceState.resolve(.failure(CancellationError())) + return + } + + let fetchTask = Task { + guard raceState.claimOperationStart() else { + return + } + + do { + raceState.resolve(.success(try await interactor.fetchOnboardingConfig())) + } catch { + raceState.resolve(.failure(error)) + } + } + + let timeoutTask = Task { + do { + try await Task.sleep(nanoseconds: timeout) + raceState.resolve(.failure(LoadError.onboardingConfigTimedOut)) + } catch { + // The other result won the race or startup was cancelled. + } + } + + raceState.registerTasks([fetchTask, timeoutTask]) + } + }, + onCancel: { + raceState.resolve(.failure(CancellationError())) + } + ) + } + + private func loadOnboardingConfig() { loadTask?.cancel() loadTask = Task { [weak self] in guard let self else { return } do { - let onboardingConfig = try await interactor.fetchOnboardingConfig() - DispatchQueue.main.async { [weak self] in + let onboardingConfig = try await fetchOnboardingConfigWithTimeout() + guard !Task.isCancelled else { return } + + await MainActor.run { [weak self] in + guard !Task.isCancelled else { return } + self?.decideModuleSynchroniously(with: onboardingConfig) } } catch { + guard !Task.isCancelled else { return } + Logger.shared.error(error.localizedDescription) - DispatchQueue.main.async { [weak self] in + await MainActor.run { [weak self] in + guard !Task.isCancelled else { return } + self?.decideModuleSynchroniously(with: nil) } } } } + private func showRetryableFailure(message: String) { + let title = R.string.localizable.commonErrorGeneralTitle( + preferredLanguages: localizationManager?.selectedLocale.rLanguages + ) + let retryTitle = R.string.localizable.commonRetry( + preferredLanguages: localizationManager?.selectedLocale.rLanguages + ) + + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + alert.addAction( + UIAlertAction(title: retryTitle, style: .default) { [weak self] _ in + self?.loadOnLaunch() + } + ) + + view?.controller.present(alert, animated: true) + } + + private func showSetupFailure() { + showRetryableFailure( + message: """ + Your wallet data is safe, but Fearless Wallet couldn't update it. \ + Please retry or install the latest build. + """ + ) + } + + private func showProtectedDataFailure() { + showRetryableFailure( + message: """ + Your wallet data is safe, but Fearless Wallet couldn't access its protected security data. \ + Unlock your device and retry. If this continues, restart your device. + """ + ) + } + + private func showUnsupportedWalletFailure() { + showRetryableFailure( + message: """ + Your wallet data is safe, but this build can't open any of the wallets stored on this device. \ + Please install the latest build and retry. + """ + ) + } +} + +extension RootPresenter: RootPresenterProtocol { + func loadOnLaunch() { + wireframe.showSplash(splashView: view, on: window) + + loadTask?.cancel() + setupPurpose = .launch + interactor.setup(runMigrations: true) + } + func reload() { loadTask?.cancel() + setupPurpose = .reload interactor.setup(runMigrations: false) + } +} - DispatchQueue.main.async { [weak self] in - self?.decideModuleSynchroniously(with: nil) +extension RootPresenter: RootInteractorOutputProtocol { + func didCompleteSetup() { + guard let setupPurpose else { + return + } + + self.setupPurpose = nil + + switch setupPurpose { + case .launch: + loadOnboardingConfig() + case .reload: + decideModuleSynchroniously(with: nil) } } -} -extension RootPresenter: RootInteractorOutputProtocol {} + func didFailSetup() { + setupPurpose = nil + loadTask?.cancel() + startupReadinessReporter.reportFailure() + showSetupFailure() + } +} extension RootPresenter: Localizable { func applyLocalization() {} } + +/// An unstructured first-result race is intentional. Structured task groups wait for cancelled +/// children before returning, so a transport that ignores cancellation could defeat the deadline. +private final class RootAsyncRaceState: @unchecked Sendable { + private let lock = NSLock() + private var continuation: CheckedContinuation? + private var resolution: Result? + private var tasks: [Task] = [] + private var operationStarted = false + + @discardableResult + func install(_ continuation: CheckedContinuation) -> Bool { + lock.lock() + + if let resolution { + lock.unlock() + continuation.resume(with: resolution) + return false + } else { + self.continuation = continuation + lock.unlock() + return true + } + } + + func claimOperationStart() -> Bool { + lock.lock() + defer { lock.unlock() } + + guard resolution == nil, !operationStarted else { + return false + } + + operationStarted = true + return true + } + + func registerTasks(_ tasks: [Task]) { + lock.lock() + + if resolution == nil { + self.tasks = tasks + lock.unlock() + } else { + lock.unlock() + tasks.forEach { $0.cancel() } + } + } + + func resolve(_ result: Result) { + lock.lock() + + guard resolution == nil else { + lock.unlock() + return + } + + resolution = result + let continuation = continuation + self.continuation = nil + let tasks = tasks + self.tasks.removeAll() + lock.unlock() + + tasks.forEach { $0.cancel() } + continuation?.resume(with: result) + } +} diff --git a/fearless/Modules/Root/RootPresenterFactory.swift b/fearless/Modules/Root/RootPresenterFactory.swift index c5f9b1cd0a..68aa2b5b15 100644 --- a/fearless/Modules/Root/RootPresenterFactory.swift +++ b/fearless/Modules/Root/RootPresenterFactory.swift @@ -7,8 +7,9 @@ import SSFNetwork final class RootPresenterFactory: RootPresenterFactoryProtocol { struct Dependencies { let settings: SettingsManager - let selectedWalletSettings: SelectedWalletSettings - let chainRegistry: ChainRegistryProtocol + let selectedWalletSettingsProvider: () -> SelectedWalletSettings + let chainRegistryProvider: () -> ChainRegistryProtocol + let storagePreflightProvider: RootStoragePreflightProvider let applicationConfig: ApplicationConfigProtocol let eventCenter: EventCenterProtocol let logger: LoggerProtocol? @@ -20,8 +21,17 @@ final class RootPresenterFactory: RootPresenterFactoryProtocol { static var `default`: Dependencies { Dependencies( settings: SettingsManager.shared, - selectedWalletSettings: SelectedWalletSettings.shared, - chainRegistry: ChainRegistryFacade.sharedRegistry, + selectedWalletSettingsProvider: { + SelectedWalletSettings.shared + }, + chainRegistryProvider: { + ChainRegistryFacade.sharedRegistry + }, + storagePreflightProvider: { + RootCoreDataStoragePreflight( + databaseService: SubstrateDataStorageFacade.shared.databaseService + ) + }, applicationConfig: ApplicationConfig.shared, eventCenter: EventCenter.shared, logger: Logger.shared, @@ -44,7 +54,8 @@ final class RootPresenterFactory: RootPresenterFactoryProtocol { let wireframe = RootWireframe() let startViewHelper = StartViewHelper( keystore: dependencies.keystore, - selectedWalletSettings: dependencies.selectedWalletSettings, + selectedWalletSettingsProvider: + dependencies.selectedWalletSettingsProvider, userDefaultsStorage: dependencies.settings ) @@ -73,8 +84,6 @@ final class RootPresenterFactory: RootPresenterFactoryProtocol { startViewHelper: startViewHelper ) - _ = AssetManagementMigratorAssembly.createDefaultMigrator() - let migrators: [Migrating] = [ languageMigrator, dbMigrator, @@ -82,8 +91,9 @@ final class RootPresenterFactory: RootPresenterFactoryProtocol { ] let interactor = RootInteractor( - chainRegistry: dependencies.chainRegistry, - settings: dependencies.selectedWalletSettings, + chainRegistryProvider: dependencies.chainRegistryProvider, + storagePreflightProvider: dependencies.storagePreflightProvider, + settingsProvider: dependencies.selectedWalletSettingsProvider, applicationConfig: dependencies.applicationConfig, eventCenter: dependencies.eventCenter, migrators: migrators, diff --git a/fearless/Modules/Root/RootProtocol.swift b/fearless/Modules/Root/RootProtocol.swift index 5e7922764e..3d9a3a385e 100644 --- a/fearless/Modules/Root/RootProtocol.swift +++ b/fearless/Modules/Root/RootProtocol.swift @@ -23,7 +23,10 @@ protocol RootInteractorInputProtocol: AnyObject { func fetchOnboardingConfig() async throws -> OnboardingConfigWrapper? } -protocol RootInteractorOutputProtocol: AnyObject {} +protocol RootInteractorOutputProtocol: AnyObject { + func didCompleteSetup() + func didFailSetup() +} protocol RootPresenterFactoryProtocol: AnyObject { static func createPresenter(with window: UIWindow) -> RootPresenterProtocol diff --git a/fearless/Modules/Root/StartViewHelper.swift b/fearless/Modules/Root/StartViewHelper.swift index 85c2e38cac..c8a5988449 100644 --- a/fearless/Modules/Root/StartViewHelper.swift +++ b/fearless/Modules/Root/StartViewHelper.swift @@ -6,6 +6,7 @@ enum StartView { case pinSetup case login case broken + case unsupportedWallet case onboarding(OnboardingConfigWrapper) } @@ -15,41 +16,71 @@ protocol StartViewHelperProtocol { final class StartViewHelper: StartViewHelperProtocol { private let keystore: KeystoreProtocol - private let selectedWalletSettings: SelectedWalletSettings + private let selectedWalletSettingsProvider: () -> SelectedWalletSettings + private lazy var selectedWalletSettings = selectedWalletSettingsProvider() private let userDefaultsStorage: SettingsManagerProtocol init( keystore: KeystoreProtocol, - selectedWalletSettings: SelectedWalletSettings, + selectedWalletSettingsProvider: @escaping () -> SelectedWalletSettings, userDefaultsStorage: SettingsManagerProtocol ) { self.keystore = keystore - self.selectedWalletSettings = selectedWalletSettings + self.selectedWalletSettingsProvider = selectedWalletSettingsProvider self.userDefaultsStorage = userDefaultsStorage } + convenience init( + keystore: KeystoreProtocol, + selectedWalletSettings: SelectedWalletSettings, + userDefaultsStorage: SettingsManagerProtocol + ) { + self.init( + keystore: keystore, + selectedWalletSettingsProvider: { selectedWalletSettings }, + userDefaultsStorage: userDefaultsStorage + ) + } + func startView(onboardingConfig: OnboardingConfigWrapper?) -> StartView { do { - if let config = onboardingConfig { - return StartView.onboarding(config) - } - - if !selectedWalletSettings.hasValue { + switch selectedWalletSettings.storeState { + case .ready: + guard selectedWalletSettings.hasValue else { + return .broken + } + case .empty: + if let config = onboardingConfig { + return .onboarding(config) + } try keystore.deleteKeyIfExists(for: KeystoreTag.pincode.rawValue) - - return StartView.login + return .login + case .unsupportedOnly: + let pincodeExists = try keystore.checkKey(for: KeystoreTag.pincode.rawValue) + if pincodeExists { + return .unsupportedWallet + } + if let config = onboardingConfig { + return .onboarding(config) + } + return .login + case .unresolved, .unavailable: + return .broken } + if let config = onboardingConfig { + return .onboarding(config) + } let pincodeExists = try keystore.checkKey(for: KeystoreTag.pincode.rawValue) if pincodeExists { - return StartView.pin + return .pin } else { - return StartView.pinSetup + return .pinSetup } } catch { - return StartView.broken + return .broken } } } diff --git a/fearless/WalletConnect.dev.entitlements b/fearless/WalletConnect.dev.entitlements new file mode 100644 index 0000000000..59012c598e --- /dev/null +++ b/fearless/WalletConnect.dev.entitlements @@ -0,0 +1,23 @@ + + + + + com.apple.developer.associated-domains + + webcredentials:fearlesswallet.io + + com.apple.developer.icloud-container-identifiers + + iCloud.jp.co.soramitsu.fearless + iCloud.jp.co.soramitsu.fearlesswallet.dev + + com.apple.developer.icloud-services + + CloudKit + + com.apple.security.application-groups + + group.jp.co.soramitsu.fearlesswallet.walletconnect + + + diff --git a/fearless/WalletConnect.entitlements b/fearless/WalletConnect.entitlements index c464aa54f5..f4e105882b 100644 --- a/fearless/WalletConnect.entitlements +++ b/fearless/WalletConnect.entitlements @@ -4,12 +4,12 @@ com.apple.developer.associated-domains + applinks:fearlesswallet.io webcredentials:fearlesswallet.io com.apple.developer.icloud-container-identifiers - iCloud.jp.co.soramitsu.fearless - iCloud.jp.co.soramitsu.fearlesswallet.dev + iCloud.jp.co.soramitsu.fearlesswallet com.apple.developer.icloud-services @@ -17,11 +17,7 @@ com.apple.security.application-groups - group.com.walletconnect.sdk - - keychain-access-groups - - group.com.walletconnect.sdk + group.jp.co.soramitsu.fearlesswallet diff --git a/fearless/fearless-Bridging-Header.h b/fearless/fearless-Bridging-Header.h new file mode 100644 index 0000000000..87479c2303 --- /dev/null +++ b/fearless/fearless-Bridging-Header.h @@ -0,0 +1 @@ +#import "Common/CoreData/FearlessObjectiveCExceptionCatcher.h" diff --git a/fearlessTests/Common/Migration/CrashConsistentStoreReplacerResourceLimitTests.swift b/fearlessTests/Common/Migration/CrashConsistentStoreReplacerResourceLimitTests.swift new file mode 100644 index 0000000000..95e7137cf4 --- /dev/null +++ b/fearlessTests/Common/Migration/CrashConsistentStoreReplacerResourceLimitTests.swift @@ -0,0 +1,552 @@ +import Foundation +import XCTest +@testable import fearless + +final class CrashConsistentStoreReplacerResourceLimitTests: + XCTestCase +{ + private var rootURL: URL! + private var storeURL: URL! + private var stagedStoreURL: URL! + + override func setUpWithError() throws { + try super.setUpWithError() + + rootURL = FileManager.default.temporaryDirectory + .appendingPathComponent( + "CrashConsistentStoreResourceLimits-\(UUID().uuidString)", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: rootURL, + withIntermediateDirectories: false + ) + storeURL = rootURL.appendingPathComponent("Live.sqlite") + stagedStoreURL = rootURL.appendingPathComponent("Staged.sqlite") + } + + override func tearDownWithError() throws { + if let rootURL { + try? FileManager.default.removeItem(at: rootURL) + } + + try super.tearDownWithError() + } + + func testReplaceStore_whenMainFileExceedsLimit_rejectsBeforeCapacityOrMutation() throws { + let maximum = + CrashConsistentStoreReplacer + .defaultMaximumStoreFamilyByteCount + let oversizedByteCount = maximum + 1 + try Data().write(to: storeURL) + let handle = try FileHandle(forWritingTo: storeURL) + try handle.truncate(atOffset: oversizedByteCount) + try handle.close() + try Data([0x03]).write(to: stagedStoreURL) + + var capacityInspectionCount = 0 + var replacementCount = 0 + var boundaries: [CrashConsistentStoreReplacementBoundary] = [] + let replacer = makeReplacer( + maximumStoreFamilyByteCount: maximum, + availableCapacityProvider: { _ in + capacityInspectionCount += 1 + return UInt64.max + }, + storeReplacer: { _, _ in + replacementCount += 1 + }, + boundaryHook: { + boundaries.append($0) + } + ) + + XCTAssertThrowsError( + try replacer.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) { error in + guard + case let .storeFamilyTooLarge( + actual, + reportedMaximum + ) = + error as? CrashConsistentStoreReplacementError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(actual, oversizedByteCount) + XCTAssertEqual(reportedMaximum, maximum) + } + + XCTAssertEqual(capacityInspectionCount, 0) + XCTAssertEqual(replacementCount, 0) + XCTAssertTrue(boundaries.isEmpty) + XCTAssertFalse(replacer.hasPendingTransaction) + let attributes = try FileManager.default + .attributesOfItem(atPath: storeURL.path) + XCTAssertEqual( + (attributes[.size] as? NSNumber)?.uint64Value, + oversizedByteCount + ) + } + + func testReplaceStore_whenAggregateFamilyExceedsLimit_rejectsBeforeMutation() throws { + try Data([0x01, 0x02]).write(to: storeURL) + try Data([0x03, 0x04]).write( + to: familyURL(storeURL, suffix: "-wal") + ) + try Data([0x05]).write(to: stagedStoreURL) + + var replacementCount = 0 + let replacer = makeReplacer( + maximumStoreFamilyByteCount: 3, + storeReplacer: { _, _ in + replacementCount += 1 + } + ) + + XCTAssertThrowsError( + try replacer.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) { error in + guard + case let .storeFamilyTooLarge( + actual, + reportedMaximum + ) = + error as? CrashConsistentStoreReplacementError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(actual, 4) + XCTAssertEqual(reportedMaximum, 3) + } + + XCTAssertEqual(replacementCount, 0) + XCTAssertFalse(replacer.hasPendingTransaction) + } + + func testReplaceStore_whenCapacityIsOneByteShort_rejectsBeforeTransactionMutation() throws { + try Data([0x01, 0x02, 0x03, 0x04]).write(to: storeURL) + try Data([0x05, 0x06]).write(to: stagedStoreURL) + + var replacementCount = 0 + var boundaries: [CrashConsistentStoreReplacementBoundary] = [] + let replacer = makeReplacer( + maximumStoreFamilyByteCount: 16, + minimumFreeStorageReserveByteCount: 3, + availableCapacityProvider: { _ in 6 }, + storeReplacer: { _, _ in + replacementCount += 1 + }, + boundaryHook: { + boundaries.append($0) + } + ) + + XCTAssertThrowsError( + try replacer.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) { error in + guard + case let .insufficientStorageCapacity(required, available) = + error as? CrashConsistentStoreReplacementError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(required, 7) + XCTAssertEqual(available, 6) + } + + XCTAssertEqual(replacementCount, 0) + XCTAssertTrue(boundaries.isEmpty) + XCTAssertFalse(replacer.hasPendingTransaction) + } + + func testReplaceStore_whenFamilyAndCapacityAreExactBoundaries_succeeds() throws { + let original = Data([0x01, 0x02, 0x03, 0x04]) + let replacement = Data([0x05, 0x06, 0x07, 0x08]) + try original.write(to: storeURL) + try replacement.write(to: stagedStoreURL) + + let replacer = makeReplacer( + maximumStoreFamilyByteCount: 4, + minimumFreeStorageReserveByteCount: 3, + availableCapacityProvider: { _ in 7 } + ) + + try replacer.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + + XCTAssertEqual(try Data(contentsOf: storeURL), replacement) + XCTAssertFalse(replacer.hasPendingTransaction) + } + + func testReplaceStore_whenCapacityRequirementOverflows_rejectsBeforeMutation() throws { + try Data([0x01]).write(to: storeURL) + try Data([0x02]).write(to: stagedStoreURL) + + var replacementCount = 0 + let replacer = makeReplacer( + maximumStoreFamilyByteCount: 1, + minimumFreeStorageReserveByteCount: UInt64.max, + availableCapacityProvider: { _ in UInt64.max }, + storeReplacer: { _, _ in + replacementCount += 1 + } + ) + + XCTAssertThrowsError( + try replacer.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) { error in + guard + case .storeFamilySizeOverflow = + error as? CrashConsistentStoreReplacementError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertEqual(replacementCount, 0) + XCTAssertFalse(replacer.hasPendingTransaction) + } + + func testCommittedRecovery_whenValidationCopyLacksSpace_preservesTransactionForRetry() throws { + let original = Data([0x10, 0x11, 0x12]) + let replacement = Data([0x20, 0x21, 0x22]) + try original.write(to: storeURL) + try replacement.write(to: stagedStoreURL) + + let interrupted = makeReplacer( + maximumStoreFamilyByteCount: 3, + minimumFreeStorageReserveByteCount: 0, + availableCapacityProvider: { _ in UInt64.max }, + boundaryHook: { boundary in + if boundary == .committedMarkerPersisted { + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + } + ) + + XCTAssertThrowsError( + try interrupted.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) { error in + guard + error is CrashConsistentStoreReplacementInterruption + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertTrue(interrupted.hasPendingTransaction) + XCTAssertEqual(try Data(contentsOf: storeURL), replacement) + + let capacityBlocked = makeReplacer( + maximumStoreFamilyByteCount: 3, + minimumFreeStorageReserveByteCount: 0, + availableCapacityProvider: { _ in 2 } + ) + XCTAssertThrowsError( + try capacityBlocked.reconcile( + validateCommittedStore: { _ in } + ) + ) { error in + guard + case let .insufficientStorageCapacity(required, available) = + error as? CrashConsistentStoreReplacementError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(required, 3) + XCTAssertEqual(available, 2) + } + XCTAssertTrue(capacityBlocked.hasPendingTransaction) + XCTAssertEqual(try Data(contentsOf: storeURL), replacement) + + let recovered = makeReplacer( + maximumStoreFamilyByteCount: 3, + minimumFreeStorageReserveByteCount: 0, + availableCapacityProvider: { _ in 3 } + ) + try recovered.reconcile(validateCommittedStore: { _ in }) + + XCTAssertFalse(recovered.hasPendingTransaction) + XCTAssertEqual(try Data(contentsOf: storeURL), replacement) + } + + func testPrivateCopy_whenSparseSourceExceedsLimit_rejectsBeforeCapacityOrCopy() throws { + let maximum = + CrashConsistentStoreReplacer + .defaultMaximumStoreFamilyByteCount + let oversizedByteCount = maximum + 1 + try Data().write(to: storeURL) + let handle = try FileHandle(forWritingTo: storeURL) + try handle.truncate(atOffset: oversizedByteCount) + try handle.close() + + var capacityInspectionCount = 0 + XCTAssertThrowsError( + try SQLiteStoreFamilyCopier.copy( + from: storeURL, + to: stagedStoreURL, + includingSharedMemory: false, + fileManager: .default, + limits: SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: maximum, + minimumFreeStorageReserveByteCount: 0 + ), + availableCapacityProvider: { _ in + capacityInspectionCount += 1 + return UInt64.max + } + ) + ) { error in + guard + case let .storeFamilyTooLarge( + actual, + reportedMaximum + ) = + error as? CrashConsistentStoreReplacementError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(actual, oversizedByteCount) + XCTAssertEqual(reportedMaximum, maximum) + } + + XCTAssertEqual(capacityInspectionCount, 0) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: stagedStoreURL.path + ) + ) + } + + func testPrivateCopy_whenCapacityIsInsufficient_rejectsBeforeFirstMember() throws { + try Data([0x01, 0x02, 0x03]).write(to: storeURL) + + XCTAssertThrowsError( + try SQLiteStoreFamilyCopier.copy( + from: storeURL, + to: stagedStoreURL, + includingSharedMemory: false, + fileManager: .default, + limits: SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: 3, + minimumFreeStorageReserveByteCount: 2 + ), + availableCapacityProvider: { _ in 4 } + ) + ) { error in + guard + case let .insufficientStorageCapacity(required, available) = + error as? CrashConsistentStoreReplacementError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(required, 5) + XCTAssertEqual(available, 4) + } + + XCTAssertFalse( + FileManager.default.fileExists( + atPath: stagedStoreURL.path + ) + ) + } + + func testPrivateCopy_whenSourceMainIsSymlink_rejectsWithoutFollowingIt() throws { + let outsideURL = rootURL.appendingPathComponent("Outside.sqlite") + try Data([0x01]).write(to: outsideURL) + try FileManager.default.createSymbolicLink( + at: storeURL, + withDestinationURL: outsideURL + ) + + XCTAssertThrowsError( + try SQLiteStoreFamilyCopier.copy( + from: storeURL, + to: stagedStoreURL, + includingSharedMemory: false, + fileManager: .default, + limits: SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: 1, + minimumFreeStorageReserveByteCount: 0 + ), + availableCapacityProvider: { _ in 1 } + ) + ) { error in + guard + case .unsafeFile = + error as? CrashConsistentStoreReplacementError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertFalse( + FileManager.default.fileExists( + atPath: stagedStoreURL.path + ) + ) + } + + func testPrivateCopy_whenDestinationHasOrphanSidecar_rejectsBeforeMainCopy() throws { + try Data([0x01]).write(to: storeURL) + let orphanDestinationWAL = familyURL( + stagedStoreURL, + suffix: "-wal" + ) + try Data([0xA5]).write(to: orphanDestinationWAL) + + XCTAssertThrowsError( + try SQLiteStoreFamilyCopier.copy( + from: storeURL, + to: stagedStoreURL, + includingSharedMemory: false, + fileManager: .default, + limits: SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: 1, + minimumFreeStorageReserveByteCount: 0 + ), + availableCapacityProvider: { _ in 1 } + ) + ) { error in + guard + case .unsafeFile = + error as? CrashConsistentStoreReplacementError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertFalse( + FileManager.default.fileExists( + atPath: stagedStoreURL.path + ) + ) + XCTAssertEqual( + try Data(contentsOf: orphanDestinationWAL), + Data([0xA5]) + ) + } + + func testPrivateCopy_atExactAggregateAndCapacityBoundary_copiesDurableMembersButNotSharedMemory() throws { + try Data([0x01, 0x02]).write(to: storeURL) + try Data([0x03]).write( + to: familyURL(storeURL, suffix: "-wal") + ) + try Data([0x04]).write( + to: familyURL(storeURL, suffix: "-shm") + ) + try Data([0x05]).write( + to: familyURL(storeURL, suffix: "-journal") + ) + + try SQLiteStoreFamilyCopier.copy( + from: storeURL, + to: stagedStoreURL, + includingSharedMemory: false, + fileManager: .default, + limits: SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: 4, + minimumFreeStorageReserveByteCount: 2 + ), + availableCapacityProvider: { _ in 6 } + ) + + XCTAssertEqual( + try Data(contentsOf: stagedStoreURL), + Data([0x01, 0x02]) + ) + XCTAssertEqual( + try Data( + contentsOf: familyURL( + stagedStoreURL, + suffix: "-wal" + ) + ), + Data([0x03]) + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: familyURL( + stagedStoreURL, + suffix: "-shm" + ).path + ) + ) + XCTAssertEqual( + try Data( + contentsOf: familyURL( + stagedStoreURL, + suffix: "-journal" + ) + ), + Data([0x05]) + ) + } + + private func makeReplacer( + maximumStoreFamilyByteCount: UInt64, + minimumFreeStorageReserveByteCount: UInt64 = 0, + availableCapacityProvider: @escaping (URL) throws -> UInt64 = { + _ in UInt64.max + }, + storeReplacer: ((URL, URL) throws -> Void)? = nil, + boundaryHook: @escaping ( + CrashConsistentStoreReplacementBoundary + ) throws -> Void = { _ in } + ) -> CrashConsistentStoreReplacer { + CrashConsistentStoreReplacer( + storeURL: storeURL, + fileManager: .default, + storeReplacer: storeReplacer ?? replaceMainStore, + boundaryHook: boundaryHook, + maximumStoreFamilyByteCount: + maximumStoreFamilyByteCount, + minimumFreeStorageReserveByteCount: + minimumFreeStorageReserveByteCount, + availableCapacityProvider: + availableCapacityProvider + ) + } + + private func replaceMainStore( + targetURL: URL, + sourceURL: URL + ) throws { + try FileManager.default.removeItem(at: targetURL) + try FileManager.default.copyItem( + at: sourceURL, + to: targetURL + ) + } + + private func familyURL( + _ storeURL: URL, + suffix: String + ) -> URL { + URL(fileURLWithPath: storeURL.path + suffix) + } +} diff --git a/fearlessTests/Common/Migration/SingleToMultiassetUserMigrationTests.swift b/fearlessTests/Common/Migration/SingleToMultiassetUserMigrationTests.swift index 74d0e6ea11..380542a511 100644 --- a/fearlessTests/Common/Migration/SingleToMultiassetUserMigrationTests.swift +++ b/fearlessTests/Common/Migration/SingleToMultiassetUserMigrationTests.swift @@ -35,6 +35,16 @@ class SingleToMultiassetUserMigrationTests: XCTestCase { let order: Int32 } + enum DuplicateRowOrder { + case watchOnlyFirst + case signerFirst + } + + enum ConflictingRowOrder { + case firstAliasFirst + case secondAliasFirst + } + let databaseDirectory = FileManager.default.temporaryDirectory.appendingPathComponent("CoreData") let databaseName = UUID().uuidString + ".sqlite" let modelDirectory = UserStorageParams.modelDirectory @@ -56,30 +66,638 @@ class SingleToMultiassetUserMigrationTests: XCTestCase { } func testMigrationForCreatedAccountWithoutDerivPath() throws { - throw XCTSkip("Legacy migration test is unavailable in the current environment") + try performTestUserMigration( + hasEntropy: true, + hasSeed: true, + hasDerivationPath: false + ) } func testMigrationForCreatedAccountWithDerivPath() throws { - throw XCTSkip("Legacy migration test is unavailable in the current environment") + try performTestUserMigration( + hasEntropy: true, + hasSeed: true, + hasDerivationPath: true + ) } func testMigrationForImportedWithSeedAccountWithoutDerivPath() throws { - throw XCTSkip("Legacy migration test is unavailable in the current environment") + try performTestUserMigration( + hasEntropy: false, + hasSeed: true, + hasDerivationPath: false + ) } func testMigrationForImportedWithSeedAccountWithDerivPath() throws { - throw XCTSkip("Legacy migration test is unavailable in the current environment") + try performTestUserMigration( + hasEntropy: false, + hasSeed: true, + hasDerivationPath: true + ) } func testMigrationForImportedWithJSONAccountWithoutDerivPath() throws { - throw XCTSkip("Legacy migration test is unavailable in the current environment") + try performTestUserMigration( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: false + ) } func testMigrationForImportedWithJSONAccountWithDerivPath() throws { - throw XCTSkip("Legacy migration test is unavailable in the current environment") + try performTestUserMigration( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: true + ) + } + + func testMigrationFromV1ToCurrentForCreatedAccountWithDerivationPath() throws { + try performTestUserMigration( + hasEntropy: true, + hasSeed: true, + hasDerivationPath: true, + targetVersion: .current + ) + } + + func testMigrationFromV1ToCurrentForImportedJSONAccount() throws { + try performTestUserMigration( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: false, + targetVersion: .current + ) + } + + func testDuplicateAccountMigration_whenWatchOnlyRowIsInsertedFirst_thenSigningSecretsArePreserved() throws { + try performDuplicateSignerMigration(rowOrder: .watchOnlyFirst) + } + + func testDuplicateAccountMigration_whenSigningRowIsInsertedFirst_thenSigningSecretsArePreserved() throws { + try performDuplicateSignerMigration(rowOrder: .signerFirst) + } + + func testDuplicateAccountMigration_whenFirstAliasHasConflictingSecret_thenFailsWithoutReplacingStore() throws { + try performConflictingDuplicateMigration(rowOrder: .firstAliasFirst) + } + + func testDuplicateAccountMigration_whenSecondAliasHasConflictingSecret_thenFailsWithoutReplacingStore() throws { + try performConflictingDuplicateMigration(rowOrder: .secondAliasFirst) + } + + func testKeystoreResourceLimits_atEveryExactBoundary_prepareSucceeds() throws { + let account = try generateOldAccount( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: false + ) + let firstMetaId = "00000000-0000-4000-8000-000000000001" + let secondMetaId = "00000000-0000-4000-8000-000000000002" + let firstDestinationIdentifier = + KeystoreTagV2.substrateSecretKeyTagForMetaId(firstMetaId) + let secondDestinationIdentifier = + KeystoreTagV2.substrateSeedTagForMetaId(secondMetaId) + let legacyIdentifier = + KeystoreTag.secretKeyTagForAddress(account.address) + let firstKey = Data([0x01, 0x02, 0x03]) + let secondKey = Data([0x04, 0x05]) + let aggregateIdentifierBytes = [ + firstDestinationIdentifier, + secondDestinationIdentifier, + legacyIdentifier + ].reduce(0) { $0 + $1.utf8.count } + let stagedKeyBytes = firstKey.count + secondKey.count + let calibrationLimits = makeResourceLimits( + maximumLegacyAccountRows: 2, + maximumStagedKeyCount: 2, + maximumIdentifierUTF8Bytes: aggregateIdentifierBytes, + maximumStagedKeyBytes: stagedKeyBytes, + maximumDeletionCount: 1, + maximumCleanupJournalBytes: Int.max + ) + let calibrationKeystore = InMemoryKeychain() + let calibrationMigrator = KeystoreMigrator( + sourceVersion: .version1, + destinationVersion: .version2, + keystore: calibrationKeystore, + resourceLimits: calibrationLimits + ) + + try stageExactBoundaryFixture( + in: calibrationMigrator, + firstIdentifier: firstDestinationIdentifier, + firstKey: firstKey, + secondIdentifier: secondDestinationIdentifier, + secondKey: secondKey, + legacyIdentifier: legacyIdentifier + ) + try calibrationMigrator.prepare() + let encodedJournal = try calibrationKeystore.fetchKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + + let exactLimits = makeResourceLimits( + maximumLegacyAccountRows: 2, + maximumStagedKeyCount: 2, + maximumIdentifierUTF8Bytes: aggregateIdentifierBytes, + maximumStagedKeyBytes: stagedKeyBytes, + maximumDeletionCount: 1, + maximumCleanupJournalBytes: encodedJournal.count + ) + let exactKeystore = InMemoryKeychain() + try exactKeystore.saveKey( + account.privateKey, + with: legacyIdentifier + ) + let exactMigrator = KeystoreMigrator( + sourceVersion: .version1, + destinationVersion: .version2, + keystore: exactKeystore, + resourceLimits: exactLimits + ) + + try stageExactBoundaryFixture( + in: exactMigrator, + firstIdentifier: firstDestinationIdentifier, + firstKey: firstKey, + secondIdentifier: secondDestinationIdentifier, + secondKey: secondKey, + legacyIdentifier: legacyIdentifier + ) + try exactMigrator.prepare() + + XCTAssertEqual( + try exactKeystore.fetchKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ).count, + encodedJournal.count + ) + XCTAssertEqual( + try exactKeystore.fetchKey( + for: firstDestinationIdentifier + ), + firstKey + ) + XCTAssertEqual( + try exactKeystore.fetchKey( + for: secondDestinationIdentifier + ), + secondKey + ) + + try exactMigrator.finalize() + + XCTAssertFalse(try exactKeystore.checkKey(for: legacyIdentifier)) + XCTAssertFalse( + try exactKeystore.checkKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + } + + func testKeystoreResourceLimits_whenLegacyRowLimitExceeded_freezesAndFailsBeforePrepareWrites() throws { + let keystore = InMemoryKeychain() + let migrator = KeystoreMigrator( + sourceVersion: .version1, + destinationVersion: .version2, + keystore: keystore, + resourceLimits: makeResourceLimits( + maximumLegacyAccountRows: 1 + ) + ) + let destinationIdentifier = + KeystoreTagV2.substrateSecretKeyTagForMetaId( + "00000000-0000-4000-8000-000000000010" + ) + + try migrator.switchVersion() + try migrator.registerLegacyAccountRow() + XCTAssertThrowsError( + try migrator.registerLegacyAccountRow() + ) { error in + self.assertResourceLimitError( + error, + resource: .legacyAccountRows, + maximum: 1 + ) + } + + migrator.save(key: Data([0x01]), for: destinationIdentifier) + + XCTAssertTrue(migrator.tempKeystore.isEmpty) + assertPrepareFailsClosed( + migrator, + keystore: keystore, + resource: .legacyAccountRows, + maximum: 1 + ) + } + + func testKeystoreResourceLimits_whenStagedKeyCountExceeded_freezesAndFailsBeforePrepareWrites() throws { + let keystore = InMemoryKeychain() + let migrator = makeVersion2KeystoreMigrator( + keystore: keystore, + resourceLimits: makeResourceLimits( + maximumStagedKeyCount: 1 + ) + ) + let firstIdentifier = + KeystoreTagV2.substrateSecretKeyTagForMetaId( + "00000000-0000-4000-8000-000000000011" + ) + let rejectedIdentifier = + KeystoreTagV2.substrateSeedTagForMetaId( + "00000000-0000-4000-8000-000000000012" + ) + + migrator.save(key: Data([0x01]), for: firstIdentifier) + migrator.save(key: Data([0x02]), for: rejectedIdentifier) + migrator.deleteKey(for: "ignored-after-first-limit") + + XCTAssertEqual(migrator.tempKeystore, [firstIdentifier: Data([0x01])]) + XCTAssertTrue(migrator.identifiersToRemoveOnFinalize.isEmpty) + assertPrepareFailsClosed( + migrator, + keystore: keystore, + resource: .stagedKeyCount, + maximum: 1 + ) + XCTAssertFalse(try keystore.checkKey(for: firstIdentifier)) + XCTAssertFalse(try keystore.checkKey(for: rejectedIdentifier)) + } + + func testKeystoreResourceLimits_whenIdentifierBytesExceeded_freezesAndFailsBeforePrepareWrites() throws { + let keystore = InMemoryKeychain() + let identifier = + KeystoreTagV2.substrateSecretKeyTagForMetaId( + "00000000-0000-4000-8000-000000000013" + ) + let maximum = identifier.utf8.count - 1 + let migrator = makeVersion2KeystoreMigrator( + keystore: keystore, + resourceLimits: makeResourceLimits( + maximumIdentifierUTF8Bytes: maximum + ) + ) + + migrator.save(key: Data([0x01]), for: identifier) + migrator.deleteKey(for: "ignored-after-first-limit") + + XCTAssertTrue(migrator.tempKeystore.isEmpty) + XCTAssertTrue(migrator.identifiersToRemoveOnFinalize.isEmpty) + assertPrepareFailsClosed( + migrator, + keystore: keystore, + resource: .identifierUTF8Bytes, + maximum: maximum + ) + XCTAssertFalse(try keystore.checkKey(for: identifier)) + } + + func testKeystoreResourceLimits_whenStagedKeyBytesExceeded_freezesAndFailsBeforePrepareWrites() throws { + let keystore = InMemoryKeychain() + let identifier = + KeystoreTagV2.substrateSecretKeyTagForMetaId( + "00000000-0000-4000-8000-000000000014" + ) + let key = Data([0x01, 0x02]) + let migrator = makeVersion2KeystoreMigrator( + keystore: keystore, + resourceLimits: makeResourceLimits( + maximumStagedKeyBytes: key.count - 1 + ) + ) + + migrator.save(key: key, for: identifier) + migrator.save( + key: Data([0x03]), + for: KeystoreTagV2.substrateSeedTagForMetaId( + "00000000-0000-4000-8000-000000000015" + ) + ) + + XCTAssertTrue(migrator.tempKeystore.isEmpty) + assertPrepareFailsClosed( + migrator, + keystore: keystore, + resource: .stagedKeyBytes, + maximum: key.count - 1 + ) + XCTAssertFalse(try keystore.checkKey(for: identifier)) + } + + func testKeystoreResourceLimits_whenDeletionCountExceeded_freezesAndFailsBeforePrepareWrites() throws { + let keystore = InMemoryKeychain() + let destinationIdentifier = + KeystoreTagV2.substrateSecretKeyTagForMetaId( + "00000000-0000-4000-8000-000000000016" + ) + let ignoredIdentifier = + KeystoreTagV2.substrateSeedTagForMetaId( + "00000000-0000-4000-8000-000000000017" + ) + let migrator = makeVersion2KeystoreMigrator( + keystore: keystore, + resourceLimits: makeResourceLimits( + maximumDeletionCount: 0 + ) + ) + + migrator.save(key: Data([0x01]), for: destinationIdentifier) + migrator.deleteKey(for: "first-rejected-deletion") + migrator.save(key: Data([0x02]), for: ignoredIdentifier) + + XCTAssertEqual( + migrator.tempKeystore, + [destinationIdentifier: Data([0x01])] + ) + XCTAssertTrue(migrator.identifiersToRemoveOnFinalize.isEmpty) + assertPrepareFailsClosed( + migrator, + keystore: keystore, + resource: .deletionCount, + maximum: 0 + ) + XCTAssertFalse(try keystore.checkKey(for: destinationIdentifier)) + XCTAssertFalse(try keystore.checkKey(for: ignoredIdentifier)) + } + + func testKeystoreResourceLimits_whenEncodedJournalExceeded_failsBeforeJournalOrDestinationWrites() throws { + let keystore = InMemoryKeychain() + let destinationIdentifier = + KeystoreTagV2.substrateSecretKeyTagForMetaId( + "00000000-0000-4000-8000-000000000018" + ) + let migrator = makeVersion2KeystoreMigrator( + keystore: keystore, + resourceLimits: makeResourceLimits( + maximumCleanupJournalBytes: 0 + ) + ) + + migrator.save(key: Data([0x01]), for: destinationIdentifier) + + assertPrepareFailsClosed( + migrator, + keystore: keystore, + resource: .cleanupJournalBytes, + maximum: 0 + ) + migrator.save( + key: Data([0x02]), + for: KeystoreTagV2.substrateSeedTagForMetaId( + "00000000-0000-4000-8000-000000000019" + ) + ) + + XCTAssertEqual( + migrator.tempKeystore, + [destinationIdentifier: Data([0x01])] + ) + XCTAssertFalse(try keystore.checkKey(for: destinationIdentifier)) + } + + func testCleanupRecovery_whenEncodedJournalExceedsProductionLimit_rejectsBeforeDecodeOrMutation() throws { + let maximum = KeystoreMigrationResourceLimits.production + .maximumCleanupJournalBytes + let oversizedJournal = Data( + repeating: 0x7B, + count: maximum + 1 + ) + let keystore = RecordingMigrationKeychain() + try keystore.saveKey( + oversizedJournal, + with: KeystoreMigrator.pendingCleanupIdentifier + ) + keystore.resetMutationHistory() + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: keystore, + currentVersion: .version1 + ) + ) { error in + self.assertResourceLimitError( + error, + resource: .cleanupJournalBytes, + maximum: maximum + ) + } + + XCTAssertTrue(keystore.mutatedIdentifiers.isEmpty) + XCTAssertEqual( + try keystore.fetchKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ), + oversizedJournal + ) + } + + func testV1Migration_whenLegacyRowLimitExceeded_preservesLiveStoreAndKeychain() throws { + let firstAccount = try generateOldAccount( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: false + ) + let secondAccount = try generateOldAccount( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: false + ) + let accounts = [firstAccount, secondAccount] + try saveOldAccountRows(accounts) + let keystore = RecordingMigrationKeychain() + try accounts.forEach { + try saveLegacySecrets(for: $0, keystore: keystore) + } + keystore.resetMutationHistory() + var replacementAttempted = false + let limits = makeResourceLimits( + maximumLegacyAccountRows: 1 + ) + let migrator = UserStorageMigrator( + targetVersion: .version2, + storeURL: storeURL, + modelDirectory: modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: FileManager.default, + modelBundle: Bundle(for: UserDataStorageFacade.self), + storeReplacer: { _, _ in + replacementAttempted = true + }, + keystoreMigratorFactory: { source, destination, keystore in + KeystoreMigrator( + sourceVersion: source, + destinationVersion: destination, + keystore: keystore, + resourceLimits: limits + ) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + self.assertResourceLimitError( + error, + resource: .legacyAccountRows, + maximum: 1 + ) + } + + XCTAssertFalse(replacementAttempted) + XCTAssertTrue(keystore.mutatedIdentifiers.isEmpty) + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual(try fetchOldAccountCount(), accounts.count) + for account in accounts { + XCTAssertEqual( + try keystore.fetchKey( + for: KeystoreTag.secretKeyTagForAddress( + account.address + ) + ), + account.privateKey + ) + } + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + } + + func testV1Migration_whenNonthrowingStagingLimitExceeded_preservesLiveStoreAndMakesNoKeychainWrites() throws { + let account = try generateOldAccount( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: false + ) + try saveOldAccountRows([account]) + let keystore = RecordingMigrationKeychain() + try saveLegacySecrets(for: account, keystore: keystore) + keystore.resetMutationHistory() + var replacementAttempted = false + let limits = makeResourceLimits( + maximumStagedKeyCount: 0 + ) + let migrator = UserStorageMigrator( + targetVersion: .version2, + storeURL: storeURL, + modelDirectory: modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: FileManager.default, + modelBundle: Bundle(for: UserDataStorageFacade.self), + storeReplacer: { _, _ in + replacementAttempted = true + }, + keystoreMigratorFactory: { source, destination, keystore in + KeystoreMigrator( + sourceVersion: source, + destinationVersion: destination, + keystore: keystore, + resourceLimits: limits + ) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + self.assertResourceLimitError( + error, + resource: .stagedKeyCount, + maximum: 0 + ) + } + + XCTAssertFalse(replacementAttempted) + XCTAssertTrue(keystore.mutatedIdentifiers.isEmpty) + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual(try fetchOldAccountCount(), 1) + XCTAssertEqual( + try keystore.fetchKey( + for: KeystoreTag.secretKeyTagForAddress(account.address) + ), + account.privateKey + ) + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + } + + func testV1Migration_whenEntropyExceedsStagedByteLimit_abortsBeforeCryptographicDerivation() throws { + let account = try generateOldAccount( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: false + ) + try saveOldAccountRows([account]) + let oversizedInvalidEntropy = Data([0xA5, 0xA5]) + let keystore = RecordingMigrationKeychain() + try saveLegacySecrets(for: account, keystore: keystore) + try keystore.saveKey( + oversizedInvalidEntropy, + with: KeystoreTag.entropyTagForAddress(account.address) + ) + keystore.resetMutationHistory() + var replacementAttempted = false + let limits = makeResourceLimits( + maximumStagedKeyBytes: oversizedInvalidEntropy.count - 1 + ) + let migrator = UserStorageMigrator( + targetVersion: .version2, + storeURL: storeURL, + modelDirectory: modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: FileManager.default, + modelBundle: Bundle(for: UserDataStorageFacade.self), + storeReplacer: { _, _ in + replacementAttempted = true + }, + keystoreMigratorFactory: { source, destination, keystore in + KeystoreMigrator( + sourceVersion: source, + destinationVersion: destination, + keystore: keystore, + resourceLimits: limits + ) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + self.assertResourceLimitError( + error, + resource: .stagedKeyBytes, + maximum: oversizedInvalidEntropy.count - 1 + ) + } + + XCTAssertFalse(replacementAttempted) + XCTAssertTrue(keystore.mutatedIdentifiers.isEmpty) + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual(try fetchOldAccountCount(), 1) + XCTAssertEqual( + try keystore.fetchKey( + for: KeystoreTag.entropyTagForAddress(account.address) + ), + oversizedInvalidEntropy + ) + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) } - private func performTestUserMigration(hasEntropy: Bool, hasSeed: Bool, hasDerivationPath: Bool) throws { + private func performTestUserMigration( + hasEntropy: Bool, + hasSeed: Bool, + hasDerivationPath: Bool, + targetVersion: UserStorageVersion = .version2 + ) throws { // given let keystore = InMemoryKeychain() @@ -98,12 +716,13 @@ class SingleToMultiassetUserMigrationTests: XCTestCase { settings.set(value: Data(), for: SettingsKey.selectedConnection.rawValue) let migrator = UserStorageMigrator( - targetVersion: .version2, + targetVersion: targetVersion, storeURL: storeURL, modelDirectory: modelDirectory, keystore: keystore, settings: settings, - fileManager: FileManager.default + fileManager: FileManager.default, + modelBundle: Bundle(for: UserDataStorageFacade.self) ) guard migrator.requiresMigration() else { @@ -111,11 +730,11 @@ class SingleToMultiassetUserMigrationTests: XCTestCase { return } - migrator.performMigration() + try migrator.performMigration() // then - let newEntities = try fetchNewEntities() + let newEntities = try fetchNewEntities(version: targetVersion) let addressFactory = SS58AddressFactory() @@ -190,6 +809,27 @@ class SingleToMultiassetUserMigrationTests: XCTestCase { } else { XCTAssertFalse(substrateDerivPathExistence) } + + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreTag.secretKeyTagForAddress(account.address) + ) + ) + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreTag.seedTagForAddress(account.address) + ) + ) + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreTag.entropyTagForAddress(account.address) + ) + ) + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreTag.deriviationTagForAddress(account.address) + ) + ) } let orders = Set(newEntities.map { $0.order }) @@ -200,6 +840,11 @@ class SingleToMultiassetUserMigrationTests: XCTestCase { XCTAssertNil(settings.data(for: SettingsKey.selectedAccount.rawValue)) XCTAssertNil(settings.data(for: SettingsKey.selectedConnection.rawValue)) + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) } // MARK: Private @@ -209,10 +854,9 @@ class SingleToMultiassetUserMigrationTests: XCTestCase { Bundle.allFrameworks + Bundle.allBundles for bundle in bundles { - if let url = bundle.url( - forResource: version.rawValue, - withExtension: "mom", - subdirectory: modelDirectory + if let url = version.modelURL( + in: bundle, + legacyModelDirectory: modelDirectory ) { return url } @@ -238,8 +882,433 @@ class SingleToMultiassetUserMigrationTests: XCTestCase { return CoreDataService(configuration: configuration) } - private func fetchNewEntities() throws -> [NewEntity] { - let dbService = createCoreDataService(for: .version2) + private func performDuplicateSignerMigration( + rowOrder: DuplicateRowOrder + ) throws { + let keystore = InMemoryKeychain() + let settings = InMemorySettingsManager() + let generatedAccount = try generateOldAccount( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: false + ) + let watchOnlyAddress = try SS58AddressFactory().address( + fromAccountId: generatedAccount.publicKey, + type: 2 + ) + let watchOnlyAccount = OldAccount( + address: watchOnlyAddress, + cryptoType: generatedAccount.cryptoType, + name: "watch-only-alias", + privateKey: generatedAccount.privateKey, + publicKey: generatedAccount.publicKey, + entropy: nil, + derivationPath: nil, + seed: nil + ) + let signingAccount = OldAccount( + address: generatedAccount.address, + cryptoType: generatedAccount.cryptoType, + name: "signing-alias", + privateKey: generatedAccount.privateKey, + publicKey: generatedAccount.publicKey, + entropy: nil, + derivationPath: nil, + seed: nil + ) + let accounts: [OldAccount] + + switch rowOrder { + case .watchOnlyFirst: + accounts = [watchOnlyAccount, signingAccount] + case .signerFirst: + accounts = [signingAccount, watchOnlyAccount] + } + + try saveOldAccountRows(accounts) + try keystore.saveKey( + signingAccount.privateKey, + with: KeystoreTag.secretKeyTagForAddress(signingAccount.address) + ) + + let migrator = UserStorageMigrator( + targetVersion: .version2, + storeURL: storeURL, + modelDirectory: modelDirectory, + keystore: keystore, + settings: settings, + fileManager: FileManager.default, + modelBundle: Bundle(for: UserDataStorageFacade.self) + ) + + try migrator.performMigration() + + let newEntities = try fetchNewEntities(version: .version2) + let migratedAccount = try XCTUnwrap(newEntities.first) + + XCTAssertEqual(newEntities.count, 1) + XCTAssertEqual(migratedAccount.name, signingAccount.name) + XCTAssertEqual( + migratedAccount.substratePublicKey, + signingAccount.publicKey + ) + XCTAssertEqual( + try keystore.fetchKey( + for: KeystoreTagV2.substrateSecretKeyTagForMetaId( + migratedAccount.metaId + ) + ), + signingAccount.privateKey + ) + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreTag.secretKeyTagForAddress(signingAccount.address) + ) + ) + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + } + + private func performConflictingDuplicateMigration( + rowOrder: ConflictingRowOrder + ) throws { + let keystore = InMemoryKeychain() + let generatedAccount = try generateOldAccount( + hasEntropy: false, + hasSeed: false, + hasDerivationPath: false + ) + let secondAddress = try SS58AddressFactory().address( + fromAccountId: generatedAccount.publicKey, + type: 2 + ) + let firstAccount = OldAccount( + address: generatedAccount.address, + cryptoType: generatedAccount.cryptoType, + name: "first-signing-alias", + privateKey: generatedAccount.privateKey, + publicKey: generatedAccount.publicKey, + entropy: nil, + derivationPath: nil, + seed: nil + ) + let conflictingPrivateKey = Data( + repeating: 0xA5, + count: generatedAccount.privateKey.count + ) + XCTAssertNotEqual(conflictingPrivateKey, generatedAccount.privateKey) + let secondAccount = OldAccount( + address: secondAddress, + cryptoType: generatedAccount.cryptoType, + name: "second-signing-alias", + privateKey: conflictingPrivateKey, + publicKey: generatedAccount.publicKey, + entropy: nil, + derivationPath: nil, + seed: nil + ) + let accounts: [OldAccount] + + switch rowOrder { + case .firstAliasFirst: + accounts = [firstAccount, secondAccount] + case .secondAliasFirst: + accounts = [secondAccount, firstAccount] + } + + try saveOldAccountRows(accounts) + try keystore.saveKey( + firstAccount.privateKey, + with: KeystoreTag.secretKeyTagForAddress(firstAccount.address) + ) + try keystore.saveKey( + secondAccount.privateKey, + with: KeystoreTag.secretKeyTagForAddress(secondAccount.address) + ) + + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version2, + storeURL: storeURL, + modelDirectory: modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: FileManager.default, + modelBundle: Bundle(for: UserDataStorageFacade.self), + storeReplacer: { _, _ in + replacementAttempted = true + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard let identifier = self.stagedConflictIdentifier(in: error) else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertTrue( + identifier.hasSuffix("-substrateSecretKey"), + "Unexpected conflicting identifier: \(identifier)" + ) + } + + XCTAssertFalse(replacementAttempted) + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual(try fetchOldAccountCount(), 2) + XCTAssertEqual( + try keystore.fetchKey( + for: KeystoreTag.secretKeyTagForAddress(firstAccount.address) + ), + firstAccount.privateKey + ) + XCTAssertEqual( + try keystore.fetchKey( + for: KeystoreTag.secretKeyTagForAddress(secondAccount.address) + ), + secondAccount.privateKey + ) + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + } + + private func makeResourceLimits( + maximumLegacyAccountRows: Int = Int.max, + maximumStagedKeyCount: Int = Int.max, + maximumIdentifierUTF8Bytes: Int = Int.max, + maximumStagedKeyBytes: Int = Int.max, + maximumDeletionCount: Int = Int.max, + maximumCleanupJournalBytes: Int = Int.max + ) -> KeystoreMigrationResourceLimits { + KeystoreMigrationResourceLimits( + maximumLegacyAccountRows: maximumLegacyAccountRows, + maximumStagedKeyCount: maximumStagedKeyCount, + maximumIdentifierUTF8Bytes: maximumIdentifierUTF8Bytes, + maximumStagedKeyBytes: maximumStagedKeyBytes, + maximumDeletionCount: maximumDeletionCount, + maximumCleanupJournalBytes: maximumCleanupJournalBytes + ) + } + + private func makeVersion2KeystoreMigrator( + keystore: KeystoreProtocol, + resourceLimits: KeystoreMigrationResourceLimits + ) -> KeystoreMigrator { + let migrator = KeystoreMigrator( + sourceVersion: .version1, + destinationVersion: .version2, + keystore: keystore, + resourceLimits: resourceLimits + ) + + do { + try migrator.switchVersion() + } catch { + XCTFail("Unable to advance keystore test migrator: \(error)") + } + + return migrator + } + + private func stageExactBoundaryFixture( + in migrator: KeystoreMigrator, + firstIdentifier: String, + firstKey: Data, + secondIdentifier: String, + secondKey: Data, + legacyIdentifier: String + ) throws { + try migrator.switchVersion() + try migrator.registerLegacyAccountRow() + try migrator.registerLegacyAccountRow() + migrator.save(key: firstKey, for: firstIdentifier) + migrator.save(key: secondKey, for: secondIdentifier) + migrator.deleteKey(for: legacyIdentifier) + } + + private func assertPrepareFailsClosed( + _ migrator: KeystoreMigrator, + keystore: KeystoreProtocol, + resource: KeystoreMigrationResource, + maximum: Int, + file: StaticString = #filePath, + line: UInt = #line + ) { + XCTAssertThrowsError( + try migrator.prepare(), + file: file, + line: line + ) { error in + self.assertResourceLimitError( + error, + resource: resource, + maximum: maximum, + file: file, + line: line + ) + } + + XCTAssertFalse( + try keystore.checkKey( + for: KeystoreMigrator.pendingCleanupIdentifier + ), + file: file, + line: line + ) + } + + private func assertResourceLimitError( + _ error: Error, + resource: KeystoreMigrationResource, + maximum: Int, + file: StaticString = #filePath, + line: UInt = #line + ) { + guard + let violation = resourceLimitViolation(in: error) + else { + return XCTFail( + "Unexpected error: \(error)", + file: file, + line: line + ) + } + + XCTAssertEqual( + violation.resource.rawValue, + resource.rawValue, + file: file, + line: line + ) + XCTAssertEqual( + violation.maximum, + maximum, + file: file, + line: line + ) + } + + private func resourceLimitViolation( + in error: Error + ) -> ( + resource: KeystoreMigrationResource, + maximum: Int + )? { + if + let migrationError = error as? KeystoreMigratingError, + case let .resourceLimitExceeded( + resource, + maximum + ) = migrationError + { + return (resource, maximum) + } + + let nsError = error as NSError + if + let underlyingError = + nsError.userInfo[NSUnderlyingErrorKey] as? Error, + let violation = resourceLimitViolation(in: underlyingError) + { + return violation + } + + if + let detailedErrors = + nsError.userInfo[NSDetailedErrorsKey] as? [Error] + { + for detailedError in detailedErrors { + if + let violation = resourceLimitViolation( + in: detailedError + ) + { + return violation + } + } + } + + return nil + } + + private func stagedConflictIdentifier(in error: Error) -> String? { + if + let migrationError = error as? KeystoreMigratingError, + case let .stagedKeyConflict(identifier) = migrationError + { + return identifier + } + + let nsError = error as NSError + if + let underlyingError = nsError.userInfo[NSUnderlyingErrorKey] as? Error, + let identifier = stagedConflictIdentifier(in: underlyingError) + { + return identifier + } + + if let detailedErrors = nsError.userInfo[NSDetailedErrorsKey] as? [Error] { + for detailedError in detailedErrors { + if let identifier = stagedConflictIdentifier(in: detailedError) { + return identifier + } + } + } + + return nil + } + + private func fetchOldAccountCount() throws -> Int { + let dbService = createCoreDataService(for: .version1) + let semaphore = DispatchSemaphore(value: 0) + var accountCount: Int? + var fetchError: Error? + + dbService.performAsync { context, error in + defer { + semaphore.signal() + } + + if let error { + fetchError = error + return + } + + guard let context else { + fetchError = MigrationTestError.coreData( + "Missing Core Data context while fetching legacy entities" + ) + return + } + + do { + accountCount = try context.count( + for: NSFetchRequest( + entityName: "CDAccountItem" + ) + ) + } catch { + fetchError = error + } + } + + semaphore.wait() + if let fetchError { + throw fetchError + } + + try dbService.close() + return accountCount ?? 0 + } + + private func fetchNewEntities( + version: UserStorageVersion + ) throws -> [NewEntity] { + let dbService = createCoreDataService(for: version) let semaphore = DispatchSemaphore(value: 0) var newEntities: [NewEntity]? var fetchError: Error? @@ -313,12 +1382,21 @@ class SingleToMultiassetUserMigrationTests: XCTestCase { hasSeed: Bool, hasDerivationPath: Bool ) throws -> [OldAccount] { - let dbService = createCoreDataService(for: .version1) - let accounts = try (0.. Data { + try keychain.fetchKey(for: identifier) + } + + func checkKey(for identifier: String) throws -> Bool { + try keychain.checkKey(for: identifier) + } + + func deleteKey(for identifier: String) throws { + mutatedIdentifiers.append(identifier) + try keychain.deleteKey(for: identifier) + } +} diff --git a/fearlessTests/Common/Migration/SubstrateStorageClassResolutionTests.swift b/fearlessTests/Common/Migration/SubstrateStorageClassResolutionTests.swift new file mode 100644 index 0000000000..092edc9213 --- /dev/null +++ b/fearlessTests/Common/Migration/SubstrateStorageClassResolutionTests.swift @@ -0,0 +1,1324 @@ +import CoreData +import CryptoKit +import RobinHood +import SSFModels +import XCTest +@testable import fearless + +#if canImport(SSFAssetManagmentStorage) + import SSFAssetManagmentStorage + private typealias TestCDScamInfo = SSFAssetManagmentStorage.CDScamInfo +#else + private typealias TestCDScamInfo = fearless.SSFAssetManagmentStorageStub.CDScamInfo +#endif + +final class SubstrateStorageClassResolutionTests: XCTestCase { + private struct EntityClassExpectation { + let entityName: String + let managedObjectClass: NSManagedObject.Type + } + + private struct RuntimeProjection: Codable { + let chain: String + let version: UInt32 + let txVersion: UInt32 + let metadataDigest: Data + + var sortKey: [String] { + [ + chain, + String(version), + String(txVersion), + metadataDigest.base64EncodedString() + ] + } + } + + private struct NodeProjection: Codable { + let url: String + let name: String + let apiQueryName: String? + let apiKeyName: String? + + var sortKey: [String] { + [ + url, + name, + apiQueryName ?? "", + apiKeyName ?? "" + ] + } + } + + private struct ChainProjection: Codable { + let chainId: String + let name: String + let disabled: Bool + let assetIds: [String] + let nodes: [NodeProjection] + let customNodes: [NodeProjection] + let selectedNode: NodeProjection? + + var sortKey: [String] { + [chainId, name] + } + } + + private struct RepositoryProjection: Codable { + let runtimes: [RuntimeProjection] + let chains: [ChainProjection] + } + + private struct RepositoryAggregate: Equatable { + let runtimeCount: Int + let chainCount: Int + let enabledChainCount: Int + let assetCount: Int + let nodeCount: Int + let defaultNodeRelationshipCount: Int + let customNodeRelationshipCount: Int + let selectedNodeRelationshipCount: Int + let standaloneSelectedNodeCount: Int + let fingerprint: Data + } + + private let expectedEntityVersionHashes = [ + "CDAsset": "OaCdB9COHi79/aWro7D/NMuFpNBI0ZFzrprILS+KmP8=", + "CDChain": "xuYLmoPjdtSUBxBnb6XTrlVhylYyXA8GEw4KmzL1b+I=", + "CDChainNode": "ss/vV1rML8kMdjwg0WBlnN+nUfbimb+iS858b2UC5co=", + "CDChainStorageItem": "tl1izvM2Yua6zVUkbOKhur324LSAxJOj9/M+5iRiFa4=", + "CDChainXcmConfig": "0HjIIf+quGUJQ/o84PdC5mHNcC86v1mrG2sBdayWiso=", + "CDContact": "DXCWS/mWPGoVysoTZy+8QKx6H5KWgV7GhaJRQRHUE3c=", + "CDContactItem": "a1f9E6n04Dw2O8avnrKh71ChA215v4tanvXG60z6M3k=", + "CDExternalApi": "n4a9GYGVRmIwWteJEbC7nUd8PyzyJ7xd+AvVlG2BGvw=", + "CDPhishingItem": "rLQn++gZqmY/EmPOCkDFxCvVXhp2Hs+ZYah6D4p9JIk=", + "CDPolkaswapDex": "jU4M5szChWjMy/D1+IUOp1fz4qD5u4oehrmgVQ3Wel8=", + "CDPolkaswapRemoteSettings": "EwsBHlXIiySVJAormij6pHo0OtZz4gJLtHcCV8od1+k=", + "CDPriceData": "63ioMabYdLDL8vNP5aK563PaV6dPU9qUvjzPxD7aOPU=", + "CDPriceProvider": "zOsAxjSu9EHzLSO95UpY38tE4XkbWUwDExKBjlM26jA=", + "CDRuntimeMetadataItem": "lmOvdNZxh3zLwJN+6ZlUcLvB9HRBv9PYHbJt4QE07oY=", + "CDScamInfo": "pjD63BxcBAQfhasAHmj+ew7KQncf9FU1ftTpGKFEcsw=", + "CDStashItem": "DmeVbIKcFdGMSBvSoYHdRuDBurJHUWE2vAWz1Hbgl34=", + "CDTransactionHistoryItem": "5kc1p0hvfdoQDmabJaZ9pIRWCJa40tpLtCvwVjtnPdU=", + "CDXcmAvailableAsset": "JKPl407BzEYe3ztSezxPOv9Z9WAhoGsJlevWpgPn7Es=", + "CDXcmAvailableDestination": "yD9mzh4EBjT1sFrqYgDIDNUlrUyxQJ81S4GZXpIZi74=" + ] + + private var appBundle: Bundle { + Bundle(for: SubstrateDataStorageFacade.self) + } + + private var fallbackEntityClasses: [EntityClassExpectation] { + [ + EntityClassExpectation(entityName: "CDAsset", managedObjectClass: fearless.CDAsset.self), + EntityClassExpectation(entityName: "CDChain", managedObjectClass: fearless.CDChain.self), + EntityClassExpectation(entityName: "CDChainNode", managedObjectClass: fearless.CDChainNode.self), + EntityClassExpectation( + entityName: "CDChainStorageItem", + managedObjectClass: fearless.CDChainStorageItem.self + ), + EntityClassExpectation( + entityName: "CDChainXcmConfig", + managedObjectClass: fearless.CDChainXcmConfig.self + ), + EntityClassExpectation(entityName: "CDContact", managedObjectClass: fearless.CDContact.self), + EntityClassExpectation( + entityName: "CDContactItem", + managedObjectClass: fearless.CDContactItem.self + ), + EntityClassExpectation( + entityName: "CDExternalApi", + managedObjectClass: fearless.CDExternalApi.self + ), + EntityClassExpectation( + entityName: "CDPhishingItem", + managedObjectClass: fearless.CDPhishingItem.self + ), + EntityClassExpectation( + entityName: "CDPolkaswapDex", + managedObjectClass: polkaswapDexClass + ), + EntityClassExpectation( + entityName: "CDPolkaswapRemoteSettings", + managedObjectClass: fearless.CDPolkaswapRemoteSettings.self + ), + EntityClassExpectation( + entityName: "CDPriceData", + managedObjectClass: fearless.CDPriceData.self + ), + EntityClassExpectation( + entityName: "CDPriceProvider", + managedObjectClass: fearless.CDPriceProvider.self + ), + EntityClassExpectation( + entityName: "CDRuntimeMetadataItem", + managedObjectClass: fearless.CDRuntimeMetadataItem.self + ), + EntityClassExpectation(entityName: "CDScamInfo", managedObjectClass: scamInfoClass), + EntityClassExpectation( + entityName: "CDStashItem", + managedObjectClass: fearless.CDStashItem.self + ), + EntityClassExpectation( + entityName: "CDXcmAvailableAsset", + managedObjectClass: fearless.CDXcmAvailableAsset.self + ), + EntityClassExpectation( + entityName: "CDXcmAvailableDestination", + managedObjectClass: fearless.CDXcmAvailableDestination.self + ) + ] + } + + private var expectedEntityClasses: [EntityClassExpectation] { + fallbackEntityClasses + [ + EntityClassExpectation( + entityName: "CDTransactionHistoryItem", + managedObjectClass: fearless.CDTransactionHistoryItem.self + ) + ] + } + + private var polkaswapDexClass: NSManagedObject.Type { + #if canImport(SSFAssetManagmentStorage) + SSFAssetManagmentStorage.CDPolkaswapDex.self + #else + fearless.SSFAssetManagmentStorageStub.CDPolkaswapDex.self + #endif + } + + private var scamInfoClass: NSManagedObject.Type { + #if canImport(SSFAssetManagmentStorage) + SSFAssetManagmentStorage.CDScamInfo.self + #else + fearless.SSFAssetManagmentStorageStub.CDScamInfo.self + #endif + } + + func testBundledV8Model_whenLoaded_thenEveryEntityResolvesToExactRuntimeClass() throws { + let model = try loadBundledV8Model() + + XCTAssertEqual(fallbackEntityClasses.count, 18) + XCTAssertEqual( + Set(model.entitiesByName.keys), + Set(expectedEntityClasses.map(\.entityName)) + ) + + for expectation in expectedEntityClasses { + let entity = try XCTUnwrap(model.entitiesByName[expectation.entityName]) + let className = try XCTUnwrap(entity.managedObjectClassName) + let resolvedClass = try XCTUnwrap( + NSClassFromString(className) as? NSManagedObject.Type, + "\(className) must resolve to an NSManagedObject subclass" + ) + + XCTAssertEqual( + className, + NSStringFromClass(expectation.managedObjectClass), + "\(expectation.entityName) does not use the expected Objective-C runtime name" + ) + XCTAssertEqual( + ObjectIdentifier(resolvedClass), + ObjectIdentifier(expectation.managedObjectClass), + "\(expectation.entityName) resolves to a different class than its app alias" + ) + } + } + + func testBundledV8Model_whenObjectsInsertedAndFetched_thenUsesExactRuntimeClasses() throws { + let model = try loadBundledV8Model() + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + try coordinator.addPersistentStore( + ofType: NSInMemoryStoreType, + configurationName: nil, + at: nil + ) + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + try performAndWait(in: context) { + for expectation in self.expectedEntityClasses { + let insertedObject = NSEntityDescription.insertNewObject( + forEntityName: expectation.entityName, + into: context + ) + + self.assertExactClass( + of: insertedObject, + is: expectation.managedObjectClass, + entityName: expectation.entityName + ) + + let request = NSFetchRequest(entityName: expectation.entityName) + let fetchedObjects = try context.fetch(request) + let fetchedObject = try XCTUnwrap( + fetchedObjects.first { $0 === insertedObject }, + "Inserted \(expectation.entityName) was not returned by its fetch" + ) + + self.assertExactClass( + of: fetchedObject, + is: expectation.managedObjectClass, + entityName: expectation.entityName + ) + } + + context.rollback() + } + } + + func testRuntimeMetadata_whenPersisted_thenCodableMapperRoundTripsBoundaryVersions() throws { + let model = try loadBundledV8Model() + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + try coordinator.addPersistentStore( + ofType: NSInMemoryStoreType, + configurationName: nil, + at: nil + ) + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + let expectedItem = fearless.RuntimeMetadataItem( + chain: "class-resolution-regression", + version: UInt32.max, + txVersion: UInt32(Int32.max) + 1, + metadata: Data([0x00, 0x7F, 0x80, 0xFF]) + ) + let mapper = fearless.RuntimeMetadataMapper() + + try performAndWait(in: context) { + let insertedObject = try XCTUnwrap( + NSEntityDescription.insertNewObject( + forEntityName: "CDRuntimeMetadataItem", + into: context + ) as? fearless.CDRuntimeMetadataItem + ) + + try mapper.populate(entity: insertedObject, from: expectedItem, using: context) + try context.save() + context.reset() + + let request = NSFetchRequest( + entityName: "CDRuntimeMetadataItem" + ) + let persistedObject = try XCTUnwrap(context.fetch(request).first) + + self.assertExactClass( + of: persistedObject, + is: fearless.CDRuntimeMetadataItem.self, + entityName: "CDRuntimeMetadataItem" + ) + XCTAssertEqual(try mapper.transform(entity: persistedObject), expectedItem) + } + } + + func testRuntimeMetadataStartupMapper_whenGetterRaises_thenReturnsSanitizedSwiftError() { + let entityDescription = NSEntityDescription() + entityDescription.name = + "RuntimeMetadataGetterExceptionFixture" + entityDescription.managedObjectClassName = + NSStringFromClass( + fearless.CDRuntimeMetadataItem.self + ) + entityDescription.properties = [] + let entity = fearless.CDRuntimeMetadataItem( + entity: entityDescription, + insertInto: nil + ) + let mapper: AnyCoreDataMapper< + fearless.RuntimeMetadataItem, + fearless.CDRuntimeMetadataItem + > = AnyCoreDataMapper( + fearless.RuntimeMetadataMapper() + ) + + XCTAssertThrowsError( + try mapper.transform(entity: entity) + ) { error in + XCTAssertEqual( + error as? SafeTransformableValueReaderError, + .objectiveCException + ) + } + } + + func testRuntimeMetadataStartupMapper_whenSetterRaises_thenReturnsSanitizedSwiftError() { + let entityDescription = NSEntityDescription() + entityDescription.name = + "RuntimeMetadataSetterExceptionFixture" + entityDescription.managedObjectClassName = + NSStringFromClass( + fearless.CDRuntimeMetadataItem.self + ) + entityDescription.properties = [] + let entity = fearless.CDRuntimeMetadataItem( + entity: entityDescription, + insertInto: nil + ) + let mapper = fearless.RuntimeMetadataMapper() + let model = fearless.RuntimeMetadataItem( + chain: "setter-exception", + version: 1, + txVersion: 2, + metadata: Data([0x01]) + ) + + XCTAssertThrowsError( + try mapper.populate( + entity: entity, + from: model, + using: NSManagedObjectContext( + concurrencyType: + .mainQueueConcurrencyType + ) + ) + ) { error in + XCTAssertEqual( + error as? SafeTransformableValueReaderError, + .objectiveCException + ) + } + } + + func testFallbackCodableEntities_whenPersisted_thenTypedAccessorsAndMappersRoundTrip() throws { + let context = try makeInMemoryContext() + + let chainStorage = ChainStorageItem( + identifier: "chain-storage-🧪", + data: Data([0x00, 0x7F, 0x80, 0xFF]) + ) + XCTAssertEqual( + try roundTrip( + chainStorage, + entityName: "CDChainStorageItem", + entityClass: fearless.CDChainStorageItem.self, + in: context + ), + chainStorage + ) + + let stash = StashItem( + stash: "stash-address-α", + controller: "controller-address-β" + ) + XCTAssertEqual( + try roundTrip( + stash, + entityName: "CDStashItem", + entityClass: fearless.CDStashItem.self, + in: context + ), + stash + ) + + let phishing = PhishingItem( + source: "https://security.example.invalid/list.json", + publicKey: "0xPHISHING-PUBLIC-KEY" + ) + let decodedPhishing = try roundTrip( + phishing, + entityName: "CDPhishingItem", + entityClass: fearless.CDPhishingItem.self, + in: context + ) + XCTAssertEqual(decodedPhishing.identifier, phishing.identifier) + XCTAssertEqual(decodedPhishing.source, phishing.source) + XCTAssertEqual(decodedPhishing.publicKey, phishing.publicKey) + + let scam = ScamInfo( + name: "Unicode scam 🚫", + address: "0x0000000000000000000000000000000000000001", + type: .lowScore, + subtype: "adversarial-subtype" + ) + XCTAssertEqual( + try roundTrip( + scam, + entityName: "CDScamInfo", + entityClass: TestCDScamInfo.self, + in: context + ), + scam + ) + + let contact = Contact( + name: "Alice 🧪", + address: "1zugcac3aa3e6b4b32c48d0843ff91c7d6b07f9df4dbe3546b1bc472d29d6e56", + chainId: "0x91b171bb158e2d3848fa23a9f1c25182" + ) + XCTAssertEqual( + try roundTrip( + contact, + entityName: "CDContact", + entityClass: fearless.CDContact.self, + in: context + ), + contact + ) + + let contactItem = ContactItem( + peerAddress: "peer-address-\u{0000}-boundary", + peerName: "Peer 🧪", + targetAddress: "target-address", + updatedAt: Int64.max + ) + let decodedContactItem = try roundTrip( + contactItem, + entityName: "CDContactItem", + entityClass: fearless.CDContactItem.self, + in: context + ) + XCTAssertEqual(decodedContactItem.identifier, contactItem.identifier) + XCTAssertEqual(decodedContactItem.peerAddress, contactItem.peerAddress) + XCTAssertEqual(decodedContactItem.peerName, contactItem.peerName) + XCTAssertEqual(decodedContactItem.targetAddress, contactItem.targetAddress) + XCTAssertEqual(decodedContactItem.updatedAt, contactItem.updatedAt) + } + + func testFallbackCodableEntities_whenRequiredFieldsAreMissing_thenMappersRejectRows() throws { + let context = try makeInMemoryContext() + + try performAndWait(in: context) { + self.assertMalformedRowRejected( + ChainStorageItem.self, + entityName: "CDChainStorageItem", + entityClass: fearless.CDChainStorageItem.self, + in: context + ) + self.assertMalformedRowRejected( + StashItem.self, + entityName: "CDStashItem", + entityClass: fearless.CDStashItem.self, + in: context + ) + self.assertMalformedRowRejected( + PhishingItem.self, + entityName: "CDPhishingItem", + entityClass: fearless.CDPhishingItem.self, + in: context + ) + self.assertMalformedRowRejected( + ScamInfo.self, + entityName: "CDScamInfo", + entityClass: TestCDScamInfo.self, + in: context + ) + self.assertMalformedRowRejected( + Contact.self, + entityName: "CDContact", + entityClass: fearless.CDContact.self, + in: context + ) + self.assertMalformedRowRejected( + ContactItem.self, + entityName: "CDContactItem", + entityClass: fearless.CDContactItem.self, + in: context + ) + + let invalidScam = try XCTUnwrap( + NSEntityDescription.insertNewObject( + forEntityName: "CDScamInfo", + into: context + ) as? TestCDScamInfo + ) + invalidScam.setValue("name", forKey: "name") + invalidScam.setValue("address", forKey: "address") + invalidScam.setValue("not-a-valid-scam-type", forKey: "type") + invalidScam.setValue("subtype", forKey: "subtype") + + let scamMapper = CodableCoreDataMapper() + XCTAssertThrowsError(try scamMapper.transform(entity: invalidScam)) + + context.rollback() + } + } + + func testBundledV8Model_whenStoreCreated_thenSchemaFingerprintsAndCompatibilityStayCanonical() throws { + let model = try loadBundledV8Model() + let hashesBeforeOpening = versionHashes(for: model) + XCTAssertEqual(hashesBeforeOpening, expectedEntityVersionHashes) + + let directoryURL = FileManager.default.temporaryDirectory + .appendingPathComponent("SubstrateStorageClassResolutionTests") + .appendingPathComponent(UUID().uuidString) + try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true) + defer { + try? FileManager.default.removeItem(at: directoryURL) + } + + let storeURL = directoryURL.appendingPathComponent("SubstrateDataModel.sqlite") + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: [ + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + try coordinator.remove(store) + + let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStore( + ofType: NSSQLiteStoreType, + at: storeURL, + options: nil + ) + + XCTAssertEqual(versionHashes(for: model), hashesBeforeOpening) + XCTAssertTrue( + model.isConfiguration(withName: nil, compatibleWithStoreMetadata: metadata) + ) + XCTAssertTrue( + model.isConfiguration( + withName: SubstrateStorageVersion.version8.rawValue, + compatibleWithStoreMetadata: metadata + ) + ) + XCTAssertEqual( + metadata["NSStoreModelVersionChecksumKey"] as? String, + "uCEwjJUN79CeWqRxzEihB72qcWaHALPET4ZxwIj+0zs=" + ) + } + + func testCopiedPhoneV8Store_whenAvailable_thenAllRowsHaveExpectedClassesAndStoreIsUnchanged() throws { + let fixtureURL = copiedPhoneStoreFixtureURL() + guard FileManager.default.fileExists(atPath: fixtureURL.path) else { + throw XCTSkip("Optional copied-phone Substrate store fixture is unavailable") + } + + let sourceFingerprintsBefore = try storeFingerprints(at: fixtureURL) + let testStoreURL = try copyStoreFixtureToTemporaryDirectory(fixtureURL) + defer { + try? FileManager.default.removeItem(at: testStoreURL.deletingLastPathComponent()) + } + + let testStoreDigestBefore = try digest(of: testStoreURL) + let metadataBefore = try NSPersistentStoreCoordinator.metadataForPersistentStore( + ofType: NSSQLiteStoreType, + at: testStoreURL, + options: nil + ) + let model = try loadBundledV8Model() + + XCTAssertTrue( + model.isConfiguration( + withName: SubstrateStorageVersion.version8.rawValue, + compatibleWithStoreMetadata: metadataBefore + ) + ) + + let countsBefore = try inspectReadOnlyStore( + at: testStoreURL, + model: model, + fetchEveryObject: true + ) + let countsAfter = try inspectReadOnlyStore( + at: testStoreURL, + model: try loadBundledV8Model(), + fetchEveryObject: false + ) + let metadataAfter = try NSPersistentStoreCoordinator.metadataForPersistentStore( + ofType: NSSQLiteStoreType, + at: testStoreURL, + options: nil + ) + + XCTAssertEqual(countsAfter, countsBefore) + XCTAssertGreaterThan(countsBefore["CDRuntimeMetadataItem"] ?? 0, 0) + XCTAssertEqual( + metadataVersionHashes(metadataAfter), + metadataVersionHashes(metadataBefore) + ) + XCTAssertEqual(try digest(of: testStoreURL), testStoreDigestBefore) + XCTAssertEqual(try storeFingerprints(at: fixtureURL), sourceFingerprintsBefore) + } + + func testCopiedPhoneV8Store_whenFetchedThroughProductionRepositories_thenMapsEveryRuntimeAndChain() throws { + // TestFlight regression path: + // CoreDataRepository.fetchAll -> Collection.map -> ChainModelMapper. + // The 2026-07-23 crashes trapped in Swift Array access on this path, so + // the copied store must traverse the production repository unchanged. + let fixtureURL = copiedPhoneStoreFixtureURL() + guard FileManager.default.fileExists(atPath: fixtureURL.path) else { + throw XCTSkip("Optional copied-phone Substrate store fixture is unavailable") + } + + let sourceFingerprintsBefore = try storeFingerprints(at: fixtureURL) + let testStoreURL = try copyStoreFixtureToTemporaryDirectory(fixtureURL) + defer { + try? FileManager.default.removeItem(at: testStoreURL.deletingLastPathComponent()) + } + let persistedAggregate = try inspectPersistedRepositoryAggregate( + at: testStoreURL, + model: try loadBundledV8Model() + ) + + let modelURL = try XCTUnwrap( + appBundle.url( + forResource: "SubstrateDataModel", + withExtension: "momd" + ) + ) + let settings = CoreDataPersistentSettings( + databaseDirectory: testStoreURL.deletingLastPathComponent(), + databaseName: testStoreURL.lastPathComponent, + incompatibleModelStrategy: .ignore, + options: [ + NSReadOnlyPersistentStoreOption: true, + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + let service = CoreDataService( + configuration: CoreDataServiceConfiguration( + modelURL: modelURL, + storageType: .persistent(settings: settings) + ) + ) + defer { + try? service.close() + } + + let runtimeRepository = CoreDataRepository< + fearless.RuntimeMetadataItem, + fearless.CDRuntimeMetadataItem + >( + databaseService: service, + mapper: AnyCoreDataMapper( + CodableCoreDataMapper< + fearless.RuntimeMetadataItem, + fearless.CDRuntimeMetadataItem + >() + ) + ) + let chainRepository = CoreDataRepository( + databaseService: service, + mapper: AnyCoreDataMapper(ChainModelMapper()) + ) + let operationQueue = OperationQueue() + + let runtimeOperation = runtimeRepository.fetchAllOperation( + with: RepositoryFetchOptions() + ) + operationQueue.addOperations([runtimeOperation], waitUntilFinished: true) + let runtimes = try runtimeOperation.extractResultData( + throwing: BaseOperationError.parentOperationCancelled + ) + + let chainOperation = chainRepository.fetchAllOperation( + with: RepositoryFetchOptions() + ) + operationQueue.addOperations([chainOperation], waitUntilFinished: true) + let chains = try chainOperation.extractResultData( + throwing: BaseOperationError.parentOperationCancelled + ) + + XCTAssertEqual(runtimes.count, 60) + XCTAssertEqual(chains.count, 116) + assertMappedRepositoryInvariants(runtimes: runtimes, chains: chains) + + let mappedAggregate = try repositoryAggregate( + runtimes: runtimes.map(runtimeProjection), + chains: chains.map(chainProjection), + nodeCount: Set( + chains.flatMap { allNodes(in: $0) }.map { $0.url.absoluteString } + ).count, + assetCount: chains.reduce(0) { $0 + $1.assets.count } + ) + + XCTAssertEqual( + mappedAggregate, + persistedAggregate, + "Mapped repository aggregate differs from the disposable store without exposing row values" + ) + XCTAssertEqual(try storeFingerprints(at: fixtureURL), sourceFingerprintsBefore) + } + + private func inspectPersistedRepositoryAggregate( + at storeURL: URL, + model: NSManagedObjectModel + ) throws -> RepositoryAggregate { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: [ + NSReadOnlyPersistentStoreOption: true, + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + var aggregate: RepositoryAggregate? + try performAndWait(in: context) { + let runtimeRequest = NSFetchRequest( + entityName: "CDRuntimeMetadataItem" + ) + let chainRequest = NSFetchRequest(entityName: "CDChain") + let nodeRequest = NSFetchRequest(entityName: "CDChainNode") + let assetRequest = NSFetchRequest(entityName: "CDAsset") + + aggregate = try self.repositoryAggregate( + runtimes: context.fetch(runtimeRequest).map(self.runtimeProjection), + chains: context.fetch(chainRequest).map(self.chainProjection), + nodeCount: context.count(for: nodeRequest), + assetCount: context.count(for: assetRequest) + ) + } + + return try XCTUnwrap(aggregate) + } + + private func assertMappedRepositoryInvariants( + runtimes: [fearless.RuntimeMetadataItem], + chains: [ChainModel], + file: StaticString = #filePath, + line: UInt = #line + ) { + let sortedRuntimes = runtimes.sorted { + runtimeProjection($0).sortKey.lexicographicallyPrecedes( + runtimeProjection($1).sortKey + ) + } + let runtimeIdentifiers = sortedRuntimes.map(\.chain) + + XCTAssertEqual( + Set(runtimeIdentifiers).count, + runtimeIdentifiers.count, + "Mapped runtime identifiers must be unique", + file: file, + line: line + ) + + for (runtimeIndex, runtime) in sortedRuntimes.enumerated() { + let canonicalIdentifier = runtime.chain.trimmingCharacters( + in: .whitespacesAndNewlines + ) + XCTAssertTrue( + !canonicalIdentifier.isEmpty && canonicalIdentifier == runtime.chain, + "Mapped runtime \(runtimeIndex) has a noncanonical identifier", + file: file, + line: line + ) + XCTAssertFalse( + runtime.metadata.isEmpty, + "Mapped runtime \(runtimeIndex) has empty metadata", + file: file, + line: line + ) + } + + let sortedChains = chains.sorted { + chainProjection($0).sortKey.lexicographicallyPrecedes( + chainProjection($1).sortKey + ) + } + let chainIdentifiers = sortedChains.map(\.chainId) + + XCTAssertEqual( + Set(chainIdentifiers).count, + chainIdentifiers.count, + "Mapped chain identifiers must be unique", + file: file, + line: line + ) + + for (chainIndex, chain) in sortedChains.enumerated() { + let canonicalIdentifier = chain.chainId.trimmingCharacters( + in: .whitespacesAndNewlines + ) + XCTAssertTrue( + !canonicalIdentifier.isEmpty && canonicalIdentifier == chain.chainId, + "Mapped chain \(chainIndex) has a noncanonical identifier", + file: file, + line: line + ) + XCTAssertFalse( + chain.chainId.hasPrefix( + ChainModelMapper.quarantinedChainIdentifierPrefix + ), + "Mapped chain \(chainIndex) unexpectedly contains a quarantine identifier", + file: file, + line: line + ) + XCTAssertTrue( + !chain.name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty, + "Mapped chain \(chainIndex) has an empty name", + file: file, + line: line + ) + XCTAssertFalse( + chain.name == ChainModelMapper.quarantinedChainName, + "Mapped chain \(chainIndex) unexpectedly contains a quarantine name", + file: file, + line: line + ) + + let assetIdentifiers = chain.assets.map(\.id) + XCTAssertEqual( + Set(assetIdentifiers).count, + assetIdentifiers.count, + "Mapped chain \(chainIndex) contains duplicate asset identifiers", + file: file, + line: line + ) + for (assetIndex, assetIdentifier) in assetIdentifiers.enumerated() { + XCTAssertFalse( + assetIdentifier.trimmingCharacters( + in: .whitespacesAndNewlines + ).isEmpty, + "Mapped chain \(chainIndex) asset \(assetIndex) has an empty identifier", + file: file, + line: line + ) + } + + let defaultNodes = Array(chain.nodes) + let customNodes = Array(chain.customNodes ?? []) + let selectedNodes = [chain.selectedNode].compactMap { $0 } + let nodeGroups = [defaultNodes, customNodes, selectedNodes] + + for (groupIndex, nodes) in nodeGroups.enumerated() { + for (nodeIndex, node) in nodes.enumerated() { + XCTAssertTrue( + ChainModelMapper.isUsableNodeURL(node.url), + "Mapped chain \(chainIndex) node \(groupIndex):\(nodeIndex) has an unusable URL", + file: file, + line: line + ) + XCTAssertTrue( + ChainModelMapper.isNodeCompatibleWithRuntime( + node, + for: chain + ), + "Mapped chain \(chainIndex) node \(groupIndex):\(nodeIndex) is runtime-incompatible", + file: file, + line: line + ) + XCTAssertFalse( + node.name.trimmingCharacters( + in: .whitespacesAndNewlines + ).isEmpty, + "Mapped chain \(chainIndex) node \(groupIndex):\(nodeIndex) has an empty name", + file: file, + line: line + ) + } + } + + XCTAssertTrue( + chain.disabled || chain.selectedNode != nil || chain.nodes.isNotEmpty, + "Enabled mapped chain \(chainIndex) has no runtime endpoint", + file: file, + line: line + ) + } + } + + private func repositoryAggregate( + runtimes: [RuntimeProjection], + chains: [ChainProjection], + nodeCount: Int, + assetCount: Int + ) throws -> RepositoryAggregate { + let canonicalRuntimes = runtimes.sorted { + $0.sortKey.lexicographicallyPrecedes($1.sortKey) + } + let canonicalChains = chains + .map { chain in + ChainProjection( + chainId: chain.chainId, + name: chain.name, + disabled: chain.disabled, + assetIds: chain.assetIds.sorted(), + nodes: chain.nodes.sorted { + $0.sortKey.lexicographicallyPrecedes($1.sortKey) + }, + customNodes: chain.customNodes.sorted { + $0.sortKey.lexicographicallyPrecedes($1.sortKey) + }, + selectedNode: chain.selectedNode + ) + } + .sorted { + $0.sortKey.lexicographicallyPrecedes($1.sortKey) + } + + let projection = RepositoryProjection( + runtimes: canonicalRuntimes, + chains: canonicalChains + ) + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys] + let encodedProjection = try encoder.encode(projection) + + let defaultNodeRelationshipCount = canonicalChains.reduce(0) { + $0 + $1.nodes.count + } + let customNodeRelationshipCount = canonicalChains.reduce(0) { + $0 + $1.customNodes.count + } + let selectedNodeRelationshipCount = canonicalChains.reduce(0) { + $0 + ($1.selectedNode == nil ? 0 : 1) + } + let standaloneSelectedNodeCount = canonicalChains.reduce(0) { count, chain in + guard let selectedNode = chain.selectedNode else { + return count + } + + let relatedURLs = Set( + (chain.nodes + chain.customNodes).map(\.url) + ) + return count + (relatedURLs.contains(selectedNode.url) ? 0 : 1) + } + + return RepositoryAggregate( + runtimeCount: canonicalRuntimes.count, + chainCount: canonicalChains.count, + enabledChainCount: canonicalChains.filter { !$0.disabled }.count, + assetCount: assetCount, + nodeCount: nodeCount, + defaultNodeRelationshipCount: defaultNodeRelationshipCount, + customNodeRelationshipCount: customNodeRelationshipCount, + selectedNodeRelationshipCount: selectedNodeRelationshipCount, + standaloneSelectedNodeCount: standaloneSelectedNodeCount, + fingerprint: Data(SHA256.hash(data: encodedProjection)) + ) + } + + private func runtimeProjection( + _ runtime: fearless.RuntimeMetadataItem + ) -> RuntimeProjection { + RuntimeProjection( + chain: runtime.chain, + version: runtime.version, + txVersion: runtime.txVersion, + metadataDigest: Data(SHA256.hash(data: runtime.metadata)) + ) + } + + private func runtimeProjection( + _ runtime: fearless.CDRuntimeMetadataItem + ) -> RuntimeProjection { + RuntimeProjection( + chain: runtime.identifier ?? "", + version: UInt32(bitPattern: runtime.version), + txVersion: UInt32(bitPattern: runtime.txVersion), + metadataDigest: Data(SHA256.hash(data: runtime.metadata ?? Data())) + ) + } + + private func chainProjection(_ chain: ChainModel) -> ChainProjection { + ChainProjection( + chainId: chain.chainId, + name: chain.name, + disabled: chain.disabled, + assetIds: chain.assets.map(\.id).sorted(), + nodes: chain.nodes.map(nodeProjection).sorted { + $0.sortKey.lexicographicallyPrecedes($1.sortKey) + }, + customNodes: (chain.customNodes ?? []).map(nodeProjection).sorted { + $0.sortKey.lexicographicallyPrecedes($1.sortKey) + }, + selectedNode: chain.selectedNode.map(nodeProjection) + ) + } + + private func chainProjection(_ chain: fearless.CDChain) -> ChainProjection { + ChainProjection( + chainId: chain.chainId ?? "", + name: chain.name ?? "", + disabled: chain.disabled, + assetIds: chain.assets?.compactMap { + ($0 as? fearless.CDAsset)?.id + }.sorted() ?? [], + nodes: chain.nodes?.compactMap { + ($0 as? fearless.CDChainNode).map(nodeProjection) + }.sorted { + $0.sortKey.lexicographicallyPrecedes($1.sortKey) + } ?? [], + customNodes: chain.customNodes?.compactMap { + ($0 as? fearless.CDChainNode).map(nodeProjection) + }.sorted { + $0.sortKey.lexicographicallyPrecedes($1.sortKey) + } ?? [], + selectedNode: chain.selectedNode.map(nodeProjection) + ) + } + + private func nodeProjection(_ node: ChainNodeModel) -> NodeProjection { + NodeProjection( + url: node.url.absoluteString, + name: node.name, + apiQueryName: node.apikey?.queryName, + apiKeyName: node.apikey?.keyName + ) + } + + private func nodeProjection(_ node: fearless.CDChainNode) -> NodeProjection { + NodeProjection( + url: node.url?.absoluteString ?? "", + name: node.name ?? "", + apiQueryName: node.apiQueryName, + apiKeyName: node.apiKeyName + ) + } + + private func allNodes(in chain: ChainModel) -> [ChainNodeModel] { + Array(chain.nodes) + + Array(chain.customNodes ?? []) + + [chain.selectedNode].compactMap { $0 } + } + + private func loadBundledV8Model() throws -> NSManagedObjectModel { + let appBundle = Bundle(for: SubstrateDataStorageFacade.self) + let modelURL = ["omo", "mom"].lazy.compactMap { + appBundle.url( + forResource: SubstrateStorageVersion.version8.rawValue, + withExtension: $0, + subdirectory: SubstrateStorageParams.modelDirectory + ) + }.first + + return try XCTUnwrap( + modelURL.flatMap(NSManagedObjectModel.init(contentsOf:)), + "Unable to load bundled SubstrateDataModel_v8" + ) + } + + private func makeInMemoryContext() throws -> NSManagedObjectContext { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: try loadBundledV8Model()) + try coordinator.addPersistentStore( + ofType: NSInMemoryStoreType, + configurationName: nil, + at: nil + ) + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + return context + } + + private func roundTrip( + _ model: Model, + entityName: String, + entityClass _: Entity.Type, + in context: NSManagedObjectContext + ) throws -> Model where + Model: Codable & Identifiable, + Entity: NSManagedObject & CoreDataCodable + { + let mapper = CodableCoreDataMapper() + var transformedModel: Model? + + try performAndWait(in: context) { + let insertedObject = try XCTUnwrap( + NSEntityDescription.insertNewObject( + forEntityName: entityName, + into: context + ) as? Entity + ) + try mapper.populate(entity: insertedObject, from: model, using: context) + try context.save() + context.reset() + + let request = NSFetchRequest(entityName: entityName) + let persistedObject = try XCTUnwrap(context.fetch(request).last) + self.assertExactClass( + of: persistedObject, + is: Entity.self, + entityName: entityName + ) + transformedModel = try mapper.transform(entity: persistedObject) + } + + return try XCTUnwrap(transformedModel) + } + + private func assertMalformedRowRejected( + _: Model.Type, + entityName: String, + entityClass _: Entity.Type, + in context: NSManagedObjectContext, + file: StaticString = #filePath, + line: UInt = #line + ) where + Model: Codable & Identifiable, + Entity: NSManagedObject & CoreDataCodable + { + guard let malformedEntity = NSEntityDescription.insertNewObject( + forEntityName: entityName, + into: context + ) as? Entity else { + XCTFail("\(entityName) did not materialize as its expected class", file: file, line: line) + return + } + + let mapper = CodableCoreDataMapper() + XCTAssertThrowsError( + try mapper.transform(entity: malformedEntity), + "\(entityName) accepted a row with missing required values", + file: file, + line: line + ) + } + + private func performAndWait( + in context: NSManagedObjectContext, + body: () throws -> Void + ) throws { + var bodyError: Error? + context.performAndWait { + do { + try body() + } catch { + bodyError = error + } + } + + if let bodyError { + throw bodyError + } + } + + private func assertExactClass( + of object: NSManagedObject, + is expectedClass: NSManagedObject.Type, + entityName: String, + file: StaticString = #filePath, + line: UInt = #line + ) { + XCTAssertEqual( + ObjectIdentifier(type(of: object)), + ObjectIdentifier(expectedClass), + "\(entityName) materialized as \(NSStringFromClass(type(of: object)))", + file: file, + line: line + ) + } + + private func versionHashes(for model: NSManagedObjectModel) -> [String: String] { + model.entityVersionHashesByName.mapValues { $0.base64EncodedString() } + } + + private func copiedPhoneStoreFixtureURL() -> URL { + if let configuredPath = ProcessInfo.processInfo.environment[ + "FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE" + ], !configuredPath.isEmpty { + return URL(fileURLWithPath: configuredPath) + } + + return URL( + fileURLWithPath: + "/private/tmp/fearless-device-coredata-20260723/SubstrateDataModel.sqlite" + ) + } + + private func copyStoreFixtureToTemporaryDirectory(_ fixtureURL: URL) throws -> URL { + let directoryURL = FileManager.default.temporaryDirectory + .appendingPathComponent("SubstrateStoragePhoneFixture") + .appendingPathComponent(UUID().uuidString) + try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true) + + let destinationURL = directoryURL.appendingPathComponent(fixtureURL.lastPathComponent) + for suffix in ["", "-wal", "-shm"] { + let sourceURL = URL(fileURLWithPath: fixtureURL.path + suffix) + guard FileManager.default.fileExists(atPath: sourceURL.path) else { + continue + } + + let copiedURL = URL(fileURLWithPath: destinationURL.path + suffix) + try FileManager.default.copyItem(at: sourceURL, to: copiedURL) + } + + return destinationURL + } + + private func inspectReadOnlyStore( + at storeURL: URL, + model: NSManagedObjectModel, + fetchEveryObject: Bool + ) throws -> [String: Int] { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: [ + NSReadOnlyPersistentStoreOption: true, + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + var counts: [String: Int] = [:] + + try performAndWait(in: context) { + for expectation in self.expectedEntityClasses { + let request = NSFetchRequest(entityName: expectation.entityName) + let count = try context.count(for: request) + counts[expectation.entityName] = count + + guard fetchEveryObject, count > 0 else { + continue + } + + request.fetchBatchSize = 512 + request.returnsObjectsAsFaults = true + let objects = try context.fetch(request) + XCTAssertEqual(objects.count, count) + + for object in objects { + self.assertExactClass( + of: object, + is: expectation.managedObjectClass, + entityName: expectation.entityName + ) + } + + context.reset() + } + } + + return counts + } + + private func metadataVersionHashes(_ metadata: [String: Any]) -> [String: Data]? { + metadata[NSStoreModelVersionHashesKey] as? [String: Data] + } + + private func storeFingerprints(at storeURL: URL) throws -> [String: Data] { + var fingerprints: [String: Data] = [:] + + for suffix in ["", "-wal", "-shm"] { + let fileURL = URL(fileURLWithPath: storeURL.path + suffix) + guard FileManager.default.fileExists(atPath: fileURL.path) else { + continue + } + + fingerprints[suffix] = try digest(of: fileURL) + } + + return fingerprints + } + + private func digest(of fileURL: URL) throws -> Data { + Data(SHA256.hash(data: try Data(contentsOf: fileURL, options: .mappedIfSafe))) + } +} diff --git a/fearlessTests/Common/Migration/SubstrateStorageMigrationSafetyTests.swift b/fearlessTests/Common/Migration/SubstrateStorageMigrationSafetyTests.swift new file mode 100644 index 0000000000..2fd0a660c8 --- /dev/null +++ b/fearlessTests/Common/Migration/SubstrateStorageMigrationSafetyTests.swift @@ -0,0 +1,7174 @@ +import CoreData +import SQLite3 +import XCTest +@testable import fearless + +final class SubstrateStorageMigrationSafetyTests: XCTestCase { + private var testDirectory: URL! + + private var storeURL: URL { + testDirectory.appendingPathComponent("SubstrateDataModel.sqlite") + } + + private var appBundle: Bundle { + Bundle(for: SubstrateDataStorageFacade.self) + } + + override func setUpWithError() throws { + try super.setUpWithError() + + testDirectory = FileManager.default.temporaryDirectory + .appendingPathComponent("SubstrateStorageMigrationSafetyTests") + .appendingPathComponent(UUID().uuidString) + try FileManager.default.createDirectory( + at: testDirectory, + withIntermediateDirectories: true + ) + } + + override func tearDownWithError() throws { + if let testDirectory { + try? FileManager.default.removeItem(at: testDirectory) + } + + try super.tearDownWithError() + } + + func testPerformMigration_whenStoreDoesNotExist_thenDoesNotCreateOrModifyAnything() throws { + let migrator = makeMigrator() + + XCTAssertFalse(migrator.requiresMigration()) + try migrator.performMigration() + + XCTAssertFalse(FileManager.default.fileExists(atPath: storeURL.path)) + XCTAssertTrue(try FileManager.default.contentsOfDirectory(atPath: testDirectory.path).isEmpty) + } + + func testPerformMigration_whenStoreIsCurrent_thenRepeatedCallsAreByteForByteIdempotent() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { context in + try self.insertRuntimeItem(identifier: "current-runtime", in: context, model: currentModel) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator() + + XCTAssertFalse(migrator.requiresMigration()) + try migrator.performMigration() + try migrator.performMigration() + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertEqual( + try count(entityName: "CDRuntimeMetadataItem", at: storeURL, model: currentModel), + 1 + ) + } + + func testPerformMigration_whenCurrentStoreHasOversizedRawArchive_thenRepairsPrivateCopyAtomicallyAndPreservesProtectedGraph() throws { + try createCurrentTransformableAndProtectedGraph() + try executeSQLite( + """ + UPDATE ZCDASSET + SET ZPURCHASEPROVIDERS = zeroblob(1025) + """, + at: storeURL + ) + let damaged = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumTransformableArchiveByteCount: 1024 + ) + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + damaged, + "Detection must never mutate the installed current store" + ) + + try migrator.performMigration() + + XCTAssertFalse(migrator.requiresMigration()) + try assertCurrentTransformableAndProtectedGraph( + expectedOptions: ["safe-option"], + expectedPurchaseProviders: nil + ) + let repaired = try durableStoreFamilySnapshot(at: storeURL) + XCTAssertNotEqual(repaired, damaged) + + try migrator.performMigration() + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + repaired, + "A repaired current store must become a byte-for-byte no-op" + ) + } + + func testPerformMigration_whenCurrentStoreHasDecodedWrongTypeArchive_thenRepairsPrivateCopyAndPreservesOtherValues() throws { + try createCurrentTransformableAndProtectedGraph() + let wrongTypeArchive = try NSKeyedArchiver.archivedData( + withRootObject: NSString(string: "not-an-array"), + requiringSecureCoding: true + ) + try executeSQLite( + """ + UPDATE ZCDCHAIN + SET ZOPTIONS = X'\(hex(wrongTypeArchive))' + """, + at: storeURL + ) + let damaged = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator() + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + damaged + ) + + try migrator.performMigration() + + XCTAssertFalse(migrator.requiresMigration()) + try assertCurrentTransformableAndProtectedGraph( + expectedOptions: [], + expectedPurchaseProviders: ["safe-provider"] + ) + } + + func testPerformMigration_whenCleanCurrentStartupGraphIsExactlyAtEveryRelationshipLimit_thenAuditsWithoutHookReplacementOrMutation() throws { + try createCurrentStartupRelationshipGraph() + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + var countedRelationships = + [(String, String, Bool, Int)]() + var materializedRelationships = [(String, String)]() + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumRelationshipMembers: 1, + maximumTotalRelationshipMembers: 8 + ), + protectedRelationshipCountDidFetch: { + countedRelationships.append( + ( + $0.entity.name ?? "unknown", + $1, + $0.hasFault(forRelationshipNamed: $1), + $2 + ) + ) + }, + protectedRelationshipWillMaterialize: { + entityName, + relationshipName, + _ in + materializedRelationships.append( + (entityName, relationshipName) + ) + } + ) + + XCTAssertFalse(migrator.requiresMigration()) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + + try migrator.performMigration() + + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + let expectedRelationships: Set = [ + "CDAsset.priceData", + "CDChain.assets", + "CDChain.customNodes", + "CDChain.explorers", + "CDChain.nodes", + "CDChainXcmConfig.availableAssets", + "CDChainXcmConfig.availableDestinations", + "CDXcmAvailableDestination.assets" + ] + let auditedRelationships = Set( + countedRelationships.map { "\($0.0).\($0.1)" } + ) + XCTAssertTrue( + expectedRelationships.isSubset( + of: auditedRelationships + ) + ) + XCTAssertTrue( + countedRelationships.allSatisfy { + $0.2 && $0.3 == 1 + }, + "Every SQL count must remain faulted at the exact boundary" + ) + XCTAssertEqual( + Set( + materializedRelationships.map { + "\($0.0).\($0.1)" + } + ), + ["CDChain.customNodes", "CDChain.nodes"], + "Only protected node relationships may materialize after the complete SQL audit" + ) + } + + func testPerformMigration_whenCleanCurrentStartupRootsAreExactlyAtRowLimits_thenAuditsWithoutHookReplacementOrMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + try self.insertRuntimeItem( + identifier: "bounded-runtime", + in: context, + model: currentModel + ) + _ = try self.insertChainWithDefaultNode( + in: context, + model: currentModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumRowsPerEntity: 1, + maximumTotalRows: 2, + maximumStartupRootRowsPerEntity: 1, + maximumRelationshipMembers: 1, + maximumTotalRelationshipMembers: 1 + ) + ) + + XCTAssertFalse(migrator.requiresMigration()) + try migrator.performMigration() + + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCleanCurrentRuntimeRootExceedsRowLimit_thenRejectsBeforeHookReplacementOrMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + for index in 0 ..< 2 { + try self.insertRuntimeItem( + identifier: "runtime-\(index)", + in: context, + model: currentModel + ) + } + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + var materializedRelationships = [(String, String, Int)]() + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumStartupRootRowsPerEntity: 1 + ), + protectedRelationshipWillMaterialize: { + materializedRelationships.append(($0, $1, $2)) + } + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + case let .entityRowLimitExceeded( + entityName, + actual, + maximum + ) = + underlyingError as? + SubstrateProtectedDataInspectionError + else { + return XCTFail( + "Expected current root row limit, got \(error)" + ) + } + + XCTAssertEqual(entityName, "CDRuntimeMetadataItem") + XCTAssertEqual(actual, 2) + XCTAssertEqual(maximum, 1) + } + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertTrue(materializedRelationships.isEmpty) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCleanCurrentRootPayloadIsExactlyAtByteLimit_thenAuditsWithoutHookReplacementOrMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + let runtime = try self.insertRuntimeItem( + identifier: "root", + in: context, + model: currentModel + ) + runtime.setValue(Data([1, 2, 3]), forKey: "metadata") + runtime.setValue(Data([4, 5]), forKey: "resolver") + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumStartupRootPayloadByteCount: 11 + ) + ) + + XCTAssertFalse(migrator.requiresMigration()) + try migrator.performMigration() + + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCleanCurrentRootPayloadExceedsByteLimit_thenRejectsBeforeHookReplacementOrMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + let runtime = try self.insertRuntimeItem( + identifier: "root", + in: context, + model: currentModel + ) + runtime.setValue(Data([1, 2, 3]), forKey: "metadata") + runtime.setValue(Data([4, 5]), forKey: "resolver") + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumStartupRootPayloadByteCount: 10 + ) + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + case let .startupRootPayloadByteLimitExceeded( + actual, + maximum + ) = + underlyingError as? + SubstrateProtectedDataInspectionError + else { + return XCTFail( + "Expected startup root payload limit, got \(error)" + ) + } + + XCTAssertEqual(actual, 11) + XCTAssertEqual(maximum, 10) + } + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCurrentPriceStringIsExactlyAtStartupChildValueLimit_thenAuditsWithoutMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + try self.insertStartupPayloadEntity( + entityName: "CDPriceData", + attributeName: "price", + payload: String(repeating: "7", count: 1_024), + in: context, + model: currentModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumStartupChildValueByteCount: 1_024 + ) + ) + + XCTAssertFalse(migrator.requiresMigration()) + try migrator.performMigration() + + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCurrentPriceStringExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation() throws { + try assertStartupChildValueLimitExceeded( + entityName: "CDPriceData", + attributeName: "price" + ) + } + + func testPerformMigration_whenCurrentAssetNameExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation() throws { + try assertStartupChildValueLimitExceeded( + entityName: "CDAsset", + attributeName: "name" + ) + } + + func testPerformMigration_whenCurrentCustomNodeNameExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation() throws { + try assertStartupChildValueLimitExceeded( + entityName: "CDChainNode", + attributeName: "name", + attachNodeAsCustomNode: true + ) + } + + func testPerformMigration_whenCurrentExplorerURLExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation() throws { + try assertStartupChildValueLimitExceeded( + entityName: "CDExternalApi", + attributeName: "url" + ) + } + + func testPerformMigration_whenCurrentXcmConfigVersionExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation() throws { + try assertStartupChildValueLimitExceeded( + entityName: "CDChainXcmConfig", + attributeName: "xcmVersion" + ) + } + + func testPerformMigration_whenCurrentXcmDestinationChainIdExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation() throws { + try assertStartupChildValueLimitExceeded( + entityName: "CDXcmAvailableDestination", + attributeName: "chainId" + ) + } + + func testPerformMigration_whenCurrentXcmAssetIdentifierExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation() throws { + try assertStartupChildValueLimitExceeded( + entityName: "CDXcmAvailableAsset", + attributeName: "id" + ) + } + + func testPerformMigration_whenCurrentPriceProviderIdentifierExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation() throws { + try assertStartupChildValueLimitExceeded( + entityName: "CDPriceProvider", + attributeName: "id" + ) + } + + func testPerformMigration_whenCurrentChildPayloadAggregateIsExactlyAtLimit_thenAuditsWithoutMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + try self.insertStartupPayloadEntity( + entityName: "CDPriceData", + attributeName: "price", + payload: "1234", + in: context, + model: currentModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumStartupChildValueByteCount: 4, + maximumStartupChildPayloadByteCount: 6 + ) + ) + + XCTAssertFalse(migrator.requiresMigration()) + try migrator.performMigration() + + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCurrentChildPayloadAggregateExceedsLimitByOne_thenRejectsBeforeCoreDataOrMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + try self.insertStartupPayloadEntity( + entityName: "CDPriceData", + attributeName: "price", + payload: "1234", + in: context, + model: currentModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumStartupChildValueByteCount: 4, + maximumStartupChildPayloadByteCount: 5 + ) + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + failedURL, + underlyingError + ) = migrationError, + case let .startupChildPayloadByteLimitExceeded( + actual, + maximum + ) = + underlyingError as? + SubstrateProtectedDataInspectionError + else { + return XCTFail( + "Expected startup child aggregate limit, got \(error)" + ) + } + + XCTAssertEqual(failedURL, self.storeURL) + XCTAssertEqual(actual, 6) + XCTAssertEqual(maximum, 5) + } + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCleanCurrentNodesExceedRelationshipLimit_thenRejectsWhileFaultedBeforeHookReplacementOrMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + try self.insertLegacyChainWithNodes( + in: context, + model: currentModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + var nodeCounts = [(Bool, Int)]() + var materializedRelationships = [(String, String, Int)]() + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumRelationshipMembers: 1 + ), + protectedRelationshipCountDidFetch: { + guard $1 == "nodes" else { + return + } + nodeCounts.append( + ( + $0.hasFault(forRelationshipNamed: $1), + $2 + ) + ) + }, + protectedRelationshipWillMaterialize: { + materializedRelationships.append(($0, $1, $2)) + } + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + case let .relationshipLimitExceeded( + entityName, + relationshipName, + actual, + maximum + ) = + underlyingError as? + SubstrateProtectedDataInspectionError + else { + return XCTFail( + "Expected current nodes limit, got \(error)" + ) + } + + XCTAssertEqual(entityName, "CDChain") + XCTAssertEqual(relationshipName, "nodes") + XCTAssertEqual(actual, 2) + XCTAssertEqual(maximum, 1) + } + XCTAssertEqual(nodeCounts.map(\.1), [2, 2]) + XCTAssertTrue(nodeCounts.allSatisfy(\.0)) + XCTAssertTrue(materializedRelationships.isEmpty) + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCleanCurrentPriceDataExceedsRelationshipLimit_thenRejectsWhileFaultedBeforeHookReplacementOrMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + let asset = try self.insertMigrationAsset( + identifier: "bounded-price-asset", + in: context, + model: currentModel + ) + try self.insertPriceData( + count: 2, + for: asset, + in: context, + model: currentModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + var priceDataCounts = [(Bool, Int)]() + var materializedRelationships = [(String, String, Int)]() + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumRelationshipMembers: 1 + ), + protectedRelationshipCountDidFetch: { + guard $1 == "priceData" else { + return + } + priceDataCounts.append( + ( + $0.hasFault(forRelationshipNamed: $1), + $2 + ) + ) + }, + protectedRelationshipWillMaterialize: { + materializedRelationships.append(($0, $1, $2)) + } + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + case let .relationshipLimitExceeded( + entityName, + relationshipName, + actual, + maximum + ) = + underlyingError as? + SubstrateProtectedDataInspectionError + else { + return XCTFail( + "Expected current priceData limit, got \(error)" + ) + } + + XCTAssertEqual(entityName, "CDAsset") + XCTAssertEqual(relationshipName, "priceData") + XCTAssertEqual(actual, 2) + XCTAssertEqual(maximum, 1) + } + XCTAssertEqual(priceDataCounts.map(\.1), [2, 2]) + XCTAssertTrue(priceDataCounts.allSatisfy(\.0)) + XCTAssertTrue(materializedRelationships.isEmpty) + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCleanCurrentXcmRelationshipsExceedAggregateLimit_thenRejectsBeforeHookReplacementOrMutation() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + let graph = try self.insertChainWithDefaultNode( + in: context, + model: currentModel + ) + try self.insertXcmRelationshipGraph( + for: graph.chain, + in: context, + model: currentModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + var xcmCounts = [(String, Bool, Int)]() + var materializedRelationships = [(String, String, Int)]() + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumRelationshipMembers: 1, + maximumTotalRelationshipMembers: 2 + ), + protectedRelationshipCountDidFetch: { + guard + $0.entity.name == "CDChainXcmConfig" + else { + return + } + xcmCounts.append( + ( + $1, + $0.hasFault(forRelationshipNamed: $1), + $2 + ) + ) + }, + protectedRelationshipWillMaterialize: { + materializedRelationships.append(($0, $1, $2)) + } + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + case let .totalRelationshipLimitExceeded( + actual, + maximum + ) = + underlyingError as? + SubstrateProtectedDataInspectionError + else { + return XCTFail( + "Expected current XCM aggregate limit, got \(error)" + ) + } + + XCTAssertEqual(actual, 3) + XCTAssertEqual(maximum, 2) + } + XCTAssertEqual( + xcmCounts.map(\.0), + [ + "availableAssets", + "availableDestinations", + "availableAssets", + "availableDestinations" + ] + ) + XCTAssertTrue( + xcmCounts.allSatisfy { + $0.1 && $0.2 == 1 + } + ) + XCTAssertTrue(materializedRelationships.isEmpty) + XCTAssertFalse(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenRepairedCurrentStageIntroducesOversizedPriceDataRelationship_thenRejectsBeforeReplacement() throws { + try createCurrentTransformableAndProtectedGraph() + let wrongTypeArchive = try NSKeyedArchiver.archivedData( + withRootObject: NSString(string: "repair-me"), + requiringSecureCoding: true + ) + try executeSQLite( + """ + UPDATE ZCDCHAIN + SET ZOPTIONS = X'\(hex(wrongTypeArchive))' + """, + at: storeURL + ) + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { stagedURL, targetModel in + stagedHookCalled = true + try self.addPriceDataToSingleAsset( + count: 2, + at: stagedURL, + model: targetModel + ) + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumRelationshipMembers: 1 + ) + ) + + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .stagedStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + case let .relationshipLimitExceeded( + entityName, + relationshipName, + actual, + maximum + ) = + underlyingError as? + SubstrateProtectedDataInspectionError + else { + return XCTFail( + "Expected staged priceData limit, got \(error)" + ) + } + + XCTAssertEqual(entityName, "CDAsset") + XCTAssertEqual(relationshipName, "priceData") + XCTAssertEqual(actual, 2) + XCTAssertEqual(maximum, 1) + } + XCTAssertTrue(stagedHookCalled) + XCTAssertFalse(replacementCalled) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenCurrentStoreHasLargeSharedMemorySidecar_thenUsesOneDisposableCopyAndCleansIt() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { context in + try self.insertRuntimeItem( + identifier: "current-large-family", + in: context, + model: currentModel + ) + } + let sharedMemoryURL = URL(fileURLWithPath: storeURL.path + "-shm") + try Data(repeating: 0xA5, count: 4 * 1_024 * 1_024).write( + to: sharedMemoryURL, + options: .atomic + ) + let before = try durableStoreFamilySnapshot(at: storeURL) + let fileManager = TemporaryStoreFootprintFileManager() + let migrator = makeMigrator(fileManager: fileManager) + + try migrator.performMigration() + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertEqual(fileManager.maximumTemporaryMainStoreCount, 1) + XCTAssertFalse(fileManager.copiedSharedMemorySidecar) + XCTAssertTrue(fileManager.temporaryRootsAreClean) + } + + func testPerformMigration_whenSourceFamilyExceedsPrivateCopyLimit_thenRejectsBeforeCapacityInspectionOrMutation() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + try self.insertRuntimeItem( + identifier: "oversized-private-copy", + in: context, + model: sourceModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var capacityInspectionCount = 0 + var replacementAttempted = false + let fileManager = TemporaryStoreFootprintFileManager() + let migrator = makeMigrator( + fileManager: fileManager, + storeReplacer: { _, _ in + replacementAttempted = true + }, + privateSourceCopyLimits: + SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: 1, + minimumFreeStorageReserveByteCount: 0 + ), + privateSourceAvailableCapacityProvider: { _ in + capacityInspectionCount += 1 + return UInt64.max + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceSnapshotFailed( + failedURL, + underlyingError + ) = migrationError, + case let .storeFamilyTooLarge( + actualByteCount, + maximumByteCount + ) = + underlyingError as? + CrashConsistentStoreReplacementError + else { + return XCTFail( + "Expected bounded source-copy rejection, got \(error)" + ) + } + + XCTAssertEqual(failedURL, self.storeURL) + XCTAssertGreaterThan(actualByteCount, 1) + XCTAssertEqual(maximumByteCount, 1) + } + XCTAssertEqual(capacityInspectionCount, 0) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + XCTAssertTrue(fileManager.temporaryRootsAreClean) + } + + func testPerformMigration_whenPrivateCopyCapacityIsInsufficient_thenRejectsBeforeCopyOrMutation() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + try self.insertRuntimeItem( + identifier: "capacity-bounded-private-copy", + in: context, + model: sourceModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var capacityInspectionCount = 0 + var replacementAttempted = false + let fileManager = TemporaryStoreFootprintFileManager() + let migrator = makeMigrator( + fileManager: fileManager, + storeReplacer: { _, _ in + replacementAttempted = true + }, + privateSourceCopyLimits: + SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: UInt64.max, + minimumFreeStorageReserveByteCount: 1 + ), + privateSourceAvailableCapacityProvider: { _ in + capacityInspectionCount += 1 + return 0 + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceSnapshotFailed( + failedURL, + underlyingError + ) = migrationError, + case let .insufficientStorageCapacity( + requiredByteCount, + availableByteCount + ) = + underlyingError as? + CrashConsistentStoreReplacementError + else { + return XCTFail( + "Expected private-copy capacity rejection, got \(error)" + ) + } + + XCTAssertEqual(failedURL, self.storeURL) + XCTAssertGreaterThan(requiredByteCount, 1) + XCTAssertEqual(availableByteCount, 0) + } + XCTAssertEqual(capacityInspectionCount, 1) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + XCTAssertTrue(fileManager.temporaryRootsAreClean) + } + + func testPerformMigration_whenStoreIsCorrupt_thenThrowsAndPreservesEveryStoreFile() throws { + try Data("not-a-core-data-store".utf8).write(to: storeURL, options: .atomic) + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator() + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case .metadataUnreadable = migrationError + else { + return XCTFail("Expected metadataUnreadable, got \(error)") + } + } + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + } + + func testSyncMigration_whenStoreIsCorrupt_thenFailsClosedAndPreservesEverySidecar() throws { + let corruptBytes = Data("not-a-core-data-store".utf8) + try corruptBytes.write(to: storeURL, options: .atomic) + try Data("substrate-wal".utf8).write( + to: URL(fileURLWithPath: storeURL.path + "-wal"), + options: .atomic + ) + + let userStoreURL = testDirectory.appendingPathComponent("UserDataModel.sqlite") + let userWALURL = URL(fileURLWithPath: userStoreURL.path + "-wal") + let userSHMURL = URL(fileURLWithPath: userStoreURL.path + "-shm") + let userJournalURL = URL(fileURLWithPath: userStoreURL.path + "-journal") + let userStoreBytes = Data("wallet-store-must-not-move".utf8) + let userWALBytes = Data("wallet-wal-must-not-move".utf8) + let userSHMBytes = Data("wallet-shm-must-not-move".utf8) + let userJournalBytes = Data("wallet-journal-must-not-move".utf8) + try userStoreBytes.write(to: userStoreURL, options: .atomic) + try userWALBytes.write(to: userWALURL, options: .atomic) + try userSHMBytes.write(to: userSHMURL, options: .atomic) + try userJournalBytes.write(to: userJournalURL, options: .atomic) + + let migrator = makeMigrator() + XCTAssertThrowsError(try migrator.migrate()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case .metadataUnreadable = migrationError + else { + return XCTFail("Expected metadataUnreadable, got \(error)") + } + } + + XCTAssertEqual(try Data(contentsOf: storeURL), corruptBytes) + XCTAssertEqual( + try Data(contentsOf: URL(fileURLWithPath: storeURL.path + "-wal")), + Data("substrate-wal".utf8) + ) + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual(try Data(contentsOf: userStoreURL), userStoreBytes) + XCTAssertEqual(try Data(contentsOf: userWALURL), userWALBytes) + XCTAssertEqual(try Data(contentsOf: userSHMURL), userSHMBytes) + XCTAssertEqual(try Data(contentsOf: userJournalURL), userJournalBytes) + XCTAssertTrue(try recoveryDirectories().isEmpty) + + XCTAssertThrowsError(try migrator.migrate()) + XCTAssertEqual(try Data(contentsOf: storeURL), corruptBytes) + XCTAssertTrue(try recoveryDirectories().isEmpty) + XCTAssertEqual(try Data(contentsOf: userStoreURL), userStoreBytes) + XCTAssertEqual(try Data(contentsOf: userWALURL), userWALBytes) + XCTAssertEqual(try Data(contentsOf: userSHMURL), userSHMBytes) + XCTAssertEqual(try Data(contentsOf: userJournalURL), userJournalBytes) + } + + func testPerformMigration_whenStoreVersionIsUnknown_thenThrowsAndPreservesEveryStoreFile() throws { + try createStore(at: storeURL, model: makeUnknownModel()) { _ in } + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator() + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case .unknownStoreVersion = migrationError + else { + return XCTFail("Expected unknownStoreVersion, got \(error)") + } + } + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + } + + func testSyncMigration_whenStoreVersionIsUnknown_thenFailsClosedAndPreservesEveryStoreFile() throws { + try createStore(at: storeURL, model: makeUnknownModel()) { _ in } + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator() + + XCTAssertThrowsError(try migrator.migrate()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case .unknownStoreVersion = migrationError + else { + return XCTFail("Expected unknownStoreVersion, got \(error)") + } + } + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertTrue(try recoveryDirectories().isEmpty) + + XCTAssertThrowsError(try migrator.migrate()) + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertTrue(try recoveryDirectories().isEmpty) + } + + func testSyncMigration_whenKnownStoreCannotBeInspected_thenFailsClosedAndPreservesEveryStoreFile() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem( + identifier: "uninspectable-runtime", + in: context, + model: sourceModel + ) + } + try executeSQLite( + "PRAGMA journal_mode=DELETE; DROP TABLE ZCDCONTACT", + at: storeURL + ) + + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator() + + for _ in 0 ..< 2 { + XCTAssertThrowsError(try migrator.migrate()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case .sourceStoreInspectionFailed = migrationError + else { + return XCTFail("Expected sourceStoreInspectionFailed, got \(error)") + } + } + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertTrue(try recoveryDirectories().isEmpty) + } + } + + func testPerformMigration_whenTargetModelIsMissing_thenThrowsBeforeCheckpointAndPreservesSource() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem(identifier: "missing-model", in: context, model: sourceModel) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let modelBundle = try makeModelBundle(omitting: .version8) + let migrator = makeMigrator(modelBundle: modelBundle) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case let .modelUnavailable(version) = migrationError + else { + return XCTFail("Expected modelUnavailable, got \(error)") + } + + XCTAssertEqual(version, .version8) + } + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertEqual( + try count(entityName: "CDRuntimeMetadataItem", at: storeURL, model: sourceModel), + 1 + ) + } + + func testPerformMigration_whenAskedToDowngrade_thenThrowsBeforeCheckpointAndPreservesSource() throws { + let sourceModel = try model(for: .version8) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem(identifier: "downgrade", in: context, model: sourceModel) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator(targetVersion: .version7) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case let .migrationPathUnavailable(source, destination) = migrationError + else { + return XCTFail("Expected migrationPathUnavailable, got \(error)") + } + + XCTAssertEqual(source, .version8) + XCTAssertEqual(destination, .version7) + } + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertEqual( + try count(entityName: "CDRuntimeMetadataItem", at: storeURL, model: sourceModel), + 1 + ) + } + + func testPerformMigration_whenVersion7Store_thenStagesValidVersion8AndPreservesRows() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem(identifier: "legacy-runtime", in: context, model: sourceModel) + try self.insertMigrationAsset( + identifier: "legacy-asset", + in: context, + model: sourceModel + ) + } + let migrator = makeMigrator() + + XCTAssertTrue(migrator.requiresMigration()) + try migrator.performMigration() + + let targetModel = try model(for: .version8) + XCTAssertFalse(migrator.requiresMigration()) + XCTAssertTrue(try isStore(at: storeURL, compatibleWith: targetModel, version: .version8)) + XCTAssertEqual( + try count(entityName: "CDRuntimeMetadataItem", at: storeURL, model: targetModel), + 1 + ) + XCTAssertEqual( + try count(entityName: "CDAsset", at: storeURL, model: targetModel), + 1 + ) + } + + func testPerformMigration_whenEverySupportedLegacyVersion_thenReachesV8AndPreservesRows() throws { + for sourceVersion in SubstrateStorageVersion.allCases where sourceVersion != .version8 { + let caseDirectory = testDirectory.appendingPathComponent( + sourceVersion.rawValue, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: caseDirectory, + withIntermediateDirectories: true + ) + let caseStoreURL = caseDirectory.appendingPathComponent( + SubstrateStorageParams.databaseName + ) + let sourceModel = try model(for: sourceVersion) + try createStore(at: caseStoreURL, model: sourceModel) { context in + try self.insertRuntimeItem( + identifier: "runtime-\(sourceVersion.rawValue)", + in: context, + model: sourceModel + ) + try self.insertChainStorageItem( + identifier: "storage-\(sourceVersion.rawValue)", + in: context, + model: sourceModel + ) + try self.insertMigrationAsset( + identifier: "asset-\(sourceVersion.rawValue)", + in: context, + model: sourceModel + ) + } + + let migrator = makeMigrator(storeURL: caseStoreURL) + XCTAssertTrue( + migrator.requiresMigration(), + "\(sourceVersion.rawValue) should require migration" + ) + + try migrator.performMigration() + + let targetModel = try model(for: .version8) + XCTAssertFalse( + migrator.requiresMigration(), + "\(sourceVersion.rawValue) should reach v8" + ) + XCTAssertTrue( + try isStore( + at: caseStoreURL, + compatibleWith: targetModel, + version: .version8 + ) + ) + XCTAssertEqual( + try count( + entityName: "CDRuntimeMetadataItem", + at: caseStoreURL, + model: targetModel + ), + 1, + "\(sourceVersion.rawValue) lost runtime metadata" + ) + XCTAssertEqual( + try count( + entityName: "CDChainStorageItem", + at: caseStoreURL, + model: targetModel + ), + 1, + "\(sourceVersion.rawValue) lost chain storage" + ) + XCTAssertEqual( + try count( + entityName: "CDAsset", + at: caseStoreURL, + model: targetModel + ), + 1, + "\(sourceVersion.rawValue) lost an asset" + ) + } + } + + func testPerformMigration_whenOldestLegacyStore_thenNeverRetainsCompletedIntermediates() throws { + let sourceModel = try model(for: .version1) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem( + identifier: "bounded-footprint-runtime", + in: context, + model: sourceModel + ) + try self.insertMigrationAsset( + identifier: "bounded-footprint-asset", + in: context, + model: sourceModel + ) + } + let fileManager = TemporaryStoreFootprintFileManager() + let migrator = makeMigrator(fileManager: fileManager) + + try migrator.performMigration() + + let expectedStepCount = SubstrateStorageVersion.allCases.count - 1 + XCTAssertEqual(fileManager.maximumTemporaryMainStoreCount, 2) + XCTAssertEqual( + fileManager.temporaryMainStoreCountsBeforeRemoval, + Array(repeating: 2, count: expectedStepCount) + ) + XCTAssertEqual( + fileManager.removedTemporaryMainStoreCount, + expectedStepCount + ) + XCTAssertTrue(fileManager.temporaryRootsAreClean) + XCTAssertTrue( + try isStore( + at: storeURL, + compatibleWith: model(for: .version8), + version: .version8 + ) + ) + } + + func testPerformMigration_whenTemporaryInputCleanupFails_thenAbortsAndCleansEveryPrivateStore() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem( + identifier: "cleanup-failure-runtime", + in: context, + model: sourceModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let fileManager = FailingTemporaryStoreCleanupFileManager() + let migrator = makeMigrator(fileManager: fileManager) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case .temporaryStoreCleanupFailed = migrationError + else { + return XCTFail("Expected temporaryStoreCleanupFailed, got \(error)") + } + } + + XCTAssertTrue(fileManager.didInjectCleanupFailure) + XCTAssertTrue(fileManager.temporaryRootsAreClean) + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + } + + func testPerformMigration_whenVersion1ChainHasNoSelectedNode_thenSelectsStableNode() throws { + let sourceModel = try model(for: .version1) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertLegacyChainWithNodes(in: context, model: sourceModel) + } + + try makeMigrator().performMigration() + + let targetModel = try model(for: .version8) + try inspectStore(at: storeURL, model: targetModel) { context in + let chain = try XCTUnwrap( + try context.fetch( + NSFetchRequest(entityName: "CDChain") + ).first + ) + let nodes = try XCTUnwrap( + chain.value(forKey: "nodes") as? Set + ) + let selectedNode = try XCTUnwrap( + chain.value(forKey: "selectedNode") as? NSManagedObject + ) + + XCTAssertEqual(nodes.count, 2) + XCTAssertEqual( + selectedNode.value(forKey: "url") as? URL, + URL(string: "wss://alpha.example.invalid") + ) + XCTAssertTrue(nodes.contains(selectedNode)) + XCTAssertEqual(selectedNode.value(forKey: "chain") as? NSManagedObject, chain) + } + } + + func testPerformMigration_whenVersion3ContainsChainGraph_thenUsesCustomV4Policy() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertLegacyChainGraph(in: context, model: sourceModel) + } + + try makeMigrator().performMigration() + + let targetModel = try model(for: .version8) + XCTAssertEqual( + try count(entityName: "CDChain", at: storeURL, model: targetModel), + 1 + ) + XCTAssertEqual( + try count(entityName: "CDChainNode", at: storeURL, model: targetModel), + 1 + ) + XCTAssertEqual( + try count(entityName: "CDAsset", at: storeURL, model: targetModel), + 1 + ) + + try inspectStore(at: storeURL, model: targetModel) { context in + let chain = try XCTUnwrap( + try context.fetch( + NSFetchRequest(entityName: "CDChain") + ).first + ) + let assets = try XCTUnwrap( + chain.value(forKey: "assets") as? Set + ) + let asset = try XCTUnwrap(assets.first) + + XCTAssertEqual(assets.count, 1) + XCTAssertEqual(asset.value(forKey: "id") as? String, "migration-asset") + XCTAssertEqual(asset.value(forKey: "symbol") as? String, "MIG") + XCTAssertEqual(asset.value(forKey: "isNative") as? Bool, true) + XCTAssertEqual(asset.value(forKey: "isUtility") as? Bool, false) + XCTAssertEqual(asset.value(forKey: "type") as? String, "normal") + XCTAssertEqual(chain.value(forKey: "disabled") as? Bool, false) + XCTAssertEqual(asset.value(forKey: "chain") as? NSManagedObject, chain) + } + } + + func testPerformMigration_whenV3ChainOptionsArchiveIsRawGarbage_thenDefaultsOnlyThatCache() throws { + try assertAdversarialTransformableMigration( + sourceVersion: .version3, + updateSQL: "UPDATE ZCDCHAIN SET ZOPTIONS = X'00FF00'", + expectedDefaultedKeys: ["CDChain.options"] + ) + } + + func testPerformMigration_whenV3ExternalTypesArchiveIsEmpty_thenDefaultsOnlyThatCache() throws { + try assertAdversarialTransformableMigration( + sourceVersion: .version3, + updateSQL: "UPDATE ZCDEXTERNALAPI SET ZTYPES = X''", + expectedDefaultedKeys: ["CDExternalApi.types"] + ) + } + + func testPerformMigration_whenV3PurchaseProvidersArchiveIsTruncated_thenV4PolicyStillPreservesGraph() throws { + let truncatedArchive = try NSKeyedArchiver.archivedData( + withRootObject: NSArray(object: "provider-a"), + requiringSecureCoding: true + ).prefix(8) + + try assertAdversarialTransformableMigration( + sourceVersion: .version3, + updateSQL: + "UPDATE ZCDCHAINASSET SET ZPURCHASEPROVIDERS = " + + "X'\(hex(Data(truncatedArchive)))'", + expectedDefaultedKeys: ["CDChainAsset.purchaseProviders"] + ) + } + + func testPerformMigration_whenV4AssetPurchaseProvidersArchiveIsRawGarbage_thenDefaultsOnlyAssetCache() throws { + try assertAdversarialTransformableMigration( + sourceVersion: .version4, + updateSQL: + "UPDATE ZCDASSET SET ZPURCHASEPROVIDERS = X'00FF00'", + expectedDefaultedKeys: ["CDAsset.purchaseProviders"] + ) + } + + func testPerformMigration_whenBothV3PolkaswapArchivesHaveWrongTypes_thenDefaultsBothRequiredArrays() throws { + let wrongTypeArchive = try NSKeyedArchiver.archivedData( + withRootObject: NSString(string: "not-an-array"), + requiringSecureCoding: true + ) + let archiveHex = hex(wrongTypeArchive) + + try assertAdversarialTransformableMigration( + sourceVersion: .version3, + updateSQL: """ + UPDATE ZCDPOLKASWAPREMOTESETTINGS + SET ZAVAILABLESOURCES = X'\(archiveHex)', + ZFORCESMARTIDS = X'\(archiveHex)' + """, + expectedDefaultedKeys: [ + "CDPolkaswapRemoteSettings.availableSources", + "CDPolkaswapRemoteSettings.forceSmartIds" + ] + ) + } + + func testPerformMigration_whenV4LegacyXcmArchiveContainsDisallowedClass_thenDefaultsConfigAndPreservesDestination() throws { + let disallowedArchive = try NSKeyedArchiver.archivedData( + withRootObject: DisallowedSubstrateTransformablePayload( + value: "must-not-decode" + ), + requiringSecureCoding: true + ) + + try assertAdversarialTransformableMigration( + sourceVersion: .version4, + updateSQL: + "UPDATE ZCDCHAINXCMCONFIG SET ZAVAILABLEASSETS = " + + "X'\(hex(disallowedArchive))'", + expectedDefaultedKeys: ["CDChainXcmConfig.availableAssets"] + ) + } + + func testPerformMigration_whenV3LegacyDestinationAssetsArchiveIsInvalid_thenDefaultsDestinationAndPreservesConfig() throws { + try assertAdversarialTransformableMigration( + sourceVersion: .version3, + updateSQL: + "UPDATE ZCDXCMAVAILABLEDESTINATION SET ZASSETS = X'00FF00'", + expectedDefaultedKeys: ["CDXcmAvailableDestination.assets"] + ) + } + + func testPerformMigration_whenAllV3TransformableArchivesAreValid_thenPreservesEveryValueAndProtectedRelationship() throws { + try assertAdversarialTransformableMigration( + sourceVersion: .version3, + updateSQL: "UPDATE ZCDCHAIN SET ZOPTIONS = ZOPTIONS", + expectedDefaultedKeys: [] + ) + } + + func testPerformMigration_whenEveryV3TransformableArchiveIsDamagedTogether_thenRepairsEveryKeyAndPreservesProtectedGraph() throws { + let wrongTypeArchive = try NSKeyedArchiver.archivedData( + withRootObject: NSString(string: "not-an-array"), + requiringSecureCoding: true + ) + let wrongTypeHex = hex(wrongTypeArchive) + + try assertAdversarialTransformableMigration( + sourceVersion: .version3, + updateSQL: """ + UPDATE ZCDCHAIN SET ZOPTIONS = X'00FF00'; + UPDATE ZCDCHAINASSET SET ZPURCHASEPROVIDERS = X''; + UPDATE ZCDEXTERNALAPI SET ZTYPES = X'\(wrongTypeHex)'; + UPDATE ZCDPOLKASWAPREMOTESETTINGS + SET ZAVAILABLESOURCES = X'00FF00', + ZFORCESMARTIDS = X'\(wrongTypeHex)'; + UPDATE ZCDCHAINXCMCONFIG + SET ZAVAILABLEASSETS = X'\(wrongTypeHex)'; + UPDATE ZCDXCMAVAILABLEDESTINATION SET ZASSETS = X'00FF00'; + """, + expectedDefaultedKeys: [ + "CDChain.options", + "CDChainAsset.purchaseProviders", + "CDExternalApi.types", + "CDPolkaswapRemoteSettings.availableSources", + "CDPolkaswapRemoteSettings.forceSmartIds", + "CDChainXcmConfig.availableAssets", + "CDXcmAvailableDestination.assets" + ] + ) + } + + func testPerformMigration_whenTransformableElementCountIsExactlyAtLimit_thenPreservesArray() throws { + try createVersion7AssetStore( + purchaseProviders: ["provider-a", "provider-b"] + ) + + try makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumTransformableElements: 2 + ) + ).performMigration() + + XCTAssertEqual( + try migratedAssetPurchaseProviders(), + ["provider-a", "provider-b"] + ) + } + + func testPerformMigration_whenTransformableElementCountExceedsLimit_thenRepairsArray() throws { + try createVersion7AssetStore( + purchaseProviders: [ + "provider-a", + "provider-b", + "provider-c" + ] + ) + + try makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumTransformableElements: 2 + ) + ).performMigration() + + XCTAssertEqual(try migratedAssetPurchaseProviders(), []) + } + + func testPerformMigration_whenTransformableUTF8BytesAreExactlyAtLimit_thenPreservesArray() throws { + // One composed character plus two ASCII characters occupy four + // cumulative UTF-8 bytes. + try createVersion7AssetStore( + purchaseProviders: ["é", "ab"] + ) + + try makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits(maximumValueByteCount: 4) + ).performMigration() + + XCTAssertEqual( + try migratedAssetPurchaseProviders(), + ["é", "ab"] + ) + } + + func testPerformMigration_whenTransformableUTF8BytesExceedLimit_thenRepairsArray() throws { + // Each element is individually within budget, while their cumulative + // UTF-8 representation is five bytes. + try createVersion7AssetStore( + purchaseProviders: ["é", "abc"] + ) + + try makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits(maximumValueByteCount: 4) + ).performMigration() + + XCTAssertEqual(try migratedAssetPurchaseProviders(), []) + } + + func testPerformMigration_whenRawTransformableArchiveIsExactlyAtLimit_thenPreservesArray() throws { + try createVersion7AssetStore( + purchaseProviders: ["raw-boundary"] + ) + let archiveByteCount = try sqliteInteger( + "SELECT length(ZPURCHASEPROVIDERS) FROM ZCDASSET LIMIT 1", + at: storeURL + ) + XCTAssertGreaterThan(archiveByteCount, 0) + XCTAssertLessThanOrEqual(archiveByteCount, Int64(Int.max)) + + try makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumTransformableArchiveByteCount: + Int(archiveByteCount) + ) + ).performMigration() + + XCTAssertEqual( + try migratedAssetPurchaseProviders(), + ["raw-boundary"] + ) + } + + func testPerformMigration_whenRawTransformableArchiveExceedsLimit_thenRepairsBeforeCoreDataDecode() throws { + try createVersion7AssetStore( + purchaseProviders: ["will-be-replaced"] + ) + try executeSQLite( + """ + UPDATE ZCDASSET + SET ZPURCHASEPROVIDERS = zeroblob(1025) + """, + at: storeURL + ) + + try makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumTransformableArchiveByteCount: 1024 + ) + ).performMigration() + + XCTAssertNil(try migratedAssetPurchaseProviders()) + } + + func testPerformMigration_whenOptionalTransformableUsesWrongSQLiteStorageClass_thenRepairsBeforeDecode() throws { + try createVersion7AssetStore( + purchaseProviders: ["will-be-replaced"] + ) + try executeSQLite( + """ + UPDATE ZCDASSET + SET ZPURCHASEPROVIDERS = 'not-a-blob' + """, + at: storeURL + ) + + try makeMigrator().performMigration() + + XCTAssertNil(try migratedAssetPurchaseProviders()) + } + + func testPerformMigration_whenRequiredTransformableUsesWrongSQLiteStorageClass_thenWritesValidEmptyArchive() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + let settings = try self.insert( + entityName: "CDPolkaswapRemoteSettings", + in: context, + model: sourceModel + ) + settings.setValue("v1", forKey: "version") + settings.setValue( + NSArray(object: "source-a"), + forKey: "availableSources" + ) + settings.setValue( + NSArray(object: "smart-a"), + forKey: "forceSmartIds" + ) + } + try executeSQLite( + """ + UPDATE ZCDPOLKASWAPREMOTESETTINGS + SET ZFORCESMARTIDS = 42 + """, + at: storeURL + ) + + try makeMigrator().performMigration() + + let targetModel = try model(for: .version8) + try inspectStore(at: storeURL, model: targetModel) { + context in + let settings = try self.fetchSingleObject( + entityName: "CDPolkaswapRemoteSettings", + context: context + ) + XCTAssertEqual( + try self.stringArray( + in: settings, + key: "availableSources" + ), + ["source-a"] + ) + XCTAssertEqual( + try self.stringArray( + in: settings, + key: "forceSmartIds" + ), + [] + ) + } + } + + func testPerformMigrationWithRecovery_whenTransformableEntityExceedsRowCap_thenRejectsBeforePagingReplacementOrQuarantine() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { + context in + try self.insertTransformableAndProtectedGraph( + in: context, + model: sourceModel + ) + } + try executeSQLite( + "UPDATE ZCDCHAIN SET ZOPTIONS = X'00FF00'", + at: storeURL + ) + let before = try durableStoreFamilySnapshot(at: storeURL) + var replacementAttempted = false + var fetchedPages = [(String, Int, Int)]() + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementAttempted = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits(maximumRowsPerEntity: 0), + transformableObjectIDPageDidFetch: { + fetchedPages.append(($0, $1, $2)) + } + ) + + XCTAssertThrowsError( + try migrator.performMigrationWithRecovery() + ) { error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .transformableSanitizationFailed( + version, + _ + ) = migrationError + else { + return XCTFail( + "Expected transformableSanitizationFailed, got \(error)" + ) + } + XCTAssertEqual(version, .version3) + } + + XCTAssertTrue(fetchedPages.isEmpty) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + XCTAssertTrue(try recoveryDirectories().isEmpty) + } + + func testPerformMigration_whenBatchRepairsResetContext_thenImmutableIDCohortRepairsEveryRowExactlyOnce() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + try self.insertMigrationAsset( + identifier: "paged-asset-a", + in: context, + model: sourceModel + ) + try self.insertMigrationAsset( + identifier: "paged-asset-b", + in: context, + model: sourceModel + ) + let request = NSFetchRequest( + entityName: "CDAsset" + ) + for asset in try context.fetch(request) { + asset.setValue( + NSArray(object: "provider"), + forKey: "purchaseProviders" + ) + } + } + try executeSQLite( + """ + UPDATE ZCDASSET + SET ZPURCHASEPROVIDERS = X'00FF00' + """, + at: storeURL + ) + var fetchedPages = [(String, Int, Int)]() + let migrator = makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits(fetchPageSize: 1), + transformableObjectIDPageDidFetch: { + fetchedPages.append(($0, $1, $2)) + } + ) + + try migrator.performMigration() + + let assetPages = fetchedPages.filter { + $0.0 == "CDAsset" + } + XCTAssertEqual(assetPages.count, 2) + XCTAssertTrue( + assetPages.allSatisfy { + $0.1 == 1 && $0.2 == 1 + } + ) + let targetModel = try model(for: .version8) + try inspectStore( + at: storeURL, + model: targetModel + ) { context in + let request = NSFetchRequest( + entityName: "CDAsset" + ) + let assets = try context.fetch(request) + XCTAssertEqual(assets.count, 2) + for asset in assets { + XCTAssertEqual( + try self.stringArray( + in: asset, + key: "purchaseProviders" + ), + [] + ) + } + } + } + + func testSyncMigration_whenFinalReplacementFails_thenSourceFamilyAndRelationshipsRemainExact() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertTransformableAndProtectedGraph( + in: context, + model: sourceModel + ) + } + try executeSQLite( + "UPDATE ZCDCHAIN SET ZOPTIONS = X'00FF00'", + at: storeURL + ) + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator( + storeReplacer: { _, _ in + throw InjectedSubstrateStoreReplacementError.failure + } + ) + + XCTAssertThrowsError(try migrator.migrate()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case .storeReplacementFailed = migrationError + else { + return XCTFail("Expected storeReplacementFailed, got \(error)") + } + } + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertTrue(try recoveryDirectories().isEmpty) + try assertSourceProtectedGraphIsExact( + at: storeURL, + model: sourceModel + ) + } + + func testPerformMigration_whenProcessDiesAfterRemovingLiveMainStore_thenRelaunchRestoresAndMigratesProtectedGraph() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertTransformableAndProtectedGraph( + in: context, + model: sourceModel + ) + } + let interruptedMigrator = makeMigrator( + storeReplacer: { targetURL, _ in + try FileManager.default.removeItem(at: targetURL) + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + + XCTAssertThrowsError( + try interruptedMigrator.performMigration() + ) { error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .storeReplacementFailed(_, underlyingError) = + migrationError, + underlyingError + is CrashConsistentStoreReplacementInterruption + else { + return XCTFail( + "Expected interrupted store replacement, got \(error)" + ) + } + } + XCTAssertFalse( + FileManager.default.fileExists(atPath: storeURL.path), + "The fixture must reproduce the missing-main startup state" + ) + + let relaunchedMigrator = makeMigrator() + try relaunchedMigrator.performMigration() + + try assertMigratedTransformableAndProtectedGraph( + expectedDefaultedKeys: [] + ) + XCTAssertFalse(relaunchedMigrator.requiresMigration()) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: testDirectory + .appendingPathComponent( + ".FearlessStoreReplacement", + isDirectory: true + ).path + ) + ) + } + + func testPerformMigration_whenStagedProtectedValuesAndSelectedNodeAreSwappedWithoutRowLoss_thenRejectsStageAndPreservesSource() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertTransformableAndProtectedGraph( + in: context, + model: sourceModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator( + stagedStoreMutationHook: { stagedURL, targetModel in + try self.mutateStagedProtectedDataWithoutChangingRowCounts( + at: stagedURL, + model: targetModel + ) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case .stagedStoreProtectedDataMismatch = migrationError + else { + return XCTFail( + "Expected stagedStoreProtectedDataMismatch, got \(error)" + ) + } + } + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + try assertSourceProtectedGraphIsExact( + at: storeURL, + model: sourceModel + ) + } + + func testPerformMigration_whenProtectedEntityExceedsRowLimit_thenFailsClosedBeforeMigration() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + for index in 0 ..< 2 { + let contact = try self.insert( + entityName: "CDContact", + in: context, + model: sourceModel + ) + contact.setValue( + "contact-\(index)", + forKey: "address" + ) + } + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits(maximumRowsPerEntity: 1) + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + failedURL, + underlyingError + ) = migrationError, + let inspectionError = + underlyingError as? + SubstrateProtectedDataInspectionError, + case let .entityRowLimitExceeded( + entityName, + actual, + maximum + ) = inspectionError + else { + return XCTFail( + "Expected entityRowLimitExceeded, got \(error)" + ) + } + + XCTAssertEqual(failedURL, self.storeURL) + XCTAssertEqual(entityName, "CDContact") + XCTAssertEqual(actual, 2) + XCTAssertEqual(maximum, 1) + } + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenProtectedEntitiesExceedTotalRowLimit_thenFailsClosedBeforePaging() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + _ = try self.insert( + entityName: "CDContact", + in: context, + model: sourceModel + ) + _ = try self.insert( + entityName: "CDContactItem", + in: context, + model: sourceModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits(maximumTotalRows: 1) + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + let inspectionError = + underlyingError as? + SubstrateProtectedDataInspectionError, + case let .totalRowLimitExceeded( + actual, + maximum + ) = inspectionError + else { + return XCTFail( + "Expected totalRowLimitExceeded, got \(error)" + ) + } + + XCTAssertEqual(actual, 2) + XCTAssertEqual(maximum, 1) + } + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenChainRelationshipExceedsMemberLimit_thenFailsClosedBeforeDigestingTopology() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + try self.insertLegacyChainWithNodes( + in: context, + model: sourceModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var relationshipCountFaultStates = + [(String, Bool, Int)]() + var materializedRelationships = + [(String, String, Int)]() + let migrator = makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumRelationshipMembers: 1 + ), + protectedRelationshipCountDidFetch: { + relationshipCountFaultStates.append( + ( + $1, + $0.hasFault( + forRelationshipNamed: $1 + ), + $2 + ) + ) + }, + protectedRelationshipWillMaterialize: { + materializedRelationships.append(($0, $1, $2)) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + let inspectionError = + underlyingError as? + SubstrateProtectedDataInspectionError, + case let .relationshipLimitExceeded( + entityName, + relationshipName, + actual, + maximum + ) = inspectionError + else { + return XCTFail( + "Expected relationshipLimitExceeded, got \(error)" + ) + } + + XCTAssertEqual(entityName, "CDChain") + XCTAssertEqual(relationshipName, "nodes") + XCTAssertEqual(actual, 2) + XCTAssertEqual(maximum, 1) + } + XCTAssertEqual( + relationshipCountFaultStates.map { $0.0 }, + ["nodes"] + ) + XCTAssertTrue( + relationshipCountFaultStates.allSatisfy { $0.1 }, + "The SQL count must leave the inverse relationship faulted" + ) + XCTAssertEqual( + relationshipCountFaultStates.map { $0.2 }, + [2] + ) + XCTAssertTrue( + materializedRelationships.isEmpty, + "An over-limit relationship must be rejected before member copying" + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenNoInverseRelationshipExceedsMemberLimit_thenRejectsWhileRelationshipRemainsFaulted() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + let graph = try self.insertChainWithDefaultNode( + in: context, + model: sourceModel + ) + for index in 0 ..< 2 { + let customNode = try self.insert( + entityName: "CDChainNode", + in: context, + model: sourceModel + ) + customNode.setValue( + "Custom \(index)", + forKey: "name" + ) + customNode.setValue( + try XCTUnwrap( + URL( + string: + "wss://custom-\(index).example.invalid" + ) + ), + forKey: "url" + ) + graph.chain.mutableSetValue( + forKey: "customNodes" + ).add(customNode) + } + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var relationshipCountFaultStates = + [(String, Bool, Int)]() + var materializedRelationships = + [(String, String, Int)]() + let migrator = makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumRelationshipMembers: 1 + ), + protectedRelationshipCountDidFetch: { + relationshipCountFaultStates.append( + ( + $1, + $0.hasFault( + forRelationshipNamed: $1 + ), + $2 + ) + ) + }, + protectedRelationshipWillMaterialize: { + materializedRelationships.append(($0, $1, $2)) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + let inspectionError = + underlyingError as? + SubstrateProtectedDataInspectionError, + case let .relationshipLimitExceeded( + entityName, + relationshipName, + actual, + maximum + ) = inspectionError + else { + return XCTFail( + "Expected no-inverse relationship limit, got \(error)" + ) + } + + XCTAssertEqual(entityName, "CDChain") + XCTAssertEqual(relationshipName, "customNodes") + XCTAssertEqual(actual, 2) + XCTAssertEqual(maximum, 1) + } + XCTAssertEqual( + relationshipCountFaultStates.map { $0.0 }, + ["nodes", "customNodes"] + ) + XCTAssertTrue( + relationshipCountFaultStates.allSatisfy { $0.1 }, + "Both relationship counts must leave their faults intact" + ) + XCTAssertEqual( + relationshipCountFaultStates.map { $0.2 }, + [1, 2] + ) + XCTAssertTrue( + materializedRelationships.isEmpty, + "Both counts must be accepted before either relationship fires" + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenAggregateRelationshipLimitIsExceeded_thenRejectsBeforeEitherRelationshipMaterializes() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + let graph = try self.insertChainWithDefaultNode( + in: context, + model: sourceModel + ) + let customNode = try self.insert( + entityName: "CDChainNode", + in: context, + model: sourceModel + ) + customNode.setValue("Custom", forKey: "name") + customNode.setValue( + try XCTUnwrap( + URL(string: "wss://custom.example.invalid") + ), + forKey: "url" + ) + graph.chain.mutableSetValue( + forKey: "customNodes" + ).add(customNode) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var materializedRelationships = + [(String, String, Int)]() + let migrator = makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumRelationshipMembers: 1, + maximumTotalRelationshipMembers: 1 + ), + protectedRelationshipWillMaterialize: { + materializedRelationships.append(($0, $1, $2)) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + let inspectionError = + underlyingError as? + SubstrateProtectedDataInspectionError, + case let .totalRelationshipLimitExceeded( + actual, + maximum + ) = inspectionError + else { + return XCTFail( + "Expected aggregate relationship limit, got \(error)" + ) + } + + XCTAssertEqual(actual, 2) + XCTAssertEqual(maximum, 1) + } + XCTAssertTrue( + materializedRelationships.isEmpty, + "Aggregate counts must pass before either relationship fires" + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenProtectedValueExceedsByteLimit_thenFailsClosedWithoutReplacingStore() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + let contact = try self.insert( + entityName: "CDContact", + in: context, + model: sourceModel + ) + contact.setValue("too-long", forKey: "name") + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits(maximumValueByteCount: 4) + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + let inspectionError = + underlyingError as? + SubstrateProtectedDataInspectionError, + case let .valueByteLimitExceeded( + entityName, + attributeName, + actual, + maximum + ) = inspectionError + else { + return XCTFail( + "Expected valueByteLimitExceeded, got \(error)" + ) + } + + XCTAssertEqual(entityName, "CDContact") + XCTAssertEqual(attributeName, "name") + XCTAssertEqual(actual, 8) + XCTAssertEqual(maximum, 4) + } + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenBoundedRelationshipMemberExceedsByteLimit_thenFailsBeforeReplacement() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + let (_, node) = try self.insertChainWithDefaultNode( + in: context, + model: sourceModel + ) + node.setValue("too-long", forKey: "name") + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var replacementAttempted = false + var materializedRelationships = + [(String, String, Int)]() + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementAttempted = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits(maximumValueByteCount: 4), + protectedRelationshipWillMaterialize: { + materializedRelationships.append(($0, $1, $2)) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + _, + underlyingError + ) = migrationError, + let inspectionError = + underlyingError as? + SubstrateProtectedDataInspectionError, + case let .valueByteLimitExceeded( + entityName, + attributeName, + actual, + maximum + ) = inspectionError + else { + return XCTFail( + "Expected relationship-member byte rejection, got \(error)" + ) + } + + XCTAssertEqual(entityName, "CDChainNode") + XCTAssertEqual(attributeName, "name") + XCTAssertEqual(actual, 8) + XCTAssertEqual(maximum, 4) + } + XCTAssertTrue( + materializedRelationships.contains { + $0.0 == "CDChain" && + $0.1 == "nodes" && + $0.2 == 1 + } + ) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenProtectedRowsSpanSingleItemPages_thenDigestPreservesEveryRecord() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + for index in 0 ..< 3 { + let contact = try self.insert( + entityName: "CDContact", + in: context, + model: sourceModel + ) + contact.setValue( + "address-\(index)", + forKey: "address" + ) + contact.setValue( + "name-\(index)", + forKey: "name" + ) + } + } + let migrator = makeMigrator( + protectedDataInspectionLimits: + makeProtectedDataLimits(fetchPageSize: 1) + ) + + try migrator.performMigration() + + XCTAssertEqual( + try count( + entityName: "CDContact", + at: storeURL, + model: try model(for: .version8) + ), + 3 + ) + } + + func testPerformMigration_whenLegacyAssetHasNoSymbolAndWrapperHasNoAsset_thenPreservesGraph() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertLegacyChainGraph( + in: context, + model: sourceModel, + symbol: nil, + includeNilAssetWrapper: true + ) + } + + try makeMigrator().performMigration() + + let targetModel = try model(for: .version8) + XCTAssertEqual( + try count(entityName: "CDAsset", at: storeURL, model: targetModel), + 1 + ) + + try inspectStore(at: storeURL, model: targetModel) { context in + let chain = try XCTUnwrap( + try context.fetch( + NSFetchRequest(entityName: "CDChain") + ).first + ) + let assets = try XCTUnwrap( + chain.value(forKey: "assets") as? Set + ) + let asset = try XCTUnwrap(assets.first) + + XCTAssertEqual(assets.count, 1) + XCTAssertEqual(asset.value(forKey: "id") as? String, "migration-asset") + XCTAssertNil(asset.value(forKey: "symbol")) + } + } + + func testChainV4Policy_whenSourceAssetHasNoDestinationAssociation_thenMigrationFails() throws { + let sourceModel = try model(for: .version3) + let destinationModel = try model(for: .version4) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertLegacyChainGraph(in: context, model: sourceModel) + } + + let mappingURL = try XCTUnwrap( + appBundle.url( + forResource: "SubstrateV3toV4", + withExtension: "cdm" + ) + ) + let mappingModel = try XCTUnwrap(NSMappingModel(contentsOf: mappingURL)) + let assetMapping = try XCTUnwrap( + mappingModel.entityMappings.first { + $0.sourceEntityName == "CDAsset" && + $0.destinationEntityName == "CDAsset" + } + ) + assetMapping.entityMigrationPolicyClassName = NSStringFromClass( + DroppingAssetMigrationPolicy.self + ) + + let manager = NSMigrationManager( + sourceModel: sourceModel, + destinationModel: destinationModel + ) + let destinationURL = testDirectory.appendingPathComponent( + "MissingAssetAssociation.sqlite" + ) + + XCTAssertThrowsError( + try manager.migrateStore( + from: storeURL, + sourceType: NSSQLiteStoreType, + options: nil, + with: mappingModel, + toDestinationURL: destinationURL, + destinationType: NSSQLiteStoreType, + destinationOptions: nil + ) + ) { error in + XCTAssertTrue( + self.flattenedErrorDescriptions(error).contains { + $0.contains("Can't find migrated CDAsset destination instance") + }, + "Expected the missing destination association error, got \(error)" + ) + } + } + + func testPerformMigration_whenVersion3ContainsOrphanAsset_thenPreservesItUnattached() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertLegacyChainGraph(in: context, model: sourceModel) + try self.insertLegacyOrphanAsset(in: context, model: sourceModel) + } + + try makeMigrator().performMigration() + + let targetModel = try model(for: .version8) + try inspectStore(at: storeURL, model: targetModel) { context in + let assets = try context.fetch( + NSFetchRequest(entityName: "CDAsset") + ) + let chain = try XCTUnwrap( + try context.fetch( + NSFetchRequest(entityName: "CDChain") + ).first + ) + let attachedAssets = try XCTUnwrap( + chain.value(forKey: "assets") as? Set + ) + let orphanAsset = try XCTUnwrap( + assets.first { + $0.value(forKey: "id") as? String == "orphan-asset" + } + ) + + XCTAssertEqual(assets.count, 2) + XCTAssertEqual(attachedAssets.count, 1) + XCTAssertFalse(attachedAssets.contains(orphanAsset)) + XCTAssertNil(orphanAsset.value(forKey: "chain")) + XCTAssertEqual(orphanAsset.value(forKey: "symbol") as? String, "ORP") + } + } + + func testPerformMigration_whenRequiredCustomMappingIsMissing_thenThrowsBeforeCheckpoint() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem( + identifier: "required-mapping", + in: context, + model: sourceModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let modelOnlyBundle = try makeModelBundle() + let migrator = makeMigrator(modelBundle: modelOnlyBundle) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case let .mappingUnavailable(source, destination, _) = migrationError + else { + return XCTFail("Expected mappingUnavailable, got \(error)") + } + + XCTAssertEqual(source, .version3) + XCTAssertEqual(destination, .version4) + } + + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + } + + func testBundledRequiredCustomMappings_matchCurrentModelsAndPolicies() throws { + let cases: [ + ( + source: SubstrateStorageVersion, + destination: SubstrateStorageVersion, + resourceName: String, + policyClassName: String + ) + ] = [ + ( + .version1, + .version2, + "SubstrateV2Mapping", + NSStringFromClass(ChainSubstrateV2MigrationPolicy.self) + ), + ( + .version3, + .version4, + "SubstrateV3toV4", + NSStringFromClass(ChainModelV4MigrationPolicy.self) + ) + ] + + for testCase in cases { + let sourceModel = try model(for: testCase.source) + let destinationModel = try model(for: testCase.destination) + let mappingURL = try XCTUnwrap( + appBundle.url( + forResource: testCase.resourceName, + withExtension: "cdm" + ) + ) + let namedMapping = try XCTUnwrap(NSMappingModel(contentsOf: mappingURL)) + let selectedMapping = NSMappingModel( + from: [appBundle], + forSourceModel: sourceModel, + destinationModel: destinationModel + ) + + XCTAssertNotNil( + selectedMapping, + "\(testCase.resourceName) is not compatible with its current models" + ) + + for entityMapping in namedMapping.entityMappings { + if let sourceEntityName = entityMapping.sourceEntityName { + XCTAssertEqual( + entityMapping.sourceEntityVersionHash, + sourceModel.entitiesByName[sourceEntityName]?.versionHash, + "\(testCase.resourceName) has a stale \(sourceEntityName) source hash" + ) + } + + if let destinationEntityName = entityMapping.destinationEntityName { + XCTAssertEqual( + entityMapping.destinationEntityVersionHash, + destinationModel.entitiesByName[destinationEntityName]?.versionHash, + "\(testCase.resourceName) has a stale \(destinationEntityName) destination hash" + ) + } + } + + let chainMapping = try XCTUnwrap( + namedMapping.entityMappings.first { + $0.sourceEntityName == "CDChain" && + $0.destinationEntityName == "CDChain" + } + ) + XCTAssertEqual( + chainMapping.entityMigrationPolicyClassName, + testCase.policyClassName + ) + } + } + + func testSyncMigration_whenKnownStoreHasZeroProtectedFootprint_thenQuarantinesOnlySubstrateFamily() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem( + identifier: "rebuildable-runtime", + in: context, + model: sourceModel + ) + _ = try self.insertChainWithDefaultNode( + in: context, + model: sourceModel + ) + } + let substrateBefore = try durableStoreFamilySnapshot(at: storeURL) + + let userStoreURL = testDirectory.appendingPathComponent("UserDataModel.sqlite") + let userWALURL = URL(fileURLWithPath: userStoreURL.path + "-wal") + let userSHMURL = URL(fileURLWithPath: userStoreURL.path + "-shm") + let userJournalURL = URL(fileURLWithPath: userStoreURL.path + "-journal") + let userStoreBytes = Data("wallet-store-must-not-move".utf8) + let userWALBytes = Data("wallet-wal-must-not-move".utf8) + let userSHMBytes = Data("wallet-shm-must-not-move".utf8) + let userJournalBytes = Data("wallet-journal-must-not-move".utf8) + try userStoreBytes.write(to: userStoreURL, options: .atomic) + try userWALBytes.write(to: userWALURL, options: .atomic) + try userSHMBytes.write(to: userSHMURL, options: .atomic) + try userJournalBytes.write(to: userJournalURL, options: .atomic) + + let modelOnlyBundle = try makeModelBundle() + let migrator = makeMigrator(modelBundle: modelOnlyBundle) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case let .mappingUnavailable(source, destination, _) = migrationError + else { + return XCTFail("Expected mappingUnavailable, got \(error)") + } + + XCTAssertEqual(source, .version3) + XCTAssertEqual(destination, .version4) + } + + try migrator.migrate() + + XCTAssertFalse(FileManager.default.fileExists(atPath: storeURL.path)) + XCTAssertFalse(migrator.requiresMigration()) + XCTAssertEqual(try Data(contentsOf: userStoreURL), userStoreBytes) + XCTAssertEqual(try Data(contentsOf: userWALURL), userWALBytes) + XCTAssertEqual(try Data(contentsOf: userSHMURL), userSHMBytes) + XCTAssertEqual(try Data(contentsOf: userJournalURL), userJournalBytes) + + let recoveryDirectory = try XCTUnwrap(try recoveryDirectories().first) + let recoveredStoreURL = recoveryDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: recoveredStoreURL), + substrateBefore + ) + + try migrator.migrate() + XCTAssertEqual(try recoveryDirectories(), [recoveryDirectory]) + XCTAssertEqual(try Data(contentsOf: userStoreURL), userStoreBytes) + XCTAssertEqual(try Data(contentsOf: userWALURL), userWALBytes) + XCTAssertEqual(try Data(contentsOf: userSHMURL), userSHMBytes) + XCTAssertEqual(try Data(contentsOf: userJournalURL), userJournalBytes) + } + + func testSyncMigration_whenCheckpointFailsWithZeroProtectedData_thenQuarantinesExactSourceFamily() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem( + identifier: "checkpoint-rebuildable-runtime", + in: context, + model: sourceModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator( + checkpointStoreHook: { _, _ in + throw InjectedSubstrateCheckpointError.failure + } + ) + + try migrator.migrate() + + XCTAssertFalse(FileManager.default.fileExists(atPath: storeURL.path)) + let recoveryDirectory = try XCTUnwrap(try recoveryDirectories().first) + let recoveredStoreURL = recoveryDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: recoveredStoreURL), + before + ) + } + + func testSyncMigration_whenCheckpointFailsWithProtectedData_thenBlocksRecoveryAndPreservesSource() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + let contact = try self.insert( + entityName: "CDContact", + in: context, + model: sourceModel + ) + contact.setValue("Checkpoint User", forKey: "name") + contact.setValue("5CheckpointProtected", forKey: "address") + contact.setValue("checkpoint-chain", forKey: "chainId") + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var checkpointCount = 0 + let migrator = makeMigrator( + checkpointStoreHook: { _, _ in + checkpointCount += 1 + throw InjectedSubstrateCheckpointError.failure + } + ) + + XCTAssertThrowsError(try migrator.migrate()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case let .cacheRecoveryBlockedByProtectedData( + blockedURL, + originalError, + counts + ) = migrationError + else { + return XCTFail("Expected cacheRecoveryBlockedByProtectedData, got \(error)") + } + + XCTAssertEqual(blockedURL, self.storeURL) + XCTAssertEqual( + counts.filter { $0.value > 0 }, + ["CDContact": 1] + ) + guard + let originalMigrationError = + originalError as? SubstrateStorageMigrationError, + case .walCheckpointFailed = originalMigrationError + else { + return XCTFail("Expected walCheckpointFailed, got \(originalError)") + } + } + + XCTAssertEqual(checkpointCount, 1) + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertTrue(try recoveryDirectories().isEmpty) + } + + func testSyncMigration_whenCheckpointFails_thenFinalRecoveryInspectionNeverCheckpointsAgain() throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem( + identifier: "single-checkpoint-runtime", + in: context, + model: sourceModel + ) + } + var checkpointCount = 0 + let migrator = makeMigrator( + checkpointStoreHook: { _, _ in + checkpointCount += 1 + throw InjectedSubstrateCheckpointError.failure + } + ) + + try migrator.migrate() + + XCTAssertEqual( + checkpointCount, + 1, + "The final protected-data inspection must not re-enter checkpointing" + ) + XCTAssertFalse(FileManager.default.fileExists(atPath: storeURL.path)) + XCTAssertEqual(try recoveryDirectories().count, 1) + } + + func testCacheRecoveryTransaction_whenInterruptedAtEveryDurableBoundary_thenRelaunchConvergesExactly() throws { + let boundaries: [SubstrateCacheRecoveryBoundary] = [ + .markerPersisted, + .familyMemberMoved(""), + .familyMemberMoved("-wal"), + .familyMemberMoved("-shm"), + .familyMemberMoved("-journal"), + .markerRemoved + ] + + for (index, boundary) in boundaries.enumerated() { + let caseDirectory = testDirectory.appendingPathComponent( + "interruption-\(index)", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: caseDirectory, + withIntermediateDirectories: false + ) + let caseStoreURL = caseDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + let expectedFamily = try writeSyntheticStoreFamily( + at: caseStoreURL, + discriminator: UInt8(index) + ) + var interruptionWasInjected = false + let interruptedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default, + boundaryHook: { reachedBoundary in + guard + reachedBoundary == boundary, + !interruptionWasInjected + else { + return + } + + interruptionWasInjected = true + throw SubstrateCacheRecoveryInterruption + .simulatedProcessDeath + } + ) + + XCTAssertThrowsError( + try interruptedTransaction.quarantine(), + "Expected simulated process death at \(boundary)" + ) { error in + guard error is SubstrateCacheRecoveryInterruption else { + return XCTFail( + "Expected cache-recovery interruption, got \(error)" + ) + } + } + XCTAssertTrue(interruptionWasInjected) + + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default + ) + _ = try relaunchedTransaction.reconcile() + + XCTAssertTrue( + try durableStoreFamilySnapshot( + at: caseStoreURL + ).isEmpty, + "Live family survived relaunch after \(boundary)" + ) + let recoveryDirectories = try contents( + of: relaunchedTransaction.recoveryRootURL + ) + let recoveryDirectory = try XCTUnwrap( + recoveryDirectories.first + ) + XCTAssertEqual(recoveryDirectories.count, 1) + XCTAssertEqual( + try durableStoreFamilySnapshot( + at: recoveryDirectory.appendingPathComponent( + caseStoreURL.lastPathComponent + ) + ), + expectedFamily, + "Quarantine changed bytes after \(boundary)" + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: recoveryDirectory + .appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + + XCTAssertNil(try relaunchedTransaction.reconcile()) + XCTAssertEqual( + try contents( + of: relaunchedTransaction.recoveryRootURL + ), + recoveryDirectories + ) + } + } + + func testCacheRecoveryTransaction_whenPreparationIsMarkerlessOrOnlyPending_thenRelaunchCleansItWithoutMovingLiveFamily() throws { + for containsPendingMarker in [false, true] { + let caseDirectory = testDirectory.appendingPathComponent( + containsPendingMarker ? "pending-marker" : "empty-marker", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: caseDirectory, + withIntermediateDirectories: false + ) + let caseStoreURL = caseDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + let expectedFamily = try writeSyntheticStoreFamily( + at: caseStoreURL, + discriminator: containsPendingMarker ? 0xB1 : 0xB0 + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default + ) + let preparationURL = transaction.recoveryRootURL + .appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: preparationURL, + withIntermediateDirectories: true + ) + if containsPendingMarker { + try Data("partial marker".utf8).write( + to: preparationURL.appendingPathComponent( + "recovery-transaction.pending" + ) + ) + } + + XCTAssertNil(try transaction.reconcile()) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: caseStoreURL), + expectedFamily + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: transaction.recoveryRootURL.path + ) + ) + } + } + + func testPerformMigrationWithRecovery_whenCacheQuarantineLostMainStore_thenReconcilesBeforeLiveStoreSafetyCheck() throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertRuntimeItem( + identifier: "interrupted-recovery-runtime", + in: context, + model: sourceModel + ) + } + try Data("recovery-wal".utf8).write( + to: URL(fileURLWithPath: storeURL.path + "-wal") + ) + try Data("recovery-shm".utf8).write( + to: URL(fileURLWithPath: storeURL.path + "-shm") + ) + let before = try durableStoreFamilySnapshot(at: storeURL) + let interruptedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + boundaryHook: { boundary in + guard boundary == .familyMemberMoved("") else { + return + } + throw SubstrateCacheRecoveryInterruption + .simulatedProcessDeath + } + ) + + XCTAssertThrowsError( + try interruptedTransaction.quarantine() + ) + XCTAssertFalse( + FileManager.default.fileExists(atPath: storeURL.path) + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: storeURL.path + "-wal" + ) + ) + + let migrator = makeMigrator() + XCTAssertNil(try migrator.performMigrationWithRecovery()) + XCTAssertTrue( + try durableStoreFamilySnapshot(at: storeURL).isEmpty + ) + let recoveryDirectory = try XCTUnwrap( + try recoveryDirectories().first + ) + XCTAssertEqual( + try durableStoreFamilySnapshot( + at: recoveryDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + ), + before + ) + } + + func testPerformMigration_whenDeployedLegacyRecoveryMovedRealSQLiteMain_thenRestoresBeforeStoreSafetyAndPreservesRowsAndWAL() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + try self.insertRuntimeItem( + identifier: "legacy-real-sqlite-runtime", + in: context, + model: currentModel + ) + } + try installRealSQLiteFamilyWithUncheckpointedWAL( + at: storeURL + ) + let before = try durableStoreFamilySnapshot(at: storeURL) + XCTAssertNotNil(before[storeURL.lastPathComponent + "-wal"]) + XCTAssertNotNil(before[storeURL.lastPathComponent + "-shm"]) + + let recoveryRootURL = testDirectory.appendingPathComponent( + "SubstrateStoreRecovery", + isDirectory: true + ) + let legacyArchiveURL = recoveryRootURL.appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: legacyArchiveURL, + withIntermediateDirectories: true + ) + try FileManager.default.moveItem( + at: storeURL, + to: legacyArchiveURL.appendingPathComponent( + storeURL.lastPathComponent + ) + ) + XCTAssertFalse( + FileManager.default.fileExists(atPath: storeURL.path) + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: storeURL.path + "-wal" + ) + ) + + try makeMigrator().performMigration() + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before + ) + XCTAssertEqual( + try Data( + contentsOf: legacyArchiveURL.appendingPathComponent( + storeURL.lastPathComponent + ) + ), + before[storeURL.lastPathComponent] + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: legacyArchiveURL.appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + XCTAssertEqual( + try count( + entityName: "CDRuntimeMetadataItem", + at: storeURL, + model: currentModel + ), + 1 + ) + XCTAssertEqual( + try sqliteInteger( + "SELECT COUNT(*) FROM ZFEARLESSRECOVERYPROBE", + at: storeURL + ), + 1 + ) + } + + func testCacheRecoveryTransaction_whenActiveTreeContainsUnknownFile_thenFailsClosedWithoutMovingFamily() throws { + let expectedFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xC1 + ) + let transactionDirectory = try interruptCacheRecovery( + at: .markerPersisted + ) + let unexpectedURL = transactionDirectory + .appendingPathComponent("unexpected") + let unexpectedData = Data("must remain".utf8) + try unexpectedData.write(to: unexpectedURL) + + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default + ) + XCTAssertThrowsError(try relaunchedTransaction.reconcile()) { + error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case .unsafeDirectory = transactionError + else { + return XCTFail("Expected unsafeDirectory, got \(error)") + } + } + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + expectedFamily + ) + XCTAssertEqual(try Data(contentsOf: unexpectedURL), unexpectedData) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: transactionDirectory + .appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + } + + func testCacheRecoveryTransaction_whenLiveFamilyChangesAfterMarker_thenFailsClosedWithoutMovingAnything() throws { + _ = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xC2 + ) + let transactionDirectory = try interruptCacheRecovery( + at: .markerPersisted + ) + let changedData = Data("externally changed main store".utf8) + try changedData.write(to: storeURL) + + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default + ) + XCTAssertThrowsError(try relaunchedTransaction.reconcile()) { + error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case .familyMismatch = transactionError + else { + return XCTFail("Expected familyMismatch, got \(error)") + } + } + + XCTAssertEqual(try Data(contentsOf: storeURL), changedData) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: storeURL.path + "-wal" + ) + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: transactionDirectory + .appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + } + + func testCacheRecoveryTransaction_whenMovedMemberChanges_thenFailsClosedAndKeepsDurableMarker() throws { + _ = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xC3 + ) + let transactionDirectory = try interruptCacheRecovery( + at: .familyMemberMoved("") + ) + let quarantinedStoreURL = transactionDirectory + .appendingPathComponent(storeURL.lastPathComponent) + let changedData = Data("changed quarantine member".utf8) + try changedData.write(to: quarantinedStoreURL) + + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default + ) + XCTAssertThrowsError(try relaunchedTransaction.reconcile()) { + error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case .familyMismatch = transactionError + else { + return XCTFail("Expected familyMismatch, got \(error)") + } + } + + XCTAssertEqual( + try Data(contentsOf: quarantinedStoreURL), + changedData + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: storeURL.path + "-wal" + ) + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: transactionDirectory + .appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + } + + func testCacheRecoveryTransaction_whenSourceContainsSymlinkOrHardlink_thenRejectsBeforeCreatingMarker() throws { + let outsideURL = testDirectory.appendingPathComponent("outside") + let outsideData = Data("outside-must-remain".utf8) + try outsideData.write(to: outsideURL) + + let symlinkDirectory = testDirectory.appendingPathComponent( + "symlink-family", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: symlinkDirectory, + withIntermediateDirectories: false + ) + let symlinkStoreURL = symlinkDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + try Data("main".utf8).write(to: symlinkStoreURL) + try FileManager.default.createSymbolicLink( + atPath: symlinkStoreURL.path + "-wal", + withDestinationPath: outsideURL.path + ) + + let symlinkTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: symlinkStoreURL, + fileManager: .default + ) + XCTAssertThrowsError(try symlinkTransaction.quarantine()) { + error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case .unsafeFile = transactionError + else { + return XCTFail("Expected unsafeFile, got \(error)") + } + } + XCTAssertFalse( + FileManager.default.fileExists( + atPath: symlinkTransaction.recoveryRootURL.path + ) + ) + + let hardlinkDirectory = testDirectory.appendingPathComponent( + "hardlink-family", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: hardlinkDirectory, + withIntermediateDirectories: false + ) + let hardlinkStoreURL = hardlinkDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + try Data("hardlinked".utf8).write(to: hardlinkStoreURL) + try FileManager.default.linkItem( + at: hardlinkStoreURL, + to: URL(fileURLWithPath: hardlinkStoreURL.path + "-wal") + ) + + let hardlinkTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: hardlinkStoreURL, + fileManager: .default + ) + XCTAssertThrowsError(try hardlinkTransaction.quarantine()) { + error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case .unsafeFile = transactionError + else { + return XCTFail("Expected unsafeFile, got \(error)") + } + } + XCTAssertFalse( + FileManager.default.fileExists( + atPath: hardlinkTransaction.recoveryRootURL.path + ) + ) + XCTAssertEqual(try Data(contentsOf: outsideURL), outsideData) + } + + func testCacheRecoveryTransaction_whenMarkerIsNoncanonicalOrOversized_thenFailsClosedAndPreservesLiveFamily() throws { + for markerMutation in ["noncanonical", "oversized"] { + let caseDirectory = testDirectory.appendingPathComponent( + markerMutation, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: caseDirectory, + withIntermediateDirectories: false + ) + let caseStoreURL = caseDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + let expectedFamily = try writeSyntheticStoreFamily( + at: caseStoreURL, + discriminator: + markerMutation == "noncanonical" ? 0xD1 : 0xD2 + ) + let transactionDirectory = try interruptCacheRecovery( + storeURL: caseStoreURL, + at: .markerPersisted + ) + let markerURL = transactionDirectory.appendingPathComponent( + "recovery-transaction" + ) + if markerMutation == "noncanonical" { + var marker = try Data(contentsOf: markerURL) + marker.append(Data("\n".utf8)) + try marker.write(to: markerURL) + } else { + try Data(repeating: 0x41, count: 4 * 1024 + 1) + .write(to: markerURL) + } + + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default + ) + XCTAssertThrowsError( + try relaunchedTransaction.reconcile() + ) { error in + guard + let transactionError = + error as? + SubstrateCacheRecoveryTransactionError + else { + return XCTFail( + "Expected recovery transaction error, got \(error)" + ) + } + + if markerMutation == "noncanonical" { + guard case .invalidMarker = transactionError else { + return XCTFail( + "Expected invalidMarker, got \(error)" + ) + } + } else { + guard case .markerTooLarge = transactionError else { + return XCTFail( + "Expected markerTooLarge, got \(error)" + ) + } + } + } + XCTAssertEqual( + try durableStoreFamilySnapshot(at: caseStoreURL), + expectedFamily + ) + } + } + + func testCacheRecoveryTransaction_whenLegacyMarkerlessMoveStoppedAtEveryBoundary_thenAdoptsDurablyAndConverges() throws { + let suffixes = ["", "-wal", "-shm", "-journal"] + + for movedMemberCount in 1 ... suffixes.count { + let caseDirectory = testDirectory.appendingPathComponent( + "legacy-boundary-\(movedMemberCount)", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: caseDirectory, + withIntermediateDirectories: false + ) + let caseStoreURL = caseDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + let expectedFamily = try writeSyntheticStoreFamily( + at: caseStoreURL, + discriminator: UInt8(0xE0 + movedMemberCount) + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default + ) + let legacyArchiveURL = transaction.recoveryRootURL + .appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: legacyArchiveURL, + withIntermediateDirectories: true + ) + + for suffix in suffixes.prefix(movedMemberCount) { + let sourceURL = URL( + fileURLWithPath: caseStoreURL.path + suffix + ) + try FileManager.default.moveItem( + at: sourceURL, + to: legacyArchiveURL.appendingPathComponent( + sourceURL.lastPathComponent + ) + ) + } + + _ = try transaction.reconcile() + + let archivedStoreURL = legacyArchiveURL + .appendingPathComponent( + caseStoreURL.lastPathComponent + ) + if movedMemberCount == suffixes.count { + XCTAssertTrue( + try durableStoreFamilySnapshot( + at: caseStoreURL + ).isEmpty + ) + XCTAssertEqual( + try durableStoreFamilySnapshot( + at: archivedStoreURL + ), + expectedFamily + ) + } else { + XCTAssertEqual( + try durableStoreFamilySnapshot( + at: caseStoreURL + ), + expectedFamily, + "Legacy split \(movedMemberCount) was not restored" + ) + XCTAssertEqual( + Set( + try durableStoreFamilySnapshot( + at: archivedStoreURL + ).keys + ), + Set( + suffixes.prefix(movedMemberCount).map { + caseStoreURL.lastPathComponent + $0 + } + ) + ) + } + XCTAssertFalse( + FileManager.default.fileExists( + atPath: legacyArchiveURL + .appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + XCTAssertNil(try transaction.reconcile()) + } + } + + func testCacheRecoveryTransaction_whenLegacyAdoptionMarkerWriteWasInterrupted_thenRemovesOnlyPendingMarkerAndConverges() throws { + let expectedFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xE9 + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default + ) + let legacyArchiveURL = transaction.recoveryRootURL + .appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: legacyArchiveURL, + withIntermediateDirectories: true + ) + let mainSourceURL = storeURL + try FileManager.default.moveItem( + at: mainSourceURL, + to: legacyArchiveURL.appendingPathComponent( + mainSourceURL.lastPathComponent + ) + ) + try Data("partial durable adoption marker".utf8).write( + to: legacyArchiveURL.appendingPathComponent( + "recovery-transaction.pending" + ) + ) + + _ = try transaction.reconcile() + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + expectedFamily + ) + XCTAssertEqual( + Set( + try durableStoreFamilySnapshot( + at: legacyArchiveURL.appendingPathComponent( + storeURL.lastPathComponent + ) + ).keys + ), + [storeURL.lastPathComponent] + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: legacyArchiveURL + .appendingPathComponent( + "recovery-transaction.pending" + ).path + ) + ) + } + + func testCacheRecoveryTransaction_whenLegacyRestorationIsInterruptedAtEveryDurableBoundary_thenRelaunchConverges() throws { + let boundaries: [SubstrateCacheRecoveryBoundary] = [ + .markerPersisted, + .legacyFamilyMemberRestored(""), + .legacyFamilyMemberRestored("-wal"), + .markerRemoved + ] + + for (index, boundary) in boundaries.enumerated() { + let caseDirectory = testDirectory.appendingPathComponent( + "legacy-restore-interruption-\(index)", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: caseDirectory, + withIntermediateDirectories: false + ) + let caseStoreURL = caseDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + let expectedFamily = try writeSyntheticStoreFamily( + at: caseStoreURL, + discriminator: UInt8(0xF0 + index) + ) + let recoveryRootURL = caseDirectory.appendingPathComponent( + "SubstrateStoreRecovery", + isDirectory: true + ) + let archiveURL = recoveryRootURL.appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: archiveURL, + withIntermediateDirectories: true + ) + for suffix in ["", "-wal"] { + let sourceURL = URL( + fileURLWithPath: caseStoreURL.path + suffix + ) + try FileManager.default.moveItem( + at: sourceURL, + to: archiveURL.appendingPathComponent( + sourceURL.lastPathComponent + ) + ) + } + + var interruptionWasInjected = false + let interruptedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default, + boundaryHook: { reachedBoundary in + guard + reachedBoundary == boundary, + !interruptionWasInjected + else { + return + } + interruptionWasInjected = true + throw SubstrateCacheRecoveryInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try interruptedTransaction.reconcile() + ) { error in + guard error is SubstrateCacheRecoveryInterruption else { + return XCTFail( + "Expected cache-recovery interruption, got \(error)" + ) + } + } + XCTAssertTrue(interruptionWasInjected) + + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default + ) + _ = try relaunchedTransaction.reconcile() + XCTAssertEqual( + try durableStoreFamilySnapshot(at: caseStoreURL), + expectedFamily, + "Legacy restoration changed bytes after \(boundary)" + ) + XCTAssertEqual( + Set( + try durableStoreFamilySnapshot( + at: archiveURL.appendingPathComponent( + caseStoreURL.lastPathComponent + ) + ).keys + ), + [ + caseStoreURL.lastPathComponent, + caseStoreURL.lastPathComponent + "-wal" + ] + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: archiveURL.appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + XCTAssertNil(try relaunchedTransaction.reconcile()) + } + } + + func testCacheRecoveryTransaction_whenLegacyTemporaryFileSynchronizationFails_thenRelaunchResynchronizesBeforeInstall() throws { + let expectedFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xF8 + ) + let recoveryRootURL = testDirectory.appendingPathComponent( + "SubstrateStoreRecovery", + isDirectory: true + ) + let archiveURL = recoveryRootURL.appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: archiveURL, + withIntermediateDirectories: true + ) + try FileManager.default.moveItem( + at: storeURL, + to: archiveURL.appendingPathComponent( + storeURL.lastPathComponent + ) + ) + var synchronizationFailureWasInjected = false + let interruptedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + restorationTemporaryFileSynchronizationHook: { + _ in + guard !synchronizationFailureWasInjected else { + return + } + synchronizationFailureWasInjected = true + throw CocoaError(.fileWriteUnknown) + } + ) + + XCTAssertThrowsError( + try interruptedTransaction.reconcile() + ) + XCTAssertTrue(synchronizationFailureWasInjected) + XCTAssertFalse( + FileManager.default.fileExists(atPath: storeURL.path) + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: archiveURL.appendingPathComponent( + "main.cache-recovery-restore.pending" + ).path + ) + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: archiveURL.appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default + ) + _ = try relaunchedTransaction.reconcile() + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + expectedFamily + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: archiveURL.appendingPathComponent( + "main.cache-recovery-restore.pending" + ).path + ) + ) + } + + func testCacheRecoveryTransaction_whenFinalQuarantineDirectorySynchronizationFails_thenRetryResynchronizesBothDirectoriesBeforeCommit() throws { + let expectedFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xF9 + ) + let suffixes = ["", "-wal", "-shm", "-journal"] + let databaseDirectoryURL = storeURL.deletingLastPathComponent() + .standardizedFileURL + var synchronizationFailureWasInjected = false + var failedTransactionDirectoryURL: URL? + let interruptedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + directorySynchronizationHook: { directoryURL in + guard + !synchronizationFailureWasInjected, + suffixes.allSatisfy({ suffix in + let liveURL = URL( + fileURLWithPath: self.storeURL.path + suffix + ) + let archivedURL = directoryURL + .appendingPathComponent( + self.storeURL.lastPathComponent + suffix + ) + return !FileManager.default.fileExists( + atPath: liveURL.path + ) && FileManager.default.fileExists( + atPath: archivedURL.path + ) + }) + else { + return + } + + synchronizationFailureWasInjected = true + failedTransactionDirectoryURL = + directoryURL.standardizedFileURL + throw CocoaError(.fileWriteUnknown) + } + ) + + XCTAssertThrowsError(try interruptedTransaction.quarantine()) { + error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case let .directorySynchronizationFailed( + failedURL, + _ + ) = transactionError + else { + return XCTFail( + "Expected directorySynchronizationFailed, got \(error)" + ) + } + XCTAssertEqual( + failedURL.standardizedFileURL, + failedTransactionDirectoryURL + ) + } + XCTAssertTrue(synchronizationFailureWasInjected) + let transactionDirectoryURL = try XCTUnwrap( + failedTransactionDirectoryURL + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: transactionDirectoryURL.appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + XCTAssertTrue( + try durableStoreFamilySnapshot(at: storeURL).isEmpty + ) + + var retrySynchronizationURLs: [URL] = [] + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + directorySynchronizationHook: { directoryURL in + retrySynchronizationURLs.append( + directoryURL.standardizedFileURL + ) + } + ) + _ = try relaunchedTransaction.reconcile() + + XCTAssertEqual( + retrySynchronizationURLs, + [ + transactionDirectoryURL, + databaseDirectoryURL, + transactionDirectoryURL + ], + "Retry must sync destination then source before marker removal" + ) + XCTAssertEqual( + try durableStoreFamilySnapshot( + at: transactionDirectoryURL.appendingPathComponent( + storeURL.lastPathComponent + ) + ), + expectedFamily + ) + XCTAssertTrue( + try durableStoreFamilySnapshot(at: storeURL).isEmpty + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: transactionDirectoryURL.appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + } + + func testCacheRecoveryTransaction_whenFinalLegacyRestoreDirectorySynchronizationFails_thenRetryResynchronizesBothDirectoriesBeforeCommit() throws { + let expectedFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xFA + ) + let suffixes = ["", "-wal", "-shm", "-journal"] + let databaseDirectoryURL = storeURL.deletingLastPathComponent() + .standardizedFileURL + let archiveURL = testDirectory.appendingPathComponent( + "SubstrateStoreRecovery", + isDirectory: true + ).appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: archiveURL, + withIntermediateDirectories: true + ) + for suffix in ["", "-wal"] { + let sourceURL = URL( + fileURLWithPath: storeURL.path + suffix + ) + try FileManager.default.moveItem( + at: sourceURL, + to: archiveURL.appendingPathComponent( + sourceURL.lastPathComponent + ) + ) + } + + var synchronizationFailureWasInjected = false + let interruptedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + directorySynchronizationHook: { directoryURL in + guard + !synchronizationFailureWasInjected, + directoryURL.standardizedFileURL == + databaseDirectoryURL, + suffixes.allSatisfy({ suffix in + FileManager.default.fileExists( + atPath: self.storeURL.path + suffix + ) + }) + else { + return + } + + synchronizationFailureWasInjected = true + throw CocoaError(.fileWriteUnknown) + } + ) + + XCTAssertThrowsError(try interruptedTransaction.reconcile()) { + error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case let .directorySynchronizationFailed( + failedURL, + _ + ) = transactionError + else { + return XCTFail( + "Expected directorySynchronizationFailed, got \(error)" + ) + } + XCTAssertEqual( + failedURL.standardizedFileURL, + databaseDirectoryURL + ) + } + XCTAssertTrue(synchronizationFailureWasInjected) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + expectedFamily + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: archiveURL.appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + + var retrySynchronizationURLs: [URL] = [] + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + directorySynchronizationHook: { directoryURL in + retrySynchronizationURLs.append( + directoryURL.standardizedFileURL + ) + } + ) + _ = try relaunchedTransaction.reconcile() + + XCTAssertEqual( + retrySynchronizationURLs, + [ + databaseDirectoryURL, + archiveURL.standardizedFileURL, + archiveURL.standardizedFileURL + ], + "Retry must sync destination then source before marker removal" + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + expectedFamily + ) + XCTAssertEqual( + Set( + try durableStoreFamilySnapshot( + at: archiveURL.appendingPathComponent( + storeURL.lastPathComponent + ) + ).keys + ), + [ + storeURL.lastPathComponent, + storeURL.lastPathComponent + "-wal" + ] + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: archiveURL.appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + } + + func testRequiresMigration_whenCacheRecoveryMarkerIsPendingBeforeFirstMove_thenReturnsTrueForCurrentStore() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { context in + try self.insertRuntimeItem( + identifier: "pending-cache-recovery", + in: context, + model: currentModel + ) + } + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + boundaryHook: { boundary in + guard boundary == .markerPersisted else { + return + } + throw SubstrateCacheRecoveryInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError(try transaction.quarantine()) + + XCTAssertTrue(makeMigrator().requiresMigration()) + } + + func testCacheRecoveryTransaction_whenCompletedLegacyArchiveExistsBesideRebuiltLiveStore_thenLeavesBothUntouched() throws { + let liveFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xEA + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default + ) + let completedArchiveURL = transaction.recoveryRootURL + .appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: completedArchiveURL, + withIntermediateDirectories: true + ) + let archivedStoreURL = completedArchiveURL + .appendingPathComponent(storeURL.lastPathComponent) + let archivedFamily = try writeSyntheticStoreFamily( + at: archivedStoreURL, + discriminator: 0xEB + ) + + XCTAssertNil(try transaction.reconcile()) + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + liveFamily + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: archivedStoreURL), + archivedFamily + ) + } + + func testCacheRecoveryRetention_whenQuarantineCompletes_thenExcludesRootAndArchiveFromBackup() throws { + let expectedFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xA0 + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default + ) + + let archiveURL = try XCTUnwrap(transaction.quarantine()) + + XCTAssertEqual( + try durableStoreFamilySnapshot( + at: archiveURL.appendingPathComponent( + storeURL.lastPathComponent + ) + ), + expectedFamily + ) + XCTAssertEqual( + try transaction.recoveryRootURL.resourceValues( + forKeys: [.isExcludedFromBackupKey] + ).isExcludedFromBackup, + true + ) + XCTAssertEqual( + try archiveURL.resourceValues( + forKeys: [.isExcludedFromBackupKey] + ).isExcludedFromBackup, + true + ) + } + + func testCacheRecoveryRetention_whenBackupExclusionFails_thenPreservesLiveFamilyBeforeMarker() throws { + let expectedFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xA4 + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + backupExclusionHook: { url in + guard + url.lastPathComponent != + "SubstrateStoreRecovery" + else { + return + } + throw InjectedSubstrateBackupExclusionError.failure + } + ) + + XCTAssertThrowsError(try transaction.quarantine()) { error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case .backupExclusionFailed = transactionError + else { + return XCTFail( + "Expected backupExclusionFailed, got \(error)" + ) + } + } + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + expectedFamily + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: transaction.recoveryRootURL.path + ) + ) + } + + func testCacheRecoveryRetention_whenCountLimitExceeded_thenDeletesOnlyOldestCompleteFamily() throws { + let liveFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xA8 + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + backupExclusionHook: { _ in }, + retainedArchiveCount: 2, + retainedArchiveByteCount: .max + ) + let oldest = try writeCompletedRecoveryArchive( + for: transaction, + identifier: "00000000-0000-0000-0000-000000000001", + discriminator: 0xB0, + completionDate: Date(timeIntervalSince1970: 1) + ) + let middle = try writeCompletedRecoveryArchive( + for: transaction, + identifier: "00000000-0000-0000-0000-000000000002", + discriminator: 0xB4, + completionDate: Date(timeIntervalSince1970: 2) + ) + let newest = try writeCompletedRecoveryArchive( + for: transaction, + identifier: "00000000-0000-0000-0000-000000000003", + discriminator: 0xB8, + completionDate: Date(timeIntervalSince1970: 3) + ) + + XCTAssertNil(try transaction.reconcile()) + + XCTAssertFalse( + FileManager.default.fileExists(atPath: oldest.url.path) + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: middle.storeURL), + middle.family + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: newest.storeURL), + newest.family + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + liveFamily + ) + } + + func testCacheRecoveryRetention_whenByteBudgetCannotHoldArchive_thenDeletesWholeFamilyAndPreservesLiveStore() throws { + let liveFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xBC + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + backupExclusionHook: { _ in }, + retainedArchiveCount: 10, + retainedArchiveByteCount: 1 + ) + let archive = try writeCompletedRecoveryArchive( + for: transaction, + identifier: "00000000-0000-0000-0000-000000000004", + discriminator: 0xC0, + completionDate: Date(timeIntervalSince1970: 4) + ) + + XCTAssertNil(try transaction.reconcile()) + + XCTAssertFalse( + FileManager.default.fileExists(atPath: archive.url.path) + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: transaction.recoveryRootURL.path + ) + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + liveFamily + ) + } + + func testCacheRecoveryRetention_whenAnyArchiveTreeIsUnrecognized_thenFailsClosedBeforeDeletingValidArchive() throws { + let liveFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xC4 + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + backupExclusionHook: { _ in }, + retainedArchiveCount: 0, + retainedArchiveByteCount: 0 + ) + let validArchive = try writeCompletedRecoveryArchive( + for: transaction, + identifier: "00000000-0000-0000-0000-000000000005", + discriminator: 0xC8, + completionDate: Date(timeIntervalSince1970: 5) + ) + let hostileArchive = try writeCompletedRecoveryArchive( + for: transaction, + identifier: "00000000-0000-0000-0000-000000000006", + discriminator: 0xCC, + completionDate: Date(timeIntervalSince1970: 6) + ) + let hostileURL = hostileArchive.url.appendingPathComponent( + "unrecognized-user-file" + ) + let hostileData = Data("must-not-be-deleted".utf8) + try hostileData.write(to: hostileURL) + + XCTAssertThrowsError(try transaction.reconcile()) { error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case .unsafeDirectory = transactionError + else { + return XCTFail( + "Expected unsafeDirectory, got \(error)" + ) + } + } + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: validArchive.storeURL), + validArchive.family + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: hostileArchive.storeURL), + hostileArchive.family + ) + XCTAssertEqual(try Data(contentsOf: hostileURL), hostileData) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + liveFamily + ) + } + + func testCacheRecoveryRetention_whenArchiveMemberHardlinksLiveStore_thenFailsClosedWithoutUnlinkingEitherPath() throws { + let liveFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xD0 + ) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default, + backupExclusionHook: { _ in }, + retainedArchiveCount: 0, + retainedArchiveByteCount: 0 + ) + let archive = try writeCompletedRecoveryArchive( + for: transaction, + identifier: "00000000-0000-0000-0000-000000000007", + discriminator: 0xD4, + completionDate: Date(timeIntervalSince1970: 7) + ) + try FileManager.default.removeItem(at: archive.storeURL) + try FileManager.default.linkItem( + at: storeURL, + to: archive.storeURL + ) + + XCTAssertThrowsError(try transaction.reconcile()) { error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case .unsafeFile = transactionError + else { + return XCTFail( + "Expected unsafeFile, got \(error)" + ) + } + } + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + liveFamily + ) + XCTAssertEqual( + try Data(contentsOf: archive.storeURL), + try Data(contentsOf: storeURL) + ) + } + + func testCacheRecoveryRetention_whenDeletionIsInterruptedAtEveryDurableBoundary_thenRelaunchConvergesWithoutTouchingNewestOrLiveFamily() throws { + let oldestIdentifier = + "00000000-0000-0000-0000-000000000008" + let boundaries: [SubstrateCacheRecoveryBoundary] = [ + .retentionMarkerPersisted(oldestIdentifier), + .retentionFamilyMemberRemoved(oldestIdentifier, ""), + .retentionFamilyMemberRemoved(oldestIdentifier, "-wal"), + .retentionFamilyMemberRemoved(oldestIdentifier, "-shm"), + .retentionFamilyMemberRemoved( + oldestIdentifier, + "-journal" + ), + .retentionMarkerRemoved(oldestIdentifier), + .retentionArchiveRemoved(oldestIdentifier) + ] + + for (index, boundary) in boundaries.enumerated() { + let caseDirectory = testDirectory.appendingPathComponent( + "retention-interruption-\(index)", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: caseDirectory, + withIntermediateDirectories: false + ) + let caseStoreURL = caseDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + let liveFamily = try writeSyntheticStoreFamily( + at: caseStoreURL, + discriminator: UInt8(0xD8 + index) + ) + var interruptionWasInjected = false + let interruptedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default, + boundaryHook: { reachedBoundary in + guard + reachedBoundary == boundary, + !interruptionWasInjected + else { + return + } + interruptionWasInjected = true + throw SubstrateCacheRecoveryInterruption + .simulatedProcessDeath + }, + backupExclusionHook: { _ in }, + retainedArchiveCount: 1, + retainedArchiveByteCount: .max + ) + let oldest = try writeCompletedRecoveryArchive( + for: interruptedTransaction, + identifier: oldestIdentifier, + discriminator: UInt8(0xE0 + index), + completionDate: Date(timeIntervalSince1970: 8) + ) + let newest = try writeCompletedRecoveryArchive( + for: interruptedTransaction, + identifier: + "00000000-0000-0000-0000-000000000009", + discriminator: UInt8(0xE8 + index), + completionDate: Date(timeIntervalSince1970: 9) + ) + + XCTAssertThrowsError( + try interruptedTransaction.reconcile() + ) { error in + guard error is SubstrateCacheRecoveryInterruption else { + return XCTFail( + "Expected retention interruption, got \(error)" + ) + } + } + XCTAssertTrue(interruptionWasInjected) + + let relaunchedTransaction = + CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default, + backupExclusionHook: { _ in }, + retainedArchiveCount: 1, + retainedArchiveByteCount: .max + ) + XCTAssertNil(try relaunchedTransaction.reconcile()) + + XCTAssertFalse( + FileManager.default.fileExists(atPath: oldest.url.path), + "Oldest archive survived \(boundary)" + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: newest.storeURL), + newest.family, + "Newest archive changed after \(boundary)" + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: caseStoreURL), + liveFamily, + "Live family changed after \(boundary)" + ) + XCTAssertEqual( + try contents( + of: relaunchedTransaction.recoveryRootURL + ), + [newest.url] + ) + } + } + + func testCacheRecoveryTransaction_whenLegacySplitHasMultipleCandidates_thenFailsClosedWithoutChoosingArchive() throws { + let expectedFamily = try writeSyntheticStoreFamily( + at: storeURL, + discriminator: 0xEC + ) + let mainData = try Data(contentsOf: storeURL) + try FileManager.default.removeItem(at: storeURL) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: storeURL, + fileManager: .default + ) + var archiveURLs: [URL] = [] + + for _ in 0 ..< 2 { + let archiveURL = transaction.recoveryRootURL + .appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: archiveURL, + withIntermediateDirectories: true + ) + try mainData.write( + to: archiveURL.appendingPathComponent( + storeURL.lastPathComponent + ) + ) + archiveURLs.append(archiveURL) + } + let liveRemainder = try durableStoreFamilySnapshot(at: storeURL) + + XCTAssertThrowsError(try transaction.reconcile()) { error in + guard + let transactionError = + error as? SubstrateCacheRecoveryTransactionError, + case .multiplePendingTransactions = transactionError + else { + return XCTFail( + "Expected multiplePendingTransactions, got \(error)" + ) + } + } + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + liveRemainder + ) + for archiveURL in archiveURLs { + XCTAssertEqual( + try Data( + contentsOf: archiveURL.appendingPathComponent( + storeURL.lastPathComponent + ) + ), + mainData + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: archiveURL.appendingPathComponent( + "recovery-transaction" + ).path + ) + ) + } + XCTAssertEqual( + Set(expectedFamily.keys), + Set(liveRemainder.keys).union( + [storeURL.lastPathComponent] + ) + ) + } + + func testCacheRecoveryTransaction_whenLegacySplitIsTamperedOrOverlapping_thenFailsClosed() throws { + for variant in ["unknown-file", "overlapping-member"] { + let caseDirectory = testDirectory.appendingPathComponent( + variant, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: caseDirectory, + withIntermediateDirectories: false + ) + let caseStoreURL = caseDirectory.appendingPathComponent( + storeURL.lastPathComponent + ) + _ = try writeSyntheticStoreFamily( + at: caseStoreURL, + discriminator: + variant == "unknown-file" ? 0xED : 0xEE + ) + let mainData = try Data(contentsOf: caseStoreURL) + try FileManager.default.removeItem(at: caseStoreURL) + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: caseStoreURL, + fileManager: .default + ) + let archiveURL = transaction.recoveryRootURL + .appendingPathComponent( + UUID().uuidString, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: archiveURL, + withIntermediateDirectories: true + ) + try mainData.write( + to: archiveURL.appendingPathComponent( + caseStoreURL.lastPathComponent + ) + ) + + if variant == "unknown-file" { + try Data("tampered".utf8).write( + to: archiveURL.appendingPathComponent( + "unexpected" + ) + ) + } else { + let liveWALURL = URL( + fileURLWithPath: caseStoreURL.path + "-wal" + ) + try Data(contentsOf: liveWALURL).write( + to: archiveURL.appendingPathComponent( + liveWALURL.lastPathComponent + ) + ) + } + let liveBefore = try durableStoreFamilySnapshot( + at: caseStoreURL + ) + let archiveBefore = try contentsSnapshot( + of: archiveURL + ) + + XCTAssertThrowsError(try transaction.reconcile()) { + error in + guard + let transactionError = + error as? + SubstrateCacheRecoveryTransactionError, + case .familyMismatch = transactionError + else { + return XCTFail( + "Expected familyMismatch, got \(error)" + ) + } + } + + XCTAssertEqual( + try durableStoreFamilySnapshot(at: caseStoreURL), + liveBefore + ) + XCTAssertEqual( + try contentsSnapshot(of: archiveURL), + archiveBefore + ) + } + } + + func testSyncMigration_whenKnownStoreHasContact_thenBlocksRecovery() throws { + try assertProtectedDataBlocksRecovery(expectedCategory: "CDContact") { context, model in + let contact = try self.insert(entityName: "CDContact", in: context, model: model) + contact.setValue("Alice", forKey: "name") + contact.setValue("5ProtectedContact", forKey: "address") + contact.setValue("protected-chain", forKey: "chainId") + } + } + + func testSyncMigration_whenKnownStoreHasContactItem_thenBlocksRecovery() throws { + try assertProtectedDataBlocksRecovery(expectedCategory: "CDContactItem") { context, model in + let contact = try self.insert(entityName: "CDContactItem", in: context, model: model) + contact.setValue("wallet-peer", forKey: "identifier") + contact.setValue("5Peer", forKey: "peerAddress") + contact.setValue("Peer", forKey: "peerName") + contact.setValue("5Wallet", forKey: "targetAddress") + contact.setValue(Int64(1_700_000_000), forKey: "updatedAt") + } + } + + func testSyncMigration_whenKnownStoreHasTransactionHistory_thenBlocksRecovery() throws { + try assertProtectedDataBlocksRecovery( + expectedCategory: "CDTransactionHistoryItem" + ) { context, model in + let transaction = try self.insert( + entityName: "CDTransactionHistoryItem", + in: context, + model: model + ) + transaction.setValue("0xprotected", forKey: "identifier") + transaction.setValue("5Sender", forKey: "sender") + transaction.setValue("5Receiver", forKey: "receiver") + transaction.setValue(Int16(0), forKey: "status") + transaction.setValue(Int64(1_700_000_000), forKey: "timestamp") + transaction.setValue("1", forKey: "fee") + transaction.setValue("Balances", forKey: "moduleName") + transaction.setValue("transfer", forKey: "callName") + } + } + + func testSyncMigration_whenKnownStoreHasCustomNode_thenBlocksRecovery() throws { + try assertProtectedDataBlocksRecovery( + expectedCategory: "CDChain.customNodes" + ) { context, model in + let graph = try self.insertChainWithDefaultNode( + in: context, + model: model + ) + let customNode = try self.insert( + entityName: "CDChainNode", + in: context, + model: model + ) + customNode.setValue("My RPC", forKey: "name") + customNode.setValue( + try XCTUnwrap(URL(string: "wss://custom.example.invalid")), + forKey: "url" + ) + graph.chain.mutableSetValue(forKey: "customNodes").add(customNode) + } + } + + func testSyncMigration_whenKnownStoreHasSelectedDefaultNode_thenBlocksRecovery() throws { + try assertProtectedDataBlocksRecovery( + expectedCategory: "CDChain.selectedNode" + ) { context, model in + let graph = try self.insertChainWithDefaultNode( + in: context, + model: model + ) + graph.chain.setValue(graph.node, forKey: "selectedNode") + } + } + + func testSyncMigration_whenKnownStoreHasOrphanNode_thenBlocksRecovery() throws { + try assertProtectedDataBlocksRecovery( + expectedCategory: "CDChainNode.orphan" + ) { context, model in + let orphanNode = try self.insert( + entityName: "CDChainNode", + in: context, + model: model + ) + orphanNode.setValue("Unattached RPC", forKey: "name") + orphanNode.setValue( + try XCTUnwrap(URL(string: "wss://orphan.example.invalid")), + forKey: "url" + ) + } + } + + func testCallbackMigration_whenStoreIsCorrupt_thenDoesNotCompleteOrQuarantine() throws { + try Data("still-not-a-core-data-store".utf8).write(to: storeURL, options: .atomic) + let before = try durableStoreFamilySnapshot(at: storeURL) + let migrator = makeMigrator() + let completionExpectation = expectation( + description: "callback must not complete after fail-closed migration" + ) + completionExpectation.isInverted = true + + migrator.migrate { + completionExpectation.fulfill() + } + + wait(for: [completionExpectation], timeout: 0.25) + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertTrue(try recoveryDirectories().isEmpty) + } + + private func writeSyntheticStoreFamily( + at syntheticStoreURL: URL, + discriminator: UInt8 + ) throws -> [String: Data] { + let suffixes = ["", "-wal", "-shm", "-journal"] + var expected: [String: Data] = [:] + + for (index, suffix) in suffixes.enumerated() { + let byte = discriminator &+ UInt8(index) + let data = Data( + repeating: byte, + count: 37 + index * 19 + ) + let url = URL( + fileURLWithPath: syntheticStoreURL.path + suffix + ) + try data.write(to: url) + expected[url.lastPathComponent] = data + } + + return expected + } + + private func writeCompletedRecoveryArchive( + for transaction: CrashConsistentSubstrateCacheRecovery, + identifier: String, + discriminator: UInt8, + completionDate: Date + ) throws -> ( + url: URL, + storeURL: URL, + family: [String: Data] + ) { + if !FileManager.default.fileExists( + atPath: transaction.recoveryRootURL.path + ) { + try FileManager.default.createDirectory( + at: transaction.recoveryRootURL, + withIntermediateDirectories: false + ) + } + + let archiveURL = transaction.recoveryRootURL + .appendingPathComponent( + identifier, + isDirectory: true + ) + try FileManager.default.createDirectory( + at: archiveURL, + withIntermediateDirectories: false + ) + let archivedStoreURL = archiveURL.appendingPathComponent( + transaction.storeURL.lastPathComponent + ) + let family = try writeSyntheticStoreFamily( + at: archivedStoreURL, + discriminator: discriminator + ) + try FileManager.default.setAttributes( + [.modificationDate: completionDate], + ofItemAtPath: archiveURL.path + ) + + return ( + url: archiveURL, + storeURL: archivedStoreURL, + family: family + ) + } + + private func interruptCacheRecovery( + storeURL interruptedStoreURL: URL? = nil, + at boundary: SubstrateCacheRecoveryBoundary + ) throws -> URL { + let interruptedStoreURL = interruptedStoreURL ?? storeURL + let transaction = CrashConsistentSubstrateCacheRecovery( + storeURL: interruptedStoreURL, + fileManager: .default, + boundaryHook: { reachedBoundary in + guard reachedBoundary == boundary else { + return + } + throw SubstrateCacheRecoveryInterruption + .simulatedProcessDeath + } + ) + + XCTAssertThrowsError(try transaction.quarantine()) { error in + guard error is SubstrateCacheRecoveryInterruption else { + return XCTFail( + "Expected cache-recovery interruption, got \(error)" + ) + } + } + + return try XCTUnwrap( + try contents(of: transaction.recoveryRootURL).first + ) + } + + private func contents(of directoryURL: URL) throws -> [URL] { + guard FileManager.default.fileExists( + atPath: directoryURL.path + ) else { + return [] + } + + return try FileManager.default.contentsOfDirectory( + at: directoryURL, + includingPropertiesForKeys: nil + ).sorted { + $0.lastPathComponent < $1.lastPathComponent + } + } + + private func contentsSnapshot( + of directoryURL: URL + ) throws -> [String: Data] { + try Dictionary( + uniqueKeysWithValues: contents(of: directoryURL).map { + url in + (url.lastPathComponent, try Data(contentsOf: url)) + } + ) + } + + private func assertProtectedDataBlocksRecovery( + expectedCategory: String, + populate: (NSManagedObjectContext, NSManagedObjectModel) throws -> Void + ) throws { + let sourceModel = try model(for: .version3) + try createStore(at: storeURL, model: sourceModel) { context in + try populate(context, sourceModel) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + let modelOnlyBundle = try makeModelBundle() + let migrator = makeMigrator(modelBundle: modelOnlyBundle) + + for _ in 0 ..< 2 { + XCTAssertThrowsError(try migrator.migrate()) { error in + guard + let migrationError = error as? SubstrateStorageMigrationError, + case let .cacheRecoveryBlockedByProtectedData( + blockedURL, + originalError, + counts + ) = migrationError + else { + return XCTFail("Expected cacheRecoveryBlockedByProtectedData, got \(error)") + } + + XCTAssertEqual(blockedURL, self.storeURL) + XCTAssertEqual( + counts.filter { $0.value > 0 }, + [expectedCategory: 1] + ) + + guard + let originalMigrationError = originalError as? SubstrateStorageMigrationError, + case let .mappingUnavailable(source, destination, _) = + originalMigrationError + else { + return XCTFail("Expected mappingUnavailable, got \(originalError)") + } + + XCTAssertEqual(source, .version3) + XCTAssertEqual(destination, .version4) + } + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual(try durableStoreFamilySnapshot(at: storeURL), before) + XCTAssertTrue(try recoveryDirectories().isEmpty) + } + } + + private func insert( + entityName: String, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws -> NSManagedObject { + let entity = try XCTUnwrap(model.entitiesByName[entityName]) + return NSManagedObject(entity: entity, insertInto: context) + } + + private func insertStartupPayloadEntity( + entityName: String, + attributeName: String, + payload: String, + attachNodeAsCustomNode: Bool = false, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + if entityName == "CDChainNode", attachNodeAsCustomNode { + let graph = try insertChainWithDefaultNode( + in: context, + model: model + ) + let customNode = try insert( + entityName: entityName, + in: context, + model: model + ) + customNode.setValue( + try XCTUnwrap( + URL(string: "wss://custom.example.invalid") + ), + forKey: "url" + ) + customNode.setValue(payload, forKey: attributeName) + graph.chain.mutableSetValue( + forKey: "customNodes" + ).add(customNode) + return + } + + let object = try insert( + entityName: entityName, + in: context, + model: model + ) + switch entityName { + case "CDAsset": + object.setValue("a", forKey: "id") + object.setValue(Int16(1), forKey: "precision") + case "CDChainNode": + object.setValue("n", forKey: "name") + object.setValue( + try XCTUnwrap( + URL(string: "wss://node.example.invalid") + ), + forKey: "url" + ) + case "CDPriceData": + object.setValue("c", forKey: "currencyId") + object.setValue("1", forKey: "price") + object.setValue("i", forKey: "priceId") + case "CDChainXcmConfig", + "CDExternalApi", + "CDPriceProvider", + "CDXcmAvailableAsset", + "CDXcmAvailableDestination": + break + default: + XCTFail( + "Unsupported startup child fixture \(entityName)" + ) + return + } + object.setValue(payload, forKey: attributeName) + } + + private func assertStartupChildValueLimitExceeded( + entityName: String, + attributeName: String, + attachNodeAsCustomNode: Bool = false, + file: StaticString = #filePath, + line: UInt = #line + ) throws { + let maximum: UInt64 = 1_024 + let actual = maximum + 1 + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + try self.insertStartupPayloadEntity( + entityName: entityName, + attributeName: attributeName, + payload: String( + repeating: "x", + count: Int(actual) + ), + attachNodeAsCustomNode: + attachNodeAsCustomNode, + in: context, + model: currentModel + ) + } + let before = try durableStoreFamilySnapshot(at: storeURL) + var stagedHookCalled = false + var replacementCalled = false + let migrator = makeMigrator( + storeReplacer: { _, _ in + replacementCalled = true + }, + stagedStoreMutationHook: { _, _ in + stagedHookCalled = true + }, + protectedDataInspectionLimits: + makeProtectedDataLimits( + maximumStartupChildValueByteCount: maximum + ) + ) + + XCTAssertTrue( + migrator.requiresMigration(), + file: file, + line: line + ) + XCTAssertThrowsError( + try migrator.performMigration(), + file: file, + line: line + ) { error in + guard + let migrationError = + error as? SubstrateStorageMigrationError, + case let .sourceStoreInspectionFailed( + failedURL, + underlyingError + ) = migrationError, + case let .startupChildValueByteLimitExceeded( + actualEntityName, + actualAttributeName, + valueByteCount, + maximumByteCount + ) = + underlyingError as? + SubstrateProtectedDataInspectionError + else { + return XCTFail( + "Expected startup child value limit, got \(error)", + file: file, + line: line + ) + } + + XCTAssertEqual( + failedURL, + self.storeURL, + file: file, + line: line + ) + XCTAssertEqual( + actualEntityName, + entityName, + file: file, + line: line + ) + XCTAssertEqual( + actualAttributeName, + attributeName, + file: file, + line: line + ) + XCTAssertEqual( + valueByteCount, + actual, + file: file, + line: line + ) + XCTAssertEqual( + maximumByteCount, + maximum, + file: file, + line: line + ) + } + XCTAssertFalse( + stagedHookCalled, + file: file, + line: line + ) + XCTAssertFalse( + replacementCalled, + file: file, + line: line + ) + XCTAssertEqual( + try durableStoreFamilySnapshot(at: storeURL), + before, + file: file, + line: line + ) + } + + private func insertChainWithDefaultNode( + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws -> (chain: NSManagedObject, node: NSManagedObject) { + let chain = try insert(entityName: "CDChain", in: context, model: model) + chain.setValue("protected-chain", forKey: "chainId") + chain.setValue("Protected Chain", forKey: "name") + + let node = try insert(entityName: "CDChainNode", in: context, model: model) + node.setValue("Default RPC", forKey: "name") + node.setValue( + try XCTUnwrap(URL(string: "wss://default.example.invalid")), + forKey: "url" + ) + node.setValue(chain, forKey: "chain") + + return (chain, node) + } + + private func makeMigrator( + targetVersion: SubstrateStorageVersion = .version8, + modelBundle: Bundle? = nil, + storeURL: URL? = nil, + fileManager: FileManager = .default, + storeReplacer: @escaping ( + URL, + URL + ) throws -> Void = { targetURL, sourceURL in + try NSPersistentStoreCoordinator.replaceStore( + at: targetURL, + withStoreAt: sourceURL + ) + }, + stagedStoreMutationHook: @escaping ( + URL, + NSManagedObjectModel + ) throws -> Void = { _, _ in }, + checkpointStoreHook: ((URL, NSManagedObjectModel) throws -> Void)? = nil, + privateSourceCopyLimits: + SQLiteStoreFamilyCopyLimits = + .substrateStorageProduction, + privateSourceAvailableCapacityProvider: + ((URL) throws -> UInt64)? = nil, + protectedDataInspectionLimits: + SubstrateProtectedDataInspectionLimits = .production, + transformableObjectIDPageDidFetch: @escaping ( + String, + Int, + Int + ) -> Void = { _, _, _ in }, + protectedRelationshipCountDidFetch: @escaping ( + NSManagedObject, + String, + Int + ) -> Void = { _, _, _ in }, + protectedRelationshipWillMaterialize: @escaping ( + String, + String, + Int + ) -> Void = { _, _, _ in } + ) -> SubstrateStorageMigrator { + SubstrateStorageMigrator( + targetVersion: targetVersion, + storeURL: storeURL ?? self.storeURL, + modelDirectory: SubstrateStorageParams.modelDirectory, + fileManager: fileManager, + modelBundle: modelBundle ?? appBundle, + storeReplacer: storeReplacer, + stagedStoreMutationHook: stagedStoreMutationHook, + checkpointStoreHook: checkpointStoreHook, + privateSourceCopyLimits: privateSourceCopyLimits, + privateSourceAvailableCapacityProvider: + privateSourceAvailableCapacityProvider, + protectedDataInspectionLimits: + protectedDataInspectionLimits, + transformableObjectIDPageDidFetch: + transformableObjectIDPageDidFetch, + protectedRelationshipCountDidFetch: + protectedRelationshipCountDidFetch, + protectedRelationshipWillMaterialize: + protectedRelationshipWillMaterialize + ) + } + + private func makeProtectedDataLimits( + fetchPageSize: Int = 16, + maximumRowsPerEntity: Int = 100, + maximumTotalRows: Int = 500, + maximumStartupRootRowsPerEntity: Int = 4_096, + maximumStartupRootPayloadByteCount: UInt64 = + 256 * 1024 * 1024, + maximumStartupChildValueByteCount: UInt64 = + 256 * 1024, + maximumStartupChildPayloadByteCount: UInt64 = + 256 * 1024 * 1024, + maximumRelationshipMembers: Int = 100, + maximumTotalRelationshipMembers: Int = 500, + maximumTransformableElements: Int = 100, + maximumTransformableArchiveByteCount: Int = 8_192, + maximumValueByteCount: Int = 1_024, + maximumRecordByteCount: Int = 8_192 + ) -> SubstrateProtectedDataInspectionLimits { + SubstrateProtectedDataInspectionLimits( + fetchPageSize: fetchPageSize, + maximumRowsPerEntity: maximumRowsPerEntity, + maximumTotalRows: maximumTotalRows, + maximumStartupRootRowsPerEntity: + maximumStartupRootRowsPerEntity, + maximumStartupRootPayloadByteCount: + maximumStartupRootPayloadByteCount, + maximumStartupChildValueByteCount: + maximumStartupChildValueByteCount, + maximumStartupChildPayloadByteCount: + maximumStartupChildPayloadByteCount, + maximumRelationshipMembers: + maximumRelationshipMembers, + maximumTotalRelationshipMembers: + maximumTotalRelationshipMembers, + maximumTransformableElements: + maximumTransformableElements, + maximumTransformableArchiveByteCount: + maximumTransformableArchiveByteCount, + maximumValueByteCount: maximumValueByteCount, + maximumRecordByteCount: maximumRecordByteCount + ) + } + + private func model( + for version: SubstrateStorageVersion, + in bundle: Bundle? = nil + ) throws -> NSManagedObjectModel { + let bundle = bundle ?? appBundle + let modelURL = bundle.url( + forResource: version.rawValue, + withExtension: "omo", + subdirectory: SubstrateStorageParams.modelDirectory + ) ?? bundle.url( + forResource: version.rawValue, + withExtension: "mom", + subdirectory: SubstrateStorageParams.modelDirectory + ) + + return try XCTUnwrap( + modelURL.flatMap(NSManagedObjectModel.init(contentsOf:)), + "Unable to load \(version.rawValue) from \(bundle.bundleURL.path)" + ) + } + + private func createStore( + at url: URL, + model: NSManagedObjectModel, + populate: (NSManagedObjectContext) throws -> Void + ) throws { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSSQLitePragmasOption: ["journal_mode": "WAL"], + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + var populationError: Error? + context.performAndWait { + do { + try populate(context) + if context.hasChanges { + try context.save() + } + } catch { + populationError = error + } + } + + if let populationError { + throw populationError + } + } + + @discardableResult + private func insertRuntimeItem( + identifier: String, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws -> NSManagedObject { + let entity = try XCTUnwrap(model.entitiesByName["CDRuntimeMetadataItem"]) + let item = NSManagedObject(entity: entity, insertInto: context) + item.setValue(identifier, forKey: "identifier") + item.setValue(Int32(1), forKey: "version") + item.setValue(Int32(1), forKey: "txVersion") + return item + } + + private func insertChainStorageItem( + identifier: String, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let entity = try XCTUnwrap(model.entitiesByName["CDChainStorageItem"]) + let item = NSManagedObject(entity: entity, insertInto: context) + item.setValue(identifier, forKey: "identifier") + item.setValue(Data([0x00, 0x80, 0xFF]), forKey: "data") + } + + @discardableResult + private func insertMigrationAsset( + identifier: String, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws -> NSManagedObject { + let entity = try XCTUnwrap(model.entitiesByName["CDAsset"]) + let asset = NSManagedObject(entity: entity, insertInto: context) + asset.setValue(identifier, forKey: "id") + asset.setValue(Int16(18), forKey: "precision") + + if entity.attributesByName["chainId"] != nil { + asset.setValue("migration-fixture-chain", forKey: "chainId") + } + + if entity.attributesByName["symbol"] != nil { + asset.setValue("FIX", forKey: "symbol") + } + + return asset + } + + private func createVersion7AssetStore( + purchaseProviders: [String] + ) throws { + let sourceModel = try model(for: .version7) + try createStore(at: storeURL, model: sourceModel) { + context in + let asset = try self.insertMigrationAsset( + identifier: "bounded-transformable-asset", + in: context, + model: sourceModel + ) + asset.setValue( + NSArray(array: purchaseProviders), + forKey: "purchaseProviders" + ) + } + } + + private func createCurrentTransformableAndProtectedGraph() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + let graph = try self.insertChainWithDefaultNode( + in: context, + model: currentModel + ) + graph.chain.setValue( + NSArray(object: "safe-option"), + forKey: "options" + ) + + let customNode = try self.insert( + entityName: "CDChainNode", + in: context, + model: currentModel + ) + customNode.setValue("Custom RPC", forKey: "name") + customNode.setValue( + try XCTUnwrap( + URL(string: "wss://current-custom.example.invalid") + ), + forKey: "url" + ) + graph.chain.mutableSetValue( + forKey: "customNodes" + ).add(customNode) + graph.chain.setValue( + customNode, + forKey: "selectedNode" + ) + + let asset = try self.insertMigrationAsset( + identifier: "current-transformable-asset", + in: context, + model: currentModel + ) + asset.setValue( + NSArray(object: "safe-provider"), + forKey: "purchaseProviders" + ) + asset.setValue(graph.chain, forKey: "chain") + } + } + + private func createCurrentStartupRelationshipGraph() throws { + let currentModel = try model(for: .version8) + try createStore(at: storeURL, model: currentModel) { + context in + try self.insertRuntimeItem( + identifier: "startup-runtime", + in: context, + model: currentModel + ) + let graph = try self.insertChainWithDefaultNode( + in: context, + model: currentModel + ) + + let customNode = try self.insert( + entityName: "CDChainNode", + in: context, + model: currentModel + ) + customNode.setValue("Startup Custom RPC", forKey: "name") + customNode.setValue( + try XCTUnwrap( + URL(string: "wss://startup-custom.example.invalid") + ), + forKey: "url" + ) + graph.chain.mutableSetValue( + forKey: "customNodes" + ).add(customNode) + + let asset = try self.insertMigrationAsset( + identifier: "startup-asset", + in: context, + model: currentModel + ) + asset.setValue(graph.chain, forKey: "chain") + try self.insertPriceData( + count: 1, + for: asset, + in: context, + model: currentModel + ) + + let explorer = try self.insert( + entityName: "CDExternalApi", + in: context, + model: currentModel + ) + explorer.setValue("subscan", forKey: "type") + explorer.setValue( + "https://explorer.example.invalid", + forKey: "url" + ) + explorer.setValue(graph.chain, forKey: "chain") + + try self.insertXcmRelationshipGraph( + for: graph.chain, + in: context, + model: currentModel + ) + } + } + + private func insertPriceData( + count: Int, + for asset: NSManagedObject, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + for index in 0 ..< count { + let priceData = try insert( + entityName: "CDPriceData", + in: context, + model: model + ) + priceData.setValue( + "currency-\(index)", + forKey: "currencyId" + ) + priceData.setValue("1.0", forKey: "price") + priceData.setValue( + "price-\(index)", + forKey: "priceId" + ) + priceData.setValue(asset, forKey: "asset") + } + } + + private func insertXcmRelationshipGraph( + for chain: NSManagedObject? = nil, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let config = try insert( + entityName: "CDChainXcmConfig", + in: context, + model: model + ) + if let chain { + config.setValue(chain, forKey: "chain") + } + + let availableAsset = try insert( + entityName: "CDXcmAvailableAsset", + in: context, + model: model + ) + availableAsset.setValue( + "xcm-asset", + forKey: "id" + ) + config.mutableSetValue( + forKey: "availableAssets" + ).add(availableAsset) + + let destination = try insert( + entityName: "CDXcmAvailableDestination", + in: context, + model: model + ) + destination.setValue( + "destination-chain", + forKey: "chainId" + ) + destination.setValue(config, forKey: "config") + destination.mutableSetValue( + forKey: "assets" + ).add(availableAsset) + } + + private func addPriceDataToSingleAsset( + count: Int, + at url: URL, + model: NSManagedObjectModel + ) throws { + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSSQLitePragmasOption: ["journal_mode": "DELETE"], + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + var mutationError: Error? + context.performAndWait { + do { + let asset = try self.fetchSingleObject( + entityName: "CDAsset", + context: context + ) + try self.insertPriceData( + count: count, + for: asset, + in: context, + model: model + ) + try context.save() + } catch { + mutationError = error + } + } + + if let mutationError { + throw mutationError + } + } + + private func assertCurrentTransformableAndProtectedGraph( + expectedOptions: [String], + expectedPurchaseProviders: [String]? + ) throws { + let currentModel = try model(for: .version8) + try inspectStore(at: storeURL, model: currentModel) { + context in + let chain = try self.fetchSingleObject( + entityName: "CDChain", + context: context + ) + XCTAssertEqual( + try self.stringArray(in: chain, key: "options"), + expectedOptions + ) + + let defaultNodes = self.relationshipObjects( + in: chain, + key: "nodes" + ) + let customNodes = self.relationshipObjects( + in: chain, + key: "customNodes" + ) + let selectedNode = try XCTUnwrap( + chain.value(forKey: "selectedNode") + as? NSManagedObject + ) + XCTAssertEqual(defaultNodes.count, 1) + XCTAssertEqual(customNodes.count, 1) + XCTAssertEqual( + selectedNode.value(forKey: "url") as? URL, + URL(string: "wss://current-custom.example.invalid") + ) + XCTAssertEqual( + customNodes.first, + selectedNode + ) + + let asset = try self.fetchSingleObject( + entityName: "CDAsset", + context: context + ) + XCTAssertEqual( + try self.stringArray( + in: asset, + key: "purchaseProviders" + ), + expectedPurchaseProviders + ) + XCTAssertEqual( + asset.value(forKey: "chain") as? NSManagedObject, + chain + ) + } + } + + private func migratedAssetPurchaseProviders() throws -> [String]? { + let targetModel = try model(for: .version8) + var purchaseProviders: [String]? + try inspectStore(at: storeURL, model: targetModel) { + context in + let asset = try self.fetchSingleObject( + entityName: "CDAsset", + context: context + ) + purchaseProviders = try self.stringArray( + in: asset, + key: "purchaseProviders" + ) + } + return purchaseProviders + } + + private func insertLegacyChainWithNodes( + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let chainEntity = try XCTUnwrap(model.entitiesByName["CDChain"]) + let nodeEntity = try XCTUnwrap(model.entitiesByName["CDChainNode"]) + + let chain = NSManagedObject(entity: chainEntity, insertInto: context) + chain.setValue("migration-chain", forKey: "chainId") + chain.setValue("Migration Chain", forKey: "name") + chain.setValue(URL(string: "https://example.invalid/icon.png"), forKey: "icon") + + let lastNode = NSManagedObject(entity: nodeEntity, insertInto: context) + lastNode.setValue("Zulu Node", forKey: "name") + lastNode.setValue(URL(string: "wss://zulu.example.invalid"), forKey: "url") + lastNode.setValue(chain, forKey: "chain") + + let firstNode = NSManagedObject(entity: nodeEntity, insertInto: context) + firstNode.setValue("Alpha Node", forKey: "name") + firstNode.setValue(URL(string: "wss://alpha.example.invalid"), forKey: "url") + firstNode.setValue(chain, forKey: "chain") + } + + private func insertLegacyChainGraph( + in context: NSManagedObjectContext, + model: NSManagedObjectModel, + symbol: String? = "MIG", + includeNilAssetWrapper: Bool = false + ) throws { + let chainEntity = try XCTUnwrap(model.entitiesByName["CDChain"]) + let nodeEntity = try XCTUnwrap(model.entitiesByName["CDChainNode"]) + let assetEntity = try XCTUnwrap(model.entitiesByName["CDAsset"]) + let chainAssetEntity = try XCTUnwrap(model.entitiesByName["CDChainAsset"]) + + let chain = NSManagedObject(entity: chainEntity, insertInto: context) + chain.setValue("migration-chain", forKey: "chainId") + chain.setValue("Migration Chain", forKey: "name") + chain.setValue(URL(string: "https://example.invalid/icon.png"), forKey: "icon") + + let node = NSManagedObject(entity: nodeEntity, insertInto: context) + node.setValue("Migration Node", forKey: "name") + node.setValue(URL(string: "wss://example.invalid"), forKey: "url") + node.setValue(chain, forKey: "chain") + + let asset = NSManagedObject(entity: assetEntity, insertInto: context) + asset.setValue("migration-chain", forKey: "chainId") + asset.setValue("migration-asset", forKey: "id") + asset.setValue(Int16(18), forKey: "precision") + asset.setValue(symbol, forKey: "symbol") + + let chainAsset = NSManagedObject( + entity: chainAssetEntity, + insertInto: context + ) + chainAsset.setValue("migration-asset", forKey: "assetId") + chainAsset.setValue(true, forKey: "isNative") + chainAsset.setValue(false, forKey: "isUtility") + chainAsset.setValue("normal", forKey: "type") + chainAsset.setValue(asset, forKey: "asset") + chainAsset.setValue(chain, forKey: "chain") + + if includeNilAssetWrapper { + let nilAssetWrapper = NSManagedObject( + entity: chainAssetEntity, + insertInto: context + ) + nilAssetWrapper.setValue("missing-asset", forKey: "assetId") + nilAssetWrapper.setValue(chain, forKey: "chain") + } + } + + private func insertLegacyOrphanAsset( + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let assetEntity = try XCTUnwrap(model.entitiesByName["CDAsset"]) + let asset = NSManagedObject(entity: assetEntity, insertInto: context) + asset.setValue("orphan-chain", forKey: "chainId") + asset.setValue("orphan-asset", forKey: "id") + asset.setValue(Int16(12), forKey: "precision") + asset.setValue("ORP", forKey: "symbol") + } + + private func assertAdversarialTransformableMigration( + sourceVersion: SubstrateStorageVersion, + updateSQL: String, + expectedDefaultedKeys: Set + ) throws { + let sourceModel = try model(for: sourceVersion) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertTransformableAndProtectedGraph( + in: context, + model: sourceModel + ) + } + try executeSQLite(updateSQL, at: storeURL) + + try makeMigrator().performMigration() + + try assertMigratedTransformableAndProtectedGraph( + expectedDefaultedKeys: expectedDefaultedKeys + ) + } + + private func insertTransformableAndProtectedGraph( + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let chain = try insert( + entityName: "CDChain", + in: context, + model: model + ) + chain.setValue("protected-transformable-chain", forKey: "chainId") + chain.setValue("Protected Transformable Chain", forKey: "name") + chain.setValue( + NSArray(object: "chain-option"), + forKey: "options" + ) + + let defaultNode = try insert( + entityName: "CDChainNode", + in: context, + model: model + ) + defaultNode.setValue("Default Node", forKey: "name") + defaultNode.setValue( + try XCTUnwrap(URL(string: "wss://default-node.example.invalid")), + forKey: "url" + ) + defaultNode.setValue("default-key", forKey: "apiKeyName") + defaultNode.setValue("default-query", forKey: "apiQueryName") + defaultNode.setValue(chain, forKey: "chain") + + let customNode = try insert( + entityName: "CDChainNode", + in: context, + model: model + ) + customNode.setValue("Custom Node", forKey: "name") + customNode.setValue( + try XCTUnwrap(URL(string: "wss://custom-node.example.invalid")), + forKey: "url" + ) + customNode.setValue("custom-key", forKey: "apiKeyName") + customNode.setValue("custom-query", forKey: "apiQueryName") + chain.mutableSetValue(forKey: "customNodes").add(customNode) + chain.setValue(customNode, forKey: "selectedNode") + + let asset = try insert( + entityName: "CDAsset", + in: context, + model: model + ) + asset.setValue("protected-asset", forKey: "id") + asset.setValue(Int16(12), forKey: "precision") + if asset.entity.attributesByName["chainId"] != nil { + asset.setValue( + "protected-transformable-chain", + forKey: "chainId" + ) + } + if asset.entity.attributesByName["symbol"] != nil { + asset.setValue("SAFE", forKey: "symbol") + } + + if model.entitiesByName["CDChainAsset"] != nil { + let wrapper = try insert( + entityName: "CDChainAsset", + in: context, + model: model + ) + wrapper.setValue("protected-asset", forKey: "assetId") + wrapper.setValue(true, forKey: "isNative") + wrapper.setValue(false, forKey: "isUtility") + wrapper.setValue("normal", forKey: "type") + wrapper.setValue( + NSArray(object: "provider-a"), + forKey: "purchaseProviders" + ) + wrapper.setValue(asset, forKey: "asset") + wrapper.setValue(chain, forKey: "chain") + } else { + asset.setValue( + NSArray(object: "provider-a"), + forKey: "purchaseProviders" + ) + chain.mutableSetValue(forKey: "assets").add(asset) + } + + let explorer = try insert( + entityName: "CDExternalApi", + in: context, + model: model + ) + explorer.setValue("subscan", forKey: "type") + explorer.setValue("https://explorer.example.invalid", forKey: "url") + explorer.setValue( + NSArray(object: "explorer-type"), + forKey: "types" + ) + explorer.setValue(chain, forKey: "chain") + + let polkaswap = try insert( + entityName: "CDPolkaswapRemoteSettings", + in: context, + model: model + ) + polkaswap.setValue("protected-v1", forKey: "version") + polkaswap.setValue( + NSArray(object: "source-a"), + forKey: "availableSources" + ) + polkaswap.setValue( + NSArray(object: "smart-a"), + forKey: "forceSmartIds" + ) + polkaswap.setValue(NSSet(), forKey: "availableDexIds") + + let xcmConfig = try insert( + entityName: "CDChainXcmConfig", + in: context, + model: model + ) + xcmConfig.setValue("v3", forKey: "xcmVersion") + xcmConfig.setValue( + NSArray(object: "XCM-A"), + forKey: "availableAssets" + ) + xcmConfig.setValue(chain, forKey: "chain") + + let xcmDestination = try insert( + entityName: "CDXcmAvailableDestination", + in: context, + model: model + ) + xcmDestination.setValue( + "destination-chain", + forKey: "chainId" + ) + xcmDestination.setValue( + NSArray(object: "XCM-B"), + forKey: "assets" + ) + xcmDestination.setValue(xcmConfig, forKey: "config") + + let contact = try insert( + entityName: "CDContact", + in: context, + model: model + ) + contact.setValue("Protected Contact", forKey: "name") + contact.setValue("contact-address", forKey: "address") + contact.setValue( + "protected-transformable-chain", + forKey: "chainId" + ) + + let contactItem = try insert( + entityName: "CDContactItem", + in: context, + model: model + ) + contactItem.setValue("contact-item", forKey: "identifier") + contactItem.setValue("peer-address", forKey: "peerAddress") + contactItem.setValue("Peer Name", forKey: "peerName") + contactItem.setValue("target-address", forKey: "targetAddress") + contactItem.setValue(Int64(1_234_567), forKey: "updatedAt") + + let history = try insert( + entityName: "CDTransactionHistoryItem", + in: context, + model: model + ) + history.setValue("balances", forKey: "moduleName") + history.setValue("transfer", forKey: "callName") + history.setValue("history-id", forKey: "identifier") + history.setValue("sender-address", forKey: "sender") + history.setValue("receiver-address", forKey: "receiver") + history.setValue("10", forKey: "fee") + history.setValue(Data([0x01, 0x02, 0xFF]), forKey: "call") + history.setValue(Int64(42), forKey: "blockNumber") + history.setValue(Int64(1_234_568), forKey: "timestamp") + history.setValue(Int16(7), forKey: "txIndex") + history.setValue(Int16(1), forKey: "status") + } + + private func assertMigratedTransformableAndProtectedGraph( + expectedDefaultedKeys: Set + ) throws { + let targetModel = try model(for: .version8) + try inspectStore(at: storeURL, model: targetModel) { context in + let chain = try self.fetchSingleObject( + entityName: "CDChain", + context: context + ) + XCTAssertEqual( + try self.stringArray(in: chain, key: "options"), + expectedDefaultedKeys.contains("CDChain.options") + ? [] + : ["chain-option"] + ) + + let defaultNodes = self.relationshipObjects( + in: chain, + key: "nodes" + ) + let customNodes = self.relationshipObjects( + in: chain, + key: "customNodes" + ) + let selectedNode = try XCTUnwrap( + chain.value(forKey: "selectedNode") as? NSManagedObject + ) + XCTAssertEqual(defaultNodes.count, 1) + XCTAssertEqual(customNodes.count, 1) + XCTAssertEqual( + defaultNodes.first?.value(forKey: "name") as? String, + "Default Node" + ) + XCTAssertEqual( + customNodes.first?.value(forKey: "name") as? String, + "Custom Node" + ) + XCTAssertEqual( + selectedNode.value(forKey: "url") as? URL, + URL(string: "wss://custom-node.example.invalid") + ) + + let asset = try XCTUnwrap( + self.relationshipObjects(in: chain, key: "assets").first + ) + XCTAssertEqual( + try self.stringArray( + in: asset, + key: "purchaseProviders" + ), + expectedDefaultedKeys.contains( + "CDChainAsset.purchaseProviders" + ) || expectedDefaultedKeys.contains( + "CDAsset.purchaseProviders" + ) + ? [] + : ["provider-a"] + ) + + let explorer = try XCTUnwrap( + self.relationshipObjects( + in: chain, + key: "explorers" + ).first + ) + XCTAssertEqual( + try self.stringArray(in: explorer, key: "types"), + expectedDefaultedKeys.contains("CDExternalApi.types") + ? [] + : ["explorer-type"] + ) + + let polkaswap = try self.fetchSingleObject( + entityName: "CDPolkaswapRemoteSettings", + context: context + ) + XCTAssertEqual( + try self.stringArray( + in: polkaswap, + key: "availableSources" + ), + expectedDefaultedKeys.contains( + "CDPolkaswapRemoteSettings.availableSources" + ) + ? [] + : ["source-a"] + ) + XCTAssertEqual( + try self.stringArray( + in: polkaswap, + key: "forceSmartIds" + ), + expectedDefaultedKeys.contains( + "CDPolkaswapRemoteSettings.forceSmartIds" + ) + ? [] + : ["smart-a"] + ) + + let xcmConfig = try XCTUnwrap( + chain.value(forKey: "xcmConfig") as? NSManagedObject + ) + let configSymbols = self.relationshipObjects( + in: xcmConfig, + key: "availableAssets" + ).compactMap { $0.value(forKey: "symbol") as? String }.sorted() + XCTAssertEqual( + configSymbols, + expectedDefaultedKeys.contains( + "CDChainXcmConfig.availableAssets" + ) + ? [] + : ["XCM-A"] + ) + + let destination = try XCTUnwrap( + self.relationshipObjects( + in: xcmConfig, + key: "availableDestinations" + ).first + ) + let destinationSymbols = self.relationshipObjects( + in: destination, + key: "assets" + ).compactMap { $0.value(forKey: "symbol") as? String }.sorted() + XCTAssertEqual( + destinationSymbols, + expectedDefaultedKeys.contains( + "CDXcmAvailableDestination.assets" + ) + ? [] + : ["XCM-B"] + ) + + let contact = try self.fetchSingleObject( + entityName: "CDContact", + context: context + ) + XCTAssertEqual( + contact.value(forKey: "name") as? String, + "Protected Contact" + ) + XCTAssertEqual( + contact.value(forKey: "address") as? String, + "contact-address" + ) + + let contactItem = try self.fetchSingleObject( + entityName: "CDContactItem", + context: context + ) + XCTAssertEqual( + contactItem.value(forKey: "peerName") as? String, + "Peer Name" + ) + XCTAssertEqual( + contactItem.value(forKey: "targetAddress") as? String, + "target-address" + ) + + let history = try self.fetchSingleObject( + entityName: "CDTransactionHistoryItem", + context: context + ) + XCTAssertEqual( + history.value(forKey: "identifier") as? String, + "history-id" + ) + XCTAssertEqual( + history.value(forKey: "call") as? Data, + Data([0x01, 0x02, 0xFF]) + ) + } + } + + private func assertSourceProtectedGraphIsExact( + at url: URL, + model: NSManagedObjectModel + ) throws { + // This assertion intentionally verifies only the protected graph. The + // caller has already compared every installed family byte. Inspect a + // disposable copy after neutralizing the deliberately corrupt cache + // transformable so Core Data cannot fault that unrelated column while + // traversing relationships. + let inspectionRootURL = testDirectory.appendingPathComponent( + "ProtectedGraphInspection-\(UUID().uuidString)", + isDirectory: true + ) + let inspectionStoreURL = inspectionRootURL.appendingPathComponent( + url.lastPathComponent + ) + try FileManager.default.createDirectory( + at: inspectionRootURL, + withIntermediateDirectories: false + ) + defer { + try? FileManager.default.removeItem(at: inspectionRootURL) + } + + for suffix in ["", "-wal", "-journal"] { + let sourceURL = URL( + fileURLWithPath: url.path + suffix + ) + guard FileManager.default.fileExists( + atPath: sourceURL.path + ) else { + continue + } + try FileManager.default.copyItem( + at: sourceURL, + to: URL( + fileURLWithPath: inspectionStoreURL.path + suffix + ) + ) + } + try executeSQLite( + "UPDATE ZCDCHAIN SET ZOPTIONS = NULL", + at: inspectionStoreURL + ) + + try inspectStore(at: inspectionStoreURL, model: model) { context in + let chain = try self.fetchSingleObject( + entityName: "CDChain", + context: context + ) + let defaultNodes = self.relationshipObjects( + in: chain, + key: "nodes" + ) + let customNodes = self.relationshipObjects( + in: chain, + key: "customNodes" + ) + XCTAssertEqual(defaultNodes.count, 1) + XCTAssertEqual(customNodes.count, 1) + XCTAssertEqual( + defaultNodes.first?.value(forKey: "name") as? String, + "Default Node" + ) + XCTAssertEqual( + customNodes.first?.value(forKey: "name") as? String, + "Custom Node" + ) + XCTAssertEqual( + (chain.value(forKey: "selectedNode") as? NSManagedObject)? + .value(forKey: "name") as? String, + "Custom Node" + ) + + let contact = try self.fetchSingleObject( + entityName: "CDContact", + context: context + ) + XCTAssertEqual( + contact.value(forKey: "name") as? String, + "Protected Contact" + ) + let history = try self.fetchSingleObject( + entityName: "CDTransactionHistoryItem", + context: context + ) + XCTAssertEqual( + history.value(forKey: "identifier") as? String, + "history-id" + ) + } + } + + private func mutateStagedProtectedDataWithoutChangingRowCounts( + at url: URL, + model: NSManagedObjectModel + ) throws { + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSSQLitePragmasOption: ["journal_mode": "DELETE"], + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + var mutationError: Error? + context.performAndWait { + do { + let contact = try self.fetchSingleObject( + entityName: "CDContact", + context: context + ) + contact.setValue( + "Same Count, Different Contact", + forKey: "name" + ) + + let chain = try self.fetchSingleObject( + entityName: "CDChain", + context: context + ) + let defaultNode = try XCTUnwrap( + self.relationshipObjects( + in: chain, + key: "nodes" + ).first + ) + chain.setValue(defaultNode, forKey: "selectedNode") + try context.save() + } catch { + mutationError = error + } + } + + if let mutationError { + throw mutationError + } + } + + private func fetchSingleObject( + entityName: String, + context: NSManagedObjectContext + ) throws -> NSManagedObject { + let request = NSFetchRequest( + entityName: entityName + ) + request.fetchLimit = 2 + request.includesPendingChanges = false + request.includesSubentities = false + let objects = try context.fetch(request) + XCTAssertEqual(objects.count, 1) + return try XCTUnwrap(objects.first) + } + + private func relationshipObjects( + in object: NSManagedObject, + key: String + ) -> [NSManagedObject] { + if let objects = object.value(forKey: key) as? Set { + return Array(objects) + } + if let objects = object.value(forKey: key) as? NSSet { + return objects.compactMap { $0 as? NSManagedObject } + } + return [] + } + + private func stringArray( + in object: NSManagedObject, + key: String + ) throws -> [String]? { + try SafeTransformableValueReader.read( + from: object, + key: key + ) + } + + private func hex(_ data: Data) -> String { + data.map { String(format: "%02X", $0) }.joined() + } + + private func inspectStore( + at url: URL, + model: NSManagedObjectModel, + body: (NSManagedObjectContext) throws -> Void + ) throws { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSReadOnlyPersistentStoreOption: true, + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + var inspectionError: Error? + context.performAndWait { + do { + try body(context) + } catch { + inspectionError = error + } + } + + if let inspectionError { + throw inspectionError + } + } + + private func count( + entityName: String, + at url: URL, + model: NSManagedObjectModel + ) throws -> Int { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + var result: Result! + context.performAndWait { + result = Result { + let request = NSFetchRequest(entityName: entityName) + return try context.count(for: request) + } + } + + return try result.get() + } + + private func isStore( + at url: URL, + compatibleWith model: NSManagedObjectModel, + version: SubstrateStorageVersion + ) throws -> Bool { + let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStore( + ofType: NSSQLiteStoreType, + at: url, + options: nil + ) + + return model.isConfiguration( + withName: version.rawValue, + compatibleWithStoreMetadata: metadata + ) + } + + private func flattenedErrorDescriptions(_ error: Error) -> [String] { + let nsError = error as NSError + var descriptions = [nsError.localizedDescription] + + if let underlyingError = nsError.userInfo[NSUnderlyingErrorKey] as? Error { + descriptions.append(contentsOf: flattenedErrorDescriptions(underlyingError)) + } + + if let detailedErrors = nsError.userInfo[NSDetailedErrorsKey] as? [Error] { + for detailedError in detailedErrors { + descriptions.append(contentsOf: flattenedErrorDescriptions(detailedError)) + } + } + + return descriptions + } + + private func makeUnknownModel() -> NSManagedObjectModel { + let model = NSManagedObjectModel() + let entity = NSEntityDescription() + entity.name = "UnknownSubstrateCache" + entity.managedObjectClassName = NSStringFromClass(NSManagedObject.self) + + let identifier = NSAttributeDescription() + identifier.name = "identifier" + identifier.attributeType = .stringAttributeType + identifier.isOptional = true + entity.properties = [identifier] + model.entities = [entity] + + return model + } + + private func makeModelBundle( + omitting omittedVersion: SubstrateStorageVersion? = nil + ) throws -> Bundle { + let bundleURL = testDirectory.appendingPathComponent( + "SubstrateModels-\(UUID().uuidString).bundle", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: bundleURL, + withIntermediateDirectories: true + ) + + let infoPlist: [String: Any] = [ + "CFBundleIdentifier": "jp.co.soramitsu.fearlesswallet.tests.substrate-models.\(UUID().uuidString)", + "CFBundleName": "SubstrateModels", + "CFBundlePackageType": "BNDL", + "CFBundleVersion": "1" + ] + let infoData = try PropertyListSerialization.data( + fromPropertyList: infoPlist, + format: .xml, + options: 0 + ) + try infoData.write(to: bundleURL.appendingPathComponent("Info.plist")) + + let sourceModelDirectory = try XCTUnwrap( + appBundle.url( + forResource: "SubstrateDataModel", + withExtension: "momd" + ) + ) + let destinationModelDirectory = bundleURL.appendingPathComponent( + SubstrateStorageParams.modelDirectory, + isDirectory: true + ) + try FileManager.default.copyItem( + at: sourceModelDirectory, + to: destinationModelDirectory + ) + + if let omittedVersion { + for fileExtension in ["omo", "mom"] { + let omittedModelURL = destinationModelDirectory.appendingPathComponent( + "\(omittedVersion.rawValue).\(fileExtension)" + ) + if FileManager.default.fileExists(atPath: omittedModelURL.path) { + try FileManager.default.removeItem(at: omittedModelURL) + } + } + } + + return try XCTUnwrap(Bundle(url: bundleURL)) + } + + private func durableStoreFamilySnapshot(at url: URL) throws -> [String: Data] { + let fileNames = try FileManager.default.contentsOfDirectory( + atPath: url.deletingLastPathComponent().path + ).filter { + $0.hasPrefix(url.lastPathComponent) + } + + return try Dictionary( + uniqueKeysWithValues: fileNames.map { fileName in + let fileURL = url.deletingLastPathComponent().appendingPathComponent(fileName) + return (fileName, try Data(contentsOf: fileURL)) + } + ) + } + + private func installRealSQLiteFamilyWithUncheckpointedWAL( + at url: URL + ) throws { + let snapshotDirectoryURL = testDirectory.appendingPathComponent( + "RealSQLiteWALSnapshot-\(UUID().uuidString)", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: snapshotDirectoryURL, + withIntermediateDirectories: false + ) + defer { + try? FileManager.default.removeItem( + at: snapshotDirectoryURL + ) + } + + var database: OpaquePointer? + let openResult = sqlite3_open_v2( + url.path, + &database, + SQLITE_OPEN_READWRITE, + nil + ) + guard openResult == SQLITE_OK, let database else { + defer { + if let database { + sqlite3_close(database) + } + } + throw NSError( + domain: "SubstrateStorageMigrationSafetyTests.SQLite", + code: Int(openResult), + userInfo: [ + NSLocalizedDescriptionKey: + "Unable to open real SQLite WAL fixture" + ] + ) + } + + do { + try executeSQLite( + """ + PRAGMA journal_mode=WAL; + PRAGMA wal_autocheckpoint=0; + CREATE TABLE IF NOT EXISTS ZFEARLESSRECOVERYPROBE ( + ZVALUE INTEGER NOT NULL + ); + BEGIN IMMEDIATE; + INSERT INTO ZFEARLESSRECOVERYPROBE (ZVALUE) VALUES (1); + COMMIT; + """, + database: database + ) + + for suffix in ["", "-wal", "-shm", "-journal"] { + let sourceURL = URL( + fileURLWithPath: url.path + suffix + ) + guard FileManager.default.fileExists( + atPath: sourceURL.path + ) else { + continue + } + try FileManager.default.copyItem( + at: sourceURL, + to: snapshotDirectoryURL.appendingPathComponent( + sourceURL.lastPathComponent + ) + ) + } + } catch { + sqlite3_close(database) + throw error + } + sqlite3_close(database) + + for suffix in ["", "-wal", "-shm", "-journal"] { + let familyURL = URL( + fileURLWithPath: url.path + suffix + ) + if FileManager.default.fileExists( + atPath: familyURL.path + ) { + try FileManager.default.removeItem(at: familyURL) + } + + let snapshotURL = snapshotDirectoryURL + .appendingPathComponent( + familyURL.lastPathComponent + ) + if FileManager.default.fileExists( + atPath: snapshotURL.path + ) { + try FileManager.default.copyItem( + at: snapshotURL, + to: familyURL + ) + } + } + } + + private func sqliteInteger( + _ sql: String, + at url: URL + ) throws -> Int64 { + var database: OpaquePointer? + let openResult = sqlite3_open_v2( + url.path, + &database, + SQLITE_OPEN_READONLY, + nil + ) + guard openResult == SQLITE_OK, let database else { + defer { + if let database { + sqlite3_close(database) + } + } + throw NSError( + domain: "SubstrateStorageMigrationSafetyTests.SQLite", + code: Int(openResult), + userInfo: [ + NSLocalizedDescriptionKey: + "Unable to open SQLite integer query" + ] + ) + } + defer { + sqlite3_close(database) + } + + var statement: OpaquePointer? + let prepareResult = sqlite3_prepare_v2( + database, + sql, + -1, + &statement, + nil + ) + guard prepareResult == SQLITE_OK, let statement else { + throw NSError( + domain: "SubstrateStorageMigrationSafetyTests.SQLite", + code: Int(prepareResult), + userInfo: [ + NSLocalizedDescriptionKey: + "Unable to prepare SQLite integer query" + ] + ) + } + defer { + sqlite3_finalize(statement) + } + + let stepResult = sqlite3_step(statement) + guard stepResult == SQLITE_ROW else { + throw NSError( + domain: "SubstrateStorageMigrationSafetyTests.SQLite", + code: Int(stepResult), + userInfo: [ + NSLocalizedDescriptionKey: + "SQLite integer query returned no row" + ] + ) + } + + return sqlite3_column_int64(statement, 0) + } + + private func executeSQLite( + _ sql: String, + database: OpaquePointer + ) throws { + var errorMessage: UnsafeMutablePointer? + let executionResult = sqlite3_exec( + database, + sql, + nil, + nil, + &errorMessage + ) + defer { + sqlite3_free(errorMessage) + } + + guard executionResult == SQLITE_OK else { + let message = errorMessage + .map { String(cString: $0) } ?? + "unknown SQLite execution error" + throw NSError( + domain: "SubstrateStorageMigrationSafetyTests.SQLite", + code: Int(executionResult), + userInfo: [NSLocalizedDescriptionKey: message] + ) + } + } + + private func executeSQLite(_ sql: String, at url: URL) throws { + var database: OpaquePointer? + let openResult = sqlite3_open_v2( + url.path, + &database, + SQLITE_OPEN_READWRITE, + nil + ) + + guard openResult == SQLITE_OK, let database else { + defer { + if let database { + sqlite3_close(database) + } + } + + let message = database + .flatMap(sqlite3_errmsg) + .map { String(cString: $0) } ?? "unknown SQLite open error" + throw NSError( + domain: "SubstrateStorageMigrationSafetyTests.SQLite", + code: Int(openResult), + userInfo: [NSLocalizedDescriptionKey: message] + ) + } + defer { + sqlite3_close(database) + } + + try executeSQLite(sql, database: database) + } + + private func recoveryDirectories() throws -> [URL] { + let recoveryRoot = testDirectory.appendingPathComponent( + "SubstrateStoreRecovery", + isDirectory: true + ) + guard FileManager.default.fileExists(atPath: recoveryRoot.path) else { + return [] + } + + return try FileManager.default.contentsOfDirectory( + at: recoveryRoot, + includingPropertiesForKeys: nil + ).sorted { $0.lastPathComponent < $1.lastPathComponent } + } +} + +@objc(FearlessTestsDroppingAssetMigrationPolicy) +private final class DroppingAssetMigrationPolicy: NSEntityMigrationPolicy { + override func createDestinationInstances( + forSource _: NSManagedObject, + in _: NSEntityMapping, + manager _: NSMigrationManager + ) throws {} +} + +private class TemporaryStoreFootprintFileManager: FileManager { + private var sourceRoots = Set() + + private(set) var maximumTemporaryMainStoreCount = 0 + private(set) var temporaryMainStoreCountsBeforeRemoval: [Int] = [] + private(set) var removedTemporaryMainStoreCount = 0 + private(set) var copiedSharedMemorySidecar = false + + var temporaryRootsAreClean: Bool { + sourceRoots.allSatisfy { + !FileManager.default.fileExists(atPath: $0.path) + } + } + + override init() { + super.init() + } + + required init?(coder _: NSCoder) { + nil + } + + override func createDirectory( + at url: URL, + withIntermediateDirectories createIntermediates: Bool, + attributes: [FileAttributeKey: Any]? = nil + ) throws { + try super.createDirectory( + at: url, + withIntermediateDirectories: createIntermediates, + attributes: attributes + ) + + if url.lastPathComponent.hasPrefix("SubstrateStorageSource-") { + sourceRoots.insert(url.standardizedFileURL) + } + + sampleTemporaryStoreCount() + } + + override func copyItem(at sourceURL: URL, to destinationURL: URL) throws { + try super.copyItem(at: sourceURL, to: destinationURL) + + if + trackedSourceRoot(containing: destinationURL) != nil, + sourceURL.lastPathComponent.hasSuffix("-shm") + { + copiedSharedMemorySidecar = true + } + + sampleTemporaryStoreCount() + } + + override func removeItem(at url: URL) throws { + let removesTemporaryMainStore = isTrackedTemporaryMainStore(url) + + if removesTemporaryMainStore { + sampleTemporaryStoreCount() + temporaryMainStoreCountsBeforeRemoval.append( + temporaryMainStoreCount() + ) + } + + try super.removeItem(at: url) + + if removesTemporaryMainStore { + removedTemporaryMainStoreCount += 1 + } + + sampleTemporaryStoreCount() + } + + func isTrackedTemporaryMainStore(_ url: URL) -> Bool { + trackedSourceRoot(containing: url) != nil && + url.pathExtension == "sqlite" + } + + private func trackedSourceRoot(containing url: URL) -> URL? { + let standardizedPath = url.standardizedFileURL.path + + return sourceRoots.first { root in + standardizedPath == root.path || + standardizedPath.hasPrefix(root.path + "/") + } + } + + private func sampleTemporaryStoreCount() { + maximumTemporaryMainStoreCount = max( + maximumTemporaryMainStoreCount, + temporaryMainStoreCount() + ) + } + + private func temporaryMainStoreCount() -> Int { + sourceRoots.reduce(into: 0) { count, root in + guard + FileManager.default.fileExists(atPath: root.path), + let enumerator = FileManager.default.enumerator( + at: root, + includingPropertiesForKeys: nil + ) + else { + return + } + + while let fileURL = enumerator.nextObject() as? URL { + if fileURL.pathExtension == "sqlite" { + count += 1 + } + } + } + } +} + +private final class FailingTemporaryStoreCleanupFileManager: + TemporaryStoreFootprintFileManager +{ + private(set) var didInjectCleanupFailure = false + + override func removeItem(at url: URL) throws { + if !didInjectCleanupFailure, isTrackedTemporaryMainStore(url) { + didInjectCleanupFailure = true + throw InjectedSubstrateTemporaryCleanupError.failure + } + + try super.removeItem(at: url) + } +} + +private enum InjectedSubstrateStoreReplacementError: Error { + case failure +} + +private enum InjectedSubstrateCheckpointError: Error { + case failure +} + +private enum InjectedSubstrateTemporaryCleanupError: Error { + case failure +} + +private enum InjectedSubstrateBackupExclusionError: Error { + case failure +} + +@objc(FearlessTestsDisallowedSubstrateTransformablePayload) +private final class DisallowedSubstrateTransformablePayload: NSObject, NSSecureCoding { + static var supportsSecureCoding: Bool { + true + } + + let value: String + + init(value: String) { + self.value = value + super.init() + } + + required init?(coder: NSCoder) { + guard let value = coder.decodeObject( + of: NSString.self, + forKey: "value" + ) as? String else { + return nil + } + + self.value = value + super.init() + } + + func encode(with coder: NSCoder) { + coder.encode(value as NSString, forKey: "value") + } +} diff --git a/fearlessTests/Common/Migration/UserStorageCompatibilityMigrationTests.swift b/fearlessTests/Common/Migration/UserStorageCompatibilityMigrationTests.swift new file mode 100644 index 0000000000..34fcd1379e --- /dev/null +++ b/fearlessTests/Common/Migration/UserStorageCompatibilityMigrationTests.swift @@ -0,0 +1,7815 @@ +import CoreData +import IrohaCrypto +import SoraKeystore +import SQLite3 +import SSFModels +import XCTest +@testable import fearless + +final class UserStorageCompatibilityMigrationTests: XCTestCase { + private struct ChainSnapshot: Equatable { + let chainId: String + let accountId: String + let publicKey: Data + let cryptoType: Int16 + let ecosystem: String? + } + + private struct WalletSnapshot: Equatable { + let metaId: String + let name: String + let substrateAccountId: String? + let substratePublicKey: Data? + let tonAddress: Data? + let tonPublicKey: Data? + let tonContractVersion: String? + let assetsVisibility: [String: Bool] + let chainAccounts: [ChainSnapshot] + } + + private let legacyChecksum = "+oGDYB1AZIk54P/liFbJ3aXArqvhW7YLFAy04AChJ+s=" + private let currentChecksum = "dX3y/Aa+rMRI3ZxRibOGIkyCHwrc0zgNO9OoBnS5G/Y=" + + private var testDirectory: URL! + private var storeURL: URL { + testDirectory.appendingPathComponent("UserDataModel.sqlite") + } + + private var appBundle: Bundle { + Bundle(for: UserDataStorageFacade.self) + } + + override func setUpWithError() throws { + try super.setUpWithError() + + testDirectory = FileManager.default.temporaryDirectory + .appendingPathComponent("UserStorageCompatibilityMigrationTests") + .appendingPathComponent(UUID().uuidString) + try FileManager.default.createDirectory( + at: testDirectory, + withIntermediateDirectories: true + ) + } + + override func tearDownWithError() throws { + if let testDirectory { + try? FileManager.default.removeItem(at: testDirectory) + } + + try super.tearDownWithError() + } + + func testCrashConsistentReplacement_whenProcessDiesAtEveryCommitBoundary_thenBothStoreFamiliesRecoverExactly() throws { + let scenarios: [ + ( + boundary: CrashConsistentStoreReplacementBoundary, + shouldCommit: Bool + ) + ] = [ + (.preparingMarkerPersisted, false), + (.backupFileCopied(""), false), + (.backupFileCopied("-wal"), false), + (.backupFileCopied("-shm"), false), + (.backupFileCopied("-journal"), false), + (.committingMarkerPersisted, false), + (.replacementReturned, false), + (.destinationValidated, false), + (.destinationFamilySynced, false), + (.committedMarkerPersisted, true), + (.cleanupBackupFileRemoved(""), true), + (.cleanupBackupFileRemoved("-wal"), true), + (.cleanupBackupFileRemoved("-shm"), true), + (.cleanupBackupFileRemoved("-journal"), true), + (.cleanupBackupDirectoryRemoved, true), + (.cleanupMarkerRemoved, true), + (.cleanupTransactionDirectoryRemoved, true), + (.cleanupRecoveryRootRemoved, true), + (.transactionCleaned, true) + ] + + for storeName in [ + "UserDataModel.sqlite", + "SubstrateDataModel.sqlite" + ] { + for (index, scenario) in scenarios.enumerated() { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "\(storeName)-commit-\(index)" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent(storeName) + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged-\(storeName)") + try writeSyntheticStoreFamily( + at: liveStoreURL, + seed: 0x10 + ) + try writeSyntheticStoreFamily( + at: stagedStoreURL, + seed: 0xA0 + ) + let originalFamily = try syntheticStoreFamilySnapshot( + at: liveStoreURL + ) + let committedFamily = try syntheticStoreFamilySnapshot( + at: stagedStoreURL + ) + var didInterrupt = false + let replacer = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily, + boundaryHook: { boundary in + guard + !didInterrupt, + boundary == scenario.boundary + else { + return + } + + didInterrupt = true + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + + XCTAssertThrowsError( + try replacer.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ), + "\(storeName) \(scenario.boundary)" + ) { error in + guard + let interruption = error as? CrashConsistentStoreReplacementInterruption, + case .simulatedProcessDeath = interruption + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertTrue( + didInterrupt, + "The requested boundary was not reached" + ) + + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try relaunched.reconcile { _ in } + + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + scenario.shouldCommit + ? committedFamily + : originalFamily, + "\(storeName) \(scenario.boundary)" + ) + XCTAssertFalse(relaunched.hasPendingTransaction) + } + } + } + + func testCrashConsistentReplacement_whenProcessDiesAtEveryRollbackFileBoundary_thenBothStoreFamiliesRestoreExactly() throws { + let rollbackBoundaries: [ + CrashConsistentStoreReplacementBoundary + ] = [ + .rollbackMarkerPersisted, + .liveFileRemoved(""), + .liveFileRemoved("-wal"), + .liveFileRemoved("-shm"), + .liveFileRemoved("-journal"), + .rollbackTemporaryFileCopied(""), + .rollbackTemporaryFileCopied("-wal"), + .rollbackTemporaryFileCopied("-shm"), + .rollbackTemporaryFileCopied("-journal"), + .rollbackFileInstalled(""), + .rollbackFileInstalled("-wal"), + .rollbackFileInstalled("-shm"), + .rollbackFileInstalled("-journal"), + .rollbackFamilyVerified, + .cleanupBackupFileRemoved(""), + .cleanupBackupFileRemoved("-wal"), + .cleanupBackupFileRemoved("-shm"), + .cleanupBackupFileRemoved("-journal"), + .cleanupBackupDirectoryRemoved, + .cleanupMarkerRemoved, + .cleanupTransactionDirectoryRemoved, + .cleanupRecoveryRootRemoved, + .transactionCleaned + ] + + for storeName in [ + "UserDataModel.sqlite", + "SubstrateDataModel.sqlite" + ] { + for (index, requestedBoundary) in + rollbackBoundaries.enumerated() { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "\(storeName)-rollback-\(index)" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent(storeName) + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged-\(storeName)") + try writeSyntheticStoreFamily( + at: liveStoreURL, + seed: 0x20 + ) + try writeSyntheticStoreFamily( + at: stagedStoreURL, + seed: 0xB0 + ) + let originalFamily = try syntheticStoreFamilySnapshot( + at: liveStoreURL + ) + var didInterrupt = false + let replacer = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: { targetURL, sourceURL in + try self.replaceSyntheticStoreFamily( + at: targetURL, + with: sourceURL + ) + throw UserStorageCommitTestError + .storeReplacementFailed + }, + boundaryHook: { boundary in + guard + !didInterrupt, + boundary == requestedBoundary + else { + return + } + + didInterrupt = true + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + + XCTAssertThrowsError( + try replacer.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ), + "\(storeName) \(requestedBoundary)" + ) + XCTAssertTrue( + didInterrupt, + "The requested rollback boundary was not reached" + ) + + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try relaunched.reconcile { _ in } + + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + originalFamily, + "\(storeName) \(requestedBoundary)" + ) + XCTAssertFalse(relaunched.hasPendingTransaction) + } + } + } + + func testCrashConsistentReplacement_whenProcessDiesDuringEveryCleanupDeletion_thenPreparingRollbackAndCommittedStatesConverge() throws { + let cleanupBoundaries: [ + CrashConsistentStoreReplacementBoundary + ] = [ + .cleanupMarkerTemporaryRemoved, + .cleanupBackupFileRemoved(""), + .cleanupBackupFileRemoved("-wal"), + .cleanupBackupFileRemoved("-shm"), + .cleanupBackupFileRemoved("-journal"), + .cleanupBackupDirectoryRemoved, + .cleanupMarkerRemoved, + .cleanupTransactionDirectoryRemoved, + .cleanupRecoveryRootRemoved, + .transactionCleaned + ] + + for transactionState in [ + "preparing", + "rolling-back", + "committed" + ] { + for (index, cleanupBoundary) in + cleanupBoundaries.enumerated() { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "cleanup-\(transactionState)-\(index)" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent("UserDataModel.sqlite") + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try writeSyntheticStoreFamily( + at: liveStoreURL, + seed: 0x24 + ) + try writeSyntheticStoreFamily( + at: stagedStoreURL, + seed: 0xB4 + ) + let originalFamily = try syntheticStoreFamilySnapshot( + at: liveStoreURL + ) + let committedFamily = try syntheticStoreFamilySnapshot( + at: stagedStoreURL + ) + var didCreateInterruptedState = false + let stateCreator = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: { targetURL, sourceURL in + try self.replaceSyntheticStoreFamily( + at: targetURL, + with: sourceURL + ) + if transactionState == "rolling-back" { + throw UserStorageCommitTestError + .storeReplacementFailed + } + }, + boundaryHook: { boundary in + let requestedBoundary: + CrashConsistentStoreReplacementBoundary + switch transactionState { + case "preparing": + requestedBoundary = + .backupFileCopied("-journal") + case "rolling-back": + requestedBoundary = + .rollbackFamilyVerified + case "committed": + requestedBoundary = + .committedMarkerPersisted + default: + return + } + + guard + !didCreateInterruptedState, + boundary == requestedBoundary + else { + return + } + didCreateInterruptedState = true + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try stateCreator.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) + XCTAssertTrue(didCreateInterruptedState) + + let pendingMarkerURL = + stateCreator.transactionDirectoryURL + .appendingPathComponent( + "transaction.json.pending" + ) + try Data("bounded-incomplete-marker".utf8) + .write(to: pendingMarkerURL) + + var didInterruptCleanup = false + let cleanupAttempt = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily, + boundaryHook: { boundary in + guard + !didInterruptCleanup, + boundary == cleanupBoundary + else { + return + } + didInterruptCleanup = true + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try cleanupAttempt.reconcile { _ in }, + "\(transactionState) \(cleanupBoundary)" + ) + XCTAssertTrue( + didInterruptCleanup, + "Cleanup boundary was not reached" + ) + + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try relaunched.reconcile { _ in } + + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + transactionState == "committed" + ? committedFamily + : originalFamily, + "\(transactionState) \(cleanupBoundary)" + ) + XCTAssertFalse(relaunched.hasPendingTransaction) + } + } + } + + func testCrashConsistentReplacement_whenProcessDiesDuringEachLowLevelFamilyMutation_thenBothStoreFamiliesRestoreExactly() throws { + let suffixes = + CrashConsistentStoreReplacer.storeFamilySuffixes + + for storeName in [ + "UserDataModel.sqlite", + "SubstrateDataModel.sqlite" + ] { + for interruptionIndex in 0 ..< suffixes.count * 2 { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "\(storeName)-partial-\(interruptionIndex)" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent(storeName) + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged-\(storeName)") + try writeSyntheticStoreFamily( + at: liveStoreURL, + seed: 0x30 + ) + try writeSyntheticStoreFamily( + at: stagedStoreURL, + seed: 0xC0 + ) + let originalFamily = try syntheticStoreFamilySnapshot( + at: liveStoreURL + ) + let replacer = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: { targetURL, sourceURL in + for (index, suffix) in suffixes.enumerated() { + try FileManager.default.removeItem( + at: self.syntheticFamilyURL( + targetURL, + suffix: suffix + ) + ) + if index == interruptionIndex { + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + } + + for (index, suffix) in suffixes.enumerated() { + try FileManager.default.copyItem( + at: self.syntheticFamilyURL( + sourceURL, + suffix: suffix + ), + to: self.syntheticFamilyURL( + targetURL, + suffix: suffix + ) + ) + if suffixes.count + index == + interruptionIndex { + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + } + } + ) + + XCTAssertThrowsError( + try replacer.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: liveStoreURL.path + ) && interruptionIndex == 0 + ) + + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try relaunched.reconcile { _ in } + + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + originalFamily, + "\(storeName) mutation \(interruptionIndex)" + ) + XCTAssertFalse(relaunched.hasPendingTransaction) + } + } + } + + func testCrashConsistentReplacement_whenFirstMarkerWriteIsInterrupted_thenOnlyExactSafePendingTreeIsCleaned() throws { + let recoverableDirectory = try makeSyntheticScenarioDirectory( + "markerless-pending-recoverable" + ) + let recoverableStoreURL = recoverableDirectory + .appendingPathComponent("UserDataModel.sqlite") + try writeSyntheticStoreFamily( + at: recoverableStoreURL, + seed: 0x38 + ) + let recoverableFamily = try syntheticStoreFamilySnapshot( + at: recoverableStoreURL + ) + let recoverableReplacer = CrashConsistentStoreReplacer( + storeURL: recoverableStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try FileManager.default.createDirectory( + at: recoverableReplacer.transactionDirectoryURL, + withIntermediateDirectories: true + ) + let recoverablePendingURL = + recoverableReplacer.transactionDirectoryURL + .appendingPathComponent("transaction.json.pending") + try Data("{\"schemaVersion\":1".utf8).write( + to: recoverablePendingURL + ) + + try recoverableReplacer.reconcile { _ in } + + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: recoverableStoreURL), + recoverableFamily + ) + XCTAssertFalse(recoverableReplacer.hasPendingTransaction) + + let unknownDirectory = try makeSyntheticScenarioDirectory( + "markerless-pending-unknown" + ) + let unknownStoreURL = unknownDirectory + .appendingPathComponent("UserDataModel.sqlite") + try writeSyntheticStoreFamily(at: unknownStoreURL, seed: 0x39) + let unknownFamily = try syntheticStoreFamilySnapshot( + at: unknownStoreURL + ) + let unknownReplacer = CrashConsistentStoreReplacer( + storeURL: unknownStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try FileManager.default.createDirectory( + at: unknownReplacer.transactionDirectoryURL, + withIntermediateDirectories: true + ) + let unknownPendingURL = unknownReplacer.transactionDirectoryURL + .appendingPathComponent("transaction.json.pending") + let unrelatedURL = unknownReplacer.transactionDirectoryURL + .appendingPathComponent("unrelated") + try Data("partial-marker".utf8).write(to: unknownPendingURL) + try Data("must-survive".utf8).write(to: unrelatedURL) + + XCTAssertThrowsError( + try unknownReplacer.reconcile { _ in } + ) + XCTAssertEqual( + try Data(contentsOf: unknownPendingURL), + Data("partial-marker".utf8) + ) + XCTAssertEqual( + try Data(contentsOf: unrelatedURL), + Data("must-survive".utf8) + ) + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: unknownStoreURL), + unknownFamily + ) + XCTAssertTrue(unknownReplacer.hasPendingTransaction) + + let symlinkDirectory = try makeSyntheticScenarioDirectory( + "markerless-pending-symlink" + ) + let symlinkStoreURL = symlinkDirectory + .appendingPathComponent("UserDataModel.sqlite") + try writeSyntheticStoreFamily(at: symlinkStoreURL, seed: 0x3A) + let symlinkFamily = try syntheticStoreFamilySnapshot( + at: symlinkStoreURL + ) + let symlinkReplacer = CrashConsistentStoreReplacer( + storeURL: symlinkStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try FileManager.default.createDirectory( + at: symlinkReplacer.transactionDirectoryURL, + withIntermediateDirectories: true + ) + let symlinkTargetURL = symlinkDirectory + .appendingPathComponent("pending-target") + try Data("must-survive".utf8).write(to: symlinkTargetURL) + try FileManager.default.createSymbolicLink( + at: symlinkReplacer.transactionDirectoryURL + .appendingPathComponent("transaction.json.pending"), + withDestinationURL: symlinkTargetURL + ) + + XCTAssertThrowsError( + try symlinkReplacer.reconcile { _ in } + ) + XCTAssertEqual( + try Data(contentsOf: symlinkTargetURL), + Data("must-survive".utf8) + ) + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: symlinkStoreURL), + symlinkFamily + ) + XCTAssertTrue(symlinkReplacer.hasPendingTransaction) + } + + func testCrashConsistentReplacement_whenPreparingBackupCopyIsPartial_thenCleansOnlyWithExactOriginalLiveFamily() throws { + for liveFamilyChanged in [false, true] { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + liveFamilyChanged + ? "partial-preparing-backup-changed-live" + : "partial-preparing-backup-exact-live" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent("UserDataModel.sqlite") + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try writeSyntheticStoreFamily(at: liveStoreURL, seed: 0x3B) + try writeSyntheticStoreFamily(at: stagedStoreURL, seed: 0xCB) + let originalFamily = try syntheticStoreFamilySnapshot( + at: liveStoreURL + ) + let interrupted = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily, + boundaryHook: { boundary in + guard boundary == .preparingMarkerPersisted else { + return + } + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try interrupted.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) + + let backupDirectoryURL = + interrupted.transactionDirectoryURL + .appendingPathComponent( + "OriginalStoreFamily", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: backupDirectoryURL, + withIntermediateDirectories: false + ) + let partialBackupURL = backupDirectoryURL + .appendingPathComponent(liveStoreURL.lastPathComponent) + try Data("partial-copy".utf8).write(to: partialBackupURL) + + if liveFamilyChanged { + try Data("changed-live-main".utf8).write( + to: liveStoreURL + ) + } + let familyBeforeReconcile = + try syntheticStoreFamilySnapshot(at: liveStoreURL) + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + + if liveFamilyChanged { + XCTAssertThrowsError( + try relaunched.reconcile { _ in } + ) + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + familyBeforeReconcile + ) + XCTAssertEqual( + try Data(contentsOf: partialBackupURL), + Data("partial-copy".utf8) + ) + XCTAssertTrue(relaunched.hasPendingTransaction) + } else { + try relaunched.reconcile { _ in } + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + originalFamily + ) + XCTAssertFalse(relaunched.hasPendingTransaction) + } + } + } + + func testCrashConsistentReplacement_whenMarkerIsAdversarial_thenFailsClosedWithoutChangingLiveFamily() throws { + for mutation in [ + "duplicate-member", + "path-traversal", + "digest-mismatch", + "size-mismatch", + "noncanonical-order", + "top-duplicate-field", + "top-unknown-field", + "member-duplicate-field", + "member-unknown-field", + "escaped-field-name", + "wrong-top-field-type", + "wrong-member-field-type", + "wrong-family-container-type", + "oversized", + "markerless-nonempty" + ] { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "adversarial-\(mutation)" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent("UserDataModel.sqlite") + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try writeSyntheticStoreFamily(at: liveStoreURL, seed: 0x40) + try writeSyntheticStoreFamily(at: stagedStoreURL, seed: 0xD0) + let originalFamily = try syntheticStoreFamilySnapshot( + at: liveStoreURL + ) + var didInterrupt = false + let interrupted = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily, + boundaryHook: { boundary in + guard + !didInterrupt, + boundary == .committingMarkerPersisted + else { + return + } + + didInterrupt = true + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try interrupted.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) + XCTAssertTrue(didInterrupt) + + let markerURL = interrupted.transactionDirectoryURL + .appendingPathComponent("transaction.json") + if mutation == "oversized" { + try Data(repeating: 0x7B, count: 64 * 1024 + 1) + .write(to: markerURL) + } else if mutation == "markerless-nonempty" { + try FileManager.default.removeItem(at: markerURL) + } else if [ + "top-duplicate-field", + "top-unknown-field", + "member-duplicate-field", + "member-unknown-field", + "escaped-field-name", + "wrong-top-field-type", + "wrong-member-field-type" + ].contains(mutation) { + let originalJSON = try XCTUnwrap( + String( + data: Data(contentsOf: markerURL), + encoding: .utf8 + ) + ) + let mutatedJSON: String + switch mutation { + case "top-duplicate-field": + mutatedJSON = + String(originalJSON.dropLast()) + + ",\"state\":\"committing\"}" + case "top-unknown-field": + mutatedJSON = + String(originalJSON.dropLast()) + + ",\"unexpected\":true}" + case "member-duplicate-field": + mutatedJSON = originalJSON.replacingOccurrences( + of: "\"suffix\":\"\"", + with: "\"suffix\":\"\",\"suffix\":\"\"" + ) + case "member-unknown-field": + mutatedJSON = originalJSON.replacingOccurrences( + of: "\"suffix\":\"\"", + with: "\"suffix\":\"\",\"unexpected\":0" + ) + case "escaped-field-name": + mutatedJSON = originalJSON.replacingOccurrences( + of: "\"state\"", + with: "\"st\\u0061te\"" + ) + case "wrong-top-field-type": + mutatedJSON = originalJSON.replacingOccurrences( + of: "\"schemaVersion\":1", + with: "\"schemaVersion\":\"1\"" + ) + case "wrong-member-field-type": + mutatedJSON = originalJSON.replacingOccurrences( + of: "\"byteCount\":31", + with: "\"byteCount\":\"31\"" + ) + default: + throw UserStorageCommitTestError + .storeReplacementFailed + } + XCTAssertNotEqual(mutatedJSON, originalJSON) + try Data(mutatedJSON.utf8).write(to: markerURL) + } else { + var marker = try XCTUnwrap( + JSONSerialization.jsonObject( + with: Data(contentsOf: markerURL) + ) as? [String: Any] + ) + var family = try XCTUnwrap( + marker["originalFamily"] + as? [[String: Any]] + ) + + switch mutation { + case "duplicate-member": + family.append(family[0]) + case "path-traversal": + family[0]["suffix"] = "../UserDataModel.sqlite" + case "digest-mismatch": + family[0]["sha256"] = String( + repeating: "0", + count: 64 + ) + case "size-mismatch": + let oldSize = ( + family[0]["byteCount"] as? NSNumber + )?.uint64Value ?? 0 + family[0]["byteCount"] = NSNumber( + value: oldSize + 1 + ) + case "noncanonical-order": + family.reverse() + case "wrong-family-container-type": + marker["originalFamily"] = + "not-an-array" + default: + XCTFail("Unhandled mutation \(mutation)") + } + + if mutation != "wrong-family-container-type" { + marker["originalFamily"] = family + } + try JSONSerialization.data( + withJSONObject: marker, + options: [.sortedKeys] + ).write(to: markerURL) + } + + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + XCTAssertThrowsError( + try relaunched.reconcile { _ in }, + mutation + ) + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + originalFamily, + mutation + ) + XCTAssertTrue(relaunched.hasPendingTransaction) + } + } + + func testCrashConsistentReplacement_whenTransactionTreeContainsUnknownFileOrDirectory_thenFailsClosed() throws { + for mutation in [ + "top-file", + "top-directory", + "backup-file", + "backup-directory" + ] { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "unknown-tree-\(mutation)" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent("UserDataModel.sqlite") + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try writeSyntheticStoreFamily(at: liveStoreURL, seed: 0x45) + try writeSyntheticStoreFamily(at: stagedStoreURL, seed: 0xD5) + let originalFamily = try syntheticStoreFamilySnapshot( + at: liveStoreURL + ) + let interrupted = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily, + boundaryHook: { boundary in + guard boundary == .committingMarkerPersisted else { + return + } + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try interrupted.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) + + let backupDirectory = interrupted + .transactionDirectoryURL + .appendingPathComponent( + "OriginalStoreFamily", + isDirectory: true + ) + let unknownURL: URL + let isDirectory: Bool + switch mutation { + case "top-file": + unknownURL = interrupted.transactionDirectoryURL + .appendingPathComponent("unknown") + isDirectory = false + case "top-directory": + unknownURL = interrupted.transactionDirectoryURL + .appendingPathComponent( + "UnknownDirectory", + isDirectory: true + ) + isDirectory = true + case "backup-file": + unknownURL = backupDirectory + .appendingPathComponent("unknown") + isDirectory = false + case "backup-directory": + unknownURL = backupDirectory + .appendingPathComponent( + "UnknownDirectory", + isDirectory: true + ) + isDirectory = true + default: + throw UserStorageCommitTestError + .storeReplacementFailed + } + + if isDirectory { + try FileManager.default.createDirectory( + at: unknownURL, + withIntermediateDirectories: false + ) + } else { + try Data("unknown".utf8).write(to: unknownURL) + } + + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + XCTAssertThrowsError( + try relaunched.reconcile { _ in }, + mutation + ) + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + originalFamily + ) + XCTAssertTrue(relaunched.hasPendingTransaction) + } + } + + func testCrashConsistentReplacement_whenCommittedFamilyOrSemanticValidationChanges_thenRestoresOriginalFamily() throws { + for mutation in [ + "live-bytes", + "semantic-validation", + "validator-mutates-live" + ] { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "committed-\(mutation)" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent("UserDataModel.sqlite") + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try writeSyntheticStoreFamily(at: liveStoreURL, seed: 0x50) + try writeSyntheticStoreFamily(at: stagedStoreURL, seed: 0xE0) + let originalFamily = try syntheticStoreFamilySnapshot( + at: liveStoreURL + ) + var didInterrupt = false + let interrupted = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily, + boundaryHook: { boundary in + guard + !didInterrupt, + boundary == .committedMarkerPersisted + else { + return + } + + didInterrupt = true + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try interrupted.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) + + if mutation == "live-bytes" { + try Data("tampered-after-commit".utf8).write( + to: liveStoreURL + ) + } + + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try relaunched.reconcile { _ in + if mutation == "semantic-validation" { + throw UserStorageCommitTestError + .storeReplacementFailed + } else if mutation == "validator-mutates-live" { + try Data("validator-mutated-live".utf8).write( + to: liveStoreURL + ) + } + } + + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + originalFamily, + mutation + ) + XCTAssertFalse(relaunched.hasPendingTransaction) + } + } + + func testCrashConsistentReplacement_whenCommittedValidationMutatesItsStoreAndCleanupIsInterrupted_thenLiveCommitStillConverges() throws { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "committed-private-validation" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent("UserDataModel.sqlite") + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try writeSyntheticStoreFamily(at: liveStoreURL, seed: 0x52) + try writeSyntheticStoreFamily(at: stagedStoreURL, seed: 0xE2) + let committedFamily = try syntheticStoreFamilySnapshot( + at: stagedStoreURL + ) + let interrupted = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily, + boundaryHook: { boundary in + guard boundary == .committedMarkerPersisted else { + return + } + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try interrupted.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) + + var validationStoreURL: URL? + var didInterruptCleanup = false + let cleanupAttempt = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily, + boundaryHook: { boundary in + guard + !didInterruptCleanup, + boundary == .cleanupBackupFileRemoved("") + else { + return + } + didInterruptCleanup = true + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try cleanupAttempt.reconcile { privateStoreURL in + validationStoreURL = privateStoreURL + XCTAssertNotEqual( + privateStoreURL.standardizedFileURL, + liveStoreURL.standardizedFileURL + ) + + for suffix in + CrashConsistentStoreReplacer.storeFamilySuffixes { + let memberURL = self.syntheticFamilyURL( + privateStoreURL, + suffix: suffix + ) + guard FileManager.default.fileExists( + atPath: memberURL.path + ) else { + continue + } + try Data("validator-mutated-\(suffix)".utf8) + .write(to: memberURL) + } + } + ) + XCTAssertTrue(didInterruptCleanup) + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + committedFamily + ) + let capturedValidationStoreURL = try XCTUnwrap( + validationStoreURL + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: capturedValidationStoreURL.path + ) + ) + + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try relaunched.reconcile { privateStoreURL in + XCTAssertNotEqual( + privateStoreURL.standardizedFileURL, + liveStoreURL.standardizedFileURL + ) + XCTAssertEqual( + try self.syntheticStoreFamilySnapshot( + at: privateStoreURL + ), + committedFamily + ) + } + + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + committedFamily + ) + XCTAssertFalse(relaunched.hasPendingTransaction) + } + + func testCrashConsistentReplacement_whenMarkerBackupOrLiveMemberIsSymlink_thenFailsClosed() throws { + for mutation in ["marker", "backup-main", "live-main"] { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "symlink-\(mutation)" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent("UserDataModel.sqlite") + let stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try writeSyntheticStoreFamily(at: liveStoreURL, seed: 0x55) + try writeSyntheticStoreFamily(at: stagedStoreURL, seed: 0xF0) + var didInterrupt = false + let interrupted = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily, + boundaryHook: { boundary in + guard + !didInterrupt, + boundary == .committingMarkerPersisted + else { + return + } + + didInterrupt = true + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + XCTAssertThrowsError( + try interrupted.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ) + ) + + let markerURL = interrupted.transactionDirectoryURL + .appendingPathComponent("transaction.json") + let backupMainURL = interrupted.transactionDirectoryURL + .appendingPathComponent( + "OriginalStoreFamily", + isDirectory: true + ) + .appendingPathComponent(liveStoreURL.lastPathComponent) + + switch mutation { + case "marker": + let displacedURL = scenarioDirectory + .appendingPathComponent("DisplacedMarker") + try FileManager.default.moveItem( + at: markerURL, + to: displacedURL + ) + try FileManager.default.createSymbolicLink( + at: markerURL, + withDestinationURL: displacedURL + ) + case "backup-main": + try FileManager.default.removeItem(at: backupMainURL) + try FileManager.default.createSymbolicLink( + at: backupMainURL, + withDestinationURL: liveStoreURL + ) + case "live-main": + let displacedURL = scenarioDirectory + .appendingPathComponent("DisplacedLiveMain") + try FileManager.default.moveItem( + at: liveStoreURL, + to: displacedURL + ) + try FileManager.default.createSymbolicLink( + at: liveStoreURL, + withDestinationURL: displacedURL + ) + default: + XCTFail("Unhandled mutation \(mutation)") + } + + let relaunched = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + XCTAssertThrowsError( + try relaunched.reconcile { _ in }, + mutation + ) + XCTAssertTrue(relaunched.hasPendingTransaction) + } + } + + func testCrashConsistentReplacement_whenLiveFamilyIsUnsafeOrOrphaned_thenNeverReportsAnEmptyStore() throws { + let orphanDirectory = try makeSyntheticScenarioDirectory( + "orphan-sidecar" + ) + let orphanStoreURL = orphanDirectory + .appendingPathComponent("UserDataModel.sqlite") + try Data("orphan-wal".utf8).write( + to: syntheticFamilyURL( + orphanStoreURL, + suffix: "-wal" + ) + ) + let orphanReplacer = CrashConsistentStoreReplacer( + storeURL: orphanStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + XCTAssertThrowsError( + try orphanReplacer.liveStoreExistsSafely() + ) + + let symlinkDirectory = try makeSyntheticScenarioDirectory( + "symlink-sidecar" + ) + let symlinkStoreURL = symlinkDirectory + .appendingPathComponent("SubstrateDataModel.sqlite") + try Data("main".utf8).write(to: symlinkStoreURL) + let symlinkTargetURL = symlinkDirectory + .appendingPathComponent("SidecarTarget") + try Data("target".utf8).write(to: symlinkTargetURL) + try FileManager.default.createSymbolicLink( + at: syntheticFamilyURL( + symlinkStoreURL, + suffix: "-shm" + ), + withDestinationURL: symlinkTargetURL + ) + let symlinkReplacer = CrashConsistentStoreReplacer( + storeURL: symlinkStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + XCTAssertThrowsError( + try symlinkReplacer.liveStoreExistsSafely() + ) + + let directoryStoreRoot = try makeSyntheticScenarioDirectory( + "directory-main" + ) + let directoryStoreURL = directoryStoreRoot + .appendingPathComponent("UserDataModel.sqlite") + try FileManager.default.createDirectory( + at: directoryStoreURL, + withIntermediateDirectories: false + ) + let directoryReplacer = CrashConsistentStoreReplacer( + storeURL: directoryStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + XCTAssertThrowsError( + try directoryReplacer.liveStoreExistsSafely() + ) + } + + func testCrashConsistentReplacement_whenStagedFamilyIsUnsafeOrAliasesProtectedPaths_thenRejectsBeforeMutation() throws { + for mutation in [ + "same-live-path", + "dotdot-live-alias", + "hardlink-main", + "intra-family-hardlink", + "symlink-main", + "symlink-sidecar", + "orphan-sidecar", + "inside-recovery-root" + ] { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "unsafe-stage-\(mutation)" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent("UserDataModel.sqlite") + try writeSyntheticStoreFamily(at: liveStoreURL, seed: 0x5A) + let originalFamily = try syntheticStoreFamilySnapshot( + at: liveStoreURL + ) + let stagedStoreURL: URL + + switch mutation { + case "same-live-path": + stagedStoreURL = liveStoreURL + case "dotdot-live-alias": + let aliasDirectory = scenarioDirectory + .appendingPathComponent( + "Alias", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: aliasDirectory, + withIntermediateDirectories: false + ) + stagedStoreURL = URL( + fileURLWithPath: + "\(aliasDirectory.path)/../\(liveStoreURL.lastPathComponent)" + ) + case "hardlink-main": + stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try FileManager.default.linkItem( + at: liveStoreURL, + to: stagedStoreURL + ) + case "intra-family-hardlink": + stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try writeSyntheticStoreFamily( + at: stagedStoreURL, + seed: 0xEA + ) + let stagedWALURL = syntheticFamilyURL( + stagedStoreURL, + suffix: "-wal" + ) + try FileManager.default.removeItem(at: stagedWALURL) + try FileManager.default.linkItem( + at: stagedStoreURL, + to: stagedWALURL + ) + case "symlink-main": + stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try FileManager.default.createSymbolicLink( + at: stagedStoreURL, + withDestinationURL: liveStoreURL + ) + case "symlink-sidecar": + stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try Data("staged-main".utf8).write( + to: stagedStoreURL + ) + try FileManager.default.createSymbolicLink( + at: syntheticFamilyURL( + stagedStoreURL, + suffix: "-wal" + ), + withDestinationURL: syntheticFamilyURL( + liveStoreURL, + suffix: "-wal" + ) + ) + case "orphan-sidecar": + stagedStoreURL = scenarioDirectory + .appendingPathComponent("Staged.sqlite") + try Data("orphan-staged-wal".utf8).write( + to: syntheticFamilyURL( + stagedStoreURL, + suffix: "-wal" + ) + ) + case "inside-recovery-root": + let recoveryDirectory = scenarioDirectory + .appendingPathComponent( + ".FearlessStoreReplacement/Attacker", + isDirectory: true + ) + try FileManager.default.createDirectory( + at: recoveryDirectory, + withIntermediateDirectories: true + ) + stagedStoreURL = recoveryDirectory + .appendingPathComponent("Staged.sqlite") + try Data("staged-main".utf8).write( + to: stagedStoreURL + ) + default: + throw UserStorageCommitTestError + .storeReplacementFailed + } + + var replacementWasCalled = false + let replacer = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: { _, _ in + replacementWasCalled = true + } + ) + XCTAssertThrowsError( + try replacer.replaceStore( + with: stagedStoreURL, + validateDestination: { _ in } + ), + mutation + ) + XCTAssertFalse(replacementWasCalled, mutation) + XCTAssertEqual( + try syntheticStoreFamilySnapshot(at: liveStoreURL), + originalFamily, + mutation + ) + XCTAssertFalse(replacer.hasPendingTransaction) + } + } + + func testCrashConsistentReplacement_whenPreMarkerDirectoryIsEmpty_thenSafelyCleansItOnlyAfterValidatingLiveFamily() throws { + let scenarioDirectory = try makeSyntheticScenarioDirectory( + "empty-pre-marker" + ) + let liveStoreURL = scenarioDirectory + .appendingPathComponent("UserDataModel.sqlite") + try writeSyntheticStoreFamily(at: liveStoreURL, seed: 0x58) + let replacer = CrashConsistentStoreReplacer( + storeURL: liveStoreURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + try FileManager.default.createDirectory( + at: replacer.transactionDirectoryURL, + withIntermediateDirectories: true + ) + + try replacer.reconcile { _ in } + + XCTAssertFalse(replacer.hasPendingTransaction) + XCTAssertTrue(try replacer.liveStoreExistsSafely()) + } + + func testCrashConsistentReplacement_whenPathsShareDirectory_thenUserAndSubstrateTransactionsCannotCollide() throws { + try writeSyntheticStoreFamily(at: storeURL, seed: 0x60) + let substrateURL = testDirectory + .appendingPathComponent("SubstrateDataModel.sqlite") + try writeSyntheticStoreFamily(at: substrateURL, seed: 0x70) + + let userReplacer = CrashConsistentStoreReplacer( + storeURL: storeURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + let substrateReplacer = CrashConsistentStoreReplacer( + storeURL: substrateURL, + fileManager: .default, + storeReplacer: replaceSyntheticStoreFamily + ) + + XCTAssertNotEqual( + userReplacer.transactionDirectoryURL.standardizedFileURL, + substrateReplacer.transactionDirectoryURL + .standardizedFileURL + ) + XCTAssertEqual( + userReplacer.transactionDirectoryURL + .deletingLastPathComponent(), + substrateReplacer.transactionDirectoryURL + .deletingLastPathComponent() + ) + } + + func testCompatibilityModels_whenBundled_thenHaveExactFingerprintsAndMigrationEdges() throws { + let expectedLegacyHashes = [ + "CDAccountInfo": "q3sBYA7JunDkaJOaTevIdD/b1Ou+4Qrdi0twbrghhf8=", + "CDAssetVisibility": "IYchCCjZ4/tlPbRVhOIyAtOY1J6500tV0GoXt7gb5Ac=", + "CDChainAccount": "AVvqEhz7A8aiXmrGYNuGkrLTmUy2GdEzHx5uh1rR+6Y=", + "CDChainSettings": "GHqxJZE9c7xLExSYsWfzpktGdVvQqqFyACPiYKaLgsQ=", + "CDCurrency": "iF3edtRVNvP9XKRuZuVOU5YFx50BLwbUqlaPKdBHgmk=", + "CDCustomChainNode": "/mUD0P2skKW0f6ao8jt07yDn3BARGk3Ve9qc2W6Zl8k=", + "CDMetaAccount": "teqUP1fwr7jL/V0Tm33An9SPbBlLr9L6ioRO8fkPIjA=" + ] + let expectedCurrentHashes = expectedLegacyHashes.merging( + ["CDChainAccount": "jvrdZWLn1+K0pe0MCQsxJP2fdOiiAAYkoSJf4x1Y5JU="] + ) { _, current in current } + + let legacyURL = try directCompatibilityModelURL(for: .version13) + let currentURL = try directCompatibilityModelURL(for: .version14) + let legacyModel = try loadModel(at: legacyURL) + let currentModel = try loadModel(at: currentURL) + + XCTAssertEqual(versionHashes(for: legacyModel), expectedLegacyHashes) + XCTAssertEqual(versionHashes(for: currentModel), expectedCurrentHashes) + XCTAssertEqual( + try storeChecksum(for: legacyModel, named: "legacy-fingerprint.sqlite"), + legacyChecksum + ) + XCTAssertEqual( + try storeChecksum(for: currentModel, named: "current-fingerprint.sqlite"), + currentChecksum + ) + + XCTAssertEqual(UserStorageVersion.version12.nextVersion(), .version14) + XCTAssertEqual(UserStorageVersion.version13.nextVersion(), .version14) + XCTAssertNil(UserStorageVersion.version14.nextVersion()) + XCTAssertEqual(UserStorageVersion.current, .version14) + } + + func testCurrentModel_whenLoaded_thenEveryEntityResolvesToTheAppRuntimeClass() throws { + let expectedClasses: [String: NSManagedObject.Type] = [ + "CDAccountInfo": fearless.CDAccountInfo.self, + "CDAssetVisibility": fearless.CDAssetVisibility.self, + "CDChainAccount": fearless.CDChainAccount.self, + "CDChainSettings": fearless.CDChainSettings.self, + "CDCurrency": fearless.CDCurrency.self, + "CDCustomChainNode": fearless.CDCustomChainNode.self, + "CDMetaAccount": fearless.CDMetaAccount.self + ] + let currentModel = try model(for: .version14) + + for (entityName, expectedClass) in expectedClasses { + let entity = try XCTUnwrap(currentModel.entitiesByName[entityName]) + let className = try XCTUnwrap(entity.managedObjectClassName) + let resolvedClass = try XCTUnwrap( + NSClassFromString(className) as? NSManagedObject.Type, + "\(className) must resolve to an NSManagedObject class" + ) + + XCTAssertEqual( + ObjectIdentifier(resolvedClass), + ObjectIdentifier(expectedClass), + "\(entityName) resolved to a different runtime class than the app alias" + ) + } + } + + func testMigration_whenVersion2PersistentFixture_thenPreservesWalletsAndAccountsAndRoutesExistingPincodeToPinOnRepeatedLaunch() throws { + let sourceModel = try model(for: .version2) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertVersion2WalletFixture( + in: context, + model: sourceModel + ) + } + let pincode = Data("246810".utf8) + let keystore = InMemoryKeychain() + try keystore.saveKey( + pincode, + with: fearless.KeystoreTag.pincode.rawValue + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + + XCTAssertTrue(try migrator.performMigration()) + XCTAssertFalse(try migrator.performMigration()) + XCTAssertEqual( + try walletSnapshots( + from: storeURL, + model: model(for: .version14) + ), + version2WalletFixtureSnapshots() + ) + + let facade = UserDataStorageFacade( + modelURL: UserStorageVersion.version14.modelURL( + in: appBundle, + legacyModelDirectory: UserStorageParams.modelDirectory + ), + databaseDirectory: testDirectory + ) + defer { + try? facade.databaseService.close() + } + let selectedWalletSettings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: OperationQueue() + ) + let setupExpectation = expectation( + description: "migrated v2 wallets are resolved" + ) + selectedWalletSettings.setup( + runningCompletionIn: .main + ) { result in + do { + XCTAssertNotNil(try result.get()) + } catch { + XCTFail("Migrated v2 wallet setup failed: \(error)") + } + setupExpectation.fulfill() + } + wait( + for: [setupExpectation], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual(selectedWalletSettings.storeState, .ready) + let helper = StartViewHelper( + keystore: keystore, + selectedWalletSettings: selectedWalletSettings, + userDefaultsStorage: InMemorySettingsManager() + ) + guard case .pin = helper.startView(onboardingConfig: nil) else { + return XCTFail( + "A nonempty migrated v2 store with a PIN must route to authentication" + ) + } + XCTAssertEqual( + try keystore.fetchKey(for: fearless.KeystoreTag.pincode.rawValue), + pincode + ) + } + + func testPerformMigration_whenIntermediateV3StoreDropsWallet_thenPerHopCountFailsClosedAndRetryPreservesFixture() throws { + let sourceModel = try model(for: .version2) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertVersion2WalletFixture( + in: context, + model: sourceModel + ) + } + let sourceChecksum = try metadataChecksum(at: storeURL) + let sourceFiles = try durableStoreSnapshot(at: storeURL) + let pincode = Data("135790".utf8) + let keystore = InMemoryKeychain() + try keystore.saveKey( + pincode, + with: fearless.KeystoreTag.pincode.rawValue + ) + var stagedMutationCount = 0 + let adversarialMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + stagedStoreWillValidate: { stagedURL, version in + guard version == .version3 else { + return + } + + stagedMutationCount += 1 + try self.executeSQLite( + "DELETE FROM ZCDMETAACCOUNT " + + "WHERE Z_PK = " + + "(SELECT MIN(Z_PK) FROM ZCDMETAACCOUNT)", + at: stagedURL + ) + } + ) + + XCTAssertThrowsError( + try adversarialMigrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertEqual(stagedMutationCount, 1) + XCTAssertEqual(try metadataChecksum(at: storeURL), sourceChecksum) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + sourceFiles + ) + XCTAssertEqual( + try keystore.fetchKey(for: fearless.KeystoreTag.pincode.rawValue), + pincode + ) + + let retryMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + XCTAssertTrue(try retryMigrator.performMigration()) + XCTAssertFalse(try retryMigrator.performMigration()) + XCTAssertEqual( + try walletSnapshots( + from: storeURL, + model: model(for: .version14) + ), + version2WalletFixtureSnapshots() + ) + XCTAssertEqual( + try keystore.fetchKey(for: fearless.KeystoreTag.pincode.rawValue), + pincode + ) + } + + func testPerformMigration_whenIntermediateV3StoreDropsChainAccountButWalletCountIsUnchanged_thenPerHopIntegrityFailsClosed() throws { + let sourceModel = try model(for: .version2) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertVersion2WalletFixture( + in: context, + model: sourceModel + ) + } + let sourceChecksum = try metadataChecksum(at: storeURL) + let sourceFiles = try durableStoreSnapshot(at: storeURL) + var stagedMutationCount = 0 + let adversarialMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + stagedStoreWillValidate: { stagedURL, version in + guard version == .version3 else { + return + } + + stagedMutationCount += 1 + try self.executeSQLite( + "DELETE FROM ZCDCHAINACCOUNT " + + "WHERE Z_PK = " + + "(SELECT MIN(Z_PK) FROM ZCDCHAINACCOUNT)", + at: stagedURL + ) + } + ) + + XCTAssertThrowsError( + try adversarialMigrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertEqual(stagedMutationCount, 1) + XCTAssertEqual(try metadataChecksum(at: storeURL), sourceChecksum) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + sourceFiles + ) + + let retryMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + XCTAssertTrue(try retryMigrator.performMigration()) + XCTAssertEqual( + try walletSnapshots( + from: storeURL, + model: model(for: .version14) + ), + version2WalletFixtureSnapshots() + ) + } + + func testPerformMigration_whenIntermediateV3StoreMutatesWalletFieldWithoutChangingCount_thenPerHopIntegrityFailsClosed() throws { + let sourceModel = try model(for: .version2) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertVersion2WalletFixture( + in: context, + model: sourceModel + ) + } + let sourceChecksum = try metadataChecksum(at: storeURL) + let sourceFiles = try durableStoreSnapshot(at: storeURL) + var stagedMutationCount = 0 + let adversarialMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + stagedStoreWillValidate: { stagedURL, version in + guard version == .version3 else { + return + } + + stagedMutationCount += 1 + try self.executeSQLite( + "UPDATE ZCDMETAACCOUNT " + + "SET ZNAME = 'adversarial-wallet-name' " + + "WHERE Z_PK = " + + "(SELECT MIN(Z_PK) FROM ZCDMETAACCOUNT)", + at: stagedURL + ) + } + ) + + XCTAssertThrowsError( + try adversarialMigrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertEqual(stagedMutationCount, 1) + XCTAssertEqual(try metadataChecksum(at: storeURL), sourceChecksum) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + sourceFiles + ) + + let retryMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + XCTAssertTrue(try retryMigrator.performMigration()) + XCTAssertEqual( + try walletSnapshots( + from: storeURL, + model: model(for: .version14) + ), + version2WalletFixtureSnapshots() + ) + } + + func testMigration_whenLegacyFieldsAreIntentionallyDerived_thenPreservesExactAssetVisibilityAndNetworkFilterSemantics() throws { + let visibilityURL = testDirectory.appendingPathComponent( + "version9-asset-visibility.sqlite" + ) + let visibilitySourceModel = try model(for: .version9) + try createStore( + at: visibilityURL, + model: visibilitySourceModel + ) { context in + let wallet = try self.insertHistoricalWallet( + metaId: "visibility-wallet", + name: "Visibility Wallet", + in: context, + model: visibilitySourceModel + ) + wallet.setValue( + ["asset-b", "asset-a"] as NSArray, + forKey: "assetIdsEnabled" + ) + } + + let visibilityMigrator = UserStorageMigrator( + targetVersion: .version10, + storeURL: visibilityURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + XCTAssertTrue(try visibilityMigrator.performMigration()) + var migratedVisibility = [String: Bool]() + try useStore( + at: visibilityURL, + model: model(for: .version10) + ) { context in + let request = NSFetchRequest( + entityName: "CDAssetVisibility" + ) + for visibility in try context.fetch(request) { + let assetId = try XCTUnwrap( + visibility.value(forKey: "assetId") as? String + ) + let hidden = try XCTUnwrap( + visibility.value(forKey: "hidden") as? NSNumber + ) + migratedVisibility[assetId] = hidden.boolValue + } + } + XCTAssertEqual( + migratedVisibility, + ["asset-a": true, "asset-b": true] + ) + + let filterURL = testDirectory.appendingPathComponent( + "version11-network-filter.sqlite" + ) + let filterSourceModel = try model(for: .version11) + try createStore( + at: filterURL, + model: filterSourceModel + ) { context in + let wallet = try self.insertHistoricalWallet( + metaId: "filter-wallet", + name: "Filter Wallet", + in: context, + model: filterSourceModel + ) + wallet.setValue( + "polkadot-filter", + forKey: "chainIdForFilter" + ) + } + + let filterMigrator = UserStorageMigrator( + targetVersion: .version12, + storeURL: filterURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + XCTAssertTrue(try filterMigrator.performMigration()) + var migratedFilter: String? + var migratedFavourites: [String]? + try useStore( + at: filterURL, + model: model(for: .version12) + ) { context in + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + let wallet = try XCTUnwrap( + context.fetch(request).first + ) + migratedFilter = wallet.value( + forKey: "networkManagmentFilter" + ) as? String + migratedFavourites = + try SafeTransformableValueReader.read( + from: wallet, + key: "favouriteChainIds" + ) + } + XCTAssertEqual(migratedFilter, "polkadot-filter") + XCTAssertEqual(migratedFavourites, []) + } + + func testMigration_whenIntentionalDerivedFieldsAreDroppedOrMutatedInStaging_thenSemanticIntegrityFailsClosed() throws { + let visibilityURL = testDirectory.appendingPathComponent( + "adversarial-version9-asset-visibility.sqlite" + ) + let visibilitySourceModel = try model(for: .version9) + try createStore( + at: visibilityURL, + model: visibilitySourceModel + ) { context in + let wallet = try self.insertHistoricalWallet( + metaId: "visibility-wallet", + name: "Visibility Wallet", + in: context, + model: visibilitySourceModel + ) + wallet.setValue( + ["asset-a", "asset-b"] as NSArray, + forKey: "assetIdsEnabled" + ) + } + let visibilitySourceFiles = + try durableStoreSnapshot(at: visibilityURL) + let visibilityMigrator = UserStorageMigrator( + targetVersion: .version10, + storeURL: visibilityURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + stagedStoreWillValidate: { stagedURL, version in + guard version == .version10 else { + return + } + + try self.executeSQLite( + "DELETE FROM ZCDASSETVISIBILITY " + + "WHERE Z_PK = " + + "(SELECT MIN(Z_PK) " + + "FROM ZCDASSETVISIBILITY)", + at: stagedURL + ) + } + ) + XCTAssertThrowsError( + try visibilityMigrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertEqual( + try durableStoreSnapshot(at: visibilityURL), + visibilitySourceFiles + ) + + let filterURL = testDirectory.appendingPathComponent( + "adversarial-version11-network-filter.sqlite" + ) + let filterSourceModel = try model(for: .version11) + try createStore( + at: filterURL, + model: filterSourceModel + ) { context in + let wallet = try self.insertHistoricalWallet( + metaId: "filter-wallet", + name: "Filter Wallet", + in: context, + model: filterSourceModel + ) + wallet.setValue( + "polkadot-filter", + forKey: "chainIdForFilter" + ) + } + let filterSourceFiles = + try durableStoreSnapshot(at: filterURL) + let filterMigrator = UserStorageMigrator( + targetVersion: .version12, + storeURL: filterURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + stagedStoreWillValidate: { stagedURL, version in + guard version == .version12 else { + return + } + + try self.executeSQLite( + "UPDATE ZCDMETAACCOUNT SET " + + "ZNETWORKMANAGMENTFILTER = " + + "'adversarial-filter'", + at: stagedURL + ) + } + ) + XCTAssertThrowsError( + try filterMigrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertEqual( + try durableStoreSnapshot(at: filterURL), + filterSourceFiles + ) + } + + func testMigration_whenV1ToV2DropsDestinationAccount_thenLegacyAccountSemanticIntegrityFailsClosed() throws { + let sourceModel = try model(for: .version1) + let addressFactory = SS58AddressFactory() + let addresses = try [UInt8(0x81), UInt8(0x82)].map { + try addressFactory.address( + fromAccountId: Data(repeating: $0, count: 32), + type: 42 + ) + } + try createStore(at: storeURL, model: sourceModel) { context in + let entity = try XCTUnwrap( + sourceModel.entitiesByName["CDAccountItem"] + ) + for (index, address) in addresses.enumerated() { + let account = NSManagedObject( + entity: entity, + insertInto: context + ) + account.setValue(address, forKey: "identifier") + account.setValue( + "Legacy \(index)", + forKey: "username" + ) + account.setValue( + Data(repeating: UInt8(0x91 + index), count: 32), + forKey: "publicKey" + ) + account.setValue(Int16(0), forKey: "cryptoType") + } + } + let sourceFiles = try durableStoreSnapshot(at: storeURL) + var stagedMutationCount = 0 + let migrator = UserStorageMigrator( + targetVersion: .version2, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + stagedStoreWillValidate: { stagedURL, version in + guard version == .version2 else { + return + } + + stagedMutationCount += 1 + try self.executeSQLite( + "DELETE FROM ZCDMETAACCOUNT " + + "WHERE Z_PK = " + + "(SELECT MIN(Z_PK) FROM ZCDMETAACCOUNT)", + at: stagedURL + ) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { + error in + + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertEqual(stagedMutationCount, 1) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + sourceFiles + ) + } + + func testMigration_whenLegacyEcosystemStore_thenPreservesWalletTonAssetAndChainData() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets(in: context, model: legacyModel) + } + + let migrator = makeMigrator() + XCTAssertTrue(migrator.requiresMigration()) + + try migrator.performMigration() + + XCTAssertFalse(migrator.requiresMigration()) + XCTAssertEqual(try metadataChecksum(at: storeURL), currentChecksum) + + let snapshots = try walletSnapshots( + from: storeURL, + model: model(for: .version14) + ) + XCTAssertEqual(snapshots.count, 2) + + let regularWallet = try XCTUnwrap( + snapshots.first { $0.metaId == "regular-wallet" } + ) + XCTAssertEqual(regularWallet.name, "Regular Wallet") + XCTAssertEqual(regularWallet.substrateAccountId, hex(byte: 0x11, count: 32)) + XCTAssertEqual(regularWallet.substratePublicKey, Data(repeating: 0x12, count: 32)) + XCTAssertEqual(regularWallet.tonAddress, Data(repeating: 0x13, count: 36)) + XCTAssertEqual(regularWallet.tonPublicKey, Data(repeating: 0x14, count: 32)) + XCTAssertEqual(regularWallet.tonContractVersion, "v4R2") + XCTAssertEqual( + regularWallet.assetsVisibility, + ["polkadot-0": false, "kusama-0": true] + ) + XCTAssertEqual( + regularWallet.chainAccounts, + [ + ChainSnapshot( + chainId: "ethereum-chain", + accountId: hex(byte: 0x31, count: 20), + publicKey: Data(repeating: 0x32, count: 33), + cryptoType: 2, + ecosystem: UniversalWalletEcosystem.evm.rawValue + ), + ChainSnapshot( + chainId: "substrate-chain", + accountId: hex(byte: 0x21, count: 32), + publicKey: Data(repeating: 0x22, count: 32), + cryptoType: 1, + ecosystem: "substrate" + ) + ] + ) + + let tonOnlyWallet = try XCTUnwrap( + snapshots.first { $0.metaId == "ton-only-wallet" } + ) + XCTAssertEqual(tonOnlyWallet.name, "TON Only Wallet") + XCTAssertNil(tonOnlyWallet.substrateAccountId) + XCTAssertNil(tonOnlyWallet.substratePublicKey) + XCTAssertEqual(tonOnlyWallet.tonAddress, Data(repeating: 0x41, count: 36)) + XCTAssertEqual(tonOnlyWallet.tonPublicKey, Data(repeating: 0x42, count: 32)) + XCTAssertEqual(tonOnlyWallet.tonContractVersion, "v5R1") + XCTAssertTrue(tonOnlyWallet.assetsVisibility.isEmpty) + XCTAssertTrue(tonOnlyWallet.chainAccounts.isEmpty) + } + + func testMigration_whenPublicV11Store_thenPreservesWalletAssetAndEthereumChainData() throws { + let publicModel = try model(for: .version12) + try createStore(at: storeURL, model: publicModel) { context in + self.insertCurrentWallet(in: context, model: publicModel) + let walletRequest = NSFetchRequest(entityName: "CDMetaAccount") + let wallet = try XCTUnwrap(context.fetch(walletRequest).first) + + try self.insertAssetVisibility( + assetId: "ethereum-mainnet-eth", + hidden: true, + wallet: wallet, + in: context, + model: publicModel + ) + try self.insertPublicChainAccount( + wallet: wallet, + in: context, + model: publicModel + ) + } + + let migrator = makeMigrator() + XCTAssertTrue(migrator.requiresMigration()) + + try migrator.performMigration() + + XCTAssertFalse(migrator.requiresMigration()) + XCTAssertEqual(try metadataChecksum(at: storeURL), currentChecksum) + + let currentModel = try model(for: .version14) + let snapshots = try walletSnapshots(from: storeURL, model: currentModel) + XCTAssertEqual(snapshots.count, 1) + XCTAssertEqual(snapshots.first?.metaId, "current-wallet") + XCTAssertEqual(snapshots.first?.name, "Current Wallet") + XCTAssertEqual( + snapshots.first?.assetsVisibility, + ["ethereum-mainnet-eth": true] + ) + + try useStore(at: storeURL, model: currentModel) { context in + let request = NSFetchRequest(entityName: "CDChainAccount") + let chainAccount = try XCTUnwrap(context.fetch(request).first) + + XCTAssertEqual(chainAccount.value(forKey: "chainId") as? String, "ethereum-mainnet") + XCTAssertEqual( + (chainAccount.value(forKey: "ethereumBased") as? NSNumber)?.boolValue, + true + ) + XCTAssertNil(chainAccount.value(forKey: "ecosystem")) + } + } + + func testMigration_whenV11OrLegacyV12PreferenceArchiveIsInvalid_thenDefaultsOnlyDamagedField() throws { + let preferences = [ + (key: "assetFilterOptions", column: "ZASSETFILTEROPTIONS"), + (key: "assetKeysOrder", column: "ZASSETKEYSORDER"), + (key: "favouriteChainIds", column: "ZFAVOURITECHAINIDS"), + (key: "unusedChainIds", column: "ZUNUSEDCHAINIDS") + ] + let expectedValues: [String: [String]] = [ + "assetFilterOptions": ["filter-option"], + "assetKeysOrder": ["asset-order"], + "favouriteChainIds": ["favourite-chain"], + "unusedChainIds": ["unused-chain"] + ] + + for sourceVersion in [ + UserStorageVersion.version12, + UserStorageVersion.version13 + ] { + for preference in preferences { + let caseURL = testDirectory.appendingPathComponent( + "\(sourceVersion.rawValue)-\(preference.key).sqlite" + ) + let sourceModel = try model(for: sourceVersion) + try createStore(at: caseURL, model: sourceModel) { context in + self.insertCurrentWallet( + in: context, + model: sourceModel + ) + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + let wallet = try XCTUnwrap(context.fetch(request).first) + for (key, value) in expectedValues { + wallet.setValue(value as NSArray, forKey: key) + } + } + + try executeSQLite( + "UPDATE ZCDMETAACCOUNT " + + "SET \(preference.column) = X'00FF00'", + at: caseURL + ) + + try makeMigrator(storeURL: caseURL).performMigration() + + XCTAssertEqual( + try metadataChecksum(at: caseURL), + currentChecksum, + "\(sourceVersion.rawValue).\(preference.key)" + ) + + try useStore( + at: caseURL, + model: model(for: .version14) + ) { context in + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + let wallet = try XCTUnwrap(context.fetch(request).first) + XCTAssertEqual( + wallet.value(forKey: "metaId") as? String, + "current-wallet" + ) + XCTAssertEqual( + wallet.value(forKey: "name") as? String, + "Current Wallet" + ) + XCTAssertEqual( + wallet.value(forKey: "substrateAccountId") as? String, + self.hex(byte: 0x51, count: 32) + ) + XCTAssertEqual( + wallet.value(forKey: "substratePublicKey") as? Data, + Data(repeating: 0x52, count: 32) + ) + + for (key, expectedValue) in expectedValues { + let actualValue = + wallet.value(forKey: key) as? [String] + XCTAssertEqual( + actualValue, + key == preference.key ? [] : expectedValue, + "\(sourceVersion.rawValue).\(preference.key).\(key)" + ) + } + } + } + } + } + + func testMigration_whenPreferenceArchiveHasWrongDecodedType_thenDefaultsOnlyDamagedField() throws { + let expectedValues = preferenceFixtureValues() + let preferences = [ + (key: "assetFilterOptions", column: "ZASSETFILTEROPTIONS"), + (key: "assetKeysOrder", column: "ZASSETKEYSORDER"), + (key: "favouriteChainIds", column: "ZFAVOURITECHAINIDS"), + (key: "unusedChainIds", column: "ZUNUSEDCHAINIDS") + ] + let wrongTypeArchive = try NSKeyedArchiver.archivedData( + withRootObject: NSString(string: "not-a-string-array"), + requiringSecureCoding: true + ) + let archiveHex = wrongTypeArchive.map { + String(format: "%02X", $0) + }.joined() + + for sourceVersion in [ + UserStorageVersion.version12, + UserStorageVersion.version13 + ] { + for preference in preferences { + let caseURL = testDirectory.appendingPathComponent( + "\(sourceVersion.rawValue)-wrong-type-" + + "\(preference.key).sqlite" + ) + try createPreferenceFixture( + at: caseURL, + sourceVersion: sourceVersion, + values: expectedValues + ) + try executeSQLite( + "UPDATE ZCDMETAACCOUNT " + + "SET \(preference.column) = X'\(archiveHex)'", + at: caseURL + ) + + try makeMigrator(storeURL: caseURL).performMigration() + + var expectedMigratedValues = expectedValues + expectedMigratedValues[preference.key] = [] + XCTAssertEqual( + try migratedPreferenceValues(at: caseURL), + expectedMigratedValues, + "\(sourceVersion.rawValue).\(preference.key)" + ) + } + } + } + + func testMigration_whenPreferenceArchivesAreValid_thenPreservesEveryValue() throws { + let expectedValues = preferenceFixtureValues() + + for sourceVersion in [ + UserStorageVersion.version12, + UserStorageVersion.version13 + ] { + let caseURL = testDirectory.appendingPathComponent( + "\(sourceVersion.rawValue)-valid-preferences.sqlite" + ) + try createPreferenceFixture( + at: caseURL, + sourceVersion: sourceVersion, + values: expectedValues + ) + + try makeMigrator(storeURL: caseURL).performMigration() + + XCTAssertEqual( + try migratedPreferenceValues(at: caseURL), + expectedValues + ) + } + } + + func testRawArchivePreflight_whenValuesCrossByteBoundary_thenRepairsOnlyOversizedArchivesAndIsIdempotent() throws { + let sourceModel = try model(for: .version13) + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version13, + values: preferenceFixtureValues() + ) + let boundaryArchive = try NSKeyedArchiver.archivedData( + withRootObject: ["boundary"] as NSArray, + requiringSecureCoding: true + ) + let oversizedArchive = try NSKeyedArchiver.archivedData( + withRootObject: [ + String(repeating: "x", count: 4096) + ] as NSArray, + requiringSecureCoding: true + ) + XCTAssertGreaterThan( + oversizedArchive.count, + boundaryArchive.count + ) + try updateSQLiteBlob( + boundaryArchive, + column: "ZASSETFILTEROPTIONS", + at: storeURL + ) + try updateSQLiteBlob( + oversizedArchive, + column: "ZASSETKEYSORDER", + at: storeURL + ) + try updateSQLiteBlob( + oversizedArchive, + column: "ZFAVOURITECHAINIDS", + at: storeURL + ) + + let entity = try XCTUnwrap( + sourceModel.entitiesByName["CDMetaAccount"] + ) + let columns = try [ + "assetFilterOptions", + "assetKeysOrder", + "favouriteChainIds" + ].map { key in + let attribute = try XCTUnwrap( + entity.attributesByName[key] + ) + return SQLiteTransformableArchiveColumn( + entityName: "CDMetaAccount", + attributeName: key, + isOptional: attribute.isOptional, + valueTransformerName: + attribute.valueTransformerName + ) + } + + XCTAssertEqual( + try SQLiteTransformableArchivePreflight + .repairOversizedArchives( + at: storeURL, + columns: columns, + maximumArchiveByteCount: + boundaryArchive.count + ), + 2 + ) + XCTAssertEqual( + try SQLiteTransformableArchivePreflight + .repairOversizedArchives( + at: storeURL, + columns: columns, + maximumArchiveByteCount: + boundaryArchive.count + ), + 0 + ) + + try useStore( + at: storeURL, + model: sourceModel + ) { context in + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + let wallet = try XCTUnwrap( + context.fetch(request).first + ) + XCTAssertEqual( + wallet.value( + forKey: "assetFilterOptions" + ) as? [String], + ["boundary"] + ) + XCTAssertNil( + wallet.value( + forKey: "assetKeysOrder" + ) + ) + XCTAssertEqual( + wallet.value( + forKey: "favouriteChainIds" + ) as? [String], + [] + ) + } + } + + func testRawArchivePreflight_whenRequiredReplacementExceedsLimit_thenRollsBackWithoutMutation() throws { + let sourceModel = try model(for: .version13) + let oversizedValue = + String(repeating: "x", count: 4096) + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version13, + values: preferenceFixtureValues() + ) + let oversizedArchive = try NSKeyedArchiver.archivedData( + withRootObject: [oversizedValue] as NSArray, + requiringSecureCoding: true + ) + try updateSQLiteBlob( + oversizedArchive, + column: "ZFAVOURITECHAINIDS", + at: storeURL + ) + + let entity = try XCTUnwrap( + sourceModel.entitiesByName["CDMetaAccount"] + ) + let attribute = try XCTUnwrap( + entity.attributesByName["favouriteChainIds"] + ) + XCTAssertFalse(attribute.isOptional) + let column = SQLiteTransformableArchiveColumn( + entityName: "CDMetaAccount", + attributeName: "favouriteChainIds", + isOptional: attribute.isOptional, + valueTransformerName: + attribute.valueTransformerName + ) + + XCTAssertThrowsError( + try SQLiteTransformableArchivePreflight + .repairOversizedArchives( + at: storeURL, + columns: [column], + maximumArchiveByteCount: 1 + ) + ) { error in + XCTAssertEqual( + error as? + SQLiteTransformableArchiveRepairError, + .invalidLimit + ) + } + + try useStore( + at: storeURL, + model: sourceModel + ) { context in + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + let wallet = try XCTUnwrap( + context.fetch(request).first + ) + XCTAssertEqual( + wallet.value( + forKey: "favouriteChainIds" + ) as? [String], + [oversizedValue] + ) + } + } + + func testMigration_whenRawPreferenceArchiveExceedsProductionLimit_thenRepairsBeforeCoreDataDecode() throws { + var expectedValues = preferenceFixtureValues() + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version13, + values: expectedValues + ) + let oversizedArchive = try NSKeyedArchiver.archivedData( + withRootObject: [ + String( + repeating: "x", + count: 1 * 1024 * 1024 + ) + ] as NSArray, + requiringSecureCoding: true + ) + XCTAssertGreaterThan( + oversizedArchive.count, + 1 * 1024 * 1024 + ) + try updateSQLiteBlob( + oversizedArchive, + column: "ZASSETKEYSORDER", + at: storeURL + ) + + try makeMigrator().performMigration() + + expectedValues.removeValue( + forKey: "assetKeysOrder" + ) + XCTAssertEqual( + try migratedPreferenceValues(at: storeURL), + expectedValues + ) + } + + func testMigration_whenDecodedPreferenceLimitsAreCrossed_thenRepairsOverLimitAndPreservesExactBoundaries() throws { + let boundaryValue = String(repeating: "b", count: 32) + let overByteValue = String(repeating: "o", count: 40) + let expectedValues: [String: [String]] = [ + "assetFilterOptions": [ + boundaryValue, + boundaryValue + ], + "assetKeysOrder": ["one", "two", "three"], + "favouriteChainIds": ["one", "two"], + "unusedChainIds": [ + overByteValue, + overByteValue + ] + ] + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version13, + values: expectedValues + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 100, + maximumRowsAcrossStore: 1_000, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 64, + maximumRelationshipDestinations: 10_000, + maximumTransformableElements: 2 + ) + ) + + try migrator.performMigration() + + XCTAssertEqual( + try migratedPreferenceValues(at: storeURL), + [ + "assetFilterOptions": [ + boundaryValue, + boundaryValue + ], + "assetKeysOrder": [], + "favouriteChainIds": ["one", "two"], + "unusedChainIds": [] + ] + ) + } + + func testMigration_whenCurrentVersionRequiredArchiveExceedsRawLimit_thenAtomicallyRepairsAndSubsequentRunIsNoOp() throws { + var expectedValues = preferenceFixtureValues() + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version14, + values: expectedValues + ) + let oversizedArchive = try NSKeyedArchiver.archivedData( + withRootObject: [ + String( + repeating: "x", + count: 1 * 1024 * 1024 + ) + ] as NSArray, + requiringSecureCoding: true + ) + try updateSQLiteBlob( + oversizedArchive, + column: "ZFAVOURITECHAINIDS", + at: storeURL + ) + let damagedStoreSnapshot = + try durableStoreSnapshot(at: storeURL) + var replacementCount = 0 + var stagedValidationCount = 0 + var keystoreMigratorCreated = false + var settingsMigratorCreated = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { targetURL, sourceURL in + replacementCount += 1 + try NSPersistentStoreCoordinator.replaceStore( + at: targetURL, + withStoreAt: sourceURL + ) + }, + keystoreMigratorFactory: { + source, + destination, + keystore in + + keystoreMigratorCreated = true + return KeystoreMigrator( + sourceVersion: source, + destinationVersion: destination, + keystore: keystore + ) + }, + settingsMigratorFactory: { + source, + destination, + settings in + + settingsMigratorCreated = true + return SettingsMigrator( + sourceVersion: source, + destinationVersion: destination, + settings: settings + ) + }, + stagedStoreWillValidate: { _, version in + XCTAssertEqual(version, .version14) + stagedValidationCount += 1 + } + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + damagedStoreSnapshot + ) + XCTAssertTrue(try migrator.performMigration()) + expectedValues["favouriteChainIds"] = [] + XCTAssertEqual( + try migratedPreferenceValues(at: storeURL), + expectedValues + ) + XCTAssertFalse(try migrator.performMigration()) + XCTAssertFalse(migrator.requiresMigration()) + XCTAssertEqual(replacementCount, 1) + XCTAssertEqual(stagedValidationCount, 1) + XCTAssertFalse(keystoreMigratorCreated) + XCTAssertFalse(settingsMigratorCreated) + } + + func testMigration_whenCurrentVersionOptionalArchiveHasWrongSQLiteType_thenAtomicallyRepairsToNullAndSubsequentRunIsNoOp() throws { + var expectedValues = preferenceFixtureValues() + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version14, + values: expectedValues + ) + try executeSQLite( + """ + UPDATE ZCDMETAACCOUNT + SET ZASSETKEYSORDER = 'not-a-blob' + """, + at: storeURL + ) + let damagedStoreSnapshot = + try durableStoreSnapshot(at: storeURL) + var replacementCount = 0 + var keystoreMigratorCreated = false + var settingsMigratorCreated = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { targetURL, sourceURL in + replacementCount += 1 + try NSPersistentStoreCoordinator.replaceStore( + at: targetURL, + withStoreAt: sourceURL + ) + }, + keystoreMigratorFactory: { + source, + destination, + keystore in + + keystoreMigratorCreated = true + return KeystoreMigrator( + sourceVersion: source, + destinationVersion: destination, + keystore: keystore + ) + }, + settingsMigratorFactory: { + source, + destination, + settings in + + settingsMigratorCreated = true + return SettingsMigrator( + sourceVersion: source, + destinationVersion: destination, + settings: settings + ) + } + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + damagedStoreSnapshot + ) + XCTAssertTrue(try migrator.performMigration()) + expectedValues.removeValue( + forKey: "assetKeysOrder" + ) + XCTAssertEqual( + try migratedPreferenceValues(at: storeURL), + expectedValues + ) + XCTAssertFalse(try migrator.performMigration()) + XCTAssertFalse(migrator.requiresMigration()) + XCTAssertEqual(replacementCount, 1) + XCTAssertFalse(keystoreMigratorCreated) + XCTAssertFalse(settingsMigratorCreated) + } + + func testMigration_whenCurrentVersionDecodedPreferenceExceedsLimit_thenCountsRepairAndSubsequentRunIsNoOp() throws { + var expectedValues = preferenceFixtureValues() + expectedValues["assetKeysOrder"] = ["one", "two"] + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version14, + values: expectedValues + ) + var replacementCount = 0 + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 100, + maximumRowsAcrossStore: 1_000, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10_000, + maximumTransformableElements: 1 + ), + storeReplacer: { targetURL, sourceURL in + replacementCount += 1 + try NSPersistentStoreCoordinator.replaceStore( + at: targetURL, + withStoreAt: sourceURL + ) + } + ) + + XCTAssertTrue(try migrator.performMigration()) + expectedValues["assetKeysOrder"] = [] + XCTAssertEqual( + try migratedPreferenceValues(at: storeURL), + expectedValues + ) + XCTAssertFalse(try migrator.performMigration()) + XCTAssertEqual(replacementCount, 1) + } + + func testMigration_whenCurrentVersionRepairFitsCopyLimitButFinalBackupCapacityIsInsufficient_thenPreservesLiveStore() throws { + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version14, + values: preferenceFixtureValues() + ) + try executeSQLite( + """ + UPDATE ZCDMETAACCOUNT + SET ZASSETKEYSORDER = 'not-a-blob' + """, + at: storeURL + ) + let before = try durableStoreSnapshot(at: storeURL) + var capacityInspectionCount = 0 + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + privateSourceCopyLimits: + SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: 512 * 1024 * 1024, + minimumFreeStorageReserveByteCount: 17 + ), + privateSourceAvailableCapacityProvider: { _ in + capacityInspectionCount += 1 + return capacityInspectionCount == 1 + ? UInt64.max + : 0 + }, + storeReplacer: { _, _ in + replacementAttempted = true + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + guard + let capacityError = + error as? CrashConsistentStoreReplacementError, + case let .insufficientStorageCapacity( + requiredByteCount, + availableByteCount + ) = capacityError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertGreaterThan(requiredByteCount, 17) + XCTAssertEqual(availableByteCount, 0) + } + XCTAssertEqual(capacityInspectionCount, 2) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testMigration_whenCurrentVersionRepairValidationHookDropsWallet_thenRejectsMutatedBaselineBeforeReplacement() throws { + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version14, + values: preferenceFixtureValues() + ) + try executeSQLite( + """ + UPDATE ZCDMETAACCOUNT + SET ZASSETKEYSORDER = 'not-a-blob' + """, + at: storeURL + ) + let before = try durableStoreSnapshot(at: storeURL) + var stagedMutationAttempted = false + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, _ in + replacementAttempted = true + }, + stagedStoreWillValidate: { stagedURL, version in + XCTAssertEqual(version, .version14) + stagedMutationAttempted = true + try self.executeSQLite( + "DELETE FROM ZCDMETAACCOUNT", + at: stagedURL + ) + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = + migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertTrue(stagedMutationAttempted) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testRelationshipCountPreflight_whenRelationshipIsFaulted_thenCountsWithoutMaterializingIt() throws { + let sourceModel = try model(for: .version13) + try createStore( + at: storeURL, + model: sourceModel + ) { context in + try self.insertLegacyWallets( + in: context, + model: sourceModel + ) + } + let migrator = makeMigrator() + + try useStore( + at: storeURL, + model: sourceModel + ) { context in + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + request.predicate = NSPredicate( + format: "metaId == %@", + "regular-wallet" + ) + let wallet = try XCTUnwrap( + context.fetch(request).first + ) + XCTAssertTrue( + wallet.hasFault( + forRelationshipNamed: "chainAccounts" + ) + ) + + XCTAssertEqual( + try migrator + .preflightRelationshipDestinationCount( + for: wallet, + relationshipName: "chainAccounts" + ), + 2 + ) + XCTAssertTrue( + wallet.hasFault( + forRelationshipNamed: "chainAccounts" + ) + ) + } + } + + func testRelationshipAggregateCounter_whenCountReachesExactBoundary_thenAcceptsIt() throws { + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 100, + maximumRowsAcrossStore: 1_000, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10, + maximumTransformableElements: 4_096, + maximumRelationshipDestinationsAcrossStore: 3 + ) + ) + var total = 1 + + try migrator.accumulateRelationshipDestinationCount( + 2, + total: &total + ) + + XCTAssertEqual(total, 3) + } + + func testRelationshipAggregateCounter_whenLimitOrIntegerRangeIsExceeded_thenFailsWithoutChangingTotal() throws { + let boundedMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 100, + maximumRowsAcrossStore: 1_000, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10, + maximumTransformableElements: 4_096, + maximumRelationshipDestinationsAcrossStore: 3 + ) + ) + var boundedTotal = 3 + + XCTAssertThrowsError( + try boundedMigrator + .accumulateRelationshipDestinationCount( + 1, + total: &boundedTotal + ) + ) + XCTAssertEqual(boundedTotal, 3) + + let overflowMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 100, + maximumRowsAcrossStore: 1_000, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10, + maximumTransformableElements: 4_096, + maximumRelationshipDestinationsAcrossStore: + Int.max + ) + ) + var overflowTotal = Int.max + + XCTAssertThrowsError( + try overflowMigrator + .accumulateRelationshipDestinationCount( + 1, + total: &overflowTotal + ) + ) + XCTAssertEqual(overflowTotal, Int.max) + } + + func testMigration_whenAggregateRelationshipDestinationsExceedStoreLimit_thenFailsBeforeStoreReplacement() throws { + let sourceModel = try model(for: .version13) + try createStore( + at: storeURL, + model: sourceModel + ) { context in + try self.insertLegacyWallets( + in: context, + model: sourceModel + ) + } + let before = try durableStoreSnapshot(at: storeURL) + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 100, + maximumRowsAcrossStore: 1_000, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10_000, + maximumTransformableElements: 4_096, + maximumRelationshipDestinationsAcrossStore: 1 + ), + storeReplacer: { _, _ in + replacementAttempted = true + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = + migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testMigration_whenRelationshipExceedsDestinationLimit_thenFailsBeforeStoreReplacement() throws { + let sourceModel = try model(for: .version13) + try createStore( + at: storeURL, + model: sourceModel + ) { context in + try self.insertLegacyWallets( + in: context, + model: sourceModel + ) + } + let before = try durableStoreSnapshot(at: storeURL) + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 100, + maximumRowsAcrossStore: 1_000, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 1, + maximumTransformableElements: 4_096 + ), + storeReplacer: { _, _ in + replacementAttempted = true + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = + migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testMigration_whenVersion1AccountRowLimitIsExceeded_thenFailsBeforeKeyOrStoreReplacement() throws { + let sourceModel = try model(for: .version1) + try createStore( + at: storeURL, + model: sourceModel + ) { context in + let entity = try XCTUnwrap( + sourceModel.entitiesByName["CDAccountItem"] + ) + for index in 0 ..< 2 { + let account = NSManagedObject( + entity: entity, + insertInto: context + ) + account.setValue( + "legacy-\(index)", + forKey: "identifier" + ) + } + } + let before = try durableStoreSnapshot(at: storeURL) + var keystoreMigratorCreated = false + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 1, + maximumRowsAcrossStore: 1, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10_000, + maximumTransformableElements: 4_096 + ), + storeReplacer: { _, _ in + replacementAttempted = true + }, + keystoreMigratorFactory: { + source, + destination, + keystore in + + keystoreMigratorCreated = true + return KeystoreMigrator( + sourceVersion: source, + destinationVersion: destination, + keystore: keystore + ) + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .privateSourceRepairFailed = + migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertFalse(keystoreMigratorCreated) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testMigration_whenVersion1RowsExceedKeystoreProductionCap_thenFailsBeforeMigrationPolicyOrKeyStaging() throws { + let sourceModel = try model(for: .version1) + let productionLimit = + KeystoreMigrationResourceLimits.production + .maximumLegacyAccountRows + try createStore( + at: storeURL, + model: sourceModel + ) { context in + let entity = try XCTUnwrap( + sourceModel.entitiesByName["CDAccountItem"] + ) + for index in 0 ... productionLimit { + let account = NSManagedObject( + entity: entity, + insertInto: context + ) + account.setValue( + "legacy-\(index)", + forKey: "identifier" + ) + } + } + let before = try durableStoreSnapshot(at: storeURL) + var keystoreMigratorCreated = false + var stagedStoreReachedValidation = false + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, _ in + replacementAttempted = true + }, + keystoreMigratorFactory: { + source, + destination, + keystore in + + keystoreMigratorCreated = true + return KeystoreMigrator( + sourceVersion: source, + destinationVersion: destination, + keystore: keystore + ) + }, + stagedStoreWillValidate: { _, _ in + stagedStoreReachedValidation = true + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .privateSourceRepairFailed = + migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertFalse(keystoreMigratorCreated) + XCTAssertFalse(stagedStoreReachedValidation) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testMigration_whenVersion1SourceFamilyExceedsCopyLimit_thenFailsBeforeCapacityKeyOrStoreReplacement() throws { + let sourceModel = try model(for: .version1) + try createStore( + at: storeURL, + model: sourceModel + ) { context in + let entity = try XCTUnwrap( + sourceModel.entitiesByName["CDAccountItem"] + ) + let account = NSManagedObject( + entity: entity, + insertInto: context + ) + account.setValue( + "legacy", + forKey: "identifier" + ) + } + let before = try durableStoreSnapshot(at: storeURL) + var capacityInspected = false + var keystoreMigratorCreated = false + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + privateSourceCopyLimits: + SQLiteStoreFamilyCopyLimits( + maximumFamilyByteCount: 1, + minimumFreeStorageReserveByteCount: 0 + ), + privateSourceAvailableCapacityProvider: { _ in + capacityInspected = true + return UInt64.max + }, + storeReplacer: { _, _ in + replacementAttempted = true + }, + keystoreMigratorFactory: { + source, + destination, + keystore in + + keystoreMigratorCreated = true + return KeystoreMigrator( + sourceVersion: source, + destinationVersion: destination, + keystore: keystore + ) + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + guard + let copyError = + error as? CrashConsistentStoreReplacementError, + case let .storeFamilyTooLarge( + actualByteCount, + maximumByteCount + ) = copyError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertGreaterThan(actualByteCount, 1) + XCTAssertEqual(maximumByteCount, 1) + } + XCTAssertFalse(capacityInspected) + XCTAssertFalse(keystoreMigratorCreated) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testMigration_whenPrivateRepairSucceedsButReplacementFails_thenOnlyStagedFieldChangesAndSourceRemainsByteIdentical() throws { + let expectedValues = preferenceFixtureValues() + try createPreferenceFixture( + at: storeURL, + sourceVersion: .version13, + values: expectedValues + ) + try executeSQLite( + "UPDATE ZCDMETAACCOUNT " + + "SET ZASSETKEYSORDER = X'00FF00'", + at: storeURL + ) + let originalDurableFiles = try durableStoreSnapshot(at: storeURL) + var replacementAttempted = false + + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, stagedURL in + replacementAttempted = true + var expectedStagedValues = expectedValues + expectedStagedValues["assetKeysOrder"] = [] + XCTAssertEqual( + try self.migratedPreferenceValues(at: stagedURL), + expectedStagedValues + ) + throw UserStorageCommitTestError + .storeReplacementFailed + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + XCTAssertEqual( + error as? UserStorageCommitTestError, + .storeReplacementFailed + ) + } + XCTAssertTrue(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + originalDurableFiles + ) + } + + func testMigration_whenPrivateRepairRowCapIsExceeded_thenRejectsBeforePagingOrReplacement() throws { + let sourceModel = try model(for: .version13) + try createStore(at: storeURL, model: sourceModel) { + context in + try self.insertLegacyWallets( + in: context, + model: sourceModel + ) + } + try executeSQLite( + """ + UPDATE ZCDMETAACCOUNT + SET ZASSETKEYSORDER = X'00FF00' + """, + at: storeURL + ) + let before = try durableStoreSnapshot(at: storeURL) + var replacementAttempted = false + var fetchedPages = [(Int, Int)]() + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 1, + maximumRowsAcrossStore: 100, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10_000, + maximumTransformableElements: 4_096 + ), + storeReplacer: { _, _ in + replacementAttempted = true + }, + privateSourceObjectIDPageDidFetch: { + fetchedPages.append(($0, $1)) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { + error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .privateSourceRepairFailed = migrationError + else { + return XCTFail( + "Expected privateSourceRepairFailed, got \(error)" + ) + } + } + XCTAssertTrue(fetchedPages.isEmpty) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testMigration_whenPrivateRepairRowsSpanSingleIDPages_thenEnumeratesEveryWalletExactlyOnce() throws { + let sourceModel = try model(for: .version13) + try createStore(at: storeURL, model: sourceModel) { + context in + try self.insertLegacyWallets( + in: context, + model: sourceModel + ) + } + var fetchedPages = [(Int, Int)]() + var integrityPages = [(Int, Int)]() + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 100, + maximumRowsAcrossStore: 1_000, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10_000, + maximumTransformableElements: 4_096 + ), + privateSourceObjectIDPageDidFetch: { + fetchedPages.append(($0, $1)) + }, + integrityObjectPageDidFetch: { + integrityPages.append(($0, $1)) + } + ) + + try migrator.performMigration() + + XCTAssertEqual(fetchedPages.count, 2) + XCTAssertTrue( + fetchedPages.allSatisfy { + $0.0 == 1 && $0.1 == 1 + } + ) + XCTAssertFalse(integrityPages.isEmpty) + XCTAssertTrue( + integrityPages.allSatisfy { + $0.0 == 1 && $0.1 == 1 + } + ) + XCTAssertEqual( + try walletSnapshots( + from: storeURL, + model: model(for: .version14) + ).count, + 2 + ) + } + + func testPerformMigration_whenStagedStoreDropsChainAccount_thenRefusesReplacementAndLeavesSourceUnchanged() throws { + let sourceModel = try model(for: .version13) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertLegacyWallets( + in: context, + model: sourceModel + ) + } + let originalDurableFiles = try durableStoreSnapshot(at: storeURL) + var replacementAttempted = false + var stagedMutationAttempted = false + + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, _ in + replacementAttempted = true + }, + stagedStoreWillValidate: { stagedURL, version in + XCTAssertEqual(version, .version14) + stagedMutationAttempted = true + try self.executeSQLite( + "DELETE FROM ZCDCHAINACCOUNT", + at: stagedURL + ) + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertTrue(stagedMutationAttempted) + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + originalDurableFiles + ) + } + + func testPerformMigration_whenIntegrityRowBudgetIsExceeded_thenFailsBeforeReplacementAndLeavesSourceUnchanged() throws { + let sourceModel = try model(for: .version13) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertLegacyWallets( + in: context, + model: sourceModel + ) + } + let originalDurableFiles = try durableStoreSnapshot(at: storeURL) + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 1, + maximumRowsAcrossStore: 100, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 1 * 1024 * 1024, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10_000, + maximumTransformableElements: 4_096 + ), + storeReplacer: { _, _ in + replacementAttempted = true + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .privateSourceRepairFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + originalDurableFiles + ) + } + + func testPerformMigration_whenCanonicalIdentityByteBudgetIsExceeded_thenFailsBeforeReplacementAndLeavesSourceUnchanged() throws { + let sourceModel = try model(for: .version13) + try createStore(at: storeURL, model: sourceModel) { context in + try self.insertLegacyWallets( + in: context, + model: sourceModel + ) + } + let originalDurableFiles = try durableStoreSnapshot(at: storeURL) + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + integrityValidationLimits: + UserStorageIntegrityValidationLimits( + maximumRowsPerEntity: 100, + maximumRowsAcrossStore: 1_000, + fetchBatchSize: 1, + maximumCanonicalRowBytes: 32, + maximumAttributeBytes: 256 * 1024, + maximumRelationshipDestinations: 10_000, + maximumTransformableElements: 4_096 + ), + storeReplacer: { _, _ in + replacementAttempted = true + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertFalse(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + originalDurableFiles + ) + } + + func testPerformMigration_whenStagedStoreMutatesSameCountGlobalContentOrRelationships_thenRefusesReplacementAndLeavesSourceUnchanged() throws { + let reorderedArchive = try NSKeyedArchiver.archivedData( + withRootObject: ["asset-b", "asset-a"] as NSArray, + requiringSecureCoding: true + ).map { + String(format: "%02X", $0) + }.joined() + let substitutedArchive = try NSKeyedArchiver.archivedData( + withRootObject: ["replacement-chain"] as NSArray, + requiringSecureCoding: true + ).map { + String(format: "%02X", $0) + }.joined() + let mutations = [ + ( + name: "chain-settings", + sql: "UPDATE ZCDCHAINSETTINGS " + + "SET ZISSUEMUTED = CASE ZISSUEMUTED " + + "WHEN 0 THEN 1 ELSE 0 END" + ), + ( + name: "custom-node", + sql: "UPDATE ZCDCUSTOMCHAINNODE " + + "SET ZNAME = 'mutated-node'" + ), + ( + name: "orphan-membership", + sql: "UPDATE ZCDMETAACCOUNT " + + "SET ZSELECTEDCURRENCY = " + + "(SELECT Z_PK FROM ZCDCURRENCY " + + "WHERE ZID = 'orphan-currency')" + ), + ( + name: "preference-reorder", + sql: "UPDATE ZCDMETAACCOUNT SET " + + "ZASSETKEYSORDER = X'\(reorderedArchive)'" + ), + ( + name: "preference-substitution", + sql: "UPDATE ZCDMETAACCOUNT SET " + + "ZFAVOURITECHAINIDS = X'\(substitutedArchive)'" + ) + ] + + for sourceVersion in [ + UserStorageVersion.version12, + UserStorageVersion.version13 + ] { + for mutation in mutations { + let caseURL = testDirectory.appendingPathComponent( + "\(sourceVersion.rawValue)-" + + "\(mutation.name).sqlite" + ) + let sourceModel = try model(for: sourceVersion) + try createStore( + at: caseURL, + model: sourceModel + ) { context in + self.insertCurrentWallet( + in: context, + model: sourceModel + ) + + let walletRequest = + NSFetchRequest( + entityName: "CDMetaAccount" + ) + let wallet = try XCTUnwrap( + context.fetch(walletRequest).first + ) + wallet.setValue( + ["filter-a", "filter-b"] as NSArray, + forKey: "assetFilterOptions" + ) + wallet.setValue( + ["asset-a", "asset-b"] as NSArray, + forKey: "assetKeysOrder" + ) + wallet.setValue( + ["favourite-a", "favourite-b"] as NSArray, + forKey: "favouriteChainIds" + ) + wallet.setValue( + ["unused-a", "unused-b"] as NSArray, + forKey: "unusedChainIds" + ) + + let settingsEntity = try XCTUnwrap( + sourceModel.entitiesByName[ + "CDChainSettings" + ] + ) + let chainSettings = NSManagedObject( + entity: settingsEntity, + insertInto: context + ) + chainSettings.setValue( + "settings-chain", + forKey: "chainId" + ) + chainSettings.setValue( + true, + forKey: "autobalanced" + ) + chainSettings.setValue( + false, + forKey: "issueMuted" + ) + + let nodeEntity = try XCTUnwrap( + sourceModel.entitiesByName[ + "CDCustomChainNode" + ] + ) + let node = NSManagedObject( + entity: nodeEntity, + insertInto: context + ) + node.setValue( + "original-node", + forKey: "name" + ) + node.setValue( + URL(string: "wss://node.example"), + forKey: "url" + ) + + let currencyEntity = try XCTUnwrap( + sourceModel.entitiesByName[ + "CDCurrency" + ] + ) + let orphan = NSManagedObject( + entity: currencyEntity, + insertInto: context + ) + orphan.setValue( + "orphan-currency", + forKey: "id" + ) + orphan.setValue( + "Orphan Currency", + forKey: "name" + ) + orphan.setValue( + "ORP", + forKey: "symbol" + ) + } + + let originalDurableFiles = + try durableStoreSnapshot(at: caseURL) + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: caseURL, + modelDirectory: + UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, _ in + replacementAttempted = true + }, + stagedStoreWillValidate: { + stagedURL, + _ in + + try self.executeSQLite( + mutation.sql, + at: stagedURL + ) + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .stagedStoreValidationFailed = + migrationError + else { + return XCTFail( + "Unexpected error for " + + "\(sourceVersion.rawValue)." + + "\(mutation.name): \(error)" + ) + } + } + XCTAssertFalse( + replacementAttempted, + "\(sourceVersion.rawValue)." + + "\(mutation.name)" + ) + XCTAssertEqual( + try durableStoreSnapshot(at: caseURL), + originalDurableFiles, + "\(sourceVersion.rawValue)." + + "\(mutation.name)" + ) + } + } + } + + func testPerformMigration_whenWALSourceReplacementFails_thenOriginalDurableFilesAreByteForByteUnchanged() throws { + let sourceModel = try model(for: .version13) + try createStore(at: storeURL, model: sourceModel) { context in + self.insertCurrentWallet(in: context, model: sourceModel) + } + + let database = try openSQLite(at: storeURL) + defer { + sqlite3_close(database) + } + try executeSQLite( + "PRAGMA wal_autocheckpoint = 0; " + + "UPDATE ZCDMETAACCOUNT SET ZNAME = 'WAL-only wallet';", + database: database + ) + + let walURL = URL(fileURLWithPath: storeURL.path + "-wal") + XCTAssertTrue(FileManager.default.fileExists(atPath: walURL.path)) + XCTAssertFalse(try Data(contentsOf: walURL).isEmpty) + let originalDurableFiles = try durableStoreSnapshot(at: storeURL) + var replacementAttempted = false + + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, stagedURL in + replacementAttempted = true + try self.useStore( + at: stagedURL, + model: self.model(for: .version14) + ) { context in + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + let wallet = try XCTUnwrap( + context.fetch(request).first + ) + XCTAssertEqual( + wallet.value(forKey: "name") as? String, + "WAL-only wallet" + ) + } + throw UserStorageCommitTestError.storeReplacementFailed + } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + XCTAssertEqual( + error as? UserStorageCommitTestError, + .storeReplacementFailed + ) + } + XCTAssertTrue(replacementAttempted) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + originalDurableFiles + ) + } + + func testCopyStoreFamily_whenRollbackJournalExists_thenCopiesRecoveryStateWithoutSourceShmOrMutation() throws { + let sourceURL = testDirectory.appendingPathComponent( + "CopyFamilySource.sqlite" + ) + let destinationURL = testDirectory.appendingPathComponent( + "CopyFamilyDestination.sqlite" + ) + let sourceFiles = [ + sourceURL: Data([0x01, 0x02]), + URL(fileURLWithPath: sourceURL.path + "-wal"): + Data([0x03, 0x04]), + URL(fileURLWithPath: sourceURL.path + "-journal"): + Data([0x05, 0x06]), + URL(fileURLWithPath: sourceURL.path + "-shm"): + Data([0x07, 0x08]) + ] + for (url, data) in sourceFiles { + try data.write(to: url, options: .atomic) + } + let originalSourceFiles = try storeFamilySnapshot(at: sourceURL) + + try makeMigrator().copyStoreFamily( + from: sourceURL, + to: destinationURL + ) + + XCTAssertEqual( + try Data(contentsOf: destinationURL), + sourceFiles[sourceURL] + ) + XCTAssertEqual( + try Data( + contentsOf: URL( + fileURLWithPath: destinationURL.path + "-wal" + ) + ), + sourceFiles[URL(fileURLWithPath: sourceURL.path + "-wal")] + ) + XCTAssertEqual( + try Data( + contentsOf: URL( + fileURLWithPath: destinationURL.path + "-journal" + ) + ), + sourceFiles[ + URL(fileURLWithPath: sourceURL.path + "-journal") + ] + ) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: destinationURL.path + "-shm" + ) + ) + XCTAssertEqual( + try storeFamilySnapshot(at: sourceURL), + originalSourceFiles + ) + } + + func testMetadataProbe_whenObjectiveCExceptionIsRaised_thenFailsClosedOnPrivateCopiesAndNeverMutatesSource() throws { + let currentModel = try model(for: .version14) + try createStore( + at: storeURL, + model: currentModel + ) { context in + self.insertCurrentWallet( + in: context, + model: currentModel + ) + } + let before = try durableStoreSnapshot(at: storeURL) + var probedURLs = [URL]() + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + metadataReader: { url in + probedURLs.append(url) + NSException( + name: .invalidArgumentException, + reason: "private metadata probe failure", + userInfo: ["stored-payload": "must-not-escape"] + ).raise() + return [:] + } + ) + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + guard + let migrationError = + error as? UserStorageMigrationError, + case .objectiveCException = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertEqual(probedURLs.count, 2) + XCTAssertTrue( + probedURLs.allSatisfy { + $0.standardizedFileURL != + self.storeURL.standardizedFileURL + } + ) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testMetadataProbe_whenSourceHasHotRollbackJournal_thenRecoversOnlyPrivateCopyAndLeavesSourceFamilyByteIdentical() throws { + let currentModel = try model(for: .version14) + try createStore( + at: storeURL, + model: currentModel + ) { context in + self.insertCurrentWallet( + in: context, + model: currentModel + ) + } + + let database = try openSQLite(at: storeURL) + defer { + try? executeSQLite( + "ROLLBACK", + database: database + ) + sqlite3_close(database) + } + try executeSQLite( + "PRAGMA journal_mode = DELETE; " + + "BEGIN IMMEDIATE; " + + "UPDATE ZCDMETAACCOUNT " + + "SET ZNAME = 'uncommitted-name';", + database: database + ) + + let journalURL = URL( + fileURLWithPath: storeURL.path + "-journal" + ) + XCTAssertTrue( + FileManager.default.fileExists( + atPath: journalURL.path + ) + ) + XCTAssertFalse( + try Data(contentsOf: journalURL).isEmpty + ) + + let before = try durableStoreSnapshot(at: storeURL) + let migrator = makeMigrator() + + XCTAssertFalse(migrator.requiresMigration()) + XCTAssertFalse(try migrator.performMigration()) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testSynchronousMigration_whenStoreIsCurrent_thenUsesSinglePrivateMetadataProbe() throws { + let currentModel = try model(for: .version14) + try createStore( + at: storeURL, + model: currentModel + ) { context in + self.insertCurrentWallet( + in: context, + model: currentModel + ) + } + let before = try durableStoreSnapshot(at: storeURL) + var probedURLs = [URL]() + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + metadataReader: { url in + probedURLs.append(url) + return try NSPersistentStoreCoordinator + .metadataForPersistentStore( + ofType: NSSQLiteStoreType, + at: url, + options: nil + ) + } + ) + + try (migrator as Migrating).migrate() + + XCTAssertEqual(probedURLs.count, 1) + XCTAssertNotEqual( + probedURLs.first?.standardizedFileURL, + storeURL.standardizedFileURL + ) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + before + ) + } + + func testPerformMigration_whenStoreAlreadyCurrent_thenRepeatedCallsAreByteForByteIdempotent() throws { + let currentModel = try model(for: .version14) + try createStore(at: storeURL, model: currentModel) { context in + self.insertCurrentWallet(in: context, model: currentModel) + } + + let before = try durableStoreSnapshot(at: storeURL) + let migrator = makeMigrator() + + XCTAssertFalse(migrator.requiresMigration()) + try migrator.performMigration() + try migrator.performMigration() + + XCTAssertFalse(migrator.requiresMigration()) + XCTAssertEqual(try durableStoreSnapshot(at: storeURL), before) + XCTAssertEqual( + try walletSnapshots(from: storeURL, model: currentModel).map(\.metaId), + ["current-wallet"] + ) + } + + func testPerformMigration_whenStoreIsCorrupt_thenThrowsAndDoesNotModifyFiles() throws { + try Data("not-a-core-data-store".utf8).write(to: storeURL, options: .atomic) + let before = try storeFamilySnapshot(at: storeURL) + let migrator = makeMigrator() + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard let migrationError = error as? UserStorageMigrationError else { + return XCTFail("Unexpected error: \(error)") + } + + guard case .metadataUnreadable = migrationError else { + return XCTFail("Expected metadataUnreadable, got \(migrationError)") + } + } + XCTAssertEqual(try storeFamilySnapshot(at: storeURL), before) + } + + func testPerformMigration_whenStoreModelIsUnknown_thenThrowsAndDoesNotModifyFiles() throws { + try createStore(at: storeURL, model: makeUnknownModel()) { _ in } + let before = try storeFamilySnapshot(at: storeURL) + let migrator = makeMigrator() + + XCTAssertTrue(migrator.requiresMigration()) + XCTAssertThrowsError(try migrator.performMigration()) { error in + guard let migrationError = error as? UserStorageMigrationError else { + return XCTFail("Unexpected error: \(error)") + } + + guard case .unknownStoreVersion = migrationError else { + return XCTFail("Expected unknownStoreVersion, got \(migrationError)") + } + } + XCTAssertEqual(try storeFamilySnapshot(at: storeURL), before) + } + + func testPerformMigration_whenProcessDiesAfterRemovingLiveMainStore_thenRelaunchRestoresAndMigratesProtectedWallets() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets( + in: context, + model: legacyModel + ) + } + let sourceWallets = try walletSnapshots( + from: storeURL, + model: legacyModel + ) + let interruptedMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { targetURL, _ in + try FileManager.default.removeItem(at: targetURL) + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + + XCTAssertThrowsError( + try interruptedMigrator.performMigration() + ) { error in + guard + let interruption = error as? CrashConsistentStoreReplacementInterruption, + case .simulatedProcessDeath = interruption + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertFalse( + FileManager.default.fileExists(atPath: storeURL.path), + "The fixture must reproduce the missing-main startup state" + ) + + let relaunchedMigrator = makeMigrator() + XCTAssertTrue(try relaunchedMigrator.performMigration()) + + XCTAssertEqual( + try metadataChecksum(at: storeURL), + currentChecksum + ) + XCTAssertEqual( + try walletSnapshots( + from: storeURL, + model: model(for: .version14) + ), + sourceWallets + ) + XCTAssertFalse(relaunchedMigrator.requiresMigration()) + XCTAssertFalse( + FileManager.default.fileExists( + atPath: testDirectory + .appendingPathComponent( + ".FearlessStoreReplacement", + isDirectory: true + ).path + ) + ) + } + + func testPerformMigration_whenStoreReplacementFails_thenProtectedDataIsNeverFinalized() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets(in: context, model: legacyModel) + } + let walletsBeforeMigration = try walletSnapshots( + from: storeURL, + model: legacyModel + ) + let recorder = UserStorageCommitRecorder() + let keystoreMigrator = RecordingKeystoreMigrator( + recorder: recorder + ) + let settingsMigrator = RecordingSettingsMigrator( + recorder: recorder + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, _ in + recorder.record(.storeReplacement) + throw UserStorageCommitTestError.storeReplacementFailed + }, + keystoreMigratorFactory: { _, _, _ in keystoreMigrator }, + settingsMigratorFactory: { _, _, _ in settingsMigrator } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + XCTAssertEqual( + error as? UserStorageCommitTestError, + .storeReplacementFailed + ) + } + + XCTAssertEqual( + recorder.events, + [ + .keystorePrepare, + .settingsPrepare, + .storeReplacement + ] + ) + XCTAssertEqual(try metadataChecksum(at: storeURL), legacyChecksum) + XCTAssertEqual( + try walletSnapshots(from: storeURL, model: legacyModel), + walletsBeforeMigration + ) + } + + func testPerformMigration_whenStoreReplacementSucceeds_thenProtectedDataFinalizesAfterward() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets(in: context, model: legacyModel) + } + let recorder = UserStorageCommitRecorder() + let keystoreMigrator = RecordingKeystoreMigrator( + recorder: recorder + ) + let settingsMigrator = RecordingSettingsMigrator( + recorder: recorder + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { targetURL, sourceURL in + recorder.record(.storeReplacement) + try NSPersistentStoreCoordinator.replaceStore( + at: targetURL, + withStoreAt: sourceURL + ) + }, + keystoreMigratorFactory: { _, _, _ in keystoreMigrator }, + settingsMigratorFactory: { _, _, _ in settingsMigrator } + ) + + try migrator.performMigration() + + XCTAssertEqual( + recorder.events, + [ + .keystorePrepare, + .settingsPrepare, + .storeReplacement, + .keystoreFinalize, + .settingsFinalize + ] + ) + XCTAssertEqual(try metadataChecksum(at: storeURL), currentChecksum) + } + + func testSettingsCleanup_whenReplacementFailsBeforeCommit_thenRelaunchRollsBackJournalWithoutDeletingLegacySelections() throws { + let legacyModel = try model(for: .version13) + try createStore( + at: storeURL, + model: legacyModel + ) { context in + self.insertCurrentWallet( + in: context, + model: legacyModel + ) + } + let sourceBefore = try durableStoreSnapshot(at: storeURL) + let settings = InMemorySettingsManager() + settings.set( + value: "legacy-account", + for: SettingsKey.selectedAccount.rawValue + ) + settings.set( + value: "legacy-connection", + for: SettingsKey.selectedConnection.rawValue + ) + let cleanupMigrator = + CleanupJournalSettingsMigrator( + sourceVersion: .version13, + destinationVersion: .version14, + settings: settings + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: settings, + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, _ in + throw UserStorageCommitTestError + .storeReplacementFailed + }, + settingsMigratorFactory: { + _, + _, + _ in + + cleanupMigrator + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + XCTAssertEqual( + error as? UserStorageCommitTestError, + .storeReplacementFailed + ) + } + XCTAssertNotNil( + settings.data( + for: SettingsMigrator.pendingCleanupKey + ) + ) + XCTAssertEqual( + try durableStoreSnapshot(at: storeURL), + sourceBefore + ) + + XCTAssertTrue( + try UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: + UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: settings, + fileManager: .default, + modelBundle: appBundle + ).performMigration() + ) + + XCTAssertEqual( + settings.string( + for: SettingsKey.selectedAccount.rawValue + ), + "legacy-account" + ) + XCTAssertEqual( + settings.string( + for: SettingsKey.selectedConnection.rawValue + ), + "legacy-connection" + ) + XCTAssertNil( + settings.anyValue( + for: SettingsMigrator.pendingCleanupKey + ) + ) + } + + func testSettingsCleanup_whenProcessStopsAfterDatabaseReplacement_thenCurrentVersionRelaunchFinishesCleanup() throws { + let legacyModel = try model(for: .version13) + try createStore( + at: storeURL, + model: legacyModel + ) { context in + self.insertCurrentWallet( + in: context, + model: legacyModel + ) + } + let settings = InMemorySettingsManager() + settings.set( + value: "legacy-account", + for: SettingsKey.selectedAccount.rawValue + ) + settings.set( + value: "legacy-connection", + for: SettingsKey.selectedConnection.rawValue + ) + let cleanupMigrator = + CleanupJournalSettingsMigrator( + sourceVersion: .version13, + destinationVersion: .version14, + settings: settings + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: settings, + fileManager: .default, + modelBundle: appBundle, + settingsMigratorFactory: { + _, + _, + _ in + + cleanupMigrator + }, + storeReplacementBoundaryHook: { boundary in + guard boundary == .committedMarkerPersisted else { + return + } + + throw CrashConsistentStoreReplacementInterruption + .simulatedProcessDeath + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) + XCTAssertEqual( + try metadataChecksum(at: storeURL), + currentChecksum + ) + XCTAssertNotNil( + settings.data( + for: SettingsMigrator.pendingCleanupKey + ) + ) + XCTAssertEqual( + settings.string( + for: SettingsKey.selectedAccount.rawValue + ), + "legacy-account" + ) + + let relaunchedMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: settings, + fileManager: .default, + modelBundle: appBundle + ) + XCTAssertFalse( + try relaunchedMigrator.performMigration() + ) + XCTAssertNil( + settings.anyValue( + for: SettingsKey.selectedAccount.rawValue + ) + ) + XCTAssertNil( + settings.anyValue( + for: SettingsKey.selectedConnection.rawValue + ) + ) + XCTAssertNil( + settings.anyValue( + for: SettingsMigrator.pendingCleanupKey + ) + ) + } + + func testSettingsCleanup_whenFinalizeFails_thenErrorPropagatesAndCurrentVersionRelaunchRetriesIdempotently() throws { + let legacyModel = try model(for: .version13) + try createStore( + at: storeURL, + model: legacyModel + ) { context in + self.insertCurrentWallet( + in: context, + model: legacyModel + ) + } + let settings = InMemorySettingsManager() + settings.set( + value: "legacy-account", + for: SettingsKey.selectedAccount.rawValue + ) + settings.set( + value: "legacy-connection", + for: SettingsKey.selectedConnection.rawValue + ) + let cleanupMigrator = + CleanupJournalSettingsMigrator( + sourceVersion: .version13, + destinationVersion: .version14, + settings: settings, + finalizeError: UserStorageCommitTestError + .settingsFinalizeFailed + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: settings, + fileManager: .default, + modelBundle: appBundle, + settingsMigratorFactory: { + _, + _, + _ in + + cleanupMigrator + } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + XCTAssertEqual( + error as? UserStorageCommitTestError, + .settingsFinalizeFailed + ) + } + XCTAssertEqual( + try metadataChecksum(at: storeURL), + currentChecksum + ) + XCTAssertNotNil( + settings.data( + for: SettingsMigrator.pendingCleanupKey + ) + ) + + let relaunchedMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: settings, + fileManager: .default, + modelBundle: appBundle + ) + XCTAssertFalse( + try relaunchedMigrator.performMigration() + ) + XCTAssertFalse( + try relaunchedMigrator.performMigration() + ) + XCTAssertNil( + settings.anyValue( + for: SettingsKey.selectedAccount.rawValue + ) + ) + XCTAssertNil( + settings.anyValue( + for: SettingsKey.selectedConnection.rawValue + ) + ) + XCTAssertNil( + settings.anyValue( + for: SettingsMigrator.pendingCleanupKey + ) + ) + } + + func testSettingsCleanup_whenJournalIsValid_thenDeletesOnlyExactLegacySelections() throws { + let settings = InMemorySettingsManager() + let unrelatedKey = "io.fearless.oauth.refresh-token" + settings.set(value: "legacy-account", for: SettingsKey.selectedAccount.rawValue) + settings.set(value: "legacy-connection", for: SettingsKey.selectedConnection.rawValue) + settings.set(value: "keep-me", for: unrelatedKey) + let journal = try JSONSerialization.data( + withJSONObject: [ + "schemaVersion": 1, + "sourceVersion": UserStorageVersion.version13.rawValue, + "destinationVersion": UserStorageVersion.version14.rawValue, + "keysToRemove": [ + SettingsKey.selectedAccount.rawValue, + SettingsKey.selectedConnection.rawValue + ] + ], + options: [.sortedKeys] + ) + settings.set(value: journal, for: SettingsMigrator.pendingCleanupKey) + + try SettingsMigrator.recoverPendingCleanup( + settings: settings, + currentVersion: .version14 + ) + + XCTAssertNil(settings.anyValue(for: SettingsKey.selectedAccount.rawValue)) + XCTAssertNil(settings.anyValue(for: SettingsKey.selectedConnection.rawValue)) + XCTAssertEqual(settings.string(for: unrelatedKey), "keep-me") + XCTAssertNil(settings.anyValue(for: SettingsMigrator.pendingCleanupKey)) + } + + func testSettingsCleanup_whenJournalTargetsUnrelatedKey_thenFailsClosedAndPreservesEverything() throws { + let settings = InMemorySettingsManager() + let unrelatedKey = "io.fearless.oauth.refresh-token" + settings.set(value: "legacy-account", for: SettingsKey.selectedAccount.rawValue) + settings.set(value: "legacy-connection", for: SettingsKey.selectedConnection.rawValue) + settings.set(value: "keep-me", for: unrelatedKey) + let journal = try JSONSerialization.data( + withJSONObject: [ + "schemaVersion": 1, + "sourceVersion": UserStorageVersion.version13.rawValue, + "destinationVersion": UserStorageVersion.version14.rawValue, + "keysToRemove": [ + SettingsKey.selectedAccount.rawValue, + unrelatedKey + ] + ], + options: [.sortedKeys] + ) + settings.set(value: journal, for: SettingsMigrator.pendingCleanupKey) + + XCTAssertThrowsError( + try SettingsMigrator.recoverPendingCleanup( + settings: settings, + currentVersion: .version14 + ) + ) { error in + guard + let migrationError = error as? SettingsMigratingError, + case .invalidCleanupJournal = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertEqual( + settings.string(for: SettingsKey.selectedAccount.rawValue), + "legacy-account" + ) + XCTAssertEqual( + settings.string(for: SettingsKey.selectedConnection.rawValue), + "legacy-connection" + ) + XCTAssertEqual(settings.string(for: unrelatedKey), "keep-me") + XCTAssertEqual( + settings.data(for: SettingsMigrator.pendingCleanupKey), + journal + ) + } + + func testSettingsCleanup_whenJournalHasDuplicateField_thenFailsClosed() { + let settings = InMemorySettingsManager() + settings.set(value: "legacy-account", for: SettingsKey.selectedAccount.rawValue) + let journal = Data( + """ + {"schemaVersion":1,"schemaVersion":1,"sourceVersion":"version13","destinationVersion":"version14","keysToRemove":["selectedAccount","selectedConnection"]} + """.utf8 + ) + settings.set(value: journal, for: SettingsMigrator.pendingCleanupKey) + + XCTAssertThrowsError( + try SettingsMigrator.recoverPendingCleanup( + settings: settings, + currentVersion: .version14 + ) + ) + XCTAssertEqual( + settings.string(for: SettingsKey.selectedAccount.rawValue), + "legacy-account" + ) + XCTAssertEqual( + settings.data(for: SettingsMigrator.pendingCleanupKey), + journal + ) + } + + func testSettingsCleanup_whenJournalHasUnknownField_thenFailsClosed() throws { + let settings = InMemorySettingsManager() + settings.set(value: "legacy-account", for: SettingsKey.selectedAccount.rawValue) + let journal = try JSONSerialization.data( + withJSONObject: [ + "schemaVersion": 1, + "sourceVersion": UserStorageVersion.version13.rawValue, + "destinationVersion": UserStorageVersion.version14.rawValue, + "keysToRemove": [ + SettingsKey.selectedAccount.rawValue, + SettingsKey.selectedConnection.rawValue + ], + "unexpected": true + ], + options: [.sortedKeys] + ) + settings.set(value: journal, for: SettingsMigrator.pendingCleanupKey) + + XCTAssertThrowsError( + try SettingsMigrator.recoverPendingCleanup( + settings: settings, + currentVersion: .version14 + ) + ) + XCTAssertEqual( + settings.string(for: SettingsKey.selectedAccount.rawValue), + "legacy-account" + ) + XCTAssertEqual( + settings.data(for: SettingsMigrator.pendingCleanupKey), + journal + ) + } + + func testSettingsCleanup_whenJournalIsOversized_thenFailsBeforeDeletingAnything() { + let settings = InMemorySettingsManager() + settings.set(value: "legacy-account", for: SettingsKey.selectedAccount.rawValue) + let journal = Data(repeating: 0x20, count: 4_097) + settings.set(value: journal, for: SettingsMigrator.pendingCleanupKey) + + XCTAssertThrowsError( + try SettingsMigrator.recoverPendingCleanup( + settings: settings, + currentVersion: .version14 + ) + ) + XCTAssertEqual( + settings.string(for: SettingsKey.selectedAccount.rawValue), + "legacy-account" + ) + XCTAssertEqual( + settings.data(for: SettingsMigrator.pendingCleanupKey), + journal + ) + } + + func testPerformMigration_whenKeychainReadFails_thenPropagatesAndLeavesLegacyStoreUntouched() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets(in: context, model: legacyModel) + } + let walletsBeforeMigration = try walletSnapshots( + from: storeURL, + model: legacyModel + ) + let keystore = FaultInjectingKeystore() + keystore.failures.insert( + .fetch(KeystoreMigrator.pendingCleanupIdentifier) + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + XCTAssertEqual( + error as? FaultInjectingKeystore.Error, + .injected(.fetch(KeystoreMigrator.pendingCleanupIdentifier)) + ) + } + XCTAssertEqual(try metadataChecksum(at: storeURL), legacyChecksum) + XCTAssertEqual( + try walletSnapshots(from: storeURL, model: legacyModel), + walletsBeforeMigration + ) + } + + func testPerformMigration_whenReplacementKeySaveFails_thenNeverReplacesStoreOrDeletesLegacyKey() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets(in: context, model: legacyModel) + } + let legacyIdentifier = try legacyDeletionIdentifier(0x01) + let replacementIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0x01, 0x02]) + let replacementKey = Data([0x03, 0x04]) + let keystore = FaultInjectingKeystore( + values: [legacyIdentifier: legacyKey] + ) + keystore.failures.insert(.add(replacementIdentifier)) + + let keystoreMigrator = KeystoreMigrator( + sourceVersion: .version13, + destinationVersion: .version14, + keystore: keystore + ) + keystoreMigrator.deleteKey(for: legacyIdentifier) + keystoreMigrator.save( + key: replacementKey, + for: replacementIdentifier + ) + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, _ in + replacementAttempted = true + }, + keystoreMigratorFactory: { _, _, _ in keystoreMigrator } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + XCTAssertEqual( + error as? FaultInjectingKeystore.Error, + .injected(.add(replacementIdentifier)) + ) + } + XCTAssertFalse(replacementAttempted) + XCTAssertEqual(keystore.value(for: legacyIdentifier), legacyKey) + XCTAssertNil(keystore.value(for: replacementIdentifier)) + XCTAssertNotNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + XCTAssertEqual(try metadataChecksum(at: storeURL), legacyChecksum) + + keystore.failures.remove(.add(replacementIdentifier)) + try KeystoreMigrator.recoverPendingCleanup( + keystore: keystore, + currentVersion: .version13 + ) + XCTAssertEqual(keystore.value(for: legacyIdentifier), legacyKey) + XCTAssertNil(keystore.value(for: replacementIdentifier)) + XCTAssertNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + } + + func testPerformMigration_whenStoreReplacementFails_thenKeepsOldAndStagedKeysUntilSafeRollback() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets(in: context, model: legacyModel) + } + let legacyIdentifier = try legacyDeletionIdentifier(0x11) + let replacementIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0x11, 0x12]) + let replacementKey = Data([0x13, 0x14]) + let keystore = FaultInjectingKeystore( + values: [legacyIdentifier: legacyKey] + ) + let keystoreMigrator = KeystoreMigrator( + sourceVersion: .version13, + destinationVersion: .version14, + keystore: keystore + ) + keystoreMigrator.deleteKey(for: legacyIdentifier) + keystoreMigrator.save( + key: replacementKey, + for: replacementIdentifier + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { _, _ in + XCTAssertEqual( + keystore.value(for: legacyIdentifier), + legacyKey + ) + XCTAssertEqual( + keystore.value(for: replacementIdentifier), + replacementKey + ) + throw UserStorageCommitTestError.storeReplacementFailed + }, + keystoreMigratorFactory: { _, _, _ in keystoreMigrator } + ) + + XCTAssertThrowsError(try migrator.performMigration()) { error in + XCTAssertEqual( + error as? UserStorageCommitTestError, + .storeReplacementFailed + ) + } + XCTAssertEqual(keystore.value(for: legacyIdentifier), legacyKey) + XCTAssertEqual( + keystore.value(for: replacementIdentifier), + replacementKey + ) + XCTAssertNotNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + XCTAssertEqual(try metadataChecksum(at: storeURL), legacyChecksum) + + try KeystoreMigrator.recoverPendingCleanup( + keystore: keystore, + currentVersion: .version13 + ) + XCTAssertEqual(keystore.value(for: legacyIdentifier), legacyKey) + XCTAssertNil(keystore.value(for: replacementIdentifier)) + XCTAssertNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + } + + func testPerformMigration_whenPostReplacementCleanupFails_thenFailsAndRelaunchFinishesCleanupWithoutLosingNewKey() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets(in: context, model: legacyModel) + } + let legacyIdentifier = try legacyDeletionIdentifier(0x21) + let replacementIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0x21, 0x22]) + let replacementKey = Data([0x23, 0x24]) + let keystore = FaultInjectingKeystore( + values: [legacyIdentifier: legacyKey] + ) + keystore.failures.insert(.delete(legacyIdentifier)) + let keystoreMigrator = KeystoreMigrator( + sourceVersion: .version13, + destinationVersion: .version14, + keystore: keystore + ) + keystoreMigrator.deleteKey(for: legacyIdentifier) + keystoreMigrator.save( + key: replacementKey, + for: replacementIdentifier + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + keystoreMigratorFactory: { _, _, _ in keystoreMigrator } + ) + + XCTAssertThrowsError( + try migrator.performMigration() + ) { error in + XCTAssertEqual( + error as? FaultInjectingKeystore.Error, + .injected(.delete(legacyIdentifier)) + ) + } + XCTAssertEqual(try metadataChecksum(at: storeURL), currentChecksum) + XCTAssertEqual(keystore.value(for: legacyIdentifier), legacyKey) + XCTAssertEqual( + keystore.value(for: replacementIdentifier), + replacementKey + ) + XCTAssertNotNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + + keystore.failures.remove(.delete(legacyIdentifier)) + let relaunchedMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + + XCTAssertNoThrow(try relaunchedMigrator.migrate()) + XCTAssertNil(keystore.value(for: legacyIdentifier)) + XCTAssertEqual( + keystore.value(for: replacementIdentifier), + replacementKey + ) + XCTAssertNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + XCTAssertEqual(try metadataChecksum(at: storeURL), currentChecksum) + } + + func testMigrate_whenDestinationSecretVerificationFails_thenReturnsFailureAndRetryConvergesOnlyAfterRepair() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets( + in: context, + model: legacyModel + ) + } + let legacyIdentifier = try legacyDeletionIdentifier(0x25) + let destinationIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0x25, 0x26]) + let destinationKey = Data([0x27, 0x28]) + let corruptedDestinationKey = Data([0x29, 0x2A]) + let keystore = FaultInjectingKeystore( + values: [legacyIdentifier: legacyKey] + ) + let journalMigrator = KeystoreMigrator( + sourceVersion: .version13, + destinationVersion: .version14, + keystore: keystore + ) + journalMigrator.deleteKey(for: legacyIdentifier) + journalMigrator.save( + key: destinationKey, + for: destinationIdentifier + ) + let failingFinalizeMigrator = + MappingFinalizeFailureKeystoreMigrator( + migrator: journalMigrator, + mappedError: UserStorageCommitTestError + .keystoreFinalizeFailed + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { targetURL, sourceURL in + try NSPersistentStoreCoordinator.replaceStore( + at: targetURL, + withStoreAt: sourceURL + ) + try keystore.updateKey( + corruptedDestinationKey, + with: destinationIdentifier + ) + }, + keystoreMigratorFactory: { + _, + _, + _ in + + failingFinalizeMigrator + } + ) + + XCTAssertThrowsError( + try migrator.migrate() + ) { error in + XCTAssertEqual( + error as? UserStorageCommitTestError, + .keystoreFinalizeFailed + ) + } + guard + let finalizeError = + failingFinalizeMigrator.underlyingFinalizeError + as? KeystoreMigratingError, + case let .cleanupDestinationKeyVerificationFailed( + identifier + ) = finalizeError + else { + return XCTFail( + "Expected destination-key verification failure" + ) + } + XCTAssertEqual(identifier, destinationIdentifier) + XCTAssertEqual( + try metadataChecksum(at: storeURL), + currentChecksum + ) + let journal = try XCTUnwrap( + keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + XCTAssertEqual( + keystore.value(for: legacyIdentifier), + legacyKey + ) + XCTAssertEqual( + keystore.value(for: destinationIdentifier), + corruptedDestinationKey + ) + + let relaunchedMigrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + XCTAssertThrowsError( + try relaunchedMigrator.migrate() + ) { error in + guard + let migrationError = + error as? KeystoreMigratingError, + case let .cleanupDestinationKeyVerificationFailed( + identifier + ) = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(identifier, destinationIdentifier) + } + XCTAssertEqual( + keystore.value(for: legacyIdentifier), + legacyKey + ) + XCTAssertEqual( + keystore.value(for: destinationIdentifier), + corruptedDestinationKey + ) + XCTAssertEqual( + keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ), + journal + ) + + try keystore.updateKey( + destinationKey, + with: destinationIdentifier + ) + XCTAssertNoThrow(try relaunchedMigrator.migrate()) + XCTAssertNil(keystore.value(for: legacyIdentifier)) + XCTAssertEqual( + keystore.value(for: destinationIdentifier), + destinationKey + ) + XCTAssertNil( + keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + XCTAssertNoThrow(try relaunchedMigrator.migrate()) + XCTAssertEqual( + try metadataChecksum(at: storeURL), + currentChecksum + ) + } + + func testPerformMigration_whenCurrentStoreCleanupJournalIsCorrupt_thenLaunchFailsClosed() throws { + let currentModel = try model(for: .version14) + try createStore(at: storeURL, model: currentModel) { context in + self.insertCurrentWallet(in: context, model: currentModel) + } + let corruptJournal = Data("not-json".utf8) + let keystore = FaultInjectingKeystore( + values: [ + KeystoreMigrator.pendingCleanupIdentifier: corruptJournal + ] + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + + XCTAssertThrowsError(try migrator.migrate()) + XCTAssertEqual(try metadataChecksum(at: storeURL), currentChecksum) + XCTAssertEqual( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier), + corruptJournal + ) + } + + func testPerformMigration_whenCurrentStoreCleanupJournalCannotBeRead_thenBlocksAndRetriesWithoutDeletingKeys() throws { + let currentModel = try model(for: .version14) + try createStore(at: storeURL, model: currentModel) { context in + self.insertCurrentWallet(in: context, model: currentModel) + } + let fixture = try prepareCleanupJournalFixture() + let journal = try XCTUnwrap( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + fixture.keystore.failures.insert( + .fetch(KeystoreMigrator.pendingCleanupIdentifier) + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: fixture.keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + + XCTAssertThrowsError(try migrator.migrate()) { error in + XCTAssertEqual( + error as? FaultInjectingKeystore.Error, + .injected( + .fetch(KeystoreMigrator.pendingCleanupIdentifier) + ) + ) + } + assertCleanupFixtureIsFullyRetained( + fixture, + expectedJournal: journal + ) + + fixture.keystore.failures.remove( + .fetch(KeystoreMigrator.pendingCleanupIdentifier) + ) + XCTAssertNoThrow(try migrator.migrate()) + + XCTAssertNil( + fixture.keystore.value(for: fixture.legacyIdentifier) + ) + XCTAssertEqual( + fixture.keystore.value(for: fixture.destinationIdentifier), + fixture.destinationKey + ) + XCTAssertNil( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + XCTAssertEqual(try metadataChecksum(at: storeURL), currentChecksum) + XCTAssertEqual( + try walletSnapshots(from: storeURL, model: currentModel).map(\.metaId), + ["current-wallet"] + ) + } + + func testPerformMigration_whenCurrentStoreDestinationKeyIsMissing_thenBlocksUntilKeyIsRestored() throws { + let currentModel = try model(for: .version14) + try createStore(at: storeURL, model: currentModel) { context in + self.insertCurrentWallet(in: context, model: currentModel) + } + let fixture = try prepareCleanupJournalFixture() + try fixture.keystore.deleteKey( + for: fixture.destinationIdentifier + ) + let journal = try XCTUnwrap( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: fixture.keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + + XCTAssertThrowsError(try migrator.migrate()) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case let .cleanupDestinationKeyMissing(identifier) = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(identifier, fixture.destinationIdentifier) + } + XCTAssertEqual( + fixture.keystore.value(for: fixture.legacyIdentifier), + fixture.legacyKey + ) + XCTAssertEqual( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ), + journal + ) + + try fixture.keystore.addKey( + fixture.destinationKey, + with: fixture.destinationIdentifier + ) + XCTAssertNoThrow(try migrator.migrate()) + + XCTAssertNil( + fixture.keystore.value(for: fixture.legacyIdentifier) + ) + XCTAssertEqual( + fixture.keystore.value(for: fixture.destinationIdentifier), + fixture.destinationKey + ) + XCTAssertNil( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + } + + func testPerformMigration_whenCurrentStoreDestinationProofIsTampered_thenBlocksUntilJournalIsRestored() throws { + let currentModel = try model(for: .version14) + try createStore(at: storeURL, model: currentModel) { context in + self.insertCurrentWallet(in: context, model: currentModel) + } + let fixture = try prepareCleanupJournalFixture() + let originalJournal = try XCTUnwrap( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + let tamperedJournal = try rewriteCleanupJournal( + in: fixture.keystore + ) { journal in + var proofs = try XCTUnwrap( + journal["destinationKeyProofs"] as? [[String: Any]] + ) + proofs[0]["sha256"] = Data( + repeating: 0xFF, + count: 32 + ).base64EncodedString() + journal["destinationKeyProofs"] = proofs + } + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: fixture.keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + + XCTAssertThrowsError(try migrator.migrate()) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case .cleanupDestinationKeyVerificationFailed = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + assertCleanupFixtureIsFullyRetained( + fixture, + expectedJournal: tamperedJournal + ) + + try fixture.keystore.updateKey( + originalJournal, + with: KeystoreMigrator.pendingCleanupIdentifier + ) + XCTAssertNoThrow(try migrator.migrate()) + + XCTAssertNil( + fixture.keystore.value(for: fixture.legacyIdentifier) + ) + XCTAssertEqual( + fixture.keystore.value(for: fixture.destinationIdentifier), + fixture.destinationKey + ) + XCTAssertNil( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + } + + func testPerformMigration_whenSourceStoreHasLegacyCleanupJournal_thenRerunsWithExistingStagedKey() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets(in: context, model: legacyModel) + } + let legacyIdentifier = try legacyDeletionIdentifier(0x91) + let destinationIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0x91, 0x92]) + let destinationKey = Data([0x93, 0x94]) + let legacyJournal = try legacyCleanupJournalData( + sourceVersion: .version13, + destinationVersion: .version14, + identifiersToRemove: [legacyIdentifier], + stagedIdentifiers: [destinationIdentifier] + ) + let keystore = FaultInjectingKeystore( + values: [ + legacyIdentifier: legacyKey, + destinationIdentifier: destinationKey, + KeystoreMigrator.pendingCleanupIdentifier: legacyJournal + ] + ) + let keystoreMigrator = KeystoreMigrator( + sourceVersion: .version13, + destinationVersion: .version14, + keystore: keystore + ) + keystoreMigrator.deleteKey(for: legacyIdentifier) + keystoreMigrator.save( + key: destinationKey, + for: destinationIdentifier + ) + var replacementAttempted = false + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle, + storeReplacer: { targetURL, sourceURL in + replacementAttempted = true + XCTAssertEqual( + keystore.value(for: legacyIdentifier), + legacyKey + ) + XCTAssertEqual( + keystore.value(for: destinationIdentifier), + destinationKey + ) + try NSPersistentStoreCoordinator.replaceStore( + at: targetURL, + withStoreAt: sourceURL + ) + }, + keystoreMigratorFactory: { _, _, _ in + keystoreMigrator + } + ) + + try migrator.performMigration() + + XCTAssertTrue(replacementAttempted) + XCTAssertEqual(try metadataChecksum(at: storeURL), currentChecksum) + XCTAssertNil(keystore.value(for: legacyIdentifier)) + XCTAssertEqual( + keystore.value(for: destinationIdentifier), + destinationKey + ) + XCTAssertNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + } + + func testMigrate_whenDestinationStoreHasLegacyCleanupJournal_thenClearsOnlyJournal() throws { + let currentModel = try model(for: .version14) + try createStore(at: storeURL, model: currentModel) { context in + self.insertCurrentWallet(in: context, model: currentModel) + } + let legacyIdentifier = try legacyDeletionIdentifier(0xB1) + let destinationIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0xB1, 0xB2]) + let destinationKey = Data([0xB3, 0xB4]) + let legacyJournal = try legacyCleanupJournalData( + sourceVersion: .version13, + destinationVersion: .version14, + identifiersToRemove: [legacyIdentifier], + stagedIdentifiers: [destinationIdentifier] + ) + let keystore = FaultInjectingKeystore( + values: [ + legacyIdentifier: legacyKey, + destinationIdentifier: destinationKey, + KeystoreMigrator.pendingCleanupIdentifier: legacyJournal + ] + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + + XCTAssertNoThrow(try migrator.migrate()) + + XCTAssertEqual(try metadataChecksum(at: storeURL), currentChecksum) + XCTAssertEqual( + keystore.value(for: legacyIdentifier), + legacyKey + ) + XCTAssertEqual( + keystore.value(for: destinationIdentifier), + destinationKey + ) + XCTAssertNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + } + + func testCleanupRecovery_whenLegacyJournalContainsReservedIdentifier_thenFailsClosed() throws { + let legacyIdentifier = try legacyDeletionIdentifier(0xC1) + let stagedIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0xC1, 0xC2]) + let stagedKey = Data([0xC3, 0xC4]) + let legacyJournal = try legacyCleanupJournalData( + sourceVersion: .version1, + destinationVersion: .version2, + identifiersToRemove: [ + legacyIdentifier, + KeystoreMigrator.pendingCleanupIdentifier + ], + stagedIdentifiers: [stagedIdentifier] + ) + let keystore = FaultInjectingKeystore( + values: [ + legacyIdentifier: legacyKey, + stagedIdentifier: stagedKey, + KeystoreMigrator.pendingCleanupIdentifier: legacyJournal + ] + ) + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: keystore, + currentVersion: .version1 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case .invalidCleanupJournal = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertEqual(keystore.value(for: legacyIdentifier), legacyKey) + XCTAssertEqual(keystore.value(for: stagedIdentifier), stagedKey) + XCTAssertEqual( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier), + legacyJournal + ) + } + + func testCleanupRecovery_whenVerifiedJournalDoesNotBracketDatabaseVersion_thenFailsClosed() throws { + let legacyIdentifier = try legacyDeletionIdentifier(0xD1) + let destinationIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0xD1, 0xD2]) + let destinationKey = Data([0xD3, 0xD4]) + let keystore = FaultInjectingKeystore( + values: [legacyIdentifier: legacyKey] + ) + let migrator = KeystoreMigrator( + sourceVersion: .version1, + destinationVersion: .current, + keystore: keystore + ) + + while migrator.currentVersion != .current { + try migrator.switchVersion() + } + + migrator.deleteKey(for: legacyIdentifier) + migrator.save( + key: destinationKey, + for: destinationIdentifier + ) + try migrator.prepare() + let journal = try XCTUnwrap( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: keystore, + currentVersion: .version2 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case .invalidCleanupJournal = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertEqual(keystore.value(for: legacyIdentifier), legacyKey) + XCTAssertEqual( + keystore.value(for: destinationIdentifier), + destinationKey + ) + XCTAssertEqual( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier), + journal + ) + } + + func testCleanupRecovery_whenLegacyJournalDoesNotBracketDatabaseVersion_thenFailsClosed() throws { + let legacyIdentifier = try legacyDeletionIdentifier(0xE1) + let stagedIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0xE1, 0xE2]) + let stagedKey = Data([0xE3, 0xE4]) + let legacyJournal = try legacyCleanupJournalData( + sourceVersion: .version1, + destinationVersion: .current, + identifiersToRemove: [legacyIdentifier], + stagedIdentifiers: [stagedIdentifier] + ) + let keystore = FaultInjectingKeystore( + values: [ + legacyIdentifier: legacyKey, + stagedIdentifier: stagedKey, + KeystoreMigrator.pendingCleanupIdentifier: legacyJournal + ] + ) + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: keystore, + currentVersion: .version2 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case .invalidCleanupJournal = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertEqual(keystore.value(for: legacyIdentifier), legacyKey) + XCTAssertEqual(keystore.value(for: stagedIdentifier), stagedKey) + XCTAssertEqual( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier), + legacyJournal + ) + } + + func testMigrate_whenStoreDoesNotExist_thenReturnsWithoutReadingKeychain() { + let keystore = FaultInjectingKeystore() + keystore.failures.insert( + .fetch(KeystoreMigrator.pendingCleanupIdentifier) + ) + let migrator = UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: keystore, + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + + XCTAssertFalse(FileManager.default.fileExists(atPath: storeURL.path)) + XCTAssertNoThrow(try migrator.migrate()) + } + + func testKeystoreMigrator_whenLegacyKeyReadFails_thenErrorIsNotTreatedAsMissingKey() throws { + let legacyIdentifier = "legacy-key" + let legacyKey = Data([0x31, 0x32]) + let keystore = FaultInjectingKeystore( + values: [legacyIdentifier: legacyKey] + ) + keystore.failures.insert(.fetch(legacyIdentifier)) + let migrator = KeystoreMigrator( + sourceVersion: .version1, + destinationVersion: .version2, + keystore: keystore + ) + try migrator.switchVersion() + + XCTAssertThrowsError(try migrator.fetchKey(for: legacyIdentifier)) { error in + XCTAssertEqual( + error as? FaultInjectingKeystore.Error, + .injected(.fetch(legacyIdentifier)) + ) + } + XCTAssertEqual(keystore.value(for: legacyIdentifier), legacyKey) + } + + func testKeystoreMigrator_whenReplacementIdentifierContainsDifferentKey_thenRefusesToOverwriteIt() throws { + let replacementIdentifier = "replacement-key" + let existingKey = Data([0x41, 0x42]) + let attemptedKey = Data([0x43, 0x44]) + let keystore = FaultInjectingKeystore( + values: [replacementIdentifier: existingKey] + ) + let migrator = KeystoreMigrator( + sourceVersion: .version1, + destinationVersion: .version2, + keystore: keystore + ) + try migrator.switchVersion() + migrator.save(key: attemptedKey, for: replacementIdentifier) + + XCTAssertThrowsError(try migrator.prepare()) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case let .stagedKeyConflict(identifier) = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(identifier, replacementIdentifier) + } + XCTAssertEqual( + keystore.value(for: replacementIdentifier), + existingKey + ) + XCTAssertNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + } + + func testKeystoreMigrator_whenJournalDeletionFails_thenRecoveryCanRepeatWithoutDeletingNewKey() throws { + let legacyIdentifier = try legacyDeletionIdentifier(0x51) + let replacementIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0x51, 0x52]) + let replacementKey = Data([0x53, 0x54]) + let keystore = FaultInjectingKeystore( + values: [legacyIdentifier: legacyKey] + ) + let migrator = KeystoreMigrator( + sourceVersion: .version1, + destinationVersion: .version2, + keystore: keystore + ) + try migrator.switchVersion() + migrator.deleteKey(for: legacyIdentifier) + migrator.save(key: replacementKey, for: replacementIdentifier) + try migrator.prepare() + keystore.failures.insert( + .delete(KeystoreMigrator.pendingCleanupIdentifier) + ) + + XCTAssertThrowsError(try migrator.finalize()) { error in + XCTAssertEqual( + error as? FaultInjectingKeystore.Error, + .injected( + .delete(KeystoreMigrator.pendingCleanupIdentifier) + ) + ) + } + XCTAssertNil(keystore.value(for: legacyIdentifier)) + XCTAssertEqual( + keystore.value(for: replacementIdentifier), + replacementKey + ) + XCTAssertNotNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + + keystore.failures.remove( + .delete(KeystoreMigrator.pendingCleanupIdentifier) + ) + try KeystoreMigrator.recoverPendingCleanup( + keystore: keystore, + currentVersion: .version2 + ) + try KeystoreMigrator.recoverPendingCleanup( + keystore: keystore, + currentVersion: .version2 + ) + XCTAssertNil(keystore.value(for: legacyIdentifier)) + XCTAssertEqual( + keystore.value(for: replacementIdentifier), + replacementKey + ) + XCTAssertNil( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + } + + func testCleanupRecovery_whenDestinationKeyIsMissing_thenRetainsLegacyKeyAndJournal() throws { + let fixture = try prepareCleanupJournalFixture() + try fixture.keystore.deleteKey(for: fixture.destinationIdentifier) + let journal = try XCTUnwrap( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: fixture.keystore, + currentVersion: .version2 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case let .cleanupDestinationKeyMissing(identifier) = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(identifier, fixture.destinationIdentifier) + } + + XCTAssertEqual( + fixture.keystore.value(for: fixture.legacyIdentifier), + fixture.legacyKey + ) + XCTAssertNil( + fixture.keystore.value(for: fixture.destinationIdentifier) + ) + XCTAssertEqual( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ), + journal + ) + } + + func testCleanupRecovery_whenDestinationKeyHasDrifted_thenRetainsLegacyKeyAndJournal() throws { + let fixture = try prepareCleanupJournalFixture() + let driftedKey = Data([0xA1, 0xA2, 0xA3]) + try fixture.keystore.updateKey( + driftedKey, + with: fixture.destinationIdentifier + ) + let journal = try XCTUnwrap( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ) + ) + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: fixture.keystore, + currentVersion: .version2 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case let .cleanupDestinationKeyVerificationFailed(identifier) = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(identifier, fixture.destinationIdentifier) + } + + XCTAssertEqual( + fixture.keystore.value(for: fixture.legacyIdentifier), + fixture.legacyKey + ) + XCTAssertEqual( + fixture.keystore.value(for: fixture.destinationIdentifier), + driftedKey + ) + XCTAssertEqual( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ), + journal + ) + } + + func testCleanupRecovery_whenDestinationDigestIsTampered_thenRetainsAllKeysAndJournal() throws { + let fixture = try prepareCleanupJournalFixture() + let tamperedJournal = try rewriteCleanupJournal( + in: fixture.keystore + ) { journal in + var proofs = try XCTUnwrap( + journal["destinationKeyProofs"] as? [[String: Any]] + ) + XCTAssertEqual(proofs.count, 1) + proofs[0]["sha256"] = Data( + repeating: 0xFF, + count: 32 + ).base64EncodedString() + journal["destinationKeyProofs"] = proofs + } + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: fixture.keystore, + currentVersion: .version2 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case let .cleanupDestinationKeyVerificationFailed(identifier) = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(identifier, fixture.destinationIdentifier) + } + + assertCleanupFixtureIsFullyRetained( + fixture, + expectedJournal: tamperedJournal + ) + } + + func testCleanupRecovery_whenDeletionListContainsReservedJournalIdentifier_thenFailsClosed() throws { + let fixture = try prepareCleanupJournalFixture() + let tamperedJournal = try rewriteCleanupJournal( + in: fixture.keystore + ) { journal in + journal["identifiersToRemove"] = [ + fixture.legacyIdentifier, + KeystoreMigrator.pendingCleanupIdentifier + ] + } + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: fixture.keystore, + currentVersion: .version2 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case .invalidCleanupJournal = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + assertCleanupFixtureIsFullyRetained( + fixture, + expectedJournal: tamperedJournal + ) + } + + func testCleanupRecovery_whenDeletionListContainsDestinationIdentifier_thenFailsClosed() throws { + let fixture = try prepareCleanupJournalFixture() + let tamperedJournal = try rewriteCleanupJournal( + in: fixture.keystore + ) { journal in + journal["identifiersToRemove"] = [ + fixture.legacyIdentifier, + fixture.destinationIdentifier + ] + } + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: fixture.keystore, + currentVersion: .version2 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case .invalidCleanupJournal = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + assertCleanupFixtureIsFullyRetained( + fixture, + expectedJournal: tamperedJournal + ) + } + + func testCleanupRecovery_whenDeletionListContainsPincode_thenFailsClosedWithoutDeletingIt() throws { + let fixture = try prepareCleanupJournalFixture() + let pincode = Data("246810".utf8) + try fixture.keystore.addKey( + pincode, + with: fearless.KeystoreTag.pincode.rawValue + ) + let tamperedJournal = try rewriteCleanupJournal( + in: fixture.keystore + ) { journal in + journal["identifiersToRemove"] = [ + fixture.legacyIdentifier, + fearless.KeystoreTag.pincode.rawValue + ] + } + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: fixture.keystore, + currentVersion: .version2 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case .invalidCleanupJournal = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + assertCleanupFixtureIsFullyRetained( + fixture, + expectedJournal: tamperedJournal + ) + XCTAssertEqual( + fixture.keystore.value(for: fearless.KeystoreTag.pincode.rawValue), + pincode + ) + } + + func testCleanupRecovery_whenDeletionListContainsUnrelatedAppKey_thenFailsClosedWithoutDeletingIt() throws { + let fixture = try prepareCleanupJournalFixture() + let unrelatedIdentifier = "io.fearless.oauth.refresh-token" + let unrelatedKey = Data([0xF1, 0xF2, 0xF3]) + try fixture.keystore.addKey( + unrelatedKey, + with: unrelatedIdentifier + ) + let tamperedJournal = try rewriteCleanupJournal( + in: fixture.keystore + ) { journal in + journal["identifiersToRemove"] = [ + fixture.legacyIdentifier, + unrelatedIdentifier + ] + } + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: fixture.keystore, + currentVersion: .version2 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case .invalidCleanupJournal = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + assertCleanupFixtureIsFullyRetained( + fixture, + expectedJournal: tamperedJournal + ) + XCTAssertEqual( + fixture.keystore.value(for: unrelatedIdentifier), + unrelatedKey + ) + } + + func testCleanupRecovery_whenRollbackStagesPincodeWithMatchingProof_thenFailsClosedWithoutDeletingIt() throws { + let fixture = try prepareCleanupJournalFixture() + let pincode = fixture.destinationKey + try fixture.keystore.addKey( + pincode, + with: fearless.KeystoreTag.pincode.rawValue + ) + let tamperedJournal = try rewriteCleanupJournal( + in: fixture.keystore + ) { journal in + var proofs = try XCTUnwrap( + journal["destinationKeyProofs"] as? [[String: Any]] + ) + var forgedPincodeProof = try XCTUnwrap(proofs.first) + forgedPincodeProof["identifier"] = fearless.KeystoreTag.pincode.rawValue + proofs.append(forgedPincodeProof) + journal["destinationKeyProofs"] = proofs + journal["stagedIdentifiers"] = [ + fearless.KeystoreTag.pincode.rawValue + ] + } + + XCTAssertThrowsError( + try KeystoreMigrator.recoverPendingCleanup( + keystore: fixture.keystore, + currentVersion: .version1 + ) + ) { error in + guard + let migrationError = error as? KeystoreMigratingError, + case .invalidCleanupJournal = migrationError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + assertCleanupFixtureIsFullyRetained( + fixture, + expectedJournal: tamperedJournal + ) + XCTAssertEqual( + fixture.keystore.value(for: fearless.KeystoreTag.pincode.rawValue), + pincode + ) + } + + func testMetaAccountMapper_whenMigratedRecordHasOnlyTonFields_thenThrowsRecoverableError() throws { + let legacyModel = try model(for: .version13) + try createStore(at: storeURL, model: legacyModel) { context in + try self.insertLegacyWallets(in: context, model: legacyModel) + } + try makeMigrator().performMigration() + + let currentModel = try model(for: .version14) + try useStore(at: storeURL, model: currentModel) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate(format: "metaId == %@", "ton-only-wallet") + let object = try XCTUnwrap(context.fetch(request).first) + let entity = try XCTUnwrap( + object as? fearless.CDMetaAccount, + "The active compatibility model must materialize the app's CDMetaAccount class" + ) + + XCTAssertThrowsError(try MetaAccountMapper().transform(entity: entity)) { error in + guard let mapperError = error as? MetaAccountMapperError else { + return XCTFail("Unexpected error: \(error)") + } + + guard case .unsupportedWalletRecord = mapperError else { + return XCTFail("Expected unsupportedWalletRecord, got \(mapperError)") + } + } + } + } + + func testMetaAccountMapper_whenEvmAccount_thenWritesCanonicalIdentifierAndReadsCanonicalAndLegacyAliases() throws { + let currentModel = try model(for: .version14) + + try createStore(at: storeURL, model: currentModel) { context in + let chainAccount = ChainAccountModel( + chainId: "ethereum-chain", + accountId: Data(repeating: 0x61, count: 20), + publicKey: Data(repeating: 0x62, count: 33), + cryptoType: 2, + ethereumBased: true + ) + let walletModel = AccountGenerator.generateMetaAccount(with: [chainAccount]) + let walletEntity = fearless.CDMetaAccount(context: context) + walletEntity.isSelected = true + walletEntity.order = 1 + walletEntity.setValue(false, forKey: "zeroBalanceAssetsHidden") + let mapper = MetaAccountMapper() + + try mapper.populate( + entity: walletEntity, + from: walletModel, + using: context + ) + + let chainEntity = try XCTUnwrap( + walletEntity.chainAccounts?.allObjects.first as? fearless.CDChainAccount + ) + XCTAssertEqual( + chainEntity.value(forKey: "ecosystem") as? String, + UniversalWalletEcosystem.evm.rawValue + ) + + for ecosystem in [ + UniversalWalletEcosystem.evm.rawValue, + "ethereum", + "ethereumBased" + ] { + chainEntity.ethereumBased = false + chainEntity.setValue(ecosystem, forKey: "ecosystem") + + let transformed = try mapper.transform(entity: walletEntity) + let transformedAccount = try XCTUnwrap( + transformed.chainAccounts.first { $0.chainId == chainAccount.chainId } + ) + + XCTAssertTrue( + transformedAccount.ethereumBased, + "\(ecosystem) must continue to resolve as an EVM account" + ) + } + } + } + + private func makeMigrator( + storeURL: URL? = nil + ) -> UserStorageMigrator { + UserStorageMigrator( + targetVersion: .version14, + storeURL: storeURL ?? self.storeURL, + modelDirectory: UserStorageParams.modelDirectory, + keystore: InMemoryKeychain(), + settings: InMemorySettingsManager(), + fileManager: .default, + modelBundle: appBundle + ) + } + + private func preferenceFixtureValues() -> [String: [String]] { + [ + "assetFilterOptions": ["filter-option"], + "assetKeysOrder": ["asset-order"], + "favouriteChainIds": ["favourite-chain"], + "unusedChainIds": ["unused-chain"] + ] + } + + private func createPreferenceFixture( + at url: URL, + sourceVersion: UserStorageVersion, + values: [String: [String]] + ) throws { + let sourceModel = try model(for: sourceVersion) + try createStore(at: url, model: sourceModel) { context in + self.insertCurrentWallet( + in: context, + model: sourceModel + ) + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + let wallet = try XCTUnwrap(context.fetch(request).first) + for (key, value) in values { + wallet.setValue(value as NSArray, forKey: key) + } + } + } + + private func migratedPreferenceValues( + at url: URL + ) throws -> [String: [String]] { + var values = [String: [String]]() + try useStore( + at: url, + model: model(for: .version14) + ) { context in + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + let wallet = try XCTUnwrap(context.fetch(request).first) + XCTAssertEqual( + wallet.value(forKey: "metaId") as? String, + "current-wallet" + ) + XCTAssertEqual( + wallet.value(forKey: "substratePublicKey") as? Data, + Data(repeating: 0x52, count: 32) + ) + + for key in self.preferenceFixtureValues().keys { + values[key] = + wallet.value(forKey: key) as? [String] + } + } + + return values + } + + private typealias CleanupJournalFixture = ( + keystore: FaultInjectingKeystore, + legacyIdentifier: String, + destinationIdentifier: String, + legacyKey: Data, + destinationKey: Data + ) + + private func prepareCleanupJournalFixture() throws -> CleanupJournalFixture { + let legacyIdentifier = try legacyDeletionIdentifier(0x71) + let destinationIdentifier = destinationMigrationIdentifier() + let legacyKey = Data([0x71, 0x72, 0x73]) + let destinationKey = Data([0x81, 0x82, 0x83]) + let keystore = FaultInjectingKeystore( + values: [legacyIdentifier: legacyKey] + ) + let migrator = KeystoreMigrator( + sourceVersion: .version1, + destinationVersion: .version2, + keystore: keystore + ) + try migrator.switchVersion() + migrator.deleteKey(for: legacyIdentifier) + migrator.save(key: destinationKey, for: destinationIdentifier) + try migrator.prepare() + + return ( + keystore: keystore, + legacyIdentifier: legacyIdentifier, + destinationIdentifier: destinationIdentifier, + legacyKey: legacyKey, + destinationKey: destinationKey + ) + } + + private func rewriteCleanupJournal( + in keystore: FaultInjectingKeystore, + mutation: (inout [String: Any]) throws -> Void + ) throws -> Data { + let originalData = try XCTUnwrap( + keystore.value(for: KeystoreMigrator.pendingCleanupIdentifier) + ) + var journal = try XCTUnwrap( + JSONSerialization.jsonObject(with: originalData) as? [String: Any] + ) + try mutation(&journal) + let rewrittenData = try JSONSerialization.data( + withJSONObject: journal, + options: [.sortedKeys] + ) + try keystore.updateKey( + rewrittenData, + with: KeystoreMigrator.pendingCleanupIdentifier + ) + + return rewrittenData + } + + private func legacyDeletionIdentifier( + _ accountByte: UInt8 + ) throws -> String { + let address = try SS58AddressFactory().address( + fromAccountId: Data(repeating: accountByte, count: 32), + type: 42 + ) + + return fearless.KeystoreTag.secretKeyTagForAddress(address) + } + + private func destinationMigrationIdentifier() -> String { + fearless.KeystoreTagV2.substrateSecretKeyTagForMetaId( + UUID().uuidString + ) + } + + private func legacyCleanupJournalData( + sourceVersion: UserStorageVersion, + destinationVersion: UserStorageVersion, + identifiersToRemove: [String], + stagedIdentifiers: [String] + ) throws -> Data { + try JSONSerialization.data( + withJSONObject: [ + "sourceVersion": sourceVersion.rawValue, + "destinationVersion": destinationVersion.rawValue, + "identifiersToRemove": identifiersToRemove, + "stagedIdentifiers": stagedIdentifiers + ], + options: [.sortedKeys] + ) + } + + private func assertCleanupFixtureIsFullyRetained( + _ fixture: CleanupJournalFixture, + expectedJournal: Data, + file: StaticString = #filePath, + line: UInt = #line + ) { + XCTAssertEqual( + fixture.keystore.value(for: fixture.legacyIdentifier), + fixture.legacyKey, + file: file, + line: line + ) + XCTAssertEqual( + fixture.keystore.value(for: fixture.destinationIdentifier), + fixture.destinationKey, + file: file, + line: line + ) + XCTAssertEqual( + fixture.keystore.value( + for: KeystoreMigrator.pendingCleanupIdentifier + ), + expectedJournal, + file: file, + line: line + ) + } + + private func directCompatibilityModelURL( + for version: UserStorageVersion + ) throws -> URL { + try XCTUnwrap( + appBundle.url( + forResource: version.rawValue, + withExtension: "mom" + ), + "\(version.rawValue).mom must be copied into the application bundle root" + ) + } + + private func model(for version: UserStorageVersion) throws -> NSManagedObjectModel { + let url = try XCTUnwrap( + version.modelURL( + in: appBundle, + legacyModelDirectory: UserStorageParams.modelDirectory + ), + "Missing model resource for \(version.rawValue)" + ) + + return try loadModel(at: url) + } + + private func loadModel(at url: URL) throws -> NSManagedObjectModel { + try XCTUnwrap( + NSManagedObjectModel(contentsOf: url), + "Unable to load Core Data model at \(url.path)" + ) + } + + private func versionHashes(for model: NSManagedObjectModel) -> [String: String] { + model.entityVersionHashesByName.mapValues { $0.base64EncodedString() } + } + + private func storeChecksum( + for model: NSManagedObjectModel, + named name: String + ) throws -> String { + let url = testDirectory.appendingPathComponent(name) + try createStore(at: url, model: model) { _ in } + return try metadataChecksum(at: url) + } + + private func metadataChecksum(at url: URL) throws -> String { + let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStore( + ofType: NSSQLiteStoreType, + at: url, + options: nil + ) + + return try XCTUnwrap( + metadata["NSStoreModelVersionChecksumKey"] as? String, + "Store metadata is missing its model checksum" + ) + } + + private func createStore( + at url: URL, + model: NSManagedObjectModel, + populate: (NSManagedObjectContext) throws -> Void + ) throws { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSSQLitePragmasOption: ["journal_mode": "WAL"], + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + var populationError: Error? + context.performAndWait { + do { + try populate(context) + if context.hasChanges { + try context.save() + } + } catch { + populationError = error + } + } + + if let populationError { + throw populationError + } + } + + private func useStore( + at url: URL, + model: NSManagedObjectModel, + body: (NSManagedObjectContext) throws -> Void + ) throws { + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + let store = try coordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: url, + options: [ + NSMigratePersistentStoresAutomaticallyOption: false, + NSInferMappingModelAutomaticallyOption: false + ] + ) + defer { + try? coordinator.remove(store) + } + + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + + var bodyError: Error? + context.performAndWait { + do { + try body(context) + } catch { + bodyError = error + } + } + + if let bodyError { + throw bodyError + } + } + + private func insertVersion2WalletFixture( + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let walletEntity = try XCTUnwrap( + model.entitiesByName["CDMetaAccount"] + ) + let firstWallet = NSManagedObject( + entity: walletEntity, + insertInto: context + ) + firstWallet.setValue("v2-wallet-alpha", forKey: "metaId") + firstWallet.setValue("Version 2 Alpha", forKey: "name") + firstWallet.setValue(true, forKey: "isSelected") + firstWallet.setValue(Int32(1), forKey: "order") + firstWallet.setValue( + hex(byte: 0x11, count: 32), + forKey: "substrateAccountId" + ) + firstWallet.setValue( + Data(repeating: 0x12, count: 32), + forKey: "substratePublicKey" + ) + firstWallet.setValue( + Int16(1), + forKey: "substrateCryptoType" + ) + + let secondWallet = NSManagedObject( + entity: walletEntity, + insertInto: context + ) + secondWallet.setValue("v2-wallet-beta", forKey: "metaId") + secondWallet.setValue("Version 2 Beta", forKey: "name") + secondWallet.setValue(false, forKey: "isSelected") + secondWallet.setValue(Int32(2), forKey: "order") + secondWallet.setValue( + hex(byte: 0x21, count: 32), + forKey: "substrateAccountId" + ) + secondWallet.setValue( + Data(repeating: 0x22, count: 32), + forKey: "substratePublicKey" + ) + secondWallet.setValue( + Int16(0), + forKey: "substrateCryptoType" + ) + + try insertVersion2ChainAccount( + chainId: "kusama", + accountId: hex(byte: 0x31, count: 32), + publicKey: Data(repeating: 0x32, count: 32), + cryptoType: 1, + wallet: firstWallet, + in: context, + model: model + ) + try insertVersion2ChainAccount( + chainId: "polkadot", + accountId: hex(byte: 0x41, count: 32), + publicKey: Data(repeating: 0x42, count: 32), + cryptoType: 0, + wallet: firstWallet, + in: context, + model: model + ) + try insertVersion2ChainAccount( + chainId: "westend", + accountId: hex(byte: 0x51, count: 32), + publicKey: Data(repeating: 0x52, count: 32), + cryptoType: 1, + wallet: secondWallet, + in: context, + model: model + ) + } + + private func insertVersion2ChainAccount( + chainId: String, + accountId: String, + publicKey: Data, + cryptoType: Int16, + wallet: NSManagedObject, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let entity = try XCTUnwrap( + model.entitiesByName["CDChainAccount"] + ) + let chainAccount = NSManagedObject( + entity: entity, + insertInto: context + ) + chainAccount.setValue(chainId, forKey: "chainId") + chainAccount.setValue(accountId, forKey: "accountId") + chainAccount.setValue(publicKey, forKey: "publicKey") + chainAccount.setValue(cryptoType, forKey: "cryptoType") + chainAccount.setValue(wallet, forKey: "metaAccount") + } + + private func version2WalletFixtureSnapshots() -> [WalletSnapshot] { + [ + WalletSnapshot( + metaId: "v2-wallet-alpha", + name: "Version 2 Alpha", + substrateAccountId: hex(byte: 0x11, count: 32), + substratePublicKey: Data(repeating: 0x12, count: 32), + tonAddress: nil, + tonPublicKey: nil, + tonContractVersion: nil, + assetsVisibility: [:], + chainAccounts: [ + ChainSnapshot( + chainId: "kusama", + accountId: hex(byte: 0x31, count: 32), + publicKey: Data(repeating: 0x32, count: 32), + cryptoType: 1, + ecosystem: nil + ), + ChainSnapshot( + chainId: "polkadot", + accountId: hex(byte: 0x41, count: 32), + publicKey: Data(repeating: 0x42, count: 32), + cryptoType: 0, + ecosystem: nil + ) + ] + ), + WalletSnapshot( + metaId: "v2-wallet-beta", + name: "Version 2 Beta", + substrateAccountId: hex(byte: 0x21, count: 32), + substratePublicKey: Data(repeating: 0x22, count: 32), + tonAddress: nil, + tonPublicKey: nil, + tonContractVersion: nil, + assetsVisibility: [:], + chainAccounts: [ + ChainSnapshot( + chainId: "westend", + accountId: hex(byte: 0x51, count: 32), + publicKey: Data(repeating: 0x52, count: 32), + cryptoType: 1, + ecosystem: nil + ) + ] + ) + ] + } + + private func insertLegacyWallets( + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let regularWallet = try insertWallet( + metaId: "regular-wallet", + name: "Regular Wallet", + in: context, + model: model + ) + regularWallet.setValue(hex(byte: 0x11, count: 32), forKey: "substrateAccountId") + regularWallet.setValue(Data(repeating: 0x12, count: 32), forKey: "substratePublicKey") + regularWallet.setValue(Int16(1), forKey: "substrateCryptoType") + regularWallet.setValue(hex(byte: 0x15, count: 20), forKey: "ethereumAddress") + regularWallet.setValue(Data(repeating: 0x16, count: 33), forKey: "ethereumPublicKey") + regularWallet.setValue(Data(repeating: 0x13, count: 36), forKey: "tonAddress") + regularWallet.setValue(Data(repeating: 0x14, count: 32), forKey: "tonPublicKey") + regularWallet.setValue("v4R2", forKey: "tonContractVersion") + + try insertAssetVisibility( + assetId: "polkadot-0", + hidden: false, + wallet: regularWallet, + in: context, + model: model + ) + try insertAssetVisibility( + assetId: "kusama-0", + hidden: true, + wallet: regularWallet, + in: context, + model: model + ) + try insertChainAccount( + chainId: "substrate-chain", + accountId: hex(byte: 0x21, count: 32), + publicKey: Data(repeating: 0x22, count: 32), + cryptoType: 1, + ecosystem: "substrate", + wallet: regularWallet, + in: context, + model: model + ) + try insertChainAccount( + chainId: "ethereum-chain", + accountId: hex(byte: 0x31, count: 20), + publicKey: Data(repeating: 0x32, count: 33), + cryptoType: 2, + ecosystem: UniversalWalletEcosystem.evm.rawValue, + wallet: regularWallet, + in: context, + model: model + ) + + let tonOnlyWallet = try insertWallet( + metaId: "ton-only-wallet", + name: "TON Only Wallet", + in: context, + model: model + ) + tonOnlyWallet.setValue(Data(repeating: 0x41, count: 36), forKey: "tonAddress") + tonOnlyWallet.setValue(Data(repeating: 0x42, count: 32), forKey: "tonPublicKey") + tonOnlyWallet.setValue("v5R1", forKey: "tonContractVersion") + } + + @discardableResult + private func insertWallet( + metaId: String, + name: String, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws -> NSManagedObject { + let entity = try XCTUnwrap(model.entitiesByName["CDMetaAccount"]) + let wallet = NSManagedObject(entity: entity, insertInto: context) + wallet.setValue(metaId, forKey: "metaId") + wallet.setValue(name, forKey: "name") + wallet.setValue(metaId == "regular-wallet", forKey: "isSelected") + wallet.setValue(Int32(metaId == "regular-wallet" ? 1 : 2), forKey: "order") + wallet.setValue(false, forKey: "canExportEthereumMnemonic") + wallet.setValue(false, forKey: "hasBackup") + wallet.setValue(false, forKey: "zeroBalanceAssetsHidden") + wallet.setValue(NSArray(), forKey: "favouriteChainIds") + return wallet + } + + private func insertCurrentWallet( + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) { + guard let entity = model.entitiesByName["CDMetaAccount"] else { + return XCTFail("Current model is missing CDMetaAccount") + } + + let wallet = NSManagedObject(entity: entity, insertInto: context) + wallet.setValue("current-wallet", forKey: "metaId") + wallet.setValue("Current Wallet", forKey: "name") + wallet.setValue(false, forKey: "isSelected") + wallet.setValue(Int32(1), forKey: "order") + wallet.setValue(false, forKey: "canExportEthereumMnemonic") + wallet.setValue(false, forKey: "hasBackup") + wallet.setValue(false, forKey: "zeroBalanceAssetsHidden") + wallet.setValue(NSArray(), forKey: "favouriteChainIds") + wallet.setValue(hex(byte: 0x51, count: 32), forKey: "substrateAccountId") + wallet.setValue(Data(repeating: 0x52, count: 32), forKey: "substratePublicKey") + wallet.setValue(Int16(1), forKey: "substrateCryptoType") + } + + @discardableResult + private func insertHistoricalWallet( + metaId: String, + name: String, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws -> NSManagedObject { + let entity = try XCTUnwrap( + model.entitiesByName["CDMetaAccount"] + ) + let wallet = NSManagedObject( + entity: entity, + insertInto: context + ) + wallet.setValue(metaId, forKey: "metaId") + wallet.setValue(name, forKey: "name") + wallet.setValue(false, forKey: "isSelected") + wallet.setValue(Int32(1), forKey: "order") + wallet.setValue( + hex(byte: 0x71, count: 32), + forKey: "substrateAccountId" + ) + wallet.setValue( + Data(repeating: 0x72, count: 32), + forKey: "substratePublicKey" + ) + wallet.setValue( + Int16(1), + forKey: "substrateCryptoType" + ) + + if entity.attributesByName[ + "canExportEthereumMnemonic" + ] != nil { + wallet.setValue( + false, + forKey: "canExportEthereumMnemonic" + ) + } + if entity.attributesByName["hasBackup"] != nil { + wallet.setValue(false, forKey: "hasBackup") + } + if entity.attributesByName[ + "zeroBalanceAssetsHidden" + ] != nil { + wallet.setValue( + false, + forKey: "zeroBalanceAssetsHidden" + ) + } + + return wallet + } + + private func insertAssetVisibility( + assetId: String, + hidden: Bool, + wallet: NSManagedObject, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let entity = try XCTUnwrap(model.entitiesByName["CDAssetVisibility"]) + let visibility = NSManagedObject(entity: entity, insertInto: context) + visibility.setValue(assetId, forKey: "assetId") + visibility.setValue(hidden, forKey: "hidden") + visibility.setValue(wallet, forKey: "wallet") + } + + private func insertChainAccount( + chainId: String, + accountId: String, + publicKey: Data, + cryptoType: Int16, + ecosystem: String, + wallet: NSManagedObject, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let entity = try XCTUnwrap(model.entitiesByName["CDChainAccount"]) + let chainAccount = NSManagedObject(entity: entity, insertInto: context) + chainAccount.setValue(chainId, forKey: "chainId") + chainAccount.setValue(accountId, forKey: "accountId") + chainAccount.setValue(publicKey, forKey: "publicKey") + chainAccount.setValue(cryptoType, forKey: "cryptoType") + chainAccount.setValue(ecosystem, forKey: "ecosystem") + chainAccount.setValue(wallet, forKey: "metaAccount") + } + + private func insertPublicChainAccount( + wallet: NSManagedObject, + in context: NSManagedObjectContext, + model: NSManagedObjectModel + ) throws { + let entity = try XCTUnwrap(model.entitiesByName["CDChainAccount"]) + let chainAccount = NSManagedObject(entity: entity, insertInto: context) + chainAccount.setValue("ethereum-mainnet", forKey: "chainId") + chainAccount.setValue(hex(byte: 0x61, count: 20), forKey: "accountId") + chainAccount.setValue(Data(repeating: 0x62, count: 33), forKey: "publicKey") + chainAccount.setValue(Int16(2), forKey: "cryptoType") + chainAccount.setValue(true, forKey: "ethereumBased") + chainAccount.setValue(wallet, forKey: "metaAccount") + } + + private func walletSnapshots( + from url: URL, + model: NSManagedObjectModel + ) throws -> [WalletSnapshot] { + var snapshots: [WalletSnapshot] = [] + + try useStore(at: url, model: model) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + let wallets = try context.fetch(request) + snapshots = wallets.map { wallet in + let visibilityObjects = + (wallet.value(forKey: "assetsVisibility") as? NSSet)? + .allObjects as? [NSManagedObject] ?? [] + let visibility: [String: Bool] = Dictionary( + uniqueKeysWithValues: visibilityObjects.compactMap { object in + guard let assetId = object.value(forKey: "assetId") as? String else { + return nil + } + + let hidden = (object.value(forKey: "hidden") as? NSNumber)?.boolValue ?? false + return (assetId, hidden) + } + ) + + let chainObjects = + (wallet.value(forKey: "chainAccounts") as? NSSet)? + .allObjects as? [NSManagedObject] ?? [] + let chains = chainObjects.compactMap { object -> ChainSnapshot? in + guard + let chainId = object.value(forKey: "chainId") as? String, + let accountId = object.value(forKey: "accountId") as? String, + let publicKey = object.value(forKey: "publicKey") as? Data + else { + return nil + } + + let cryptoType = (object.value(forKey: "cryptoType") as? NSNumber)?.int16Value ?? 0 + return ChainSnapshot( + chainId: chainId, + accountId: accountId, + publicKey: publicKey, + cryptoType: cryptoType, + ecosystem: object.value(forKey: "ecosystem") as? String + ) + }.sorted { $0.chainId < $1.chainId } + + return WalletSnapshot( + metaId: wallet.value(forKey: "metaId") as? String ?? "", + name: wallet.value(forKey: "name") as? String ?? "", + substrateAccountId: wallet.value(forKey: "substrateAccountId") as? String, + substratePublicKey: wallet.value(forKey: "substratePublicKey") as? Data, + tonAddress: wallet.value(forKey: "tonAddress") as? Data, + tonPublicKey: wallet.value(forKey: "tonPublicKey") as? Data, + tonContractVersion: wallet.value(forKey: "tonContractVersion") as? String, + assetsVisibility: visibility, + chainAccounts: chains + ) + }.sorted { $0.metaId < $1.metaId } + } + + return snapshots + } + + private func makeUnknownModel() -> NSManagedObjectModel { + let model = NSManagedObjectModel() + let entity = NSEntityDescription() + entity.name = "UnknownWallet" + entity.managedObjectClassName = NSStringFromClass(NSManagedObject.self) + + let identifier = NSAttributeDescription() + identifier.name = "identifier" + identifier.attributeType = .stringAttributeType + identifier.isOptional = true + entity.properties = [identifier] + model.entities = [entity] + + return model + } + + private func storeFamilySnapshot(at url: URL) throws -> [String: Data] { + let fileNames = try FileManager.default.contentsOfDirectory( + atPath: url.deletingLastPathComponent().path + ).filter { $0.hasPrefix(url.lastPathComponent) } + + return try Dictionary( + uniqueKeysWithValues: fileNames.map { fileName in + let fileURL = url.deletingLastPathComponent().appendingPathComponent(fileName) + return (fileName, try Data(contentsOf: fileURL)) + } + ) + } + + private func durableStoreSnapshot(at url: URL) throws -> [String: Data] { + try storeFamilySnapshot(at: url).filter { fileName, _ in + !fileName.hasSuffix("-shm") + } + } + + private func makeSyntheticScenarioDirectory( + _ name: String + ) throws -> URL { + let url = testDirectory + .appendingPathComponent(name, isDirectory: true) + try FileManager.default.createDirectory( + at: url, + withIntermediateDirectories: false + ) + return url + } + + private func syntheticFamilyURL( + _ storeURL: URL, + suffix: String + ) -> URL { + URL(fileURLWithPath: storeURL.path + suffix) + } + + private func writeSyntheticStoreFamily( + at url: URL, + seed: UInt8 + ) throws { + for (index, suffix) in + CrashConsistentStoreReplacer.storeFamilySuffixes + .enumerated() { + try Data( + repeating: seed &+ UInt8(index), + count: 31 + index * 7 + ).write( + to: syntheticFamilyURL(url, suffix: suffix), + options: .atomic + ) + } + } + + private func syntheticStoreFamilySnapshot( + at url: URL + ) throws -> [String: Data] { + var snapshot: [String: Data] = [:] + + for suffix in + CrashConsistentStoreReplacer.storeFamilySuffixes { + let memberURL = syntheticFamilyURL( + url, + suffix: suffix + ) + guard + FileManager.default.fileExists( + atPath: memberURL.path + ) + else { + continue + } + + snapshot[suffix] = try Data(contentsOf: memberURL) + } + + return snapshot + } + + private func replaceSyntheticStoreFamily( + at targetURL: URL, + with sourceURL: URL + ) throws { + for suffix in + CrashConsistentStoreReplacer.storeFamilySuffixes { + let targetMemberURL = syntheticFamilyURL( + targetURL, + suffix: suffix + ) + if FileManager.default.fileExists( + atPath: targetMemberURL.path + ) { + try FileManager.default.removeItem( + at: targetMemberURL + ) + } + } + + for suffix in + CrashConsistentStoreReplacer.storeFamilySuffixes { + let sourceMemberURL = syntheticFamilyURL( + sourceURL, + suffix: suffix + ) + guard + FileManager.default.fileExists( + atPath: sourceMemberURL.path + ) + else { + continue + } + + try FileManager.default.copyItem( + at: sourceMemberURL, + to: syntheticFamilyURL( + targetURL, + suffix: suffix + ) + ) + } + } + + private func executeSQLite( + _ sql: String, + at url: URL + ) throws { + let database = try openSQLite(at: url) + defer { + sqlite3_close(database) + } + try executeSQLite(sql, database: database) + } + + private func executeSQLite( + _ sql: String, + database: OpaquePointer + ) throws { + var errorMessage: UnsafeMutablePointer? + let result = sqlite3_exec( + database, + sql, + nil, + nil, + &errorMessage + ) + defer { + sqlite3_free(errorMessage) + } + + guard result == SQLITE_OK else { + let description = errorMessage.map { + String(cString: $0) + } ?? "Unknown SQLite error" + throw NSError( + domain: "UserStorageCompatibilityMigrationTests.SQLite", + code: Int(result), + userInfo: [NSLocalizedDescriptionKey: description] + ) + } + } + + private func updateSQLiteBlob( + _ data: Data, + column: String, + at url: URL + ) throws { + let allowedColumns: Set = [ + "ZASSETFILTEROPTIONS", + "ZASSETKEYSORDER", + "ZFAVOURITECHAINIDS", + "ZUNUSEDCHAINIDS" + ] + guard allowedColumns.contains(column) else { + throw NSError( + domain: + "UserStorageCompatibilityMigrationTests.SQLite", + code: Int(SQLITE_MISUSE), + userInfo: [ + NSLocalizedDescriptionKey: + "Unexpected SQLite test column" + ] + ) + } + + let database = try openSQLite(at: url) + defer { + sqlite3_close(database) + } + + var statement: OpaquePointer? + let prepareResult = sqlite3_prepare_v2( + database, + "UPDATE ZCDMETAACCOUNT SET \(column) = ?1", + -1, + &statement, + nil + ) + guard prepareResult == SQLITE_OK, let statement else { + throw NSError( + domain: + "UserStorageCompatibilityMigrationTests.SQLite", + code: Int(prepareResult) + ) + } + defer { + sqlite3_finalize(statement) + } + + let sqliteTransient = unsafeBitCast( + -1, + to: sqlite3_destructor_type.self + ) + let bindResult = data.withUnsafeBytes { + rawBuffer in + + sqlite3_bind_blob( + statement, + 1, + rawBuffer.baseAddress, + Int32(rawBuffer.count), + sqliteTransient + ) + } + guard bindResult == SQLITE_OK else { + throw NSError( + domain: + "UserStorageCompatibilityMigrationTests.SQLite", + code: Int(bindResult) + ) + } + + let stepResult = sqlite3_step(statement) + guard stepResult == SQLITE_DONE else { + throw NSError( + domain: + "UserStorageCompatibilityMigrationTests.SQLite", + code: Int(stepResult) + ) + } + } + + private func openSQLite(at url: URL) throws -> OpaquePointer { + var database: OpaquePointer? + let result = sqlite3_open_v2( + url.path, + &database, + SQLITE_OPEN_READWRITE, + nil + ) + + guard result == SQLITE_OK, let database else { + defer { + if let database { + sqlite3_close(database) + } + } + throw NSError( + domain: "UserStorageCompatibilityMigrationTests.SQLite", + code: Int(result), + userInfo: [ + NSLocalizedDescriptionKey: "Unable to open SQLite store" + ] + ) + } + + return database + } + + private func hex(byte: UInt8, count: Int) -> String { + Data(repeating: byte, count: count) + .map { String(format: "%02x", $0) } + .joined() + } +} + +private enum UserStorageCommitTestError: Error, Equatable { + case storeReplacementFailed + case keystoreFinalizeFailed + case settingsFinalizeFailed +} + +private enum UserStorageCommitEvent: Equatable { + case keystorePrepare + case settingsPrepare + case storeReplacement + case keystoreFinalize + case settingsFinalize +} + +private final class UserStorageCommitRecorder { + private let lock = NSLock() + private var recordedEvents: [UserStorageCommitEvent] = [] + + var events: [UserStorageCommitEvent] { + lock.with { recordedEvents } + } + + func record(_ event: UserStorageCommitEvent) { + lock.with { + recordedEvents.append(event) + } + } +} + +private final class RecordingKeystoreMigrator: KeystoreMigrating { + private let recorder: UserStorageCommitRecorder + private let finalizeError: Error? + + init( + recorder: UserStorageCommitRecorder, + finalizeError: Error? = nil + ) { + self.recorder = recorder + self.finalizeError = finalizeError + } + + func switchVersion() throws {} + + func fetchKey(for _: String) throws -> Data? { + nil + } + + func deleteKey(for _: String) {} + + func save(key _: Data, for _: String) {} + + func prepare() throws { + recorder.record(.keystorePrepare) + } + + func finalize() throws { + recorder.record(.keystoreFinalize) + + if let finalizeError { + throw finalizeError + } + } +} + +private final class MappingFinalizeFailureKeystoreMigrator: + KeystoreMigrating { + private let migrator: KeystoreMigrating + private let mappedError: Error + private(set) var underlyingFinalizeError: Error? + + init( + migrator: KeystoreMigrating, + mappedError: Error + ) { + self.migrator = migrator + self.mappedError = mappedError + } + + func switchVersion() throws { + try migrator.switchVersion() + } + + func fetchKey(for identifier: String) throws -> Data? { + try migrator.fetchKey(for: identifier) + } + + func deleteKey(for identifier: String) { + migrator.deleteKey(for: identifier) + } + + func save(key: Data, for identifier: String) { + migrator.save(key: key, for: identifier) + } + + func prepare() throws { + try migrator.prepare() + } + + func finalize() throws { + do { + try migrator.finalize() + } catch { + underlyingFinalizeError = error + throw mappedError + } + } +} + +private final class RecordingSettingsMigrator: SettingsMigrating { + private let recorder: UserStorageCommitRecorder + + init(recorder: UserStorageCommitRecorder) { + self.recorder = recorder + } + + func switchVersion() throws {} + + func value(for _: String) -> Any? { + nil + } + + func remove(key _: String) {} + + func set(value _: Any, for _: String) {} + + func prepare() throws { + recorder.record(.settingsPrepare) + } + + func finalize() throws { + recorder.record(.settingsFinalize) + } +} + +private final class CleanupJournalSettingsMigrator: + SettingsMigrating { + private let migrator: SettingsMigrator + private let finalizeError: Error? + + init( + sourceVersion: UserStorageVersion, + destinationVersion: UserStorageVersion, + settings: SettingsManagerProtocol, + finalizeError: Error? = nil + ) { + migrator = SettingsMigrator( + sourceVersion: sourceVersion, + destinationVersion: destinationVersion, + settings: settings + ) + self.finalizeError = finalizeError + } + + func switchVersion() throws { + try migrator.switchVersion() + } + + func value(for key: String) -> Any? { + migrator.value(for: key) + } + + func remove(key: String) { + migrator.remove(key: key) + } + + func set(value: Any, for key: String) { + migrator.set(value: value, for: key) + } + + func prepare() throws { + migrator.remove( + key: SettingsKey.selectedAccount.rawValue + ) + migrator.remove( + key: SettingsKey.selectedConnection.rawValue + ) + try migrator.prepare() + } + + func finalize() throws { + if let finalizeError { + throw finalizeError + } + + try migrator.finalize() + } +} + +private final class FaultInjectingKeystore: KeystoreProtocol { + enum Operation: Hashable { + case add(String) + case update(String) + case fetch(String) + case check(String) + case delete(String) + } + + enum Error: Swift.Error, Equatable { + case injected(Operation) + } + + var failures = Set() + private var values: [String: Data] + + init(values: [String: Data] = [:]) { + self.values = values + } + + func value(for identifier: String) -> Data? { + values[identifier] + } + + func addKey( + _ key: Data, + with identifier: String + ) throws { + try throwIfNeeded(.add(identifier)) + + guard values[identifier] == nil else { + throw KeystoreError.duplicatedItem + } + + values[identifier] = key + } + + func updateKey( + _ key: Data, + with identifier: String + ) throws { + try throwIfNeeded(.update(identifier)) + + guard values[identifier] != nil else { + throw KeystoreError.noKeyFound + } + + values[identifier] = key + } + + func fetchKey(for identifier: String) throws -> Data { + try throwIfNeeded(.fetch(identifier)) + + guard let value = values[identifier] else { + throw KeystoreError.noKeyFound + } + + return value + } + + func checkKey(for identifier: String) throws -> Bool { + try throwIfNeeded(.check(identifier)) + return values[identifier] != nil + } + + func deleteKey(for identifier: String) throws { + try throwIfNeeded(.delete(identifier)) + + guard values.removeValue(forKey: identifier) != nil else { + throw KeystoreError.noKeyFound + } + } + + private func throwIfNeeded(_ operation: Operation) throws { + if failures.contains(operation) { + throw Error.injected(operation) + } + } +} diff --git a/fearlessTests/Common/Services/ChainRegistry/ChainRegistryTests.swift b/fearlessTests/Common/Services/ChainRegistry/ChainRegistryTests.swift index 2e0cd564c6..66314de809 100644 --- a/fearlessTests/Common/Services/ChainRegistry/ChainRegistryTests.swift +++ b/fearlessTests/Common/Services/ChainRegistry/ChainRegistryTests.swift @@ -1,147 +1,451 @@ -//import XCTest -//@testable import fearless -//import RobinHood -//import Cuckoo -// -//class ChainRegistryTests: XCTestCase { -// func testSetupCompletion() throws { -// // given -// -// let runtimeProviderPool = MockRuntimeProviderPoolProtocol() -// let connectionPool = MockConnectionPoolProtocol() -// let specVersionSubscriptionFactory = MockSpecVersionSubscriptionFactoryProtocol() -// let runtimeSyncService = MockRuntimeSyncServiceProtocol() -// -// stub(runtimeSyncService) { stub in -// stub.register(chain: any(), with: any()).thenDoNothing() -// stub.unregister(chainId: any()).thenDoNothing() -// } -// -// let commonTypesSyncService = MockCommonTypesSyncServiceProtocol() -// -// stub(commonTypesSyncService) { stub in -// stub.syncUp().thenDoNothing() -// } -// -// let dataOperationFactory = MockDataOperationFactoryProtocol() -// -// let eventCenter = MockEventCenterProtocol() -// -// stub(eventCenter) { stub in -// stub.notify(with: any()).thenDoNothing() -// } -// -// let chainCount = 10 -// let expectedChains = ChainModelGenerator.generate(count: chainCount) -// let expectedChainIds = Set(expectedChains.map { $0.chainId }) -// let chainsData = try JSONEncoder().encode(expectedChains) -// -// stub(dataOperationFactory) { stub in -// stub.fetchData(from: any()).thenReturn(BaseOperation.createWithResult(chainsData)) -// } -// -// stub(runtimeProviderPool) { stub in -// let runtimeProvider = MockRuntimeProviderProtocol() -// stub.setupRuntimeProvider(for: any()).thenReturn(runtimeProvider) -// stub.getRuntimeProvider(for: any()).thenReturn(runtimeProvider) -// } -// -// stub(connectionPool) { stub in -// let connection = MockConnection() -// stub.setupConnection(for: any()).thenReturn(connection) -// stub.getConnection(for: any()).thenReturn(connection) -// } -// -// let mockSubscription = MockSpecVersionSubscriptionProtocol() -// stub(mockSubscription) { stub in -// stub.subscribe().thenDoNothing() -// stub.unsubscribe().thenDoNothing() -// } -// -// stub(specVersionSubscriptionFactory) { stub in -// stub.createSubscription(for: any(), connection: any()).thenReturn(mockSubscription) -// } -// -// let storageFacade = SubstrateStorageTestFacade() -// -// let mapper = ChainModelMapper() -// let repository: CoreDataRepository = storageFacade.createRepository( -// mapper: AnyCoreDataMapper(mapper) -// ) -// -// let chainSyncService = ChainSyncService( -// chainsUrl: URL(string: "https://google.com")!, -// assetsUrl: URL(string: "https://google.com")!, -// dataFetchFactory: dataOperationFactory, -// repository: AnyDataProviderRepository(repository), -// eventCenter: eventCenter, -// operationQueue: OperationQueue() -// ) -// -// let chainObserver = CoreDataContextObservable( -// service: storageFacade.databaseService, -// mapper: repository.dataMapper, -// predicate: { _ in true } -// ) -// -// chainObserver.start { error in -// if let error = error { -// Logger.shared.error("Chain database observer unexpectedly failed: \(error)") -// } -// } -// -// let chainProvider = StreamableProvider( -// source: AnyStreamableSource(EmptyStreamableSource()), -// repository: AnyDataProviderRepository(repository), -// observable: AnyDataProviderRepositoryObservable(chainObserver), -// operationManager: OperationManagerFacade.sharedManager -// ) -// -// let registry = ChainRegistry( -// runtimeProviderPool: runtimeProviderPool, -// connectionPool: connectionPool, -// chainSyncService: chainSyncService, -// runtimeSyncService: runtimeSyncService, -// commonTypesSyncService: commonTypesSyncService, -// chainProvider: chainProvider, -// specVersionSubscriptionFactory: specVersionSubscriptionFactory, -// eventCenter: EventCenter.shared -// ) -// -// registry.syncUp() -// -// // when -// -// var setupChainIds = Set() -// -// let expectation = XCTestExpectation() -// -// registry.chainsSubscribe(self, runningInQueue: .main) { changes in -// guard !changes.isEmpty else { -// return -// } -// -// changes.forEach { change in -// if case let .insert(item) = change { -// setupChainIds.insert(item.chainId) -// } -// } -// -// expectation.fulfill() -// } -// -// // then -// -// wait(for: [expectation], timeout: 10) -// -// XCTAssertEqual(expectedChainIds, setupChainIds) -// XCTAssertEqual(expectedChainIds, registry.availableChainIds) -// -// for chain in expectedChains { -// XCTAssertNotNil(registry.getConnection(for: chain.chainId)) -// XCTAssertNotNil(registry.getRuntimeProvider(for: chain.chainId)) -// } -// -// verify(runtimeSyncService, times(chainCount)).register(chain: any(), with: any()) -// } -//} +import Cuckoo +import RobinHood +import SSFModels +import SSFRuntimeCodingService +import SSFUtils +import Web3 +import XCTest +@testable import fearless + +final class ChainRegistryTests: XCTestCase { + func testDisabledThenReenabledChainDisconnectsAndUsesNewNode() throws { + let storageFacade = SubstrateStorageTestFacade() + let repository = ChainRepositoryFactory( + storageFacade: storageFacade + ).createRepository() + let provider = makeChainProvider( + storageFacade: storageFacade, + repository: repository + ) + + let oldNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "wss://old-node.example")), + name: "Old", + apikey: nil + ) + let newNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "wss://new-node.example")), + name: "New", + apikey: nil + ) + let enabledOld = makeChain( + identifier: "lifecycle-chain", + disabled: false, + node: oldNode + ) + let disabled = makeChain( + identifier: enabledOld.chainId, + disabled: true, + node: oldNode + ) + let enabledNew = makeChain( + identifier: enabledOld.chainId, + disabled: false, + node: newNode + ) + + let connectionFactory = RecordingConnectionFactory() + let connectionPool = ConnectionPool( + connectionFactory: connectionFactory + ) + let runtimeProviderPool = makeRuntimeProviderPool() + let runtimeSyncService = makeRuntimeSyncService() + let subscriptionFactory = makeSubscriptionFactory() + let registry = ChainRegistry( + snapshotHotBootBuilder: NoopSnapshotHotBootBuilder(), + runtimeProviderPool: runtimeProviderPool, + connectionPools: [connectionPool], + chainSyncService: NoopChainSyncService(), + runtimeSyncService: runtimeSyncService, + chainsTypesSyncService: NoopChainsTypesSyncService(), + chainProvider: provider, + specVersionSubscriptionFactory: subscriptionFactory, + networkIssuesCenter: NoopNetworkIssuesCenter(), + eventCenter: NoopEventCenter() + ) + registry.subscribeToChains() + + try save(enabledOld, in: repository) + let firstConnection: ChainConnection = try waitForValue { + guard + registry.getChain(for: enabledOld.chainId)?.selectedNode == oldNode + else { + return nil + } + + return registry.getConnection(for: enabledOld.chainId) + } + XCTAssertEqual(connectionFactory.requestedURLs, [[oldNode.url]]) + + try save(disabled, in: repository) + try waitForCondition { + registry.getChain(for: enabledOld.chainId) == nil && + registry.getConnection(for: enabledOld.chainId) == nil + } + XCTAssertNil(registry.getConnection(for: enabledOld.chainId)) + XCTAssertEqual( + (firstConnection as? MockConnection)?.disconnectCallCount, + 1 + ) + XCTAssertEqual(connectionFactory.requestedURLs, [[oldNode.url]]) + + try save(enabledNew, in: repository) + let secondConnection: ChainConnection = try waitForValue { + guard + registry.getChain(for: enabledOld.chainId)?.selectedNode == newNode + else { + return nil + } + + return registry.getConnection(for: enabledOld.chainId) + } + XCTAssertFalse(firstConnection === secondConnection) + XCTAssertEqual( + connectionFactory.requestedURLs, + [[oldNode.url], [newNode.url]] + ) + XCTAssertEqual( + (firstConnection as? MockConnection)?.disconnectCallCount, + 1 + ) + XCTAssertEqual( + (secondConnection as? MockConnection)?.disconnectCallCount, + 0 + ) + + provider.removeObserver(registry) + } + + func testUpdatedEthereumChainUsesReplacementNodeImmediately() throws { + let storageFacade = SubstrateStorageTestFacade() + let repository = ChainRepositoryFactory( + storageFacade: storageFacade + ).createRepository() + let provider = makeChainProvider( + storageFacade: storageFacade, + repository: repository + ) + let oldNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "https://old-rpc.example")), + name: "Old Ethereum RPC", + apikey: nil + ) + let newNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "https://new-rpc.example")), + name: "New Ethereum RPC", + apikey: nil + ) + let chainId = "ethereum-lifecycle-chain" + let oldChain = makeEthereumChain( + identifier: chainId, + node: oldNode + ) + let updatedChain = makeEthereumChain( + identifier: chainId, + node: newNode + ) + let nodeFetching = RecordingEthereumNodeFetching() + let ethereumPool = EthereumConnectionPool( + nodeFetching: nodeFetching + ) + let registry = ChainRegistry( + snapshotHotBootBuilder: NoopSnapshotHotBootBuilder(), + runtimeProviderPool: makeRuntimeProviderPool(), + connectionPools: [ethereumPool], + chainSyncService: NoopChainSyncService(), + runtimeSyncService: makeRuntimeSyncService(), + chainsTypesSyncService: NoopChainsTypesSyncService(), + chainProvider: provider, + specVersionSubscriptionFactory: makeSubscriptionFactory(), + networkIssuesCenter: NoopNetworkIssuesCenter(), + eventCenter: NoopEventCenter() + ) + registry.subscribeToChains() + + try save(oldChain, in: repository) + let firstURL: URL = try waitForValue { + nodeFetching.requestedURLs.first + } + + try save(updatedChain, in: repository) + let secondURL: URL = try waitForValue { + let urls = nodeFetching.requestedURLs + return urls.count >= 2 ? urls.last : nil + } + + XCTAssertEqual(firstURL, oldNode.url) + XCTAssertEqual(secondURL, newNode.url) + XCTAssertEqual( + nodeFetching.requestedURLs, + [oldNode.url, newNode.url] + ) + XCTAssertNotNil( + registry.getEthereumConnection(for: chainId) + ) + XCTAssertEqual( + registry.getChain(for: chainId)?.selectedNode, + newNode + ) + + provider.removeObserver(registry) + } + + private func makeChainProvider( + storageFacade: SubstrateStorageTestFacade, + repository: CoreDataRepository + ) -> StreamableProvider { + let observable = CoreDataContextObservable( + service: storageFacade.databaseService, + mapper: repository.dataMapper, + predicate: { _ in true } + ) + observable.start { error in + XCTAssertNil(error) + } + let source = fearless.EmptyStreamableSource() + + return StreamableProvider( + source: AnyStreamableSource(source), + repository: AnyDataProviderRepository(repository), + observable: AnyDataProviderRepositoryObservable(observable), + operationManager: fearless.OperationManagerFacade.sharedManager + ) + } + + private func makeChain( + identifier: String, + disabled: Bool, + node: ChainNodeModel + ) -> ChainModel { + ChainModel( + rank: 1, + disabled: disabled, + chainId: identifier, + paraId: nil, + name: "Lifecycle", + xcm: nil, + nodes: [node], + addressPrefix: 42, + icon: nil, + selectedNode: node, + iosMinAppVersion: nil, + identityChain: nil + ) + } + + private func makeEthereumChain( + identifier: String, + node: ChainNodeModel + ) -> ChainModel { + ChainModel( + rank: 1, + disabled: false, + chainId: identifier, + paraId: nil, + name: "Ethereum Lifecycle", + xcm: nil, + nodes: [node], + addressPrefix: 0, + icon: nil, + options: [.ethereum], + selectedNode: node, + iosMinAppVersion: nil, + identityChain: nil + ) + } + + private func waitForValue( + timeout: TimeInterval = 2, + _ valueProvider: () -> T? + ) throws -> T { + let deadline = Date().addingTimeInterval(timeout) + + while Date() < deadline { + if let value = valueProvider() { + return value + } + + RunLoop.current.run( + until: Date().addingTimeInterval(0.01) + ) + } + + throw ChainRegistryTestError.timeout + } + + private func waitForCondition( + timeout: TimeInterval = 2, + _ condition: () -> Bool + ) throws { + let _: Bool = try waitForValue(timeout: timeout) { + condition() ? true : nil + } + } + + private func save( + _ chain: ChainModel, + in repository: CoreDataRepository + ) throws { + let operation = repository.saveOperation({ [chain] }, { [] }) + OperationQueue().addOperations([operation], waitUntilFinished: true) + let _: Void = try XCTUnwrap(operation.result).get() + } + + private func makeRuntimeProviderPool() -> MockRuntimeProviderPoolProtocol { + let pool = MockRuntimeProviderPoolProtocol() + let provider = NoopRuntimeProvider() + stub(pool) { stub in + stub.setupRuntimeProvider( + for: any(), + chainTypes: any() + ).thenReturn(provider) + stub.destroyRuntimeProvider(for: any()).thenDoNothing() + } + return pool + } + + private func makeRuntimeSyncService() -> MockRuntimeSyncServiceProtocol { + let service = MockRuntimeSyncServiceProtocol() + stub(service) { stub in + stub.register(chain: any(), with: any()).thenDoNothing() + stub.unregister(chainId: any()).thenDoNothing() + } + return service + } + + private func makeSubscriptionFactory() + -> MockSpecVersionSubscriptionFactoryProtocol { + let factory = MockSpecVersionSubscriptionFactoryProtocol() + let subscription = MockSpecVersionSubscriptionProtocol() + stub(subscription) { stub in + stub.subscribe().thenDoNothing() + stub.unsubscribe().thenDoNothing() + } + stub(factory) { stub in + stub.createSubscription( + for: any(), + connection: any() + ).thenReturn(subscription) + } + return factory + } +} + +private enum ChainRegistryTestError: Error { + case timeout +} + +private final class RecordingEthereumNodeFetching: + EthereumNodeFetchingProtocol { + private let lock = NSLock() + private var urls: [URL] = [] + + var requestedURLs: [URL] { + lock.lock() + defer { lock.unlock() } + + return urls + } + + func getNode(for chain: ChainModel) throws -> Web3.Eth { + if let selectedURL = chain.selectedNode?.url { + lock.lock() + urls.append(selectedURL) + lock.unlock() + } + + return try EthereumNodeFetching().getNode(for: chain) + } +} + +private final class RecordingConnectionFactory: ConnectionFactoryProtocol { + private let lock = NSLock() + private var connections: [MockConnection] = [] + private var urls: [[URL]] = [] + + var requestedURLs: [[URL]] { + lock.lock() + defer { lock.unlock() } + return urls + } + + func createConnection( + connectionName: String?, + for urls: [URL], + delegate _: WebSocketEngineDelegate + ) throws -> ChainConnection { + let connection = MockConnection() + connection.connectionName = connectionName + connection.url = urls.first + + lock.lock() + self.urls.append(urls) + connections.append(connection) + lock.unlock() + + return connection + } +} + +private final class NoopSnapshotHotBootBuilder: + SnapshotHotBootBuilderProtocol { + func startHotBoot() {} +} + +private final class NoopChainSyncService: ChainSyncServiceProtocol { + func syncUp() {} +} + +private final class NoopChainsTypesSyncService: + ChainsTypesSyncServiceProtocol { + func syncUp() {} +} + +private final class NoopNetworkIssuesCenter: NetworkIssuesCenterProtocol { + func addIssuesListener( + _: NetworkIssuesCenterListener, + getExisting _: Bool + ) {} + + func removeIssuesListener(_: NetworkIssuesCenterListener) {} + + func forceNotify() {} +} + +private final class NoopEventCenter: EventCenterProtocol { + func notify(with _: EventProtocol) {} + + func add( + observer _: EventVisitorProtocol, + dispatchIn _: DispatchQueue? + ) {} + + func remove(observer _: EventVisitorProtocol) {} +} + +private final class NoopRuntimeProvider: RuntimeProviderProtocol { + var runtimeSpecVersion: RuntimeSpecVersion = .defaultVersion + var snapshot: RuntimeSnapshot? + + func setup() {} + + func setupHot() {} + + func cleanup() {} + + func readySnapshot() async throws -> RuntimeSnapshot { + throw SSFRuntimeCodingService.RuntimeProviderError + .providerUnavailable + } + + func fetchCoderFactoryOperation() + -> BaseOperation { + BaseOperation() + } + + func fetchCoderFactory() async throws + -> RuntimeCoderFactoryProtocol { + throw SSFRuntimeCodingService.RuntimeProviderError + .providerUnavailable + } +} diff --git a/fearlessTests/Common/Services/ChainRegistry/ChainSyncServiceCompatibilityTests.swift b/fearlessTests/Common/Services/ChainRegistry/ChainSyncServiceCompatibilityTests.swift index c655a103f8..a77e96dbdf 100644 --- a/fearlessTests/Common/Services/ChainRegistry/ChainSyncServiceCompatibilityTests.swift +++ b/fearlessTests/Common/Services/ChainRegistry/ChainSyncServiceCompatibilityTests.swift @@ -1,4 +1,8 @@ import XCTest +import RobinHood +import SoraFoundation +import SSFModels +import SSFUtils @testable import fearless final class ChainSyncServiceCompatibilityTests: XCTestCase { @@ -36,8 +40,1931 @@ final class ChainSyncServiceCompatibilityTests: XCTestCase { let explorers = try XCTUnwrap(externalApi["explorers"] as? [[String: Any]]) XCTAssertEqual(history["type"] as? String, ChainSyncService.historyExplorerCompatibilityType) - XCTAssertEqual(staking["type"] as? String, ChainSyncService.historyExplorerCompatibilityType) - XCTAssertEqual(explorers.first?["type"] as? String, ChainSyncService.historyExplorerCompatibilityType) + XCTAssertEqual(staking["type"] as? String, ChainSyncService.stakingExplorerCompatibilityType) + XCTAssertEqual(explorers.first?["type"] as? String, ChainSyncService.genericExplorerCompatibilityType) XCTAssertEqual(explorers.last?["type"] as? String, "etherscan") } + + func testPreservingLocalNodePreferencesKeepsCustomAndSelectedNodes() throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let customNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "wss://user-node.example")), + name: "My private node", + apikey: nil + ) + let localChain = remoteChain + .replacingCustomNodes([customNode]) + .replacingSelectedNode(customNode) + + let mergedChains = ChainSyncService.preservingLocalNodePreferences( + remoteChains: [remoteChain], + localChains: [localChain] + ) + + let mergedChain = try XCTUnwrap(mergedChains.first) + XCTAssertEqual(mergedChain.customNodes, Set([customNode])) + XCTAssertEqual(mergedChain.selectedNode, customNode) + XCTAssertNil(remoteChain.customNodes) + XCTAssertNil(remoteChain.selectedNode) + } + + func testPreservingLocalNodePreferencesDoesNotApplyPreferencesToAnotherChain() throws { + let remoteChains = ChainModelGenerator.generate(count: 2) + let customNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "wss://user-node.example")), + name: "My private node", + apikey: nil + ) + let localChain = remoteChains[0] + .replacingCustomNodes([customNode]) + .replacingSelectedNode(customNode) + + let mergedChains = ChainSyncService.preservingLocalNodePreferences( + remoteChains: remoteChains, + localChains: [localChain] + ) + + XCTAssertEqual(mergedChains[0].customNodes, Set([customNode])) + XCTAssertEqual(mergedChains[0].selectedNode, customNode) + XCTAssertNil(mergedChains[1].customNodes) + XCTAssertNil(mergedChains[1].selectedNode) + } + + func testPreservingLocalNodePreferencesRejectsRemoteCustomNodeInjection() throws { + let localChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let injectedNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "wss://untrusted-remote-node.example")), + name: "Injected node", + apikey: nil + ) + let remoteChain = localChain + .replacingCustomNodes([injectedNode]) + .replacingSelectedNode(injectedNode) + + let mergedChains = ChainSyncService.preservingLocalNodePreferences( + remoteChains: [remoteChain], + localChains: [localChain] + ) + + let mergedChain = try XCTUnwrap(mergedChains.first) + XCTAssertEqual(mergedChain.customNodes, Set()) + XCTAssertNil(mergedChain.selectedNode) + } + + func testPreservingLocalNodePreferencesDropsRetiredDefaultSelection() throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let retiredNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "wss://retired-default.example")), + name: "Retired default", + apikey: nil + ) + let localChain = remoteChain.replacingSelectedNode(retiredNode) + + let mergedChains = ChainSyncService.preservingLocalNodePreferences( + remoteChains: [remoteChain], + localChains: [localChain] + ) + + let mergedChain = try XCTUnwrap(mergedChains.first) + XCTAssertNil(mergedChain.selectedNode) + XCTAssertFalse(mergedChain.nodes.contains(retiredNode)) + } + + func testPreservingLocalNodePreferencesRefreshesSelectedDefaultByURL() throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let remoteNode = try XCTUnwrap(remoteChain.nodes.first) + let staleSelectedNode = ChainNodeModel( + url: remoteNode.url, + name: "Stale display name", + apikey: nil + ) + let localChain = remoteChain.replacingSelectedNode(staleSelectedNode) + + let mergedChains = ChainSyncService.preservingLocalNodePreferences( + remoteChains: [remoteChain], + localChains: [localChain] + ) + + XCTAssertEqual(try XCTUnwrap(mergedChains.first).selectedNode, remoteNode) + } + + func testRepositoryWriteFailureEmitsFailureWithoutFalseCompletion() throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let data = try JSONEncoder().encode([remoteChain]) + let repository = SaveFailingChainRepository( + error: ChainSyncCompatibilityTestError.saveFailed + ) + let eventCenter = RecordingChainSyncEventCenter() + let failureExpectation = expectation(description: "save failure is propagated") + let falseCompletionExpectation = expectation( + description: "failed save never emits completion" + ) + falseCompletionExpectation.isInverted = true + eventCenter.onEvent = { event in + if event is ChainSyncDidFail { + failureExpectation.fulfill() + } else if event is ChainSyncDidComplete { + falseCompletionExpectation.fulfill() + } + } + let service = ChainSyncService( + chainsUrl: try XCTUnwrap(URL(string: "https://chains.example/chains.json")), + dataFetchFactory: StaticDataOperationFactory(data: data), + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + operationQueue: OperationQueue(), + retryStrategy: NeverReconnectStrategy(), + applicationHandler: ApplicationHandler() + ) + + service.syncUp() + + wait( + for: [failureExpectation, falseCompletionExpectation], + timeout: 1 + ) + XCTAssertEqual(repository.saveCallCount, 1) + XCTAssertEqual(eventCenter.failureCount, 1) + XCTAssertEqual(eventCenter.completionCount, 0) + XCTAssertTrue( + eventCenter.lastFailure is ChainSyncCompatibilityTestError + ) + } + + func testRepositoryFetchFailureDoesNotWriteOrReplaceCache() throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let repository = ScriptedChainRepository( + fetchAllError: ChainSyncCompatibilityTestError.fetchFailed + ) + let eventCenter = RecordingChainSyncEventCenter() + let failureExpectation = expectation( + description: "database failure is propagated" + ) + eventCenter.onEvent = { event in + if event is ChainSyncDidFail { + failureExpectation.fulfill() + } + } + let service = makeService( + data: try JSONEncoder().encode([remoteChain]), + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter + ) + + service.syncUp() + + wait(for: [failureExpectation], timeout: 1) + XCTAssertEqual(repository.replaceCallCount, 0) + XCTAssertEqual(eventCenter.failureCount, 1) + XCTAssertEqual(eventCenter.completionCount, 0) + } + + func testEmptyRemotePayloadNeverDeletesReadableCache() throws { + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let failureExpectation = expectation( + description: "empty authoritative payload is rejected" + ) + eventCenter.onEvent = { event in + if event is ChainSyncDidFail { + failureExpectation.fulfill() + } + } + let service = makeService( + data: try JSONEncoder().encode([ChainModel]()), + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter + ) + + service.syncUp() + + wait(for: [failureExpectation], timeout: 1) + XCTAssertEqual(repository.replaceCallCount, 0) + XCTAssertEqual(eventCenter.failureCount, 1) + XCTAssertEqual(eventCenter.completionCount, 0) + XCTAssertTrue(eventCenter.lastFailure is ChainSyncServiceError) + } + + func testActiveRemoteChainWithOnlyUnusableNodesPreservesWorkingCache() + throws { + let workingChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let unusableNodes: Set = [ + ChainNodeModel( + url: try XCTUnwrap( + URL(string: "ftp://attacker.example/node") + ), + name: "Unsupported scheme", + apikey: nil + ), + ChainNodeModel( + url: try XCTUnwrap(URL(string: "relative/node")), + name: "Relative endpoint", + apikey: nil + ) + ] + let hostileRemoteChain = workingChain.replacingNodes( + unusableNodes + ) + let repository = ScriptedChainRepository( + localChains: [workingChain] + ) + let eventCenter = RecordingChainSyncEventCenter() + let failureExpectation = expectation( + description: "an unusable active chain is rejected" + ) + eventCenter.onEvent = { event in + if event is ChainSyncDidFail { + failureExpectation.fulfill() + } + } + let service = makeService( + data: try JSONEncoder().encode([hostileRemoteChain]), + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter + ) + + service.syncUp() + + wait(for: [failureExpectation], timeout: 1) + XCTAssertEqual(repository.saveCallCount, 0) + XCTAssertEqual(repository.replaceCallCount, 0) + XCTAssertTrue(repository.savedModels.isEmpty) + XCTAssertTrue(repository.deletedIdentifiers.isEmpty) + XCTAssertEqual(eventCenter.failureCount, 1) + XCTAssertEqual(eventCenter.completionCount, 0) + } + + func testMixedRemoteNodesPersistOnlyUsableUniqueEndpoints() throws { + let baseChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let validNode = try XCTUnwrap(baseChain.nodes.first) + let duplicateURLNode = ChainNodeModel( + url: validNode.url, + name: validNode.name + " duplicate", + apikey: nil + ) + let invalidNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "file:///tmp/not-a-node")), + name: "Local file", + apikey: nil + ) + let mixedRemoteChain = baseChain.replacingNodes( + Set([validNode, duplicateURLNode, invalidNode]) + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let completionExpectation = expectation( + description: "usable endpoints are saved" + ) + eventCenter.onEvent = { event in + if event is ChainSyncDidComplete { + completionExpectation.fulfill() + } + } + let service = makeService( + data: try JSONEncoder().encode([mixedRemoteChain]), + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter + ) + + service.syncUp() + + wait(for: [completionExpectation], timeout: 1) + let savedChain = try XCTUnwrap(repository.savedModels.first) + XCTAssertEqual(savedChain.nodes.count, 1) + XCTAssertEqual(savedChain.nodes.first?.url, validNode.url) + XCTAssertTrue( + savedChain.nodes.allSatisfy { + ChainModelMapper.isUsableNodeURL($0.url) + } + ) + XCTAssertEqual(eventCenter.failureCount, 0) + XCTAssertEqual(eventCenter.completionCount, 1) + } + + func testPartialRemotePayloadDisablesOmittedChainWithoutDeletingPreferences() throws { + let remoteChains = ChainModelGenerator.generate(count: 2) + let retainedRemoteChain = remoteChains[0] + let omittedRemoteChain = remoteChains[1] + let customNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "wss://omitted-user-node.example")), + name: "Omitted chain preference", + apikey: nil + ) + let omittedLocalChain = omittedRemoteChain + .replacingCustomNodes([customNode]) + .replacingSelectedNode(customNode) + let repository = ScriptedChainRepository( + localChains: [retainedRemoteChain, omittedLocalChain] + ) + let eventCenter = RecordingChainSyncEventCenter() + let completionExpectation = expectation( + description: "partial payload is retained non-destructively" + ) + eventCenter.onEvent = { event in + if event is ChainSyncDidComplete { + completionExpectation.fulfill() + } + } + let service = makeService( + data: try JSONEncoder().encode([retainedRemoteChain]), + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter + ) + + service.syncUp() + + wait(for: [completionExpectation], timeout: 1) + let disabledChain = try XCTUnwrap( + repository.savedModels.first { + $0.chainId == omittedRemoteChain.chainId + } + ) + XCTAssertTrue(disabledChain.disabled) + XCTAssertEqual(disabledChain.customNodes, Set([customNode])) + XCTAssertEqual(disabledChain.selectedNode, customNode) + XCTAssertTrue(repository.deletedIdentifiers.isEmpty) + XCTAssertEqual(eventCenter.failureCount, 0) + } + + func testReappearingRemoteChainRestoresDisabledPreferences() throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let customNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "wss://restored-user-node.example")), + name: "Restored preference", + apikey: nil + ) + let disabledLocalChain = remoteChain + .replacingCustomNodes([customNode]) + .replacingSelectedNode(customNode) + .replacingDisabled(true) + + let mergedChains = ChainSyncService.preservingLocalNodePreferences( + remoteChains: [remoteChain], + localChains: [disabledLocalChain] + ) + + let restoredChain = try XCTUnwrap(mergedChains.first) + XCTAssertFalse(restoredChain.disabled) + XCTAssertEqual(restoredChain.customNodes, Set([customNode])) + XCTAssertEqual(restoredChain.selectedNode, customNode) + } + + func testQuarantinedLocalChainDoesNotDiscardHealthyNodePreferences() throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let customNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "wss://user-node.example")), + name: "My private node", + apikey: nil + ) + let healthyLocalChain = remoteChain + .replacingCustomNodes([customNode]) + .replacingSelectedNode(customNode) + let quarantinedChain = ChainModel( + rank: nil, + disabled: true, + chainId: ChainModelMapper.quarantinedChainIdentifierPrefix + "fixture", + paraId: nil, + name: ChainModelMapper.quarantinedChainName, + xcm: nil, + nodes: [], + addressPrefix: 0, + icon: nil, + iosMinAppVersion: nil, + identityChain: nil + ) + let repository = ScriptedChainRepository( + localChains: [healthyLocalChain, quarantinedChain] + ) + let eventCenter = RecordingChainSyncEventCenter() + let completionExpectation = expectation( + description: "healthy preferences survive quarantine cleanup" + ) + eventCenter.onEvent = { event in + if event is ChainSyncDidComplete { + completionExpectation.fulfill() + } + } + let service = makeService( + data: try JSONEncoder().encode([remoteChain]), + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter + ) + + service.syncUp() + + wait(for: [completionExpectation], timeout: 1) + XCTAssertEqual(repository.replaceCallCount, 0) + XCTAssertEqual(repository.saveCallCount, 1) + XCTAssertTrue(repository.savedModels.isEmpty) + XCTAssertTrue(repository.deletedIdentifiers.isEmpty) + XCTAssertEqual(eventCenter.failureCount, 0) + XCTAssertEqual(eventCenter.completionCount, 1) + } + + func testMalformedChainCleanupFailurePreventsRepositoryMutation() throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let failureExpectation = expectation( + description: "cleanup failure is propagated before sync" + ) + eventCenter.onEvent = { event in + if event is ChainSyncDidFail { + failureExpectation.fulfill() + } + } + let service = makeService( + data: try JSONEncoder().encode([remoteChain]), + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + malformedChainCleanupOperationFactory: { + ClosureOperation { + throw ChainSyncCompatibilityTestError.cleanupFailed + } + } + ) + + service.syncUp() + + wait(for: [failureExpectation], timeout: 1) + XCTAssertEqual(repository.saveCallCount, 0) + XCTAssertEqual(repository.replaceCallCount, 0) + XCTAssertEqual(eventCenter.failureCount, 1) + XCTAssertEqual(eventCenter.completionCount, 0) + } + + func testConcurrentSyncRequestsStartSingleDeterministicPipeline() + throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let expectedChain = try XCTUnwrap( + ChainSyncService.sanitizingRemoteChains([remoteChain]).first + ) + let dataFactory = CountingDataOperationFactory( + data: try JSONEncoder().encode([remoteChain]) + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let cleanupCounter = LockedCounter() + let cleanupRelease = DispatchSemaphore(value: 0) + let cleanupStarted = expectation( + description: "one cleanup pipeline starts" + ) + let completion = expectation( + description: "the reserved pipeline completes" + ) + eventCenter.onEvent = { event in + if event is ChainSyncDidComplete { + completion.fulfill() + } + } + let service = ChainSyncService( + chainsUrl: try XCTUnwrap( + URL(string: "https://chains.example/chains.json") + ), + dataFetchFactory: dataFactory, + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + operationQueue: OperationQueue(), + retryStrategy: NeverReconnectStrategy(), + applicationHandler: ApplicationHandler(), + malformedChainCleanupOperationFactory: { + if cleanupCounter.increment() == 1 { + cleanupStarted.fulfill() + } + + return ClosureOperation { + cleanupRelease.wait() + } + } + ) + + DispatchQueue.concurrentPerform(iterations: 32) { index in + if index.isMultiple(of: 2) { + service.syncUp() + } else { + service.didReceiveDidBecomeActive( + notification: Notification( + name: Notification.Name( + "ChainSyncConcurrencyRegression" + ) + ) + ) + } + } + + wait(for: [cleanupStarted], timeout: 1) + XCTAssertEqual(cleanupCounter.value, 1) + XCTAssertEqual(eventCenter.startCount, 1) + XCTAssertEqual(dataFactory.fetchCallCount, 0) + XCTAssertEqual(repository.fetchAllCallCount, 0) + XCTAssertEqual(repository.saveCallCount, 0) + + cleanupRelease.signal() + wait(for: [completion], timeout: 1) + + XCTAssertEqual(cleanupCounter.value, 1) + XCTAssertEqual(dataFactory.fetchCallCount, 1) + XCTAssertEqual(repository.fetchAllCallCount, 1) + XCTAssertEqual(repository.saveCallCount, 1) + XCTAssertEqual(eventCenter.startCount, 1) + XCTAssertEqual(eventCenter.failureCount, 0) + XCTAssertEqual(eventCenter.completionCount, 1) + XCTAssertEqual(repository.savedModels, [expectedChain]) + } + + func testCooldownExpiryDoesNotReleaseBlockedPipeline() throws { + let remoteChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let expectedChain = try XCTUnwrap( + ChainSyncService.sanitizingRemoteChains([remoteChain]).first + ) + let firstFetchRelease = DispatchSemaphore(value: 0) + let firstFetchStarted = expectation( + description: "first fetch remains unresolved" + ) + let dataFactory = CountingDataOperationFactory( + data: try JSONEncoder().encode([remoteChain]), + firstFetchGate: firstFetchRelease, + onFirstFetchStart: { + firstFetchStarted.fulfill() + } + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let cleanupCounter = LockedCounter() + let cooldownTimer = ManualCountdownTimer() + let cooldownTimerQueue = DispatchQueue( + label: "jp.co.soramitsu.fearless.tests.cooldown.expiry-success" + ) + let firstCompletion = expectation( + description: "first pipeline completes" + ) + let secondCompletion = expectation( + description: "next pipeline starts after completion" + ) + eventCenter.onEvent = { event in + guard event is ChainSyncDidComplete else { + return + } + + if eventCenter.completionCount == 1 { + firstCompletion.fulfill() + } else if eventCenter.completionCount == 2 { + secondCompletion.fulfill() + } + } + let service = ChainSyncService( + chainsUrl: try XCTUnwrap( + URL(string: "https://chains.example/chains.json") + ), + dataFetchFactory: dataFactory, + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + operationQueue: OperationQueue(), + retryStrategy: NeverReconnectStrategy(), + applicationHandler: ApplicationHandler(), + malformedChainCleanupOperationFactory: { + _ = cleanupCounter.increment() + return ClosureOperation { () } + }, + cooldownTimer: cooldownTimer, + cooldownTimerQueue: cooldownTimerQueue + ) + + service.syncUp() + wait(for: [firstFetchStarted], timeout: 1) + drain(cooldownTimerQueue) + XCTAssertEqual(cooldownTimer.startCount, 1) + + cooldownTimer.expire() + + DispatchQueue.concurrentPerform(iterations: 32) { index in + if index.isMultiple(of: 2) { + service.syncUp() + } else { + service.didReceiveDidBecomeActive( + notification: Notification( + name: Notification.Name( + "ChainSyncCooldownExpiryRegression" + ) + ) + ) + } + } + + XCTAssertEqual(cleanupCounter.value, 1) + XCTAssertEqual(dataFactory.fetchCallCount, 1) + XCTAssertEqual(repository.fetchAllCallCount, 0) + XCTAssertEqual(repository.saveCallCount, 0) + XCTAssertEqual(eventCenter.startCount, 1) + XCTAssertEqual(eventCenter.completionCount, 0) + + firstFetchRelease.signal() + wait(for: [firstCompletion], timeout: 1) + + XCTAssertEqual(cleanupCounter.value, 1) + XCTAssertEqual(dataFactory.fetchCallCount, 1) + XCTAssertEqual(repository.fetchAllCallCount, 1) + XCTAssertEqual(repository.saveCallCount, 1) + XCTAssertEqual(eventCenter.startCount, 1) + XCTAssertEqual(repository.savedModels, [expectedChain]) + + service.syncUp() + wait(for: [secondCompletion], timeout: 1) + + XCTAssertEqual(cleanupCounter.value, 2) + XCTAssertEqual(dataFactory.fetchCallCount, 2) + XCTAssertEqual(repository.fetchAllCallCount, 2) + XCTAssertEqual(repository.saveCallCount, 2) + XCTAssertEqual(eventCenter.startCount, 2) + XCTAssertEqual(eventCenter.failureCount, 0) + XCTAssertEqual(eventCenter.completionCount, 2) + XCTAssertEqual(repository.savedModels, [expectedChain]) + } + + func testSuccessBeforeTimerStartRetainsCooldownUntilExpiry() throws { + let data = try JSONEncoder().encode([ + makeValidChain(generatingAssets: 1, addressPrefix: 42) + ]) + let dataFactory = ScriptedDataOperationFactory( + scripts: [ + { data }, + { data } + ] + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let completionSignal = DispatchSemaphore(value: 0) + eventCenter.onEvent = { event in + if event is ChainSyncDidComplete { + completionSignal.signal() + } + } + let cooldownTimer = ManualCountdownTimer() + let cooldownTimerQueue = DispatchQueue( + label: "jp.co.soramitsu.fearless.tests.cooldown.before-success" + ) + cooldownTimerQueue.suspend() + var timerQueueIsSuspended = true + defer { + if timerQueueIsSuspended { + cooldownTimerQueue.resume() + } + } + let service = makeService( + dataFetchFactory: dataFactory, + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + cooldownTimer: cooldownTimer, + cooldownTimerQueue: cooldownTimerQueue + ) + + service.syncUp() + waitForSignal( + completionSignal, + description: "success before timer start" + ) + + DispatchQueue.concurrentPerform(iterations: 32) { _ in + service.syncUp() + } + XCTAssertEqual(eventCenter.startCount, 1) + XCTAssertEqual(dataFactory.fetchCallCount, 1) + XCTAssertEqual(cooldownTimer.startCount, 0) + + cooldownTimerQueue.resume() + timerQueueIsSuspended = false + drain(cooldownTimerQueue) + XCTAssertEqual(cooldownTimer.startCount, 1) + + cooldownTimer.expire() + service.syncUp() + waitForSignal( + completionSignal, + description: "success after deferred timer expiry" + ) + + XCTAssertEqual(eventCenter.startCount, 2) + XCTAssertEqual(dataFactory.fetchCallCount, 2) + XCTAssertEqual(eventCenter.failureCount, 0) + XCTAssertEqual(eventCenter.completionCount, 2) + } + + func testSuccessDuringCooldownRemainsBlockedUntilExpiry() throws { + let data = try JSONEncoder().encode([ + makeValidChain(generatingAssets: 1, addressPrefix: 42) + ]) + let firstFetchStarted = DispatchSemaphore(value: 0) + let firstFetchRelease = DispatchSemaphore(value: 0) + let dataFactory = ScriptedDataOperationFactory( + scripts: [ + { + firstFetchStarted.signal() + guard firstFetchRelease.wait( + timeout: .now() + 2 + ) == .success else { + throw ChainSyncCompatibilityTestError.gateTimedOut + } + return data + }, + { data } + ] + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let completionSignal = DispatchSemaphore(value: 0) + eventCenter.onEvent = { event in + if event is ChainSyncDidComplete { + completionSignal.signal() + } + } + let cooldownTimer = ManualCountdownTimer() + let cooldownTimerQueue = DispatchQueue( + label: "jp.co.soramitsu.fearless.tests.cooldown.during-success" + ) + let service = makeService( + dataFetchFactory: dataFactory, + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + cooldownTimer: cooldownTimer, + cooldownTimerQueue: cooldownTimerQueue + ) + + service.syncUp() + waitForSignal(firstFetchStarted, description: "first gated fetch") + drain(cooldownTimerQueue) + XCTAssertEqual(cooldownTimer.startCount, 1) + + firstFetchRelease.signal() + waitForSignal( + completionSignal, + description: "success during cooldown" + ) + DispatchQueue.concurrentPerform(iterations: 32) { _ in + service.syncUp() + } + XCTAssertEqual(eventCenter.startCount, 1) + XCTAssertEqual(dataFactory.fetchCallCount, 1) + + cooldownTimer.expire() + service.syncUp() + waitForSignal( + completionSignal, + description: "success after active cooldown" + ) + + XCTAssertEqual(eventCenter.startCount, 2) + XCTAssertEqual(dataFactory.fetchCallCount, 2) + XCTAssertEqual(eventCenter.failureCount, 0) + XCTAssertEqual(eventCenter.completionCount, 2) + } + + func testFailureBeforeTimerStartInvalidatesOnlyFailedReservation() + throws { + let data = try JSONEncoder().encode([ + makeValidChain(generatingAssets: 1, addressPrefix: 42) + ]) + let dataFactory = ScriptedDataOperationFactory( + scripts: [ + { + throw ChainSyncCompatibilityTestError.fetchFailed + }, + { data } + ] + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let failureSignal = DispatchSemaphore(value: 0) + let completionSignal = DispatchSemaphore(value: 0) + eventCenter.onEvent = { event in + if event is ChainSyncDidFail { + failureSignal.signal() + } else if event is ChainSyncDidComplete { + completionSignal.signal() + } + } + let cooldownTimer = ManualCountdownTimer() + let cooldownTimerQueue = DispatchQueue( + label: "jp.co.soramitsu.fearless.tests.cooldown.before-failure" + ) + cooldownTimerQueue.suspend() + var timerQueueIsSuspended = true + defer { + if timerQueueIsSuspended { + cooldownTimerQueue.resume() + } + } + let service = makeService( + dataFetchFactory: dataFactory, + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + cooldownTimer: cooldownTimer, + cooldownTimerQueue: cooldownTimerQueue + ) + + service.syncUp() + waitForSignal( + failureSignal, + description: "failure before timer start" + ) + XCTAssertEqual(cooldownTimer.startCount, 0) + + DispatchQueue.concurrentPerform(iterations: 32) { _ in + service.syncUp() + } + waitForSignal( + completionSignal, + description: "single replacement pipeline" + ) + XCTAssertEqual(eventCenter.startCount, 2) + XCTAssertEqual(dataFactory.fetchCallCount, 2) + + cooldownTimerQueue.resume() + timerQueueIsSuspended = false + drain(cooldownTimerQueue) + + XCTAssertEqual( + cooldownTimer.startCount, + 1, + "the invalidated timer must not start" + ) + XCTAssertEqual(eventCenter.failureCount, 1) + XCTAssertEqual(eventCenter.completionCount, 1) + } + + func testFailureDuringCooldownStopsOldTimerAndAllowsOneReplacement() + throws { + let data = try JSONEncoder().encode([ + makeValidChain(generatingAssets: 1, addressPrefix: 42) + ]) + let firstFetchStarted = DispatchSemaphore(value: 0) + let firstFetchRelease = DispatchSemaphore(value: 0) + let dataFactory = ScriptedDataOperationFactory( + scripts: [ + { + firstFetchStarted.signal() + guard firstFetchRelease.wait( + timeout: .now() + 2 + ) == .success else { + throw ChainSyncCompatibilityTestError.gateTimedOut + } + throw ChainSyncCompatibilityTestError.fetchFailed + }, + { data } + ] + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let failureSignal = DispatchSemaphore(value: 0) + let completionSignal = DispatchSemaphore(value: 0) + eventCenter.onEvent = { event in + if event is ChainSyncDidFail { + failureSignal.signal() + } else if event is ChainSyncDidComplete { + completionSignal.signal() + } + } + let cooldownTimer = ManualCountdownTimer() + let cooldownTimerQueue = DispatchQueue( + label: "jp.co.soramitsu.fearless.tests.cooldown.during-failure" + ) + let service = makeService( + dataFetchFactory: dataFactory, + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + cooldownTimer: cooldownTimer, + cooldownTimerQueue: cooldownTimerQueue + ) + + service.syncUp() + waitForSignal(firstFetchStarted, description: "first gated fetch") + drain(cooldownTimerQueue) + XCTAssertEqual(cooldownTimer.startCount, 1) + + firstFetchRelease.signal() + waitForSignal( + failureSignal, + description: "failure during cooldown" + ) + drain(cooldownTimerQueue) + XCTAssertEqual(cooldownTimer.stopCount, 1) + if case .stopped = cooldownTimer.state { + // Expected. + } else { + XCTFail("Failed reservation timer must be stopped") + } + + DispatchQueue.concurrentPerform(iterations: 32) { _ in + service.syncUp() + } + waitForSignal( + completionSignal, + description: "replacement after active failure" + ) + drain(cooldownTimerQueue) + + XCTAssertEqual(eventCenter.startCount, 2) + XCTAssertEqual(dataFactory.fetchCallCount, 2) + XCTAssertEqual(cooldownTimer.startCount, 2) + XCTAssertEqual(eventCenter.failureCount, 1) + XCTAssertEqual(eventCenter.completionCount, 1) + } + + func testFailureAfterCooldownExpiryAllowsReplacementWithoutOverlap() + throws { + let data = try JSONEncoder().encode([ + makeValidChain(generatingAssets: 1, addressPrefix: 42) + ]) + let firstFetchStarted = DispatchSemaphore(value: 0) + let firstFetchRelease = DispatchSemaphore(value: 0) + let dataFactory = ScriptedDataOperationFactory( + scripts: [ + { + firstFetchStarted.signal() + guard firstFetchRelease.wait( + timeout: .now() + 2 + ) == .success else { + throw ChainSyncCompatibilityTestError.gateTimedOut + } + throw ChainSyncCompatibilityTestError.fetchFailed + }, + { data } + ] + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let failureSignal = DispatchSemaphore(value: 0) + let completionSignal = DispatchSemaphore(value: 0) + eventCenter.onEvent = { event in + if event is ChainSyncDidFail { + failureSignal.signal() + } else if event is ChainSyncDidComplete { + completionSignal.signal() + } + } + let cooldownTimer = ManualCountdownTimer() + let cooldownTimerQueue = DispatchQueue( + label: "jp.co.soramitsu.fearless.tests.cooldown.after-failure" + ) + let service = makeService( + dataFetchFactory: dataFactory, + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + cooldownTimer: cooldownTimer, + cooldownTimerQueue: cooldownTimerQueue + ) + + service.syncUp() + waitForSignal(firstFetchStarted, description: "first gated fetch") + drain(cooldownTimerQueue) + cooldownTimer.expire() + + DispatchQueue.concurrentPerform(iterations: 32) { _ in + service.syncUp() + } + XCTAssertEqual( + eventCenter.startCount, + 1, + "timer expiry must not release an in-flight pipeline" + ) + XCTAssertEqual(dataFactory.fetchCallCount, 1) + + firstFetchRelease.signal() + waitForSignal( + failureSignal, + description: "failure after cooldown expiry" + ) + DispatchQueue.concurrentPerform(iterations: 32) { _ in + service.syncUp() + } + waitForSignal( + completionSignal, + description: "replacement after expired failure" + ) + + XCTAssertEqual(eventCenter.startCount, 2) + XCTAssertEqual(dataFactory.fetchCallCount, 2) + XCTAssertEqual(eventCenter.failureCount, 1) + XCTAssertEqual(eventCenter.completionCount, 1) + } + + func testStaleStopCallbackCannotClearNewerCooldown() throws { + let data = try JSONEncoder().encode([ + makeValidChain(generatingAssets: 1, addressPrefix: 42) + ]) + let dataFactory = ScriptedDataOperationFactory( + scripts: [ + { data }, + { data }, + { data } + ] + ) + let repository = ScriptedChainRepository() + let eventCenter = RecordingChainSyncEventCenter() + let completionSignal = DispatchSemaphore(value: 0) + eventCenter.onEvent = { event in + if event is ChainSyncDidComplete { + completionSignal.signal() + } + } + let cooldownTimer = ManualCountdownTimer() + let cooldownTimerQueue = DispatchQueue( + label: "jp.co.soramitsu.fearless.tests.cooldown.stale-stop" + ) + let service = makeService( + dataFetchFactory: dataFactory, + repository: AnyDataProviderRepository(repository), + eventCenter: eventCenter, + cooldownTimer: cooldownTimer, + cooldownTimerQueue: cooldownTimerQueue + ) + + service.syncUp() + waitForSignal(completionSignal, description: "first success") + drain(cooldownTimerQueue) + cooldownTimer.expire() + + service.syncUp() + waitForSignal(completionSignal, description: "second success") + drain(cooldownTimerQueue) + XCTAssertEqual(cooldownTimer.startCount, 2) + + cooldownTimer.emitStaleStopWhileRunning() + DispatchQueue.concurrentPerform(iterations: 32) { _ in + service.syncUp() + } + XCTAssertEqual( + eventCenter.startCount, + 2, + "a stale callback must not clear the current cooldown" + ) + XCTAssertEqual(dataFactory.fetchCallCount, 2) + + cooldownTimer.expire() + DispatchQueue.concurrentPerform(iterations: 32) { _ in + service.syncUp() + } + waitForSignal( + completionSignal, + description: "third success after real expiry" + ) + + XCTAssertEqual(eventCenter.startCount, 3) + XCTAssertEqual(dataFactory.fetchCallCount, 3) + XCTAssertEqual(eventCenter.failureCount, 0) + XCTAssertEqual(eventCenter.completionCount, 3) + } + + func testSanitizerRejectsDuplicateRemoteIdentifiers() { + let chain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + + XCTAssertThrowsError( + try ChainSyncService.sanitizingRemoteChains([chain, chain]) + ) { error in + guard + let syncError = error as? ChainSyncServiceError, + case let .duplicateRemoteChainIdentifier(identifier) = + syncError + else { + return XCTFail("Unexpected error: \(error)") + } + + XCTAssertEqual(identifier, chain.chainId) + } + } + + func testSanitizerRejectsBlankNoncanonicalAndReservedIdentifiers() { + let chain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let invalidIdentifiers = [ + "", + " \n", + " leading-space", + "trailing-space ", + ChainModelMapper.quarantinedChainIdentifierPrefix + "remote" + ] + + for identifier in invalidIdentifiers { + let invalidChain = copy( + chain, + chainId: identifier + ) + + XCTAssertThrowsError( + try ChainSyncService.sanitizingRemoteChains( + [invalidChain] + ), + "identifier \(identifier.debugDescription) must fail" + ) + } + } + + func testSanitizerRejectsBlankRemoteName() { + let chain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let invalidChain = copy(chain, name: " \n\t") + + XCTAssertThrowsError( + try ChainSyncService.sanitizingRemoteChains([invalidChain]) + ) + } + + func testSanitizerAllowsDisabledChainWithoutNodes() throws { + let chain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let disabledChain = copy( + chain, + disabled: true, + nodes: [] + ) + + let sanitized = try ChainSyncService.sanitizingRemoteChains( + [disabledChain] + ) + + XCTAssertEqual(sanitized.count, 1) + XCTAssertTrue(try XCTUnwrap(sanitized.first).disabled) + XCTAssertTrue(try XCTUnwrap(sanitized.first).nodes.isEmpty) + } + + func testSanitizerDeterministicallyDeduplicatesNodeCredentialMetadata() + throws { + let chain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let url = try XCTUnwrap(URL(string: "wss://same-node.example")) + let expectedAPIKey = ChainNodeModel.ApiKey( + queryName: "a-query", + keyName: "a-key" + ) + let nodes: Set = [ + ChainNodeModel( + url: url, + name: "Same Node", + apikey: .init( + queryName: "z-query", + keyName: "z-key" + ) + ), + ChainNodeModel( + url: url, + name: "Same Node", + apikey: expectedAPIKey + ) + ] + + for _ in 0 ..< 10 { + let sanitized = try ChainSyncService + .sanitizingRemoteChains([ + copy(chain, nodes: nodes) + ]) + let node = try XCTUnwrap( + sanitized.first?.nodes.first + ) + + XCTAssertEqual(node.apikey, expectedAPIKey) + } + } + + func testSanitizerRejectsEthereumChainWithOnlyIncompatibleSchemes() + throws { + let baseChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let insecureNodes: Set = [ + ChainNodeModel( + url: try XCTUnwrap( + URL(string: "http://rpc.example") + ), + name: "HTTP", + apikey: nil + ), + ChainNodeModel( + url: try XCTUnwrap(URL(string: "ws://rpc.example")), + name: "WS", + apikey: nil + ) + ] + let ethereumChain = copy( + baseChain, + nodes: insecureNodes, + options: [.ethereum] + ) + + XCTAssertThrowsError( + try ChainSyncService.sanitizingRemoteChains( + [ethereumChain] + ) + ) + } + + func testSanitizerKeepsOnlyRuntimeCompatibleEthereumNodes() throws { + let baseChain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let httpsNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "https://rpc.example")), + name: "HTTPS", + apikey: nil + ) + let httpNode = ChainNodeModel( + url: try XCTUnwrap(URL(string: "http://rpc.example")), + name: "HTTP", + apikey: nil + ) + let ethereumChain = copy( + baseChain, + nodes: [httpsNode, httpNode], + options: [.ethereum] + ) + + let sanitized = try ChainSyncService.sanitizingRemoteChains( + [ethereumChain] + ) + + XCTAssertEqual( + try XCTUnwrap(sanitized.first).nodes, + Set([httpsNode]) + ) + } + + func testPreservingPreferencesDropsRuntimeIncompatibleCustomSelection() + throws { + let substrateRemote = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let incompatibleSubstrateNode = ChainNodeModel( + url: try XCTUnwrap( + URL(string: "https://not-a-websocket.example") + ), + name: "Wrong protocol", + apikey: nil + ) + let substrateLocal = substrateRemote + .replacingCustomNodes([incompatibleSubstrateNode]) + .replacingSelectedNode(incompatibleSubstrateNode) + + let merged = ChainSyncService.preservingLocalNodePreferences( + remoteChains: [substrateRemote], + localChains: [substrateLocal] + ) + + XCTAssertEqual( + try XCTUnwrap(merged.first).customNodes, + Set() + ) + XCTAssertNil(try XCTUnwrap(merged.first).selectedNode) + } + + func testSanitizerStripsRemotePreferencesForBrandNewChain() throws { + let chain = makeValidChain( + generatingAssets: 1, + addressPrefix: 42 + ) + let injectedNode = ChainNodeModel( + url: try XCTUnwrap( + URL(string: "wss://remote-injection.example") + ), + name: "Injected", + apikey: nil + ) + let injectedChain = chain + .replacingCustomNodes([injectedNode]) + .replacingSelectedNode(injectedNode) + + let sanitized = try ChainSyncService.sanitizingRemoteChains( + [injectedChain] + ) + + XCTAssertEqual( + try XCTUnwrap(sanitized.first).customNodes, + Set() + ) + XCTAssertNil(try XCTUnwrap(sanitized.first).selectedNode) + } + + private func copy( + _ chain: ChainModel, + chainId: String? = nil, + name: String? = nil, + disabled: Bool? = nil, + nodes: Set? = nil, + options: [ChainOptions]? = nil + ) -> ChainModel { + ChainModel( + rank: chain.rank, + disabled: disabled ?? chain.disabled, + chainId: chainId ?? chain.chainId, + parentId: chain.parentId, + paraId: chain.paraId, + name: name ?? chain.name, + assets: chain.assets, + xcm: chain.xcm, + nodes: nodes ?? chain.nodes, + addressPrefix: chain.addressPrefix, + types: chain.types, + icon: chain.icon, + options: options ?? chain.options, + externalApi: chain.externalApi, + selectedNode: nil, + customNodes: nil, + iosMinAppVersion: chain.iosMinAppVersion, + identityChain: chain.identityChain + ) + } + + private func makeValidChain( + generatingAssets count: Int, + addressPrefix: UInt16 + ) -> ChainModel { + let chain = ChainModelGenerator.generateChain( + generatingAssets: count, + addressPrefix: addressPrefix + ) + let node = ChainNodeModel( + url: URL( + string: "wss://node.example/\(chain.chainId)" + )!, + name: "Valid substrate node", + apikey: nil + ) + + return chain.replacingNodes([node]) + } + + private func makeService( + data: Data, + repository: AnyDataProviderRepository, + eventCenter: EventCenterProtocol, + malformedChainCleanupOperationFactory: (() -> BaseOperation)? = nil + ) -> ChainSyncService { + makeService( + dataFetchFactory: StaticDataOperationFactory(data: data), + repository: repository, + eventCenter: eventCenter, + malformedChainCleanupOperationFactory: + malformedChainCleanupOperationFactory + ) + } + + private func makeService( + dataFetchFactory: DataOperationFactoryProtocol, + repository: AnyDataProviderRepository, + eventCenter: EventCenterProtocol, + malformedChainCleanupOperationFactory: (() -> BaseOperation)? = nil, + cooldownTimer: CountdownTimerProtocol = CountdownTimer( + notificationInterval: 300 + ), + cooldownTimerQueue: DispatchQueue = .main + ) -> ChainSyncService { + ChainSyncService( + chainsUrl: URL(string: "https://chains.example/chains.json")!, + dataFetchFactory: dataFetchFactory, + repository: repository, + eventCenter: eventCenter, + operationQueue: OperationQueue(), + retryStrategy: NeverReconnectStrategy(), + applicationHandler: ApplicationHandler(), + malformedChainCleanupOperationFactory: + malformedChainCleanupOperationFactory, + cooldownTimer: cooldownTimer, + cooldownTimerQueue: cooldownTimerQueue + ) + } + + private func waitForSignal( + _ semaphore: DispatchSemaphore, + description: String, + timeout: TimeInterval = 2, + file: StaticString = #filePath, + line: UInt = #line + ) { + guard semaphore.wait( + timeout: .now() + timeout + ) == .success else { + return XCTFail( + "Timed out waiting for \(description)", + file: file, + line: line + ) + } + } + + private func drain( + _ queue: DispatchQueue, + file: StaticString = #filePath, + line: UInt = #line + ) { + let drained = DispatchSemaphore(value: 0) + queue.async { + drained.signal() + } + waitForSignal( + drained, + description: "serial cooldown timer queue", + file: file, + line: line + ) + } +} + +private enum ChainSyncCompatibilityTestError: Error { + case fetchFailed + case saveFailed + case cleanupFailed + case gateTimedOut + case unexpectedFetch +} + +private struct StaticDataOperationFactory: DataOperationFactoryProtocol { + let data: Data + + func fetchData(from _: URL) -> BaseOperation { + ClosureOperation { data } + } +} + +private final class CountingDataOperationFactory: + DataOperationFactoryProtocol { + private let lock = NSLock() + private let data: Data + private let firstFetchGate: DispatchSemaphore? + private let onFirstFetchStart: (() -> Void)? + private var fetchCalls = 0 + + var fetchCallCount: Int { + lock.with { fetchCalls } + } + + init( + data: Data, + firstFetchGate: DispatchSemaphore? = nil, + onFirstFetchStart: (() -> Void)? = nil + ) { + self.data = data + self.firstFetchGate = firstFetchGate + self.onFirstFetchStart = onFirstFetchStart + } + + func fetchData(from _: URL) -> BaseOperation { + let callIndex = lock.with { + fetchCalls += 1 + return fetchCalls + } + + return ClosureOperation { + if callIndex == 1, let firstFetchGate = self.firstFetchGate { + self.onFirstFetchStart?() + firstFetchGate.wait() + } + + return self.data + } + } +} + +private final class ScriptedDataOperationFactory: + DataOperationFactoryProtocol { + typealias FetchScript = () throws -> Data + + private let lock = NSLock() + private let scripts: [FetchScript] + private var fetchCalls = 0 + + var fetchCallCount: Int { + lock.with { fetchCalls } + } + + init(scripts: [FetchScript]) { + self.scripts = scripts + } + + func fetchData(from _: URL) -> BaseOperation { + let script: FetchScript = lock.with { + let index = fetchCalls + fetchCalls += 1 + + guard scripts.indices.contains(index) else { + return { + throw ChainSyncCompatibilityTestError.unexpectedFetch + } + } + + return scripts[index] + } + + return ClosureOperation { + try script() + } + } +} + +private final class ManualCountdownTimer: CountdownTimerProtocol { + weak var delegate: CountdownTimerDelegate? + + private let lock = NSLock() + private var currentState: CountdownTimerState = .stopped + private var currentRemainedInterval: TimeInterval = 0 + private var starts = 0 + private var stops = 0 + + let notificationInterval: TimeInterval + + var state: CountdownTimerState { + lock.with { currentState } + } + + var remainedInterval: TimeInterval { + lock.with { currentRemainedInterval } + } + + var startCount: Int { + lock.with { starts } + } + + var stopCount: Int { + lock.with { stops } + } + + init(notificationInterval: TimeInterval = 300) { + self.notificationInterval = notificationInterval + } + + func start( + with interval: TimeInterval, + runLoop _: RunLoop, + mode _: RunLoop.Mode + ) { + stop() + + lock.with { + currentState = .inProgress + currentRemainedInterval = interval + starts += 1 + } + delegate?.didStart(with: interval) + } + + func stop() { + let stoppedInterval: TimeInterval? = lock.with { + switch currentState { + case .inProgress, .paused: + let interval = currentRemainedInterval + currentState = .stopped + currentRemainedInterval = 0 + stops += 1 + return interval + case .stopped: + return nil + } + } + + if let stoppedInterval { + delegate?.didStop(with: stoppedInterval) + } + } + + func expire() { + let shouldNotify = lock.with { + guard case .inProgress = currentState else { + return false + } + + currentState = .stopped + currentRemainedInterval = 0 + stops += 1 + return true + } + + if shouldNotify { + delegate?.didStop(with: 0) + } + } + + func emitStaleStopWhileRunning() { + let interval = remainedInterval + delegate?.didStop(with: interval) + } +} + +private final class LockedCounter { + private let lock = NSLock() + private var count = 0 + + var value: Int { + lock.with { count } + } + + func increment() -> Int { + lock.with { + count += 1 + return count + } + } +} + +private struct NeverReconnectStrategy: ReconnectionStrategyProtocol { + func reconnectAfter(attempt _: Int) -> TimeInterval? { + nil + } +} + +private final class RecordingChainSyncEventCenter: EventCenterProtocol { + private let lock = NSLock() + private var failures: [Error] = [] + private var completions = 0 + private var starts = 0 + + var onEvent: ((EventProtocol) -> Void)? + + var failureCount: Int { + lock.with { failures.count } + } + + var completionCount: Int { + lock.with { completions } + } + + var startCount: Int { + lock.with { starts } + } + + var lastFailure: Error? { + lock.with { failures.last } + } + + func notify(with event: EventProtocol) { + lock.with { + if event is ChainSyncDidStart { + starts += 1 + } else if let failure = event as? ChainSyncDidFail { + failures.append(failure.error) + } else if event is ChainSyncDidComplete { + completions += 1 + } + } + + onEvent?(event) + } + + func add(observer _: EventVisitorProtocol, dispatchIn _: DispatchQueue?) {} + + func remove(observer _: EventVisitorProtocol) {} +} + +private final class SaveFailingChainRepository: DataProviderRepositoryProtocol { + typealias Model = ChainModel + + private let lock = NSLock() + private let error: Error + private var saves = 0 + + var saveCallCount: Int { + lock.with { saves } + } + + init(error: Error) { + self.error = error + } + + func fetchOperation( + by _: @escaping () throws -> [String], + options _: RepositoryFetchOptions + ) -> BaseOperation<[ChainModel]> { + ClosureOperation { [] } + } + + func fetchOperation( + by _: @escaping () throws -> String, + options _: RepositoryFetchOptions + ) -> BaseOperation { + ClosureOperation { nil } + } + + func fetchAllOperation( + with _: RepositoryFetchOptions + ) -> BaseOperation<[ChainModel]> { + ClosureOperation { [] } + } + + func fetchOperation( + by _: RepositorySliceRequest, + options _: RepositoryFetchOptions + ) -> BaseOperation<[ChainModel]> { + ClosureOperation { [] } + } + + func saveOperation( + _: @escaping () throws -> [ChainModel], + _: @escaping () throws -> [String] + ) -> BaseOperation { + lock.with { + saves += 1 + } + + return ClosureOperation { [error] in + throw error + } + } + + func saveBatchOperation( + _ updateModelsBlock: @escaping () throws -> [ChainModel], + _ deleteIdsBlock: @escaping () throws -> [String] + ) -> BaseOperation { + saveOperation(updateModelsBlock, deleteIdsBlock) + } + + func replaceOperation( + _: @escaping () throws -> [ChainModel] + ) -> BaseOperation { + ClosureOperation { [error] in + throw error + } + } + + func fetchCountOperation() -> BaseOperation { + ClosureOperation { 0 } + } + + func deleteAllOperation() -> BaseOperation { + ClosureOperation { () } + } +} + +private final class ScriptedChainRepository: DataProviderRepositoryProtocol { + typealias Model = ChainModel + + private let lock = NSLock() + private let fetchAllError: Error? + private let localChains: [ChainModel] + private var fetchAllCalls = 0 + private var replaceCalls = 0 + private var saveCalls = 0 + private var saved: [ChainModel] = [] + private var deleted: [String] = [] + + var replaceCallCount: Int { + lock.with { replaceCalls } + } + + var fetchAllCallCount: Int { + lock.with { fetchAllCalls } + } + + var saveCallCount: Int { + lock.with { saveCalls } + } + + var savedModels: [ChainModel] { + lock.with { saved } + } + + var deletedIdentifiers: [String] { + lock.with { deleted } + } + + init( + fetchAllError: Error? = nil, + localChains: [ChainModel] = [] + ) { + self.fetchAllError = fetchAllError + self.localChains = localChains + } + + func fetchOperation( + by _: @escaping () throws -> [String], + options _: RepositoryFetchOptions + ) -> BaseOperation<[ChainModel]> { + ClosureOperation { [] } + } + + func fetchOperation( + by _: @escaping () throws -> String, + options _: RepositoryFetchOptions + ) -> BaseOperation { + ClosureOperation { nil } + } + + func fetchAllOperation( + with _: RepositoryFetchOptions + ) -> BaseOperation<[ChainModel]> { + lock.with { + fetchAllCalls += 1 + } + + return ClosureOperation { [fetchAllError] in + if let fetchAllError { + throw fetchAllError + } + + return self.localChains + } + } + + func fetchOperation( + by _: RepositorySliceRequest, + options _: RepositoryFetchOptions + ) -> BaseOperation<[ChainModel]> { + ClosureOperation { [] } + } + + func saveOperation( + _ updateModelsBlock: @escaping () throws -> [ChainModel], + _ deleteIdsBlock: @escaping () throws -> [String] + ) -> BaseOperation { + ClosureOperation { [weak self] in + guard let self else { + throw BaseOperationError.parentOperationCancelled + } + + let models = try updateModelsBlock() + let identifiers = try deleteIdsBlock() + lock.with { + self.saveCalls += 1 + self.saved = models + self.deleted = identifiers + } + } + } + + func saveBatchOperation( + _: @escaping () throws -> [ChainModel], + _: @escaping () throws -> [String] + ) -> BaseOperation { + ClosureOperation { () } + } + + func replaceOperation( + _ modelsBlock: @escaping () throws -> [ChainModel] + ) -> BaseOperation { + ClosureOperation { [weak self] in + guard let self else { + throw BaseOperationError.parentOperationCancelled + } + + _ = try modelsBlock() + lock.with { + self.replaceCalls += 1 + } + } + } + + func fetchCountOperation() -> BaseOperation { + ClosureOperation { 0 } + } + + func deleteAllOperation() -> BaseOperation { + ClosureOperation { () } + } } diff --git a/fearlessTests/Common/Services/ChainRegistry/MockConnection.swift b/fearlessTests/Common/Services/ChainRegistry/MockConnection.swift index 8fb1a4308c..3a7beb8793 100644 --- a/fearlessTests/Common/Services/ChainRegistry/MockConnection.swift +++ b/fearlessTests/Common/Services/ChainRegistry/MockConnection.swift @@ -7,6 +7,14 @@ final class MockConnection: JSONRPCEngine { var connectionName: String? var url: URL? var pendingEngineRequests: [JSONRPCRequest] { [] } + private let disconnectLock = NSLock() + private var disconnectCalls = 0 + + var disconnectCallCount: Int { + disconnectLock.lock() + defer { disconnectLock.unlock() } + return disconnectCalls + } private var nextId: UInt16 = 1 private struct AnySubscription { @@ -60,7 +68,11 @@ final class MockConnection: JSONRPCEngine { func reconnect(url: URL) { self.url = url } func connectIfNeeded() {} - func disconnectIfNeeded() {} + func disconnectIfNeeded() { + disconnectLock.lock() + disconnectCalls += 1 + disconnectLock.unlock() + } func unsubsribe(_ identifier: UInt16) throws {} // MARK: - Test helpers diff --git a/fearlessTests/Common/Storage/ChainModelMapperTests.swift b/fearlessTests/Common/Storage/ChainModelMapperTests.swift index 7a6334890a..e9398aa1fe 100644 --- a/fearlessTests/Common/Storage/ChainModelMapperTests.swift +++ b/fearlessTests/Common/Storage/ChainModelMapperTests.swift @@ -1,9 +1,78 @@ import XCTest @testable import fearless +import CoreData import RobinHood import SSFModels final class ChainModelMapperTests: XCTestCase { + func testStartupWrapperConvertsMandatoryGetterExceptionToSanitizedSwiftError() { + let entityDescription = makeEntityDescription( + managedObjectClass: CDChain.self, + properties: [] + ) + let entity = CDChain( + entity: entityDescription, + insertInto: nil + ) + let startupMapper: AnyCoreDataMapper = + AnyCoreDataMapper(ChainModelMapper()) + + XCTAssertThrowsError( + try startupMapper.transform(entity: entity) + ) { error in + XCTAssertEqual( + error as? SafeTransformableValueReaderError, + .objectiveCException + ) + } + } + + func testThrowingNodeRelationshipFailsClosedAsSwiftError() throws { + let nodeDescription = makeEntityDescription( + managedObjectClass: CDChainNode.self, + properties: [] + ) + let nodes = NSRelationshipDescription() + nodes.name = "nodes" + nodes.destinationEntity = nodeDescription + nodes.minCount = 0 + nodes.maxCount = 0 + nodes.isOptional = true + nodes.deleteRule = .nullifyDeleteRule + + let chainDescription = makeEntityDescription( + managedObjectClass: CDChain.self, + properties: [ + makeAttribute(name: "chainId", type: .stringAttributeType), + makeAttribute(name: "name", type: .stringAttributeType), + nodes + ] + ) + let context = try makeContext( + entities: [chainDescription, nodeDescription] + ) + let entity = CDChain( + entity: chainDescription, + insertInto: context + ) + entity.setValue("throwing-node-chain", forKey: "chainId") + entity.setValue("Throwing node chain", forKey: "name") + let throwingNode = CDChainNode( + entity: nodeDescription, + insertInto: context + ) + entity.setValue(NSSet(object: throwingNode), forKey: "nodes") + + XCTAssertThrowsError( + try ChainModelMapper().transform(entity: entity) + ) { error in + XCTAssertEqual( + error as? SafeTransformableValueReaderError, + .objectiveCException + ) + } + } + func testSaveAndFetchPreservesParaIdAndIdentityChain() throws { let facade = SubstrateStorageTestFacade() let repository: CoreDataRepository = facade.createRepository( @@ -48,4 +117,1731 @@ final class ChainModelMapperTests: XCTestCase { XCTAssertEqual(fetched.paraId, chain.paraId) XCTAssertEqual(fetched.identityChain, chain.identityChain) } + + func testTransformQuarantinesChainWithoutIdentifier() throws { + let context = try createContext() + let entity = CDChain(context: context) + entity.name = "Malformed chain" + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertTrue( + chain.chainId.hasPrefix( + ChainModelMapper.quarantinedChainIdentifierPrefix + ) + ) + XCTAssertEqual(chain.name, ChainModelMapper.quarantinedChainName) + XCTAssertTrue(chain.disabled) + XCTAssertTrue(chain.nodes.isEmpty) + XCTAssertTrue(chain.assets.isEmpty) + } + + func testTransformQuarantinesNoncanonicalIdentifierUntilCleanup() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + entity.chainId = " valid-chain " + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertTrue( + chain.chainId.hasPrefix( + ChainModelMapper.quarantinedChainIdentifierPrefix + ) + ) + XCTAssertTrue(chain.disabled) + } + + func testTransformQuarantinesNameButKeepsIdentifierAndPreferences() throws { + let context = try createContext() + let entity = CDChain(context: context) + entity.chainId = "malformed-chain" + let customNode = CDChainNode(context: context) + customNode.url = try XCTUnwrap(URL(string: "wss://custom.example")) + customNode.name = "Custom" + entity.customNodes = NSSet(object: customNode) + entity.selectedNode = customNode + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertEqual(chain.chainId, "malformed-chain") + XCTAssertEqual(chain.name, ChainModelMapper.quarantinedChainName) + XCTAssertTrue(chain.disabled) + XCTAssertEqual(chain.customNodes, Set([try makeNode(from: customNode)])) + XCTAssertEqual(chain.selectedNode, try makeNode(from: customNode)) + } + + func testTransformSkipsDefaultNodeWithoutURL() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let node = CDChainNode(context: context) + node.name = "Malformed node" + entity.nodes = NSSet(object: node) + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertTrue(chain.nodes.isEmpty) + } + + func testTransformSkipsSelectedNodeWithoutName() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let node = CDChainNode(context: context) + node.url = try XCTUnwrap(URL(string: "wss://malformed.example")) + entity.selectedNode = node + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertNil(chain.selectedNode) + } + + func testTransformSkipsSelectedNodeWithUnusableURL() throws { + let context = try createContext() + let unusableURLs = [ + try XCTUnwrap(URL(string: "http:relative")), + try XCTUnwrap(URL(string: "relative/node")), + try XCTUnwrap(URL(string: "file:///tmp/not-a-node")), + try XCTUnwrap(URL(string: "data:text/plain,not-a-node")) + ] + + for (index, unusableURL) in unusableURLs.enumerated() { + let entity = makeValidChainEntity(in: context) + entity.chainId = "invalid-node-\(index)" + let node = CDChainNode(context: context) + node.url = unusableURL + node.name = "Unusable" + entity.selectedNode = node + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertNil(chain.selectedNode, "\(unusableURL) must be ignored") + } + } + + func testTransformAcceptsSubstrateWebSocketNodeURLs() throws { + let context = try createContext() + let supportedURLs = [ + try XCTUnwrap(URL(string: "wss://node.example")), + try XCTUnwrap(URL(string: "ws://127.0.0.1:9944")) + ] + + for (index, supportedURL) in supportedURLs.enumerated() { + let entity = makeValidChainEntity(in: context) + entity.chainId = "valid-node-\(index)" + let node = CDChainNode(context: context) + node.url = supportedURL + node.name = "Supported" + entity.nodes = NSSet(object: node) + entity.selectedNode = node + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertEqual(chain.selectedNode?.url, supportedURL) + XCTAssertFalse(chain.disabled) + } + } + + func testTransformKeepsCompatibleCustomNodeAsOnlyRuntimeEndpoint() + throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let customNode = CDChainNode(context: context) + customNode.url = try XCTUnwrap( + URL(string: "wss://custom-only.example") + ) + customNode.name = "Custom only" + entity.customNodes = NSSet(object: customNode) + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertTrue(chain.nodes.isEmpty) + XCTAssertNil(chain.selectedNode) + XCTAssertEqual( + chain.customNodes, + Set([try makeNode(from: customNode)]) + ) + XCTAssertFalse(chain.disabled) + } + + func testTransformDisablesChainWithOnlyIncompatibleCustomNode() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let customNode = CDChainNode(context: context) + customNode.url = try XCTUnwrap( + URL(string: "https://not-a-substrate-websocket.example") + ) + customNode.name = "Wrong runtime protocol" + entity.customNodes = NSSet(object: customNode) + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertTrue(chain.nodes.isEmpty) + XCTAssertNil(chain.selectedNode) + XCTAssertEqual(chain.customNodes, Set()) + XCTAssertTrue(chain.disabled) + } + + func testTransformRejectsHTTPNodesForSubstrateRuntime() throws { + let context = try createContext() + let incompatibleURLs = [ + try XCTUnwrap(URL(string: "https://node.example")), + try XCTUnwrap(URL(string: "http://localhost:8080")) + ] + + for (index, incompatibleURL) in incompatibleURLs.enumerated() { + let entity = makeValidChainEntity(in: context) + entity.chainId = "incompatible-substrate-\(index)" + let node = CDChainNode(context: context) + node.url = incompatibleURL + node.name = "Wrong runtime protocol" + entity.nodes = NSSet(object: node) + entity.selectedNode = node + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertTrue(chain.nodes.isEmpty) + XCTAssertNil(chain.selectedNode) + XCTAssertTrue(chain.disabled) + } + } + + func testTransformAcceptsOnlySecureEthereumRuntimeSchemes() throws { + let context = try createContext() + let candidates: [(String, Bool)] = [ + ("https://rpc.example", true), + ("wss://rpc.example", true), + ("http://rpc.example", false), + ("ws://rpc.example", false) + ] + + for (index, candidate) in candidates.enumerated() { + let entity = makeValidChainEntity(in: context) + entity.chainId = "ethereum-runtime-\(index)" + entity.options = NSArray(object: ChainOptions.ethereum.rawValue) + let node = CDChainNode(context: context) + node.url = try XCTUnwrap(URL(string: candidate.0)) + node.name = "Ethereum RPC" + entity.nodes = NSSet(object: node) + entity.selectedNode = node + + let chain = try ChainModelMapper().transform(entity: entity) + + if candidate.1 { + XCTAssertEqual(chain.selectedNode?.url, node.url) + XCTAssertFalse(chain.disabled) + } else { + XCTAssertTrue(chain.nodes.isEmpty) + XCTAssertNil(chain.selectedNode) + XCTAssertTrue(chain.disabled) + } + } + } + + func testTransformAppliesStrictTonServerShape() throws { + let context = try createContext() + let candidates: [(String, Bool)] = [ + ("https://tonapi.io", true), + ("https://tonapi.io/", true), + ("https://tonapi.io/path", false), + ("https://user@tonapi.io", false), + ("http://tonapi.io", false), + ("wss://tonapi.io", false) + ] + + for (index, candidate) in candidates.enumerated() { + let entity = makeValidChainEntity(in: context) + entity.chainId = "ton-runtime-\(index)" + entity.name = "TON Mainnet" + let node = CDChainNode(context: context) + node.url = try XCTUnwrap(URL(string: candidate.0)) + node.name = "TON API" + entity.nodes = NSSet(object: node) + entity.selectedNode = node + + let chain = try ChainModelMapper().transform(entity: entity) + + if candidate.1 { + XCTAssertEqual(chain.selectedNode?.url, node.url) + XCTAssertFalse(chain.disabled) + } else { + XCTAssertTrue(chain.nodes.isEmpty) + XCTAssertNil(chain.selectedNode) + XCTAssertTrue(chain.disabled) + } + } + } + + func testTransformKeepsValidNodesWhileSkippingMalformedOnes() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let validNode = CDChainNode(context: context) + validNode.url = try XCTUnwrap(URL(string: "wss://valid.example")) + validNode.name = "Valid" + let malformedNode = CDChainNode(context: context) + malformedNode.name = "Malformed" + entity.nodes = NSSet(array: [malformedNode, validNode]) + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertEqual(chain.nodes.count, 1) + XCTAssertEqual(chain.nodes.first?.url, validNode.url) + } + + func testPopulateRoundTripPreservesValidStandaloneSelectedNode() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let defaultNode = ChainNodeModel( + url: try XCTUnwrap( + URL(string: "wss://default-round-trip.example") + ), + name: "Default", + apikey: nil + ) + let standaloneSelection = ChainNodeModel( + url: try XCTUnwrap( + URL(string: "wss://standalone-selection.example") + ), + name: "Standalone selection", + apikey: nil + ) + let model = ChainModel( + rank: 1, + disabled: false, + chainId: "standalone-selection-chain", + paraId: nil, + name: "Standalone selection chain", + xcm: nil, + nodes: [defaultNode], + addressPrefix: 42, + icon: nil, + selectedNode: standaloneSelection, + iosMinAppVersion: nil, + identityChain: nil + ) + + try ChainModelMapper().populate( + entity: entity, + from: model, + using: context + ) + + let selectedEntity = try XCTUnwrap(entity.selectedNode) + XCTAssertFalse( + (entity.nodes as? Set)? + .contains(selectedEntity) ?? true + ) + XCTAssertFalse( + (entity.customNodes as? Set)? + .contains(selectedEntity) ?? false + ) + + let transformed = try ChainModelMapper().transform(entity: entity) + + XCTAssertEqual(transformed.nodes, Set([defaultNode])) + XCTAssertEqual(transformed.selectedNode, standaloneSelection) + XCTAssertFalse(transformed.disabled) + } + + func testTransformDropsUnsupportedStandaloneSelectionButKeepsHealthyChain() + throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let defaultNode = CDChainNode(context: context) + defaultNode.url = try XCTUnwrap( + URL(string: "wss://healthy-default.example") + ) + defaultNode.name = "Healthy default" + entity.nodes = NSSet(object: defaultNode) + + let unsupportedSelection = CDChainNode(context: context) + unsupportedSelection.url = try XCTUnwrap( + URL(string: "https://not-a-substrate-websocket.example") + ) + unsupportedSelection.name = "Unsupported standalone selection" + entity.selectedNode = unsupportedSelection + + let transformed = try ChainModelMapper().transform(entity: entity) + + XCTAssertEqual(transformed.nodes.count, 1) + XCTAssertEqual(transformed.nodes.first?.url, defaultNode.url) + XCTAssertNil(transformed.selectedNode) + XCTAssertFalse(transformed.disabled) + } + + func testTransformSkipsMalformedCachedAsset() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let malformedAsset = CDAsset(context: context) + malformedAsset.name = "Missing identifier" + entity.assets = NSSet(object: malformedAsset) + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertTrue(chain.assets.isEmpty) + } + + func testTransformIgnoresRelationshipWithOnlyMalformedPrices() + throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let assetEntity = CDAsset(context: context) + let expectedAsset = ChainModelGenerator.generateAssetWithId( + "valid-asset", + symbol: "VAL", + assetPresicion: 12 + ) + try AssetModelMapper().populate( + entity: assetEntity, + from: expectedAsset, + using: context + ) + let malformedPrice = CDPriceData(context: context) + assetEntity.setValue( + NSSet(object: malformedPrice), + forKey: "priceData" + ) + entity.assets = NSSet(object: assetEntity) + + let chain = try ChainModelMapper().transform(entity: entity) + + XCTAssertEqual(chain.assets, Set([expectedAsset])) + } + + func testCachedPriceExtractionRejectsUnexpectedEntityBeforeReadingUndefinedKeys() { + let entity = NSEntityDescription() + entity.name = "UnexpectedCachedPrice" + entity.managedObjectClassName = NSStringFromClass( + NSManagedObject.self + ) + let model = NSManagedObjectModel() + model.entities = [entity] + let unexpectedRow = NSManagedObject( + entity: entity, + insertInto: nil + ) + + XCTAssertNil( + ChainModelMapper().createPriceData(from: unexpectedRow) + ) + } + + func testCachedPriceExtractionSkipsRowWhenAttributeReadRaisesException() { + let fixture = makeCachedPriceEntity( + managedObjectClass: ExceptionRaisingCachedPrice.self, + priceType: .stringAttributeType + ) + let row = ExceptionRaisingCachedPrice( + entity: fixture.entity, + insertInto: nil + ) + row.setValue("usd", forKey: "currencyId") + row.setValue("dot", forKey: "priceId") + + XCTAssertNil(ChainModelMapper().createPriceData(from: row)) + } + + func testCachedPriceExtractionPreservesLegacyDecimalWithoutOptionalFields() throws { + let fixture = makeCachedPriceEntity( + managedObjectClass: NSManagedObject.self, + priceType: .decimalAttributeType + ) + let row = NSManagedObject( + entity: fixture.entity, + insertInto: nil + ) + row.setValue("usd", forKey: "currencyId") + row.setValue("dot", forKey: "priceId") + row.setValue( + NSDecimalNumber(string: "12.5"), + forKey: "price" + ) + + let priceData = try XCTUnwrap( + ChainModelMapper().createPriceData(from: row) + ) + + XCTAssertEqual(priceData.currencyId, "usd") + XCTAssertEqual(priceData.priceId, "dot") + XCTAssertEqual(priceData.price, "12.5") + XCTAssertNil(priceData.fiatDayChange) + XCTAssertNil(priceData.coingeckoPriceId) + } + + func testTransformUsesSingleValidUnmatchedCachedPrice() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let asset = makeAssetWithUnmatchedPricing(identifier: "single-price") + let assetEntity = CDAsset(context: context) + try AssetModelMapper().populate( + entity: assetEntity, + from: asset, + using: context + ) + let cachedPrice = makeCachedPrice( + currencyId: "unmatched-currency", + priceId: "unmatched-price", + price: "7.25", + fiatDayChange: "-0.5", + in: context + ) + assetEntity.setValue( + NSSet(object: cachedPrice), + forKey: "priceData" + ) + entity.assets = NSSet(object: assetEntity) + + let chain = try ChainModelMapper().transform(entity: entity) + let transformedAsset = try XCTUnwrap( + chain.assets.first { $0.id == asset.id } + ) + + XCTAssertEqual(transformedAsset.price, Decimal(string: "7.25")) + XCTAssertEqual( + transformedAsset.fiatDayChange, + Decimal(string: "-0.5") + ) + } + + func testTransformDeterministicallyChoosesCanonicalUnmatchedCachedPrice() + throws { + let priceFixtures = [ + ( + currencyId: "z-currency", + priceId: "z-price", + price: "99.5", + fiatDayChange: "9.5" + ), + ( + currencyId: "a-currency", + priceId: "a-price", + price: "1.25", + fiatDayChange: "-1.5" + ) + ] + + for shouldReverseInsertion in [false, true] { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + entity.chainId = "two-prices-\(shouldReverseInsertion)" + let asset = makeAssetWithUnmatchedPricing( + identifier: "two-prices-\(shouldReverseInsertion)" + ) + let assetEntity = CDAsset(context: context) + try AssetModelMapper().populate( + entity: assetEntity, + from: asset, + using: context + ) + let orderedFixtures = shouldReverseInsertion + ? Array(priceFixtures.reversed()) + : priceFixtures + let cachedPrices = orderedFixtures.map { + makeCachedPrice( + currencyId: $0.currencyId, + priceId: $0.priceId, + price: $0.price, + fiatDayChange: $0.fiatDayChange, + in: context + ) + } + assetEntity.setValue( + NSSet(array: cachedPrices), + forKey: "priceData" + ) + entity.assets = NSSet(object: assetEntity) + + let chain = try ChainModelMapper().transform(entity: entity) + let transformedAsset = try XCTUnwrap( + chain.assets.first { $0.id == asset.id } + ) + + XCTAssertEqual( + transformedAsset.price, + Decimal(string: "1.25") + ) + XCTAssertEqual( + transformedAsset.fiatDayChange, + Decimal(string: "-1.5") + ) + } + } + + func testTransformUsesValidCachedPriceAmongMalformedRows() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let asset = makeAssetWithUnmatchedPricing(identifier: "mixed-prices") + let assetEntity = CDAsset(context: context) + try AssetModelMapper().populate( + entity: assetEntity, + from: asset, + using: context + ) + let missingCurrency = CDPriceData(context: context) + missingCurrency.priceId = "missing-currency" + missingCurrency.price = "100" + let missingPriceIdentifier = CDPriceData(context: context) + missingPriceIdentifier.currencyId = "missing-price-id" + missingPriceIdentifier.price = "200" + let missingPrice = CDPriceData(context: context) + missingPrice.currencyId = "missing-price" + missingPrice.priceId = "missing-price" + let validPrice = makeCachedPrice( + currencyId: "valid-unmatched-currency", + priceId: "valid-unmatched-price", + price: "3.75", + fiatDayChange: "0.75", + in: context + ) + assetEntity.setValue( + NSSet( + array: [ + missingCurrency, + validPrice, + missingPriceIdentifier, + missingPrice + ] + ), + forKey: "priceData" + ) + entity.assets = NSSet(object: assetEntity) + + let chain = try ChainModelMapper().transform(entity: entity) + let transformedAsset = try XCTUnwrap( + chain.assets.first { $0.id == asset.id } + ) + + XCTAssertEqual(transformedAsset.price, Decimal(string: "3.75")) + XCTAssertEqual( + transformedAsset.fiatDayChange, + Decimal(string: "0.75") + ) + } + + func testTransformRejectsMalformedNonfiniteAndNegativeCachedPrices() + throws { + let invalidPrices = [ + "", + " ", + "not-a-price", + "NaN", + "Infinity", + "-Infinity", + "1e9999", + "-0.01", + "1,23", + "0x10" + ] + + for shouldReverseInsertion in [false, true] { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + entity.chainId = "invalid-prices-\(shouldReverseInsertion)" + let asset = makeAssetWithUnmatchedPricing( + identifier: "invalid-prices-\(shouldReverseInsertion)" + ) + let assetEntity = CDAsset(context: context) + try AssetModelMapper().populate( + entity: assetEntity, + from: asset, + using: context + ) + let invalidRows = invalidPrices.enumerated().map { + makeCachedPrice( + currencyId: String( + format: "a-invalid-%02d", + $0.offset + ), + priceId: "asset-price", + price: $0.element, + fiatDayChange: "99", + in: context + ) + } + let validFallback = makeCachedPrice( + currencyId: "z-valid-currency", + priceId: "asset-price", + price: "4.25", + fiatDayChange: "-0.25", + in: context + ) + let rows = shouldReverseInsertion + ? [validFallback] + Array(invalidRows.reversed()) + : invalidRows + [validFallback] + assetEntity.setValue( + NSSet(array: Array(rows)), + forKey: "priceData" + ) + entity.assets = NSSet(object: assetEntity) + + let chain = try ChainModelMapper().transform(entity: entity) + let transformedAsset = try XCTUnwrap( + chain.assets.first { $0.id == asset.id } + ) + + XCTAssertEqual( + transformedAsset.price, + Decimal(string: "4.25") + ) + XCTAssertEqual( + transformedAsset.fiatDayChange, + Decimal(string: "-0.25") + ) + } + } + + func testTransformPreservesSupportedCachedPriceStringFormats() throws { + let fixtures: [(String, Decimal)] = [ + ("0", 0), + (".5", 0.5), + ("+7.5", 7.5), + ("1.25e2", 125), + (" 9.75 ", 9.75) + ] + + for (index, fixture) in fixtures.enumerated() { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + entity.chainId = "valid-price-format-\(index)" + let asset = makeAssetWithUnmatchedPricing( + identifier: "valid-price-format-\(index)" + ) + let assetEntity = CDAsset(context: context) + try AssetModelMapper().populate( + entity: assetEntity, + from: asset, + using: context + ) + let cachedPrice = makeCachedPrice( + currencyId: "format-currency", + priceId: "asset-price", + price: fixture.0, + fiatDayChange: "0", + in: context + ) + assetEntity.setValue( + NSSet(object: cachedPrice), + forKey: "priceData" + ) + entity.assets = NSSet(object: assetEntity) + + let chain = try ChainModelMapper().transform(entity: entity) + let transformedAsset = try XCTUnwrap( + chain.assets.first { $0.id == asset.id } + ) + + XCTAssertEqual( + transformedAsset.price, + fixture.1, + "expected cached price format \(fixture.0)" + ) + } + } + + func testPopulateDeletesMalformedStaleNodesInsteadOfForceUnwrapping() throws { + let context = try createContext() + let entity = makeValidChainEntity(in: context) + let malformedDefaultNode = CDChainNode(context: context) + malformedDefaultNode.name = "Malformed default" + let malformedCustomNode = CDChainNode(context: context) + malformedCustomNode.name = "Malformed custom" + entity.nodes = NSSet(object: malformedDefaultNode) + entity.customNodes = NSSet(object: malformedCustomNode) + let replacement = ChainModelGenerator.generateChain( + generatingAssets: 1, + addressPrefix: 42 + ).replacingCustomNodes([]) + + try ChainModelMapper().populate( + entity: entity, + from: replacement, + using: context + ) + + XCTAssertTrue(malformedDefaultNode.isDeleted) + XCTAssertTrue(malformedCustomNode.isDeleted) + XCTAssertFalse(entity.nodes?.allObjects.isEmpty ?? true) + XCTAssertTrue(entity.customNodes?.allObjects.isEmpty ?? true) + } + + func testMalformedChainCleanup_whenGetterRaisesDuringQuarantine_thenFailsSafelyAndRollsBack() throws { + let chainEntity = NSEntityDescription() + chainEntity.name = String(describing: CDChain.self) + chainEntity.managedObjectClassName = NSStringFromClass( + CDChain.self + ) + let disabled = NSAttributeDescription() + disabled.name = "disabled" + disabled.attributeType = .booleanAttributeType + disabled.isOptional = false + disabled.defaultValue = false + chainEntity.properties = [ + makeAttribute( + name: "chainId", + type: .stringAttributeType + ), + disabled + ] + + let model = NSManagedObjectModel() + model.entities = [chainEntity] + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + try coordinator.addPersistentStore( + ofType: NSInMemoryStoreType, + configurationName: nil, + at: nil + ) + let context = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + let facade = ChainCleanupFixtureStorageFacade( + context: context + ) + + try perform(in: facade.databaseService) { + context in + + let chain = CDChain( + entity: chainEntity, + insertInto: context + ) + chain.chainId = "" + chain.disabled = false + try context.save() + } + + let operation = ChainRepositoryFactory( + storageFacade: facade + ).createMalformedChainCleanupOperation() + let queue = OperationQueue() + queue.addOperations( + [operation], + waitUntilFinished: true + ) + + XCTAssertThrowsError( + try XCTUnwrap(operation.result).get() + ) { error in + XCTAssertEqual( + error as? SafeTransformableValueReaderError, + .objectiveCException + ) + } + + try perform(in: facade.databaseService) { + context in + + let request = NSFetchRequest( + entityName: String(describing: CDChain.self) + ) + let chains = try context.fetch(request) + let chain = try XCTUnwrap(chains.first) + XCTAssertEqual(chains.count, 1) + XCTAssertEqual(chain.chainId, "") + XCTAssertFalse(chain.disabled) + XCTAssertFalse( + chain.chainId?.hasPrefix( + ChainModelMapper + .quarantinedChainIdentifierPrefix + ) == true + ) + } + } + + func testMalformedChainCleanupQuarantinesBlankIdentifiersWithoutDataLoss() + throws { + let facade = SubstrateStorageTestFacade() + let malformedFixtures: [(identifier: String?, suffix: String)] = [ + ("", "empty"), + (" \n\t", "whitespace") + ] + + try perform(in: facade.databaseService) { context in + for fixture in malformedFixtures { + let malformedChain = CDChain(context: context) + malformedChain.chainId = fixture.identifier + malformedChain.name = "Malformed \(fixture.suffix)" + + let defaultNode = CDChainNode(context: context) + defaultNode.url = try XCTUnwrap( + URL( + string: + "wss://default-\(fixture.suffix).example" + ) + ) + defaultNode.name = "Default \(fixture.suffix)" + malformedChain.nodes = NSSet(object: defaultNode) + + let customNode = CDChainNode(context: context) + customNode.url = try XCTUnwrap( + URL( + string: + "wss://custom-\(fixture.suffix).example" + ) + ) + customNode.name = "Custom \(fixture.suffix)" + malformedChain.customNodes = NSSet(object: customNode) + malformedChain.selectedNode = customNode + + let asset = CDAsset(context: context) + asset.id = "asset-\(fixture.suffix)" + asset.name = "Asset \(fixture.suffix)" + asset.symbol = "AS\(fixture.suffix)" + asset.precision = 12 + malformedChain.assets = NSSet(object: asset) + } + + let healthyChain = CDChain(context: context) + healthyChain.chainId = "healthy-chain" + healthyChain.name = "Healthy" + try context.save() + } + + let factory = ChainRepositoryFactory(storageFacade: facade) + let queue = OperationQueue() + var identifiersAfterFirstCleanup: [String: String] = [:] + + for cleanupIndex in 0 ..< 2 { + let cleanupOperation = factory.createMalformedChainCleanupOperation() + queue.addOperations([cleanupOperation], waitUntilFinished: true) + let _: Void = try XCTUnwrap(cleanupOperation.result).get() + + if cleanupIndex == 0 { + try perform(in: facade.databaseService) { context in + let request = NSFetchRequest( + entityName: String(describing: CDChain.self) + ) + identifiersAfterFirstCleanup = Dictionary( + uniqueKeysWithValues: try context.fetch(request) + .compactMap { chain in + guard + let name = chain.name, + name.hasPrefix("Malformed "), + let identifier = chain.chainId + else { + return nil + } + + return (name, identifier) + } + ) + } + } + } + + try perform(in: facade.databaseService) { context in + let request = NSFetchRequest( + entityName: String(describing: CDChain.self) + ) + let chains = try context.fetch(request) + XCTAssertEqual(chains.count, malformedFixtures.count + 1) + + let healthy = try XCTUnwrap( + chains.first { $0.chainId == "healthy-chain" } + ) + XCTAssertFalse(healthy.disabled) + + let quarantinedChains = chains.filter { + $0.chainId?.hasPrefix( + ChainModelMapper.quarantinedChainIdentifierPrefix + ) == true + } + XCTAssertEqual( + quarantinedChains.count, + malformedFixtures.count + ) + XCTAssertEqual( + Set(quarantinedChains.compactMap(\.chainId)).count, + malformedFixtures.count, + "each malformed row must receive a unique identifier" + ) + + for fixture in malformedFixtures { + let name = "Malformed \(fixture.suffix)" + let chain = try XCTUnwrap( + quarantinedChains.first { $0.name == name } + ) + XCTAssertTrue(chain.disabled) + XCTAssertEqual( + chain.chainId, + identifiersAfterFirstCleanup[name], + "quarantine identifiers must remain stable on relaunch" + ) + XCTAssertEqual( + Set( + (chain.nodes?.allObjects as? [CDChainNode] ?? []) + .compactMap(\.url?.absoluteString) + ), + Set(["wss://default-\(fixture.suffix).example"]) + ) + XCTAssertEqual( + Set( + ( + chain.customNodes?.allObjects + as? [CDChainNode] ?? [] + ) + .compactMap(\.url?.absoluteString) + ), + Set(["wss://custom-\(fixture.suffix).example"]) + ) + XCTAssertEqual( + chain.selectedNode?.url?.absoluteString, + "wss://custom-\(fixture.suffix).example" + ) + XCTAssertEqual( + Set( + (chain.assets?.allObjects as? [CDAsset] ?? []) + .compactMap(\.id) + ), + Set(["asset-\(fixture.suffix)"]) + ) + } + } + + // Exercise the same repository fetch/map frame sequence as the + // TestFlight _ArrayBuffer._getElementSlowPath crash after cleanup. + let repository = factory.createRepository() + let fetchOperation = repository.fetchAllOperation( + with: RepositoryFetchOptions() + ) + queue.addOperations([fetchOperation], waitUntilFinished: true) + let chains: [ChainModel] = try XCTUnwrap( + fetchOperation.result + ).get() + XCTAssertEqual(chains.count, malformedFixtures.count + 1) + XCTAssertEqual( + chains.filter { + $0.chainId.hasPrefix( + ChainModelMapper.quarantinedChainIdentifierPrefix + ) + }.count, + malformedFixtures.count + ) + for fixture in malformedFixtures { + let chain = try XCTUnwrap( + chains.first { $0.name == "Malformed \(fixture.suffix)" } + ) + XCTAssertEqual( + chain.customNodes?.first?.url.absoluteString, + "wss://custom-\(fixture.suffix).example" + ) + XCTAssertEqual( + chain.selectedNode?.url.absoluteString, + "wss://custom-\(fixture.suffix).example" + ) + XCTAssertEqual( + Set(chain.assets.map(\.id)), + Set(["asset-\(fixture.suffix)"]) + ) + } + } + + func testMalformedChainQuarantineCannotCollideWithStoredIdentifier() + throws { + let facade = SubstrateStorageTestFacade() + var reservedIdentifier = "" + + try perform(in: facade.databaseService) { context in + let malformedChain = CDChain(context: context) + malformedChain.chainId = "" + malformedChain.name = "Malformed collision" + try context.save() + + reservedIdentifier = + ChainModelMapper.quarantinedChainIdentifierPrefix + + malformedChain.objectID.uriRepresentation().absoluteString + + let preexistingChain = CDChain(context: context) + preexistingChain.chainId = reservedIdentifier + preexistingChain.name = "Preexisting identifier" + try context.save() + } + + let factory = ChainRepositoryFactory(storageFacade: facade) + let queue = OperationQueue() + for _ in 0 ..< 2 { + let cleanupOperation = factory.createMalformedChainCleanupOperation() + queue.addOperations([cleanupOperation], waitUntilFinished: true) + let _: Void = try XCTUnwrap(cleanupOperation.result).get() + } + + try perform(in: facade.databaseService) { context in + let request = NSFetchRequest( + entityName: String(describing: CDChain.self) + ) + let chains = try context.fetch(request) + XCTAssertEqual(chains.count, 2) + + let preexistingChain = try XCTUnwrap( + chains.first { $0.name == "Preexisting identifier" } + ) + XCTAssertEqual(preexistingChain.chainId, reservedIdentifier) + XCTAssertFalse(preexistingChain.disabled) + + let quarantinedChain = try XCTUnwrap( + chains.first { $0.name == "Malformed collision" } + ) + XCTAssertEqual( + quarantinedChain.chainId, + "\(reservedIdentifier)#1" + ) + XCTAssertTrue(quarantinedChain.disabled) + } + } + + func testCleanupCanonicalizesIdentifiersAndMergesPreferencesWithoutLoss() + throws { + let facade = SubstrateStorageTestFacade() + let canonicalSelectedURL = try XCTUnwrap( + URL(string: "wss://canonical-user.example") + ) + let collidingDefaultURL = try XCTUnwrap( + URL(string: "wss://colliding-default.example") + ) + let collidingCustomURL = try XCTUnwrap( + URL(string: "wss://colliding-user.example") + ) + let normalizedSelectedURL = try XCTUnwrap( + URL(string: "wss://normalized-user.example") + ) + let historyApiURL = try XCTUnwrap( + URL(string: "https://history.example") + ) + + try perform(in: facade.databaseService) { context in + let canonical = CDChain(context: context) + canonical.chainId = "collision-chain" + canonical.name = "Canonical" + let canonicalNode = CDChainNode(context: context) + canonicalNode.url = canonicalSelectedURL + canonicalNode.name = "Canonical selection" + canonical.nodes = NSSet(object: canonicalNode) + canonical.customNodes = NSSet(object: canonicalNode) + canonical.selectedNode = canonicalNode + + let colliding = CDChain(context: context) + colliding.chainId = " collision-chain \n" + colliding.name = "Canonical" + colliding.rank = "7" + colliding.historyApiType = "subquery" + colliding.historyApiUrl = historyApiURL + colliding.setValue( + NSArray(object: ChainOptions.poolStaking.rawValue), + forKey: "options" + ) + let collidingDefaultNode = CDChainNode(context: context) + collidingDefaultNode.url = collidingDefaultURL + collidingDefaultNode.name = "Colliding default" + colliding.nodes = NSSet(object: collidingDefaultNode) + let collidingCustomNode = CDChainNode(context: context) + collidingCustomNode.url = collidingCustomURL + collidingCustomNode.name = "Colliding custom" + colliding.customNodes = NSSet(object: collidingCustomNode) + + let collidingAsset = CDAsset(context: context) + collidingAsset.id = "colliding-asset" + collidingAsset.name = "Colliding asset" + collidingAsset.symbol = "COL" + collidingAsset.precision = 12 + colliding.assets = NSSet(object: collidingAsset) + + let collidingExplorer = CDExternalApi(context: context) + collidingExplorer.type = "subscan" + collidingExplorer.url = "https://explorer.example" + collidingExplorer.setValue( + NSArray(object: "extrinsic"), + forKey: "types" + ) + colliding.explorers = NSSet(object: collidingExplorer) + + let collidingXcm = CDChainXcmConfig(context: context) + collidingXcm.xcmVersion = "V3" + collidingXcm.availableAssets = NSSet() + collidingXcm.availableDestinations = NSSet() + colliding.xcmConfig = collidingXcm + + let normalizationOnly = CDChain(context: context) + normalizationOnly.chainId = "\tnormalized-chain " + normalizationOnly.name = "Normalization only" + let normalizedNode = CDChainNode(context: context) + normalizedNode.url = normalizedSelectedURL + normalizedNode.name = "Normalized selection" + normalizationOnly.nodes = NSSet(object: normalizedNode) + normalizationOnly.customNodes = NSSet(object: normalizedNode) + normalizationOnly.selectedNode = normalizedNode + + try context.save() + } + + let factory = ChainRepositoryFactory(storageFacade: facade) + let queue = OperationQueue() + for _ in 0 ..< 2 { + let operation = factory.createMalformedChainCleanupOperation() + queue.addOperations([operation], waitUntilFinished: true) + let _: Void = try XCTUnwrap(operation.result).get() + } + + try perform(in: facade.databaseService) { context in + let request = NSFetchRequest( + entityName: String(describing: CDChain.self) + ) + let chains = try context.fetch(request) + let chainsByIdentifier = Dictionary( + uniqueKeysWithValues: chains.compactMap { chain in + chain.chainId.map { ($0, chain) } + } + ) + + XCTAssertEqual( + Set(chainsByIdentifier.keys), + Set(["collision-chain", "normalized-chain"]) + ) + + let merged = try XCTUnwrap( + chainsByIdentifier["collision-chain"] + ) + let mergedCustomURLs = Set( + (merged.customNodes?.allObjects as? [CDChainNode] ?? []) + .compactMap(\.url) + ) + XCTAssertEqual( + mergedCustomURLs, + Set([canonicalSelectedURL, collidingCustomURL]) + ) + let mergedDefaultURLs = Set( + (merged.nodes?.allObjects as? [CDChainNode] ?? []) + .compactMap(\.url) + ) + XCTAssertEqual( + mergedDefaultURLs, + Set([canonicalSelectedURL, collidingDefaultURL]) + ) + XCTAssertEqual( + merged.selectedNode?.url, + canonicalSelectedURL, + "the canonical row's explicit selection wins collisions" + ) + XCTAssertEqual(merged.rank, "7") + XCTAssertEqual(merged.historyApiType, "subquery") + XCTAssertEqual(merged.historyApiUrl, historyApiURL) + let mergedOptions: [String]? = + try SafeTransformableValueReader.read( + from: merged, + key: "options" + ) + XCTAssertEqual( + mergedOptions, + [ChainOptions.poolStaking.rawValue] + ) + XCTAssertEqual( + Set( + (merged.assets?.allObjects as? [CDAsset] ?? []) + .compactMap(\.id) + ), + Set(["colliding-asset"]) + ) + XCTAssertEqual( + Set( + ( + merged.explorers?.allObjects + as? [CDExternalApi] ?? [] + ) + .compactMap(\.url) + ), + Set(["https://explorer.example"]) + ) + XCTAssertEqual(merged.xcmConfig?.xcmVersion, "V3") + + let normalized = try XCTUnwrap( + chainsByIdentifier["normalized-chain"] + ) + XCTAssertEqual( + normalized.selectedNode?.url, + normalizedSelectedURL + ) + } + + let repository = factory.createRepository() + let fetchOperation = repository.fetchAllOperation( + with: RepositoryFetchOptions() + ) + queue.addOperations([fetchOperation], waitUntilFinished: true) + let chains: [ChainModel] = try XCTUnwrap( + fetchOperation.result + ).get() + XCTAssertEqual( + Set(chains.map(\.chainId)), + Set(["collision-chain", "normalized-chain"]) + ) + } + + func testCleanupCollisionPreservesCustomSelectionWhenDefaultRetires() + throws { + let facade = SubstrateStorageTestFacade() + let chainId = "shared-node-collision" + let sharedURL = try XCTUnwrap( + URL(string: "wss://shared-node.example") + ) + let replacementURL = try XCTUnwrap( + URL(string: "wss://replacement-default.example") + ) + + try perform(in: facade.databaseService) { context in + let canonical = CDChain(context: context) + canonical.chainId = chainId + canonical.name = "Canonical" + let sharedNode = CDChainNode(context: context) + sharedNode.url = sharedURL + sharedNode.name = "Shared user selection" + canonical.nodes = NSSet(object: sharedNode) + + let colliding = CDChain(context: context) + colliding.chainId = " \(chainId) " + colliding.name = "Canonical" + colliding.customNodes = NSSet(object: sharedNode) + colliding.selectedNode = sharedNode + + try context.save() + } + + let factory = ChainRepositoryFactory(storageFacade: facade) + let queue = OperationQueue() + let cleanup = factory.createMalformedChainCleanupOperation() + queue.addOperations([cleanup], waitUntilFinished: true) + let _: Void = try XCTUnwrap(cleanup.result).get() + + let repository = factory.createRepository() + let initialFetch = repository.fetchAllOperation( + with: RepositoryFetchOptions() + ) + queue.addOperations([initialFetch], waitUntilFinished: true) + let localChain = try XCTUnwrap( + try XCTUnwrap(initialFetch.result) + .get() + .first { $0.chainId == chainId } + ) + + XCTAssertEqual(localChain.customNodes?.first?.url, sharedURL) + XCTAssertEqual( + localChain.customNodes?.first?.name, + "Shared user selection" + ) + XCTAssertEqual(localChain.selectedNode?.url, sharedURL) + + let replacementDefault = ChainNodeModel( + url: replacementURL, + name: "Replacement default", + apikey: nil + ) + let remoteChain = localChain.replacingNodeConfiguration( + nodes: [replacementDefault], + selectedNode: nil, + customNodes: nil + ) + let mergedChain = try XCTUnwrap( + ChainSyncService.preservingLocalNodePreferences( + remoteChains: [remoteChain], + localChains: [localChain] + ).first + ) + + XCTAssertEqual(mergedChain.nodes, Set([replacementDefault])) + XCTAssertEqual(mergedChain.customNodes?.first?.url, sharedURL) + XCTAssertEqual(mergedChain.selectedNode?.url, sharedURL) + + try perform(in: facade.databaseService) { context in + let request = NSFetchRequest( + entityName: String(describing: CDChain.self) + ) + let entity = try XCTUnwrap( + try context.fetch(request).first { + $0.chainId == chainId + } + ) + + try ChainModelMapper().populate( + entity: entity, + from: mergedChain, + using: context + ) + try context.save() + } + + let finalFetch = repository.fetchAllOperation( + with: RepositoryFetchOptions() + ) + queue.addOperations([finalFetch], waitUntilFinished: true) + let refetchedChain = try XCTUnwrap( + try XCTUnwrap(finalFetch.result) + .get() + .first { $0.chainId == chainId } + ) + + XCTAssertEqual(refetchedChain.nodes, Set([replacementDefault])) + XCTAssertEqual(refetchedChain.customNodes?.first?.url, sharedURL) + XCTAssertEqual( + refetchedChain.customNodes?.first?.name, + "Shared user selection" + ) + XCTAssertEqual(refetchedChain.selectedNode?.url, sharedURL) + } + + func testCleanupQuarantinesConflictingCollisionWithoutDeletingItsData() + throws { + let facade = SubstrateStorageTestFacade() + let chainId = "conflicting-collision" + let canonicalURL = try XCTUnwrap( + URL(string: "wss://canonical-collision.example") + ) + let conflictingURL = try XCTUnwrap( + URL(string: "wss://conflicting-collision.example") + ) + + try perform(in: facade.databaseService) { context in + let canonical = CDChain(context: context) + canonical.chainId = chainId + canonical.name = "Collision chain" + let canonicalNode = CDChainNode(context: context) + canonicalNode.url = canonicalURL + canonicalNode.name = "Canonical selection" + canonical.nodes = NSSet(object: canonicalNode) + canonical.selectedNode = canonicalNode + + let conflicting = CDChain(context: context) + conflicting.chainId = " \(chainId) " + conflicting.name = "Collision chain" + let conflictingNode = CDChainNode(context: context) + conflictingNode.url = conflictingURL + conflictingNode.name = "Conflicting selection" + conflicting.nodes = NSSet(object: conflictingNode) + conflicting.selectedNode = conflictingNode + + let conflictingAsset = CDAsset(context: context) + conflictingAsset.id = "conflicting-asset" + conflictingAsset.name = "Conflicting asset" + conflictingAsset.symbol = "CON" + conflictingAsset.precision = 12 + conflicting.assets = NSSet(object: conflictingAsset) + + try context.save() + } + + let factory = ChainRepositoryFactory(storageFacade: facade) + let queue = OperationQueue() + + for _ in 0 ..< 2 { + let cleanup = factory.createMalformedChainCleanupOperation() + queue.addOperations([cleanup], waitUntilFinished: true) + let _: Void = try XCTUnwrap(cleanup.result).get() + } + + try perform(in: facade.databaseService) { context in + let request = NSFetchRequest( + entityName: String(describing: CDChain.self) + ) + let chains = try context.fetch(request) + XCTAssertEqual(chains.count, 2) + + let canonical = try XCTUnwrap( + chains.first { $0.chainId == chainId } + ) + XCTAssertFalse(canonical.disabled) + XCTAssertEqual(canonical.selectedNode?.url, canonicalURL) + XCTAssertEqual( + Set( + (canonical.nodes?.allObjects as? [CDChainNode] ?? []) + .compactMap(\.url) + ), + Set([canonicalURL]) + ) + XCTAssertTrue(canonical.assets?.allObjects.isEmpty ?? true) + + let quarantined = try XCTUnwrap( + chains.first { + $0.chainId?.hasPrefix( + ChainModelMapper + .quarantinedChainIdentifierPrefix + ) == true + } + ) + XCTAssertTrue(quarantined.disabled) + XCTAssertEqual(quarantined.name, "Collision chain") + XCTAssertEqual(quarantined.selectedNode?.url, conflictingURL) + XCTAssertEqual( + Set( + ( + quarantined.nodes?.allObjects + as? [CDChainNode] ?? [] + ) + .compactMap(\.url) + ), + Set([conflictingURL]) + ) + XCTAssertEqual( + Set( + (quarantined.assets?.allObjects as? [CDAsset] ?? []) + .compactMap(\.id) + ), + Set(["conflicting-asset"]) + ) + } + } + + private func makeNode(from entity: CDChainNode) throws -> ChainNodeModel { + ChainNodeModel( + url: try XCTUnwrap(entity.url), + name: try XCTUnwrap(entity.name), + apikey: nil + ) + } + + private func makeAssetWithUnmatchedPricing( + identifier: String + ) -> AssetModel { + AssetModel( + id: identifier, + name: "Cached price fixture", + symbol: "CPF", + precision: 12, + currencyId: "asset-currency", + isUtility: false, + isNative: false, + coingeckoPriceId: "asset-price" + ) + } + + private func makeCachedPrice( + currencyId: String, + priceId: String, + price: String, + fiatDayChange: String, + in context: NSManagedObjectContext + ) -> CDPriceData { + let entity = CDPriceData(context: context) + entity.currencyId = currencyId + entity.priceId = priceId + entity.price = price + entity.fiatDayByChange = fiatDayChange + return entity + } + + private func makeValidChainEntity( + in context: NSManagedObjectContext + ) -> CDChain { + let entity = CDChain(context: context) + entity.chainId = "valid-chain" + entity.name = "Valid Chain" + return entity + } + + private func makeCachedPriceEntity( + managedObjectClass: AnyClass, + priceType: NSAttributeType + ) -> ( + model: NSManagedObjectModel, + entity: NSEntityDescription + ) { + let entity = NSEntityDescription() + entity.name = "CachedPriceFixture_" + UUID().uuidString + .replacingOccurrences(of: "-", with: "") + entity.managedObjectClassName = NSStringFromClass( + managedObjectClass + ) + entity.properties = [ + makeAttribute( + name: "currencyId", + type: .stringAttributeType + ), + makeAttribute( + name: "priceId", + type: .stringAttributeType + ), + makeAttribute(name: "price", type: priceType) + ] + + let model = NSManagedObjectModel() + model.entities = [entity] + return (model, entity) + } + + private func makeEntityDescription( + managedObjectClass: AnyClass, + properties: [NSPropertyDescription] + ) -> NSEntityDescription { + let entity = NSEntityDescription() + entity.name = "MapperExceptionFixture_" + UUID().uuidString + .replacingOccurrences(of: "-", with: "") + entity.managedObjectClassName = NSStringFromClass( + managedObjectClass + ) + entity.properties = properties + return entity + } + + private func makeAttribute( + name: String, + type: NSAttributeType + ) -> NSAttributeDescription { + let attribute = NSAttributeDescription() + attribute.name = name + attribute.attributeType = type + attribute.isOptional = true + return attribute + } + + private func makeContext( + entities: [NSEntityDescription] + ) throws -> NSManagedObjectContext { + let model = NSManagedObjectModel() + model.entities = entities + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + try coordinator.addPersistentStore( + ofType: NSInMemoryStoreType, + configurationName: nil, + at: nil, + options: nil + ) + let context = NSManagedObjectContext( + concurrencyType: .mainQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + return context + } + + private func createContext() throws -> NSManagedObjectContext { + let modelURL = try XCTUnwrap( + Bundle.main.url( + forResource: "SubstrateDataModel", + withExtension: "momd" + ) + ) + let model = try XCTUnwrap(NSManagedObjectModel(contentsOf: modelURL)) + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + try coordinator.addPersistentStore( + ofType: NSInMemoryStoreType, + configurationName: nil, + at: nil, + options: nil + ) + + let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + return context + } + + private func perform( + in service: CoreDataServiceProtocol, + _ closure: @escaping (NSManagedObjectContext) throws -> Void + ) throws { + let semaphore = DispatchSemaphore(value: 0) + var result: Result? + + service.performAsync { context, error in + defer { semaphore.signal() } + + do { + if let error { + throw error + } + + try closure( + XCTUnwrap(context, "Expected a Core Data context") + ) + result = .success(()) + } catch { + result = .failure(error) + } + } + + semaphore.wait() + try XCTUnwrap(result).get() + } +} + +private final class ExceptionRaisingCachedPrice: NSManagedObject { + override func willAccessValue(forKey key: String?) { + guard key == "price" else { + super.willAccessValue(forKey: key) + return + } + + NSException( + name: .invalidArgumentException, + reason: "adversarial cached-price row", + userInfo: nil + ).raise() + } +} + +private final class ChainCleanupFixtureCoreDataService: + CoreDataServiceProtocol { + let configuration: CoreDataServiceConfigurationProtocol + + private let context: NSManagedObjectContext + + init(context: NSManagedObjectContext) { + self.context = context + configuration = CoreDataServiceConfiguration( + modelURL: URL( + fileURLWithPath: + "/dev/null/ChainCleanupFixture.mom" + ), + storageType: .inMemory + ) + } + + func performAsync( + block: @escaping CoreDataContextInvocationBlock + ) { + context.perform { + block(self.context, nil) + } + } + + func close() throws {} + + func drop() throws {} +} + +private final class ChainCleanupFixtureStorageFacade: + StorageFacadeProtocol { + let databaseService: CoreDataServiceProtocol + + init(context: NSManagedObjectContext) { + databaseService = + ChainCleanupFixtureCoreDataService( + context: context + ) + } + + func createRepository( + filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor], + mapper: AnyCoreDataMapper + ) -> CoreDataRepository + where T: Identifiable, U: NSManagedObject { + CoreDataRepository( + databaseService: databaseService, + mapper: mapper, + filter: filter, + sortDescriptors: sortDescriptors + ) + } + + func createAsyncRepository( + filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor], + mapper: AnyCoreDataMapper + ) -> AsyncCoreDataRepositoryDefault + where T: Identifiable, U: NSManagedObject { + AsyncCoreDataRepositoryDefault( + databaseService: databaseService, + mapper: mapper, + filter: filter, + sortDescriptors: sortDescriptors + ) + } } diff --git a/fearlessTests/Common/Storage/MetaAccountMapperTests.swift b/fearlessTests/Common/Storage/MetaAccountMapperTests.swift index d9f2363750..59aa324457 100644 --- a/fearlessTests/Common/Storage/MetaAccountMapperTests.swift +++ b/fearlessTests/Common/Storage/MetaAccountMapperTests.swift @@ -5,6 +5,83 @@ import SSFModels import CoreData class MetaAccountMapperTests: XCTestCase { + func testTransformConvertsMandatoryGetterExceptionToSanitizedSwiftError() { + let entityDescription = makeEntityDescription( + managedObjectClass: CDMetaAccount.self, + properties: [] + ) + let entity = CDMetaAccount( + entity: entityDescription, + insertInto: nil + ) + + XCTAssertThrowsError( + try MetaAccountMapper().transform(entity: entity) + ) { error in + XCTAssertEqual( + error as? SafeTransformableValueReaderError, + .objectiveCException + ) + } + } + + func testMalformedChildRelationshipFailsClosedThroughDirectAndSelectionMappers() + throws { + let fixture = try makeMetaAccountWithThrowingChainAccountRelationship() + + XCTAssertThrowsError( + try MetaAccountMapper().transform(entity: fixture.entity) + ) { error in + XCTAssertEqual( + error as? SafeTransformableValueReaderError, + .objectiveCException + ) + } + + let startupMapper: + AnyCoreDataMapper = + AnyCoreDataMapper(MetaAccountSelectionMapper()) + let projection = try startupMapper.transform(entity: fixture.entity) + + XCTAssertEqual(projection.identifier, "relationship-wallet") + XCTAssertEqual(projection.recordState, .corrupt) + XCTAssertNil(projection.wallet) + XCTAssertFalse(projection.recordState.allowsStoredRecordUpdates) + } + + func testSelectionStartupWrapperQuarantinesOwnIdentifierGetterException() + throws { + let entityDescription = makeEntityDescription( + managedObjectClass: CDMetaAccount.self, + properties: [ + makeAttribute( + name: "isSelected", + type: .booleanAttributeType + ), + makeAttribute(name: "order", type: .integer32AttributeType) + ] + ) + let entity = CDMetaAccount( + entity: entityDescription, + insertInto: nil + ) + let startupMapper: + AnyCoreDataMapper = + AnyCoreDataMapper(MetaAccountSelectionMapper()) + let projection = try startupMapper.transform(entity: entity) + + XCTAssertTrue( + projection.identifier.hasPrefix( + "fearless.quarantined-wallet:" + ) + ) + XCTAssertEqual(projection.recordState, .corrupt) + XCTAssertNil(projection.wallet) + XCTAssertFalse(projection.isSelected) + XCTAssertEqual(projection.order, 0) + XCTAssertFalse(projection.recordState.allowsStoredRecordUpdates) + } + func testSaveAndFetch() throws { // given @@ -57,4 +134,454 @@ class MetaAccountMapperTests: XCTestCase { XCTAssertEqual(differentOrders.count, accountCount) } + func testCanonicalEcdsaSubstratePublicKeyIsAccepted() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let generated = AccountGenerator.generateMetaAccount(generatingChainAccounts: 1) + let ecdsaChainAccount = ChainAccountModel( + chainId: "canonical-ecdsa-chain", + accountId: Data(repeating: 0x59, count: 20), + publicKey: Data(repeating: 0x58, count: 33), + cryptoType: CryptoType.ecdsa.rawValue, + ethereumBased: true + ) + let wallet = MetaAccountModel( + metaId: "canonical-ecdsa-wallet", + name: generated.name, + substrateAccountId: generated.substrateAccountId, + substrateCryptoType: CryptoType.ecdsa.rawValue, + substratePublicKey: Data(repeating: 0x5A, count: 33), + ethereumAddress: generated.ethereumAddress, + ethereumPublicKey: generated.ethereumPublicKey, + chainAccounts: [ecdsaChainAccount], + assetKeysOrder: generated.assetKeysOrder, + canExportEthereumMnemonic: generated.canExportEthereumMnemonic, + unusedChainIds: generated.unusedChainIds, + selectedCurrency: generated.selectedCurrency, + networkManagmentFilter: generated.networkManagmentFilter, + assetsVisibility: generated.assetsVisibility, + hasBackup: generated.hasBackup, + favouriteChainIds: generated.favouriteChainIds + ) + let storageRepository = facade.createRepository( + mapper: AnyCoreDataMapper(ManagedMetaAccountMapper()) + ) + + let saveOperation = storageRepository.saveOperation( + { [ManagedMetaAccountModel(info: wallet, isSelected: true)] }, + { [] } + ) + operationQueue.addOperations([saveOperation], waitUntilFinished: true) + _ = try XCTUnwrap(saveOperation.result).get() + + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository(for: nil, sortDescriptors: []) + let fetchOperation = repository.fetchAllOperation( + with: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ) + operationQueue.addOperations([fetchOperation], waitUntilFinished: true) + + XCTAssertEqual(try XCTUnwrap(fetchOperation.result).get(), [wallet]) + } + + func testNonPersistableNilRequiredFieldsAreQuarantinedByMappersWithoutSaving() throws { + let facade = UserDataStorageTestFacade() + let callbackExpectation = expectation( + description: "unsaved required-field corruptions are mapped" + ) + var callbackResult: Result<[NonPersistableCorruptionObservation], Error>? + + facade.databaseService.performAsync { context, error in + defer { + callbackExpectation.fulfill() + } + + do { + if error != nil { + throw MetaAccountMapperTestFixtureError( + message: "Core Data setup failed" + ) + } + guard let context else { + throw MetaAccountMapperTestFixtureError( + message: "Core Data setup returned no context" + ) + } + + let mapper = MetaAccountMapper() + let selectionMapper = MetaAccountSelectionMapper() + var observations: [NonPersistableCorruptionObservation] = [] + + for corruption in NonPersistableSupportedWalletCorruption.allCases { + let generated = AccountGenerator.generateMetaAccount( + generatingChainAccounts: 1 + ) + let model = MetaAccountModel( + metaId: "unsaved-\(corruption.identifier)", + name: generated.name, + substrateAccountId: generated.substrateAccountId, + substrateCryptoType: generated.substrateCryptoType, + substratePublicKey: generated.substratePublicKey, + ethereumAddress: generated.ethereumAddress, + ethereumPublicKey: generated.ethereumPublicKey, + chainAccounts: generated.chainAccounts, + assetKeysOrder: generated.assetKeysOrder, + canExportEthereumMnemonic: generated.canExportEthereumMnemonic, + unusedChainIds: generated.unusedChainIds, + selectedCurrency: generated.selectedCurrency, + networkManagmentFilter: generated.networkManagmentFilter, + assetsVisibility: generated.assetsVisibility, + hasBackup: generated.hasBackup, + favouriteChainIds: generated.favouriteChainIds + ) + let entity = CDMetaAccount(context: context) + try mapper.populate(entity: entity, from: model, using: context) + guard + let child = entity.chainAccounts?.allObjects.first + as? CDChainAccount + else { + throw MetaAccountMapperTestFixtureError( + message: "Generated wallet has no child chain account" + ) + } + + switch corruption { + case .missingMetaId: + entity.metaId = nil + case .missingName: + entity.name = nil + case .missingChildAccountId: + child.accountId = nil + case .missingChildChainId: + child.chainId = nil + case .missingChildPublicKey: + child.publicKey = nil + } + + let coreDataRejectsInsert: Bool + do { + try entity.validateForInsert() + coreDataRejectsInsert = false + } catch { + coreDataRejectsInsert = true + } + + let directMapperRejectsAsInvalid: Bool + do { + _ = try mapper.transform(entity: entity) + directMapperRejectsAsInvalid = false + } catch MetaAccountMapperError.invalidWalletRecord { + directMapperRejectsAsInvalid = true + } + + let projection = try selectionMapper.transform(entity: entity) + let replacement = projection.replacingSelection( + !projection.isSelected + ) + observations.append( + NonPersistableCorruptionObservation( + identifier: corruption.identifier, + coreDataRejectsInsert: coreDataRejectsInsert, + directMapperRejectsAsInvalid: directMapperRejectsAsInvalid, + recordState: projection.recordState, + hasProjectedWallet: projection.wallet != nil, + allowsStoredRecordUpdates: + projection.recordState.allowsStoredRecordUpdates, + replacementUpdatesWalletPayload: + replacement.updatesWalletPayload, + replacementUpdatesSelection: + replacement.updatesSelection + ) + ) + + context.rollback() + } + + callbackResult = .success(observations) + } catch { + callbackResult = .failure(error) + } + } + + wait( + for: [callbackExpectation], + timeout: Constants.defaultExpectationDuration + ) + guard let callbackResult else { + throw MetaAccountMapperTestFixtureError( + message: "Core Data mapper callback produced no result" + ) + } + let observations = try callbackResult.get() + + XCTAssertEqual( + observations.map(\.identifier), + NonPersistableSupportedWalletCorruption.allCases.map(\.identifier) + ) + XCTAssertTrue(observations.allSatisfy(\.coreDataRejectsInsert)) + XCTAssertTrue(observations.allSatisfy(\.directMapperRejectsAsInvalid)) + XCTAssertTrue(observations.allSatisfy { $0.recordState == .corrupt }) + XCTAssertTrue(observations.allSatisfy { !$0.hasProjectedWallet }) + XCTAssertTrue(observations.allSatisfy { !$0.allowsStoredRecordUpdates }) + XCTAssertTrue( + observations.allSatisfy { !$0.replacementUpdatesWalletPayload } + ) + XCTAssertTrue( + observations.allSatisfy { !$0.replacementUpdatesSelection } + ) + } + + func testRepositorySliceDecoderAcceptsExactShapeAndFailsClosedOtherwise() throws { + let decoded = try ValidatedRepositorySlice( + request: RepositorySliceRequest( + offset: 2, + count: 3, + reversed: true + ) + ) + + XCTAssertEqual(decoded.offset, 2) + XCTAssertEqual(decoded.count, 3) + XCTAssertTrue(decoded.reversed) + + let invalidShapes: [[ValidatedRepositorySlice.ReflectedField]] = [ + [ + (label: "offset", value: 0), + (label: "count", value: 1) + ], + [ + (label: "offset", value: 0), + (label: "offset", value: 1), + (label: "reversed", value: false) + ], + [ + (label: "offset", value: 0), + (label: "count", value: 1), + (label: "unexpected", value: false) + ], + [ + (label: nil, value: 0), + (label: "count", value: 1), + (label: "reversed", value: false) + ], + [ + (label: "offset", value: "0"), + (label: "count", value: 1), + (label: "reversed", value: false) + ], + [ + (label: "offset", value: 0), + (label: "count", value: true), + (label: "reversed", value: false) + ], + [ + (label: "offset", value: 0), + (label: "count", value: 1), + (label: "reversed", value: 0) + ], + [ + (label: "offset", value: -1), + (label: "count", value: 1), + (label: "reversed", value: false) + ], + [ + (label: "offset", value: 0), + (label: "count", value: -1), + (label: "reversed", value: false) + ], + [ + (label: "offset", value: 0), + (label: "count", value: 1), + (label: "reversed", value: false), + (label: "extra", value: false) + ] + ] + + for (index, fields) in invalidShapes.enumerated() { + XCTAssertThrowsError( + try ValidatedRepositorySlice(reflectedFields: fields), + "Invalid reflected shape \(index) was accepted" + ) { error in + XCTAssertEqual( + error as? TolerantMetaAccountRepositoryError, + .invalidSliceRequest + ) + XCTAssertFalse( + (error as? LocalizedError)? + .errorDescription? + .isEmpty ?? true + ) + } + } + } + + private func makeMetaAccountWithThrowingChainAccountRelationship() + throws -> ( + context: NSManagedObjectContext, + entity: CDMetaAccount + ) { + let chainAccountDescription = makeEntityDescription( + managedObjectClass: CDChainAccount.self, + properties: [] + ) + let chainAccounts = NSRelationshipDescription() + chainAccounts.name = "chainAccounts" + chainAccounts.destinationEntity = chainAccountDescription + chainAccounts.minCount = 0 + chainAccounts.maxCount = 0 + chainAccounts.isOptional = true + chainAccounts.deleteRule = .nullifyDeleteRule + + let metaAccountDescription = makeEntityDescription( + managedObjectClass: CDMetaAccount.self, + properties: [ + makeAttribute(name: "metaId", type: .stringAttributeType), + makeAttribute(name: "name", type: .stringAttributeType), + makeAttribute( + name: "substrateAccountId", + type: .stringAttributeType + ), + makeAttribute( + name: "substratePublicKey", + type: .binaryDataAttributeType + ), + makeAttribute( + name: "substrateCryptoType", + type: .integer16AttributeType + ), + makeAttribute( + name: "isSelected", + type: .booleanAttributeType + ), + makeAttribute(name: "order", type: .integer32AttributeType), + chainAccounts + ] + ) + let context = try makeContext( + entities: [metaAccountDescription, chainAccountDescription] + ) + let entity = CDMetaAccount( + entity: metaAccountDescription, + insertInto: context + ) + entity.setValue("relationship-wallet", forKey: "metaId") + entity.setValue("Relationship wallet", forKey: "name") + entity.setValue( + String(repeating: "11", count: 32), + forKey: "substrateAccountId" + ) + entity.setValue( + Data(repeating: 0x22, count: 32), + forKey: "substratePublicKey" + ) + entity.setValue( + NSNumber(value: CryptoType.sr25519.rawValue), + forKey: "substrateCryptoType" + ) + entity.setValue(true, forKey: "isSelected") + entity.setValue(Int32(9), forKey: "order") + + let throwingChild = CDChainAccount( + entity: chainAccountDescription, + insertInto: context + ) + entity.setValue( + NSSet(object: throwingChild), + forKey: "chainAccounts" + ) + + return (context, entity) + } + + private func makeEntityDescription( + managedObjectClass: AnyClass, + properties: [NSPropertyDescription] + ) -> NSEntityDescription { + let entity = NSEntityDescription() + entity.name = "MapperExceptionFixture_" + UUID().uuidString + .replacingOccurrences(of: "-", with: "") + entity.managedObjectClassName = NSStringFromClass( + managedObjectClass + ) + entity.properties = properties + return entity + } + + private func makeAttribute( + name: String, + type: NSAttributeType + ) -> NSAttributeDescription { + let attribute = NSAttributeDescription() + attribute.name = name + attribute.attributeType = type + attribute.isOptional = true + return attribute + } + + private func makeContext( + entities: [NSEntityDescription] + ) throws -> NSManagedObjectContext { + let model = NSManagedObjectModel() + model.entities = entities + let coordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + try coordinator.addPersistentStore( + ofType: NSInMemoryStoreType, + configurationName: nil, + at: nil, + options: nil + ) + let context = NSManagedObjectContext( + concurrencyType: .mainQueueConcurrencyType + ) + context.persistentStoreCoordinator = coordinator + return context + } + +} + +private enum NonPersistableSupportedWalletCorruption: CaseIterable { + case missingMetaId + case missingName + case missingChildAccountId + case missingChildChainId + case missingChildPublicKey + + var identifier: String { + switch self { + case .missingMetaId: + return "missing-meta-id" + case .missingName: + return "missing-name" + case .missingChildAccountId: + return "missing-child-account-id" + case .missingChildChainId: + return "missing-child-chain-id" + case .missingChildPublicKey: + return "missing-child-public-key" + } + } +} + +private struct NonPersistableCorruptionObservation { + let identifier: String + let coreDataRejectsInsert: Bool + let directMapperRejectsAsInvalid: Bool + let recordState: MetaAccountSelectionRecordState + let hasProjectedWallet: Bool + let allowsStoredRecordUpdates: Bool + let replacementUpdatesWalletPayload: Bool + let replacementUpdatesSelection: Bool +} + +private struct MetaAccountMapperTestFixtureError: Error, CustomStringConvertible { + let message: String + + var description: String { + message + } } diff --git a/fearlessTests/Common/Storage/SelectedAccountSettingsTests.swift b/fearlessTests/Common/Storage/SelectedAccountSettingsTests.swift index f98cb97d59..a3d1bd5808 100644 --- a/fearlessTests/Common/Storage/SelectedAccountSettingsTests.swift +++ b/fearlessTests/Common/Storage/SelectedAccountSettingsTests.swift @@ -1,6 +1,9 @@ import XCTest @testable import fearless +import CoreData import RobinHood +import enum SSFModels.CryptoType +import struct SSFModels.ChainAccountModel class SelectedAccountSettingsTests: XCTestCase { func testSelectFirst() throws { @@ -119,4 +122,3846 @@ class SelectedAccountSettingsTests: XCTestCase { XCTAssertEqual(expectedAccounts, actualAccounts) } + + func testSetupWhenWalletsExistWithoutSelectionRepairsDeterministicFallback() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let selectedAccountSettings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + let repository = facade.createRepository( + mapper: AnyCoreDataMapper(ManagedMetaAccountMapper()) + ) + let firstByOrder = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: false, + order: 1 + ) + let laterByOrder = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: false, + order: 2 + ) + + let seedOperation = repository.saveOperation({ + [firstByOrder, laterByOrder] + }, { + [] + }) + operationQueue.addOperations([seedOperation], waitUntilFinished: true) + _ = try XCTUnwrap(seedOperation.result).get() + + let setupExpectation = expectation(description: "missing selection is repaired") + var setupResult: Result? + selectedAccountSettings.setup(runningCompletionIn: .main) { result in + setupResult = result + setupExpectation.fulfill() + } + + wait(for: [setupExpectation], timeout: Constants.defaultExpectationDuration) + + let selectedWallet = try XCTUnwrap(try setupResult?.get()) + XCTAssertEqual(selectedWallet, firstByOrder.info) + XCTAssertEqual(selectedAccountSettings.value, firstByOrder.info) + + let fetchOperation = repository.fetchAllOperation(with: RepositoryFetchOptions()) + operationQueue.addOperations([fetchOperation], waitUntilFinished: true) + let persistedAccounts: [ManagedMetaAccountModel] = try XCTUnwrap(fetchOperation.result).get() + let selectedAccounts = persistedAccounts.filter(\.isSelected) + + XCTAssertEqual(selectedAccounts.map(\.identifier), [firstByOrder.identifier]) + XCTAssertEqual(persistedAccounts.count, 2) + } + + func testSetupToleratesTonOnlyRowAlongsideSelectedValidWalletWithoutChangingEitherPayload() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let selectedAccountSettings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + let validWallet = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: true, + order: 2 + ) + + try seed([validWallet], in: facade, using: operationQueue) + try insertTonOnlyWallet( + identifier: "ton-only-unselected", + isSelected: false, + order: 1, + in: facade, + malformedChainAccount: true + ) + let before = try rawWalletSnapshots(in: facade) + let malformedChainAccountsBefore = try rawChainAccountSnapshots( + walletIdentifier: "ton-only-unselected", + in: facade + ) + + let result = try setup(selectedAccountSettings) + + XCTAssertEqual(result, validWallet.info) + XCTAssertEqual(selectedAccountSettings.value, validWallet.info) + XCTAssertEqual(selectedAccountSettings.storeState, .ready) + XCTAssertEqual(try rawWalletSnapshots(in: facade), before) + XCTAssertEqual( + try rawChainAccountSnapshots( + walletIdentifier: "ton-only-unselected", + in: facade + ), + malformedChainAccountsBefore + ) + } + + func testSetupWithOnlyTonOnlyWalletReportsUnsupportedWithoutMutatingRow() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let selectedAccountSettings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + + try insertTonOnlyWallet( + identifier: "ton-only-selected", + isSelected: true, + order: 1, + in: facade, + malformedChainAccount: true + ) + let before = try rawWalletSnapshots(in: facade) + let malformedChainAccountsBefore = try rawChainAccountSnapshots( + walletIdentifier: "ton-only-selected", + in: facade + ) + + let result = try setup(selectedAccountSettings) + + XCTAssertNil(result) + XCTAssertNil(selectedAccountSettings.value) + XCTAssertEqual(selectedAccountSettings.storeState, .unsupportedOnly) + XCTAssertEqual(try rawWalletSnapshots(in: facade), before) + XCTAssertEqual( + try rawChainAccountSnapshots( + walletIdentifier: "ton-only-selected", + in: facade + ), + malformedChainAccountsBefore + ) + } + + func testStartupQuarantinesMixedCorruptSupportedRowsAndPreservesEveryStoredField() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let settings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + let healthyWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "healthy-wallet" + ) + let corruptions = PersistedSupportedWalletCorruption.allCases + let corruptIdentifiers = corruptions.map { + "corrupt-\($0.identifier)" + } + let corruptOrders = Set( + corruptions.indices.map { Int32($0 + 100) } + ) + + try seed( + [ManagedMetaAccountModel(info: healthyWallet, isSelected: false)], + in: facade, + using: operationQueue + ) + + for (index, corruption) in corruptions.enumerated() { + try insertCorruptSupportedWallet( + identifier: corruptIdentifiers[index], + corruption: corruption, + isSelected: true, + order: Int32(index + 100), + in: facade, + using: operationQueue + ) + } + + let corruptRowsBefore = try rawStoredWalletSnapshots( + orders: corruptOrders, + in: facade + ) + let sortDescriptors = [ + NSSortDescriptor(key: #keyPath(CDMetaAccount.metaId), ascending: true) + ] + let factory = AccountRepositoryFactory(storageFacade: facade) + let repository = factory.createMetaAccountRepository( + for: nil, + sortDescriptors: sortDescriptors + ) + let managedRepository = factory.createManagedMetaAccountRepository( + for: nil, + sortDescriptors: sortDescriptors + ) + let options = RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + let projectionRepository = facade.createRepository( + mapper: AnyCoreDataMapper(MetaAccountSelectionMapper()) + ) + let projections = try execute( + projectionRepository.fetchAllOperation(with: options), + using: operationQueue + ) + let corruptProjections = projections.filter { + $0.recordState == .corrupt + } + + XCTAssertEqual(corruptProjections.count, corruptions.count) + XCTAssertTrue(corruptProjections.allSatisfy { $0.wallet == nil }) + XCTAssertTrue( + corruptProjections.allSatisfy { + !$0.recordState.allowsStoredRecordUpdates + } + ) + XCTAssertTrue( + corruptProjections.allSatisfy { + let replacement = $0.replacingSelection(!$0.isSelected) + return replacement.recordState == .corrupt && + !replacement.updatesWalletPayload && + !replacement.updatesSelection + } + ) + XCTAssertEqual( + try execute( + repository.fetchAllOperation(with: options), + using: operationQueue + ), + [healthyWallet] + ) + XCTAssertEqual( + try execute( + managedRepository.fetchAllOperation(with: options), + using: operationQueue + ).map(\.identifier), + [healthyWallet.identifier] + ) + XCTAssertEqual( + try execute(repository.fetchCountOperation(), using: operationQueue), + 1 + ) + XCTAssertEqual( + try execute( + repository.fetchOperation( + by: { corruptIdentifiers + [healthyWallet.identifier] }, + options: options + ), + using: operationQueue + ), + [healthyWallet] + ) + + for identifier in corruptIdentifiers { + let corruptWallet: MetaAccountModel? = try execute( + repository.fetchOperation( + by: { identifier }, + options: options + ), + using: operationQueue + ) + XCTAssertNil(corruptWallet, "Corrupt row escaped quarantine: \(identifier)") + } + + let asyncExpectation = expectation(description: "corrupt-row tolerant async fetch completes") + var asyncResult: Result<[MetaAccountModel], Error>? + let asyncRepository = factory.createAsyncMetaAccountRepository( + for: nil, + sortDescriptors: sortDescriptors + ) + Task { + do { + asyncResult = .success(try await asyncRepository.fetchAll()) + } catch { + asyncResult = .failure(error) + } + asyncExpectation.fulfill() + } + wait(for: [asyncExpectation], timeout: Constants.defaultExpectationDuration) + XCTAssertEqual(try XCTUnwrap(asyncResult).get(), [healthyWallet]) + + XCTAssertEqual(try setup(settings), healthyWallet) + XCTAssertEqual(settings.value, healthyWallet) + XCTAssertEqual(settings.storeState, .ready) + XCTAssertEqual( + try rawStoredWalletSnapshots( + orders: corruptOrders, + in: facade + ), + corruptRowsBefore + ) + + _ = try execute( + repository.saveOperation({ [] }, { corruptIdentifiers }), + using: operationQueue + ) + _ = try execute( + repository.replaceOperation { [healthyWallet] }, + using: operationQueue + ) + + let collidingWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: corruptIdentifiers[0] + ) + let collisionOperation = repository.saveOperation( + { [collidingWallet] }, + { [] } + ) + operationQueue.addOperations([collisionOperation], waitUntilFinished: true) + XCTAssertThrowsError(try XCTUnwrap(collisionOperation.result).get()) { error in + guard + let settingsError = error as? SelectedWalletSettingsError, + case .unsupportedWalletIdentifierConflict = settingsError + else { + return XCTFail("Unexpected collision error: \(error)") + } + } + + XCTAssertEqual( + try rawStoredWalletSnapshots( + orders: corruptOrders, + in: facade + ), + corruptRowsBefore + ) + XCTAssertEqual( + try execute( + repository.fetchAllOperation(with: options), + using: operationQueue + ), + [healthyWallet] + ) + } + + func testCorruptOnlyStoreReportsUnavailableAndPreservesEveryStoredField() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let settings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + let corruptions: [PersistedSupportedWalletCorruption] = [ + .malformedSubstrateAccountId, + .emptyMetaId, + .whitespaceMetaId, + .emptyName, + .whitespaceName + ] + let corruptOrders = Set( + corruptions.indices.map { Int32($0 + 500) } + ) + + for (index, corruption) in corruptions.enumerated() { + try insertCorruptSupportedWallet( + identifier: "corrupt-only-\(corruption.identifier)", + corruption: corruption, + isSelected: true, + order: Int32(index + 500), + in: facade, + using: operationQueue + ) + } + + let before = try rawStoredWalletSnapshots( + orders: corruptOrders, + in: facade + ) + + XCTAssertNil(try setup(settings)) + XCTAssertNil(settings.value) + XCTAssertEqual(settings.storeState, .unavailable) + XCTAssertEqual( + try rawStoredWalletSnapshots( + orders: corruptOrders, + in: facade + ), + before + ) + } + + func testStructurallyValidUnsupportedWalletKeepsUnsupportedOnlyWithCorruptSibling() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let settings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + + try insertTonOnlyWallet( + identifier: "valid-unsupported-ton-wallet", + isSelected: true, + order: 1, + in: facade, + malformedChainAccount: true + ) + try insertCorruptSupportedWallet( + identifier: "corrupt-supported-sibling", + corruption: .malformedEthereumAddress, + isSelected: true, + order: 700, + in: facade, + using: operationQueue + ) + let parentRowsBefore = try rawWalletSnapshots(in: facade) + let corruptRowBefore = try rawStoredWalletSnapshots( + orders: [700], + in: facade + ) + let tonChildrenBefore = try rawChainAccountSnapshots( + walletIdentifier: "valid-unsupported-ton-wallet", + in: facade + ) + + XCTAssertNil(try setup(settings)) + XCTAssertNil(settings.value) + XCTAssertEqual(settings.storeState, .unsupportedOnly) + XCTAssertEqual(try rawWalletSnapshots(in: facade), parentRowsBefore) + XCTAssertEqual( + try rawStoredWalletSnapshots(orders: [700], in: facade), + corruptRowBefore + ) + XCTAssertEqual( + try rawChainAccountSnapshots( + walletIdentifier: "valid-unsupported-ton-wallet", + in: facade + ), + tonChildrenBefore + ) + } + + func testSetupReplacesSelectedTonOnlyRowWithDeterministicValidFallbackAndPreservesPayloads() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let selectedAccountSettings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + let expectedFallback = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: false, + order: 2 + ) + let laterWallet = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: false, + order: 3 + ) + + // New rows receive their order from the mapper, so insert them separately to make + // the persisted order deterministic instead of relying on a batch's iteration order. + try seed([expectedFallback], in: facade, using: operationQueue) + try seed([laterWallet], in: facade, using: operationQueue) + try insertTonOnlyWallet( + identifier: "ton-only-selected", + isSelected: true, + order: 1, + in: facade + ) + let before = try rawWalletSnapshots(in: facade) + + let result = try setup(selectedAccountSettings) + let after = try rawWalletSnapshots(in: facade) + + XCTAssertEqual(result, expectedFallback.info) + XCTAssertEqual(selectedAccountSettings.value, expectedFallback.info) + XCTAssertEqual(selectedAccountSettings.storeState, .ready) + XCTAssertEqual(after.count, before.count) + XCTAssertEqual( + after.filter(\.isSelected).map(\.identifier), + [expectedFallback.identifier] + ) + + for original in before { + let updated = try XCTUnwrap( + after.first { $0.identifier == original.identifier } + ) + XCTAssertEqual(updated.payload, original.payload) + XCTAssertEqual(updated.order, original.order) + } + } + + func testSaveAfterUnsupportedOnlyAddsValidWalletWithoutOverwritingTonPayload() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let selectedAccountSettings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + + try insertTonOnlyWallet( + identifier: "ton-only-selected", + isSelected: true, + order: 7, + in: facade + ) + let before = try XCTUnwrap(rawWalletSnapshots(in: facade).first) + XCTAssertNil(try setup(selectedAccountSettings)) + XCTAssertEqual(selectedAccountSettings.storeState, .unsupportedOnly) + + let validWallet = AccountGenerator.generateMetaAccount(generatingChainAccounts: 1) + XCTAssertEqual( + try save(validWallet, in: selectedAccountSettings), + validWallet + ) + + let after = try rawWalletSnapshots(in: facade) + let preservedTonWallet = try XCTUnwrap( + after.first { $0.identifier == before.identifier } + ) + let newValidWallet = try XCTUnwrap( + after.first { $0.identifier == validWallet.identifier } + ) + + XCTAssertEqual(after.count, 2) + XCTAssertEqual(preservedTonWallet.payload, before.payload) + XCTAssertEqual(preservedTonWallet.order, before.order) + XCTAssertFalse(preservedTonWallet.isSelected) + XCTAssertTrue(newValidWallet.isSelected) + XCTAssertEqual(selectedAccountSettings.value, validWallet) + XCTAssertEqual(selectedAccountSettings.storeState, .ready) + } + + func testSaveRejectsIdentifierCollisionWithUnsupportedWalletWithoutMutatingStore() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let selectedAccountSettings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + let unsupportedIdentifier = "ton-only-selected" + + try insertTonOnlyWallet( + identifier: unsupportedIdentifier, + isSelected: true, + order: 1, + in: facade + ) + let before = try rawWalletSnapshots(in: facade) + XCTAssertNil(try setup(selectedAccountSettings)) + + let generatedWallet = AccountGenerator.generateMetaAccount(generatingChainAccounts: 1) + let collidingWallet = MetaAccountModel( + metaId: unsupportedIdentifier, + name: generatedWallet.name, + substrateAccountId: generatedWallet.substrateAccountId, + substrateCryptoType: generatedWallet.substrateCryptoType, + substratePublicKey: generatedWallet.substratePublicKey, + ethereumAddress: generatedWallet.ethereumAddress, + ethereumPublicKey: generatedWallet.ethereumPublicKey, + chainAccounts: generatedWallet.chainAccounts, + assetKeysOrder: generatedWallet.assetKeysOrder, + canExportEthereumMnemonic: generatedWallet.canExportEthereumMnemonic, + unusedChainIds: generatedWallet.unusedChainIds, + selectedCurrency: generatedWallet.selectedCurrency, + networkManagmentFilter: generatedWallet.networkManagmentFilter, + assetsVisibility: generatedWallet.assetsVisibility, + hasBackup: generatedWallet.hasBackup, + favouriteChainIds: generatedWallet.favouriteChainIds + ) + + XCTAssertThrowsError( + try save(collidingWallet, in: selectedAccountSettings) + ) { error in + guard + let settingsError = error as? SelectedWalletSettingsError, + case .unsupportedWalletIdentifierConflict = settingsError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertEqual(try rawWalletSnapshots(in: facade), before) + XCTAssertNil(selectedAccountSettings.value) + XCTAssertEqual(selectedAccountSettings.storeState, .unsupportedOnly) + } + + func testAccountRepositoryDeleteAllRemovesSupportedAndUnsupportedWalletsForLogout() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let supportedWallet = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: true + ) + + try seed([supportedWallet], in: facade, using: operationQueue) + try insertTonOnlyWallet( + identifier: "ton-wallet-that-must-be-deleted-on-logout", + isSelected: false, + order: 2, + in: facade + ) + XCTAssertEqual(try rawWalletSnapshots(in: facade).count, 2) + + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository(for: nil, sortDescriptors: []) + let deleteAllOperation = repository.deleteAllOperation() + operationQueue.addOperations([deleteAllOperation], waitUntilFinished: true) + _ = try XCTUnwrap(deleteAllOperation.result).get() + + XCTAssertEqual(try rawWalletSnapshots(in: facade), []) + } + + func testFilteredAccountRepositoryDeleteAllRemainsScopedAndIncludesUnsupportedMatches() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let deletedSupportedWallet = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: true + ) + let retainedSupportedWallet = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: false + ) + + try seed( + [deletedSupportedWallet, retainedSupportedWallet], + in: facade, + using: operationQueue + ) + try insertTonOnlyWallet( + identifier: "deleted-ton-wallet", + isSelected: false, + order: 3, + in: facade + ) + try insertTonOnlyWallet( + identifier: "retained-ton-wallet", + isSelected: false, + order: 4, + in: facade + ) + + let filter = NSPredicate( + format: "%K IN %@", + #keyPath(CDMetaAccount.metaId), + [deletedSupportedWallet.identifier, "deleted-ton-wallet"] + ) + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository(for: filter, sortDescriptors: []) + let deleteAllOperation = repository.deleteAllOperation() + operationQueue.addOperations([deleteAllOperation], waitUntilFinished: true) + _ = try XCTUnwrap(deleteAllOperation.result).get() + + XCTAssertEqual( + try rawWalletSnapshots(in: facade).map(\.identifier), + [retainedSupportedWallet.identifier, "retained-ton-wallet"].sorted() + ) + } + + func testAccountRepositoriesProjectMixedStoreBeforePagingAndSupportAsyncReads() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let generatedFirst = AccountGenerator.generateMetaAccount(generatingChainAccounts: 1) + let generatedSecond = AccountGenerator.generateMetaAccount(generatingChainAccounts: 1) + let firstWallet = copyWallet(generatedFirst, identifier: "a-supported-wallet") + let secondWallet = copyWallet(generatedSecond, identifier: "c-supported-wallet") + + try seed( + [ + ManagedMetaAccountModel(info: firstWallet, isSelected: true), + ManagedMetaAccountModel(info: secondWallet, isSelected: false) + ], + in: facade, + using: operationQueue + ) + try insertTonOnlyWallet( + identifier: "b-ton-wallet", + isSelected: false, + order: 3, + in: facade + ) + let before = try rawWalletSnapshots(in: facade) + let sortDescriptors = [ + NSSortDescriptor(key: #keyPath(CDMetaAccount.metaId), ascending: true) + ] + let factory = AccountRepositoryFactory(storageFacade: facade) + let metaRepository = factory.createMetaAccountRepository( + for: nil, + sortDescriptors: sortDescriptors + ) + let managedRepository = factory.createManagedMetaAccountRepository( + for: nil, + sortDescriptors: sortDescriptors + ) + let options = RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + + let allMetaAccounts = try execute( + metaRepository.fetchAllOperation(with: options), + using: operationQueue + ) + let allManagedAccounts = try execute( + managedRepository.fetchAllOperation(with: options), + using: operationQueue + ) + let firstPage = try execute( + metaRepository.fetchOperation( + by: RepositorySliceRequest(offset: 0, count: 1, reversed: false), + options: options + ), + using: operationQueue + ) + let secondPage = try execute( + metaRepository.fetchOperation( + by: RepositorySliceRequest(offset: 1, count: 1, reversed: false), + options: options + ), + using: operationQueue + ) + let supportedByIdentifier: MetaAccountModel? = try execute( + metaRepository.fetchOperation( + by: { firstWallet.identifier }, + options: options + ), + using: operationQueue + ) + let unsupportedByIdentifier: MetaAccountModel? = try execute( + metaRepository.fetchOperation( + by: { "b-ton-wallet" }, + options: options + ), + using: operationQueue + ) + let mixedByIdentifiers: [MetaAccountModel] = try execute( + metaRepository.fetchOperation( + by: { + [ + firstWallet.identifier, + "b-ton-wallet", + secondWallet.identifier + ] + }, + options: options + ), + using: operationQueue + ) + let count = try execute( + metaRepository.fetchCountOperation(), + using: operationQueue + ) + + XCTAssertEqual( + allMetaAccounts.map(\.identifier), + [firstWallet.identifier, secondWallet.identifier] + ) + XCTAssertEqual( + allManagedAccounts.map(\.identifier), + [firstWallet.identifier, secondWallet.identifier] + ) + XCTAssertEqual(firstPage.map(\.identifier), [firstWallet.identifier]) + XCTAssertEqual(secondPage.map(\.identifier), [secondWallet.identifier]) + XCTAssertEqual(supportedByIdentifier, firstWallet) + XCTAssertNil(unsupportedByIdentifier) + XCTAssertEqual( + mixedByIdentifiers.map(\.identifier), + [firstWallet.identifier, secondWallet.identifier] + ) + XCTAssertEqual(count, 2) + + let asyncExpectation = expectation(description: "async mixed-store fetch completes") + var asyncResult: Result<[MetaAccountModel], Error>? + let asyncRepository = factory.createAsyncMetaAccountRepository( + for: nil, + sortDescriptors: sortDescriptors + ) + Task { + do { + asyncResult = .success(try await asyncRepository.fetchAll()) + } catch { + asyncResult = .failure(error) + } + asyncExpectation.fulfill() + } + + wait(for: [asyncExpectation], timeout: Constants.defaultExpectationDuration) + XCTAssertEqual( + try XCTUnwrap(asyncResult).get().map(\.identifier), + [firstWallet.identifier, secondWallet.identifier] + ) + XCTAssertEqual(try rawWalletSnapshots(in: facade), before) + } + + func testRepositoryPagingSlicesHealthyProjectionAcrossPersistedCorruptRows() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let healthyWallets = [ + copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "b-healthy-first" + ), + copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "d-healthy-second" + ), + copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "e-healthy-third" + ) + ] + let corruptOrders: Set = [800, 801, 802] + + try seed( + healthyWallets.enumerated().map { + ManagedMetaAccountModel( + info: $0.element, + isSelected: $0.offset == 0 + ) + }, + in: facade, + using: operationQueue + ) + try insertCorruptSupportedWallet( + identifier: "a-corrupt-before", + corruption: .malformedSubstrateAccountId, + isSelected: false, + order: 800, + in: facade, + using: operationQueue + ) + try insertCorruptSupportedWallet( + identifier: "c-corrupt-inside", + corruption: .shortChainPublicKey, + isSelected: false, + order: 801, + in: facade, + using: operationQueue + ) + try insertCorruptSupportedWallet( + identifier: "f-corrupt-after", + corruption: .emptyName, + isSelected: false, + order: 802, + in: facade, + using: operationQueue + ) + + let corruptRowsBefore = try rawStoredWalletSnapshots( + orders: corruptOrders, + in: facade + ) + let sortDescriptors = [ + NSSortDescriptor(key: #keyPath(CDMetaAccount.metaId), ascending: true) + ] + let factory = AccountRepositoryFactory(storageFacade: facade) + let repository = factory.createMetaAccountRepository( + for: nil, + sortDescriptors: sortDescriptors + ) + let managedRepository = factory.createManagedMetaAccountRepository( + for: nil, + sortDescriptors: sortDescriptors + ) + let options = RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + + func page( + offset: Int, + count: Int, + reversed: Bool + ) throws -> [String] { + try execute( + repository.fetchOperation( + by: RepositorySliceRequest( + offset: offset, + count: count, + reversed: reversed + ), + options: options + ), + using: operationQueue + ).map(\.identifier) + } + + func managedPage( + offset: Int, + count: Int, + reversed: Bool + ) throws -> [String] { + try execute( + managedRepository.fetchOperation( + by: RepositorySliceRequest( + offset: offset, + count: count, + reversed: reversed + ), + options: options + ), + using: operationQueue + ).map(\.identifier) + } + + let forwardIdentifiers = healthyWallets.map(\.identifier) + let reversedIdentifiers = Array(forwardIdentifiers.reversed()) + + XCTAssertEqual(try page(offset: 0, count: 1, reversed: false), [forwardIdentifiers[0]]) + XCTAssertEqual(try page(offset: 1, count: 1, reversed: false), [forwardIdentifiers[1]]) + XCTAssertEqual(try page(offset: 2, count: 1, reversed: false), [forwardIdentifiers[2]]) + XCTAssertEqual( + try page(offset: 0, count: 2, reversed: false), + Array(forwardIdentifiers.prefix(2)) + ) + XCTAssertEqual( + try page(offset: 1, count: 2, reversed: false), + Array(forwardIdentifiers.dropFirst()) + ) + XCTAssertEqual( + try page(offset: 0, count: Int.max, reversed: false), + forwardIdentifiers + ) + XCTAssertEqual(try page(offset: 0, count: 0, reversed: false), []) + XCTAssertEqual(try page(offset: 3, count: 1, reversed: false), []) + XCTAssertEqual( + try page(offset: Int.max, count: Int.max, reversed: false), + [] + ) + + XCTAssertEqual(try page(offset: 0, count: 1, reversed: true), [reversedIdentifiers[0]]) + XCTAssertEqual(try page(offset: 1, count: 1, reversed: true), [reversedIdentifiers[1]]) + XCTAssertEqual(try page(offset: 2, count: 1, reversed: true), [reversedIdentifiers[2]]) + XCTAssertEqual( + try page(offset: 0, count: 2, reversed: true), + Array(reversedIdentifiers.prefix(2)) + ) + XCTAssertEqual( + try page(offset: 1, count: 2, reversed: true), + Array(reversedIdentifiers.dropFirst()) + ) + XCTAssertEqual(try page(offset: 0, count: 0, reversed: true), []) + XCTAssertEqual(try page(offset: 3, count: 1, reversed: true), []) + + XCTAssertEqual( + try managedPage(offset: 0, count: 3, reversed: false), + forwardIdentifiers + ) + XCTAssertEqual( + try managedPage(offset: 0, count: 3, reversed: true), + reversedIdentifiers + ) + XCTAssertEqual( + try execute(repository.fetchCountOperation(), using: operationQueue), + healthyWallets.count + ) + XCTAssertEqual( + try rawStoredWalletSnapshots(orders: corruptOrders, in: facade), + corruptRowsBefore + ) + } + + func testAccountRepositoryUpdatePreservesUnsupportedPayloadAndWalletMetadata() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let wallet = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: true + ) + + try seed([wallet], in: facade, using: operationQueue) + try insertTonOnlyWallet( + identifier: "ton-wallet-preserved-across-update", + isSelected: false, + order: 17, + in: facade + ) + let before = try rawWalletSnapshots(in: facade) + let walletBefore = try XCTUnwrap( + before.first { $0.identifier == wallet.identifier } + ) + let tonBefore = try XCTUnwrap( + before.first { $0.identifier == "ton-wallet-preserved-across-update" } + ) + let renamedWallet = copyWallet( + wallet.info, + identifier: wallet.identifier, + name: "Renamed without collateral damage" + ) + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository(for: nil, sortDescriptors: []) + + _ = try execute( + repository.saveOperation({ [renamedWallet] }, { [] }), + using: operationQueue + ) + + let after = try rawWalletSnapshots(in: facade) + let walletAfter = try XCTUnwrap( + after.first { $0.identifier == wallet.identifier } + ) + XCTAssertEqual( + after.first { $0.identifier == tonBefore.identifier }, + tonBefore + ) + XCTAssertEqual(walletAfter.order, walletBefore.order) + XCTAssertEqual(walletAfter.isSelected, walletBefore.isSelected) + XCTAssertEqual(walletAfter.payload, walletBefore.payload) + } + + func testAccountRepositoryReplacePreservesUnsupportedRowsAndDeletesOnlySupportedRows() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let removedWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "removed-supported-wallet" + ) + let retainedWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "retained-supported-wallet" + ) + + try seed( + [ + ManagedMetaAccountModel(info: removedWallet, isSelected: true), + ManagedMetaAccountModel(info: retainedWallet, isSelected: false) + ], + in: facade, + using: operationQueue + ) + try insertTonOnlyWallet( + identifier: "preserved-ton-wallet", + isSelected: false, + order: 3, + in: facade + ) + let tonBefore = try XCTUnwrap( + rawWalletSnapshots(in: facade).first { + $0.identifier == "preserved-ton-wallet" + } + ) + let renamedWallet = copyWallet( + retainedWallet, + identifier: retainedWallet.identifier, + name: "Retained and updated" + ) + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository(for: nil, sortDescriptors: []) + + _ = try execute( + repository.replaceOperation { [renamedWallet] }, + using: operationQueue + ) + + let after = try rawWalletSnapshots(in: facade) + XCTAssertNil(after.first { $0.identifier == removedWallet.identifier }) + XCTAssertNotNil(after.first { $0.identifier == renamedWallet.identifier }) + XCTAssertEqual( + after.first { $0.identifier == tonBefore.identifier }, + tonBefore + ) + + let storedWallets = try execute( + repository.fetchAllOperation(with: RepositoryFetchOptions()), + using: operationQueue + ) + XCTAssertEqual(storedWallets, [renamedWallet]) + } + + func testAccountRepositoryRejectsUnsupportedIdentifierCollisionWithoutMutation() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let collidingIdentifier = "existing-ton-wallet" + + try insertTonOnlyWallet( + identifier: collidingIdentifier, + isSelected: true, + order: 1, + in: facade + ) + let before = try rawWalletSnapshots(in: facade) + let collidingWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: collidingIdentifier + ) + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository(for: nil, sortDescriptors: []) + let saveOperation = repository.saveOperation({ [collidingWallet] }, { [] }) + operationQueue.addOperations([saveOperation], waitUntilFinished: true) + + XCTAssertThrowsError(try XCTUnwrap(saveOperation.result).get()) { error in + guard + let settingsError = error as? SelectedWalletSettingsError, + case .unsupportedWalletIdentifierConflict = settingsError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertEqual(try rawWalletSnapshots(in: facade), before) + } + + func testManagedMapperFailsSafelyWhenWalletOrderHasReachedInt32Max() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let existingWallet = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: true + ) + + try seed([existingWallet], in: facade, using: operationQueue) + try setRawWalletOrder( + identifier: existingWallet.identifier, + order: Int32.max, + in: facade + ) + let before = try rawWalletSnapshots(in: facade) + let newWallet = ManagedMetaAccountModel( + info: AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + isSelected: false + ) + let repository = facade.createRepository( + mapper: AnyCoreDataMapper(ManagedMetaAccountMapper()) + ) + let saveOperation = repository.saveOperation({ [newWallet] }, { [] }) + operationQueue.addOperations([saveOperation], waitUntilFinished: true) + + XCTAssertThrowsError(try XCTUnwrap(saveOperation.result).get()) { error in + guard + let mapperError = error as? MetaAccountMapperError, + case .walletOrderOverflow = mapperError + else { + return XCTFail("Unexpected error: \(error)") + } + } + XCTAssertEqual(try rawWalletSnapshots(in: facade), before) + } + + func testSelectionMapperFailsSafelyWhenUnsupportedWalletOrderHasReachedInt32Max() throws { + let operationQueue = OperationQueue() + let facade = UserDataStorageTestFacade() + let selectedAccountSettings = SelectedWalletSettings( + storageFacade: facade, + operationQueue: operationQueue + ) + + try insertTonOnlyWallet( + identifier: "max-order-ton-wallet", + isSelected: true, + order: Int32.max, + in: facade + ) + let before = try rawWalletSnapshots(in: facade) + XCTAssertNil(try setup(selectedAccountSettings)) + XCTAssertEqual(selectedAccountSettings.storeState, .unsupportedOnly) + + XCTAssertThrowsError( + try save( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + in: selectedAccountSettings + ) + ) { error in + guard + let mapperError = error as? MetaAccountMapperError, + case .walletOrderOverflow = mapperError + else { + return XCTFail("Unexpected error: \(error)") + } + } + + XCTAssertEqual(try rawWalletSnapshots(in: facade), before) + XCTAssertNil(selectedAccountSettings.value) + XCTAssertEqual(selectedAccountSettings.storeState, .unsupportedOnly) + } + + func testOutOfOrderSetupCannotOverwriteLatestValueStateOrPersistStaleRepair() throws { + let operationQueue = OperationQueue() + operationQueue.maxConcurrentOperationCount = 8 + let currentFacade = UserDataStorageTestFacade() + let staleFacade = UserDataStorageTestFacade() + let firstWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "first-wallet" + ) + let latestWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "latest-wallet" + ) + + try seed( + [ManagedMetaAccountModel(info: firstWallet, isSelected: false)], + in: currentFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: latestWallet, isSelected: true)], + in: currentFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: firstWallet, isSelected: false)], + in: staleFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: latestWallet, isSelected: false)], + in: staleFacade, + using: operationQueue + ) + + let firstRequest = expectation(description: "first setup reaches Core Data") + let latestRequest = expectation(description: "latest setup reaches Core Data") + let controlledService = ControllableWalletCoreDataService( + configuration: currentFacade.databaseService.configuration, + requestExpectations: [firstRequest, latestRequest] + ) + let controlledFacade = ControllableWalletStorageFacade( + databaseService: controlledService + ) + let settings = SelectedWalletSettings( + storageFacade: controlledFacade, + operationQueue: operationQueue + ) + let staleCompletion = expectation(description: "stale setup completes") + let latestCompletion = expectation(description: "latest setup completes") + var staleResult: Result? + var latestResult: Result? + + settings.setup(runningCompletionIn: .main) { + staleResult = $0 + staleCompletion.fulfill() + } + wait(for: [firstRequest], timeout: Constants.defaultExpectationDuration) + + settings.setup(runningCompletionIn: .main) { + latestResult = $0 + latestCompletion.fulfill() + } + wait(for: [latestRequest], timeout: Constants.defaultExpectationDuration) + + try controlledService.resolveRequest( + at: 1, + using: currentFacade.databaseService + ) + wait(for: [latestCompletion], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(try XCTUnwrap(latestResult).get(), latestWallet) + XCTAssertEqual(settings.value, latestWallet) + XCTAssertEqual(settings.storeState, .ready) + + try controlledService.resolveRequest( + at: 0, + using: staleFacade.databaseService + ) + wait(for: [staleCompletion], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(try XCTUnwrap(staleResult).get(), firstWallet) + XCTAssertEqual(settings.value, latestWallet) + XCTAssertEqual(settings.storeState, .ready) + XCTAssertEqual(controlledService.requestCount, 2) + XCTAssertEqual( + try rawWalletSnapshots(in: currentFacade) + .filter(\.isSelected) + .map(\.identifier), + [latestWallet.identifier] + ) + XCTAssertEqual( + try rawWalletSnapshots(in: staleFacade) + .filter(\.isSelected) + .map(\.identifier), + [] + ) + } + + func testSetupGenerationCannotChangeInsideAtomicValueAndStateCommit() throws { + let operationQueue = OperationQueue() + operationQueue.maxConcurrentOperationCount = 8 + let firstFacade = UserDataStorageTestFacade() + let latestFacade = UserDataStorageTestFacade() + let firstWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "first-wallet" + ) + let latestWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "latest-wallet" + ) + + try seed( + [ManagedMetaAccountModel(info: firstWallet, isSelected: true)], + in: firstFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: latestWallet, isSelected: true)], + in: latestFacade, + using: operationQueue + ) + + let firstFetch = expectation(description: "first setup fetch starts") + let latestFetch = expectation(description: "latest setup waits for atomic commit") + let firstCommitEntered = expectation(description: "first setup begins atomic commit") + let releaseFirstCommit = DispatchSemaphore(value: 0) + let setupPrepared = DispatchSemaphore(value: 0) + let commitCountLock = NSLock() + var commitCount = 0 + let controlledService = ControllableWalletCoreDataService( + configuration: firstFacade.databaseService.configuration, + requestExpectations: [firstFetch, latestFetch] + ) + let settings = SelectedWalletSettings( + storageFacade: ControllableWalletStorageFacade( + databaseService: controlledService + ), + operationQueue: operationQueue, + setupPreparationHook: { + setupPrepared.signal() + }, + setupCommitHook: { + commitCountLock.lock() + commitCount += 1 + let shouldPause = commitCount == 1 + commitCountLock.unlock() + + if shouldPause { + firstCommitEntered.fulfill() + _ = releaseFirstCommit.wait( + timeout: .now() + Constants.defaultExpectationDuration + ) + } + } + ) + let firstCompletion = expectation(description: "first setup completes") + let latestInvocationStarted = expectation(description: "latest setup invocation starts") + let latestCompletion = expectation(description: "latest setup completes") + var firstResult: Result? + var latestResult: Result? + + settings.setup(runningCompletionIn: .main) { + firstResult = $0 + firstCompletion.fulfill() + } + XCTAssertEqual( + setupPrepared.wait( + timeout: .now() + Constants.defaultExpectationDuration + ), + .success + ) + wait(for: [firstFetch], timeout: Constants.defaultExpectationDuration) + try controlledService.resolveRequest( + at: 0, + using: firstFacade.databaseService + ) + wait(for: [firstCommitEntered], timeout: Constants.defaultExpectationDuration) + + DispatchQueue.global().async { + latestInvocationStarted.fulfill() + settings.setup(runningCompletionIn: .main) { + latestResult = $0 + latestCompletion.fulfill() + } + } + wait(for: [latestInvocationStarted], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual( + setupPrepared.wait(timeout: .now() + 0.2), + .timedOut + ) + XCTAssertEqual(controlledService.requestCount, 1) + + releaseFirstCommit.signal() + wait( + for: [firstCompletion, latestFetch], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual( + setupPrepared.wait( + timeout: .now() + Constants.defaultExpectationDuration + ), + .success + ) + + try controlledService.resolveRequest( + at: 1, + using: latestFacade.databaseService + ) + wait(for: [latestCompletion], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(try XCTUnwrap(firstResult).get(), firstWallet) + XCTAssertEqual(try XCTUnwrap(latestResult).get(), latestWallet) + XCTAssertEqual(settings.value, latestWallet) + XCTAssertEqual(settings.storeState, .ready) + XCTAssertEqual(controlledService.requestCount, 2) + } + + func testConcurrentSavesAreSerializedAndOlderFailureCannotRollbackLatestSelection() throws { + let operationQueue = OperationQueue() + operationQueue.maxConcurrentOperationCount = 8 + let sourceFacade = UserDataStorageTestFacade() + let initialWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "initial-wallet" + ) + let olderWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "older-wallet" + ) + let latestWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "latest-wallet" + ) + + try seed( + [ManagedMetaAccountModel(info: initialWallet, isSelected: true)], + in: sourceFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: olderWallet, isSelected: false)], + in: sourceFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: latestWallet, isSelected: false)], + in: sourceFacade, + using: operationQueue + ) + + let olderFetch = expectation(description: "older save fetch starts") + let latestFetch = expectation(description: "latest save waits then fetches") + let latestPersist = expectation(description: "latest save persists") + let controlledService = ControllableWalletCoreDataService( + configuration: sourceFacade.databaseService.configuration, + requestExpectations: [olderFetch, latestFetch, latestPersist] + ) + let settings = SelectedWalletSettings( + storageFacade: ControllableWalletStorageFacade( + databaseService: controlledService + ), + operationQueue: operationQueue + ) + let olderCompletion = expectation(description: "older save fails") + let latestCompletion = expectation(description: "latest save succeeds") + var olderResult: Result? + var latestResult: Result? + + settings.save(value: olderWallet, runningCompletionIn: .main) { + olderResult = $0 + olderCompletion.fulfill() + } + wait(for: [olderFetch], timeout: Constants.defaultExpectationDuration) + + settings.save(value: latestWallet, runningCompletionIn: .main) { + latestResult = $0 + latestCompletion.fulfill() + } + + XCTAssertEqual(settings.value, latestWallet) + XCTAssertEqual(controlledService.requestCount, 1) + + try controlledService.failRequest( + at: 0, + with: ControllableWalletCoreDataServiceError.injectedFailure + ) + wait( + for: [olderCompletion, latestFetch], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertThrowsError(try XCTUnwrap(olderResult).get()) + XCTAssertEqual(settings.value, latestWallet) + + try controlledService.resolveRequest( + at: 1, + using: sourceFacade.databaseService + ) + wait(for: [latestPersist], timeout: Constants.defaultExpectationDuration) + try controlledService.resolveRequest( + at: 2, + using: sourceFacade.databaseService + ) + wait(for: [latestCompletion], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(try XCTUnwrap(latestResult).get(), latestWallet) + XCTAssertEqual(settings.value, latestWallet) + XCTAssertEqual(settings.storeState, .ready) + XCTAssertEqual(controlledService.requestCount, 3) + XCTAssertEqual( + try rawWalletSnapshots(in: sourceFacade) + .filter(\.isSelected) + .map(\.identifier), + [latestWallet.identifier] + ) + } + + func testSaveInvalidatesOlderSetupBeforeItCanCommitOrRepairSelection() throws { + let operationQueue = OperationQueue() + operationQueue.maxConcurrentOperationCount = 8 + let currentFacade = UserDataStorageTestFacade() + let staleFacade = UserDataStorageTestFacade() + let firstWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "first-wallet" + ) + let savedWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "saved-wallet" + ) + + try seed( + [ManagedMetaAccountModel(info: firstWallet, isSelected: true)], + in: currentFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: savedWallet, isSelected: false)], + in: currentFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: firstWallet, isSelected: false)], + in: staleFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: savedWallet, isSelected: false)], + in: staleFacade, + using: operationQueue + ) + + let setupFetch = expectation(description: "setup fetch starts") + let saveFetch = expectation(description: "save fetch starts") + let savePersist = expectation(description: "save persists") + let controlledService = ControllableWalletCoreDataService( + configuration: currentFacade.databaseService.configuration, + requestExpectations: [setupFetch, saveFetch, savePersist] + ) + let settings = SelectedWalletSettings( + storageFacade: ControllableWalletStorageFacade( + databaseService: controlledService + ), + operationQueue: operationQueue + ) + let setupCompletion = expectation(description: "stale setup completes") + let saveCompletion = expectation(description: "save completes") + var setupResult: Result? + var saveResult: Result? + + settings.setup(runningCompletionIn: .main) { + setupResult = $0 + setupCompletion.fulfill() + } + wait(for: [setupFetch], timeout: Constants.defaultExpectationDuration) + + settings.save(value: savedWallet, runningCompletionIn: .main) { + saveResult = $0 + saveCompletion.fulfill() + } + wait(for: [saveFetch], timeout: Constants.defaultExpectationDuration) + + try controlledService.resolveRequest( + at: 1, + using: currentFacade.databaseService + ) + wait(for: [savePersist], timeout: Constants.defaultExpectationDuration) + try controlledService.resolveRequest( + at: 2, + using: currentFacade.databaseService + ) + wait(for: [saveCompletion], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(try XCTUnwrap(saveResult).get(), savedWallet) + XCTAssertEqual(settings.value, savedWallet) + XCTAssertEqual(settings.storeState, .ready) + + try controlledService.resolveRequest( + at: 0, + using: staleFacade.databaseService + ) + wait(for: [setupCompletion], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(try XCTUnwrap(setupResult).get(), firstWallet) + XCTAssertEqual(settings.value, savedWallet) + XCTAssertEqual(settings.storeState, .ready) + XCTAssertEqual(controlledService.requestCount, 3) + XCTAssertEqual( + try rawWalletSnapshots(in: currentFacade) + .filter(\.isSelected) + .map(\.identifier), + [savedWallet.identifier] + ) + XCTAssertEqual( + try rawWalletSnapshots(in: staleFacade) + .filter(\.isSelected) + .map(\.identifier), + [] + ) + } + + func testSetupStartedDuringSaveWaitsForPersistenceAndCannotReadStaleSelection() throws { + let asynchronousTimeout = + Constants.defaultExpectationDuration * 4 + let operationQueue = OperationQueue() + operationQueue.maxConcurrentOperationCount = 8 + let sourceFacade = UserDataStorageTestFacade() + let initialWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "initial-wallet" + ) + let savedWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "saved-wallet" + ) + + try seed( + [ManagedMetaAccountModel(info: initialWallet, isSelected: true)], + in: sourceFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: savedWallet, isSelected: false)], + in: sourceFacade, + using: operationQueue + ) + + let saveFetch = expectation(description: "save fetch starts") + let savePersist = expectation(description: "save persists") + let setupFetch = expectation(description: "setup starts after save") + let controlledService = ControllableWalletCoreDataService( + configuration: sourceFacade.databaseService.configuration, + requestExpectations: [saveFetch, savePersist, setupFetch] + ) + let settings = SelectedWalletSettings( + storageFacade: ControllableWalletStorageFacade( + databaseService: controlledService + ), + operationQueue: operationQueue + ) + let saveCompletion = expectation(description: "save completes") + let setupCompletion = expectation(description: "setup completes") + var saveResult: Result? + var setupResult: Result? + + settings.save(value: savedWallet, runningCompletionIn: .main) { + saveResult = $0 + saveCompletion.fulfill() + } + wait(for: [saveFetch], timeout: asynchronousTimeout) + + settings.setup(runningCompletionIn: .main) { + setupResult = $0 + setupCompletion.fulfill() + } + + XCTAssertEqual(controlledService.requestCount, 1) + XCTAssertEqual(settings.value, savedWallet) + + try controlledService.resolveRequest( + at: 0, + using: sourceFacade.databaseService + ) + wait(for: [savePersist], timeout: asynchronousTimeout) + try controlledService.resolveRequest( + at: 1, + using: sourceFacade.databaseService + ) + wait( + for: [saveCompletion, setupFetch], + timeout: asynchronousTimeout + ) + + XCTAssertEqual(try XCTUnwrap(saveResult).get(), savedWallet) + try controlledService.resolveRequest( + at: 2, + using: sourceFacade.databaseService + ) + wait(for: [setupCompletion], timeout: asynchronousTimeout) + + XCTAssertEqual(try XCTUnwrap(setupResult).get(), savedWallet) + XCTAssertEqual(settings.value, savedWallet) + XCTAssertEqual(settings.storeState, .ready) + XCTAssertEqual( + try rawWalletSnapshots(in: sourceFacade) + .filter(\.isSelected) + .map(\.identifier), + [savedWallet.identifier] + ) + } + + func testSaveRegistrationIsAtomicAgainstSetupAtPreparationBoundary() throws { + let operationQueue = OperationQueue() + operationQueue.maxConcurrentOperationCount = 8 + let sourceFacade = UserDataStorageTestFacade() + let initialWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "initial-wallet" + ) + let savedWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "saved-wallet" + ) + + try seed( + [ManagedMetaAccountModel(info: initialWallet, isSelected: true)], + in: sourceFacade, + using: operationQueue + ) + try seed( + [ManagedMetaAccountModel(info: savedWallet, isSelected: false)], + in: sourceFacade, + using: operationQueue + ) + + let saveFetch = expectation(description: "save fetch starts") + let savePersist = expectation(description: "save persists") + let setupFetch = expectation(description: "setup fetch waits for persistence") + let savePrepared = expectation(description: "save invalidates setup generation") + let setupPrepared = expectation(description: "setup replaces generation during paused save") + let releaseSavePreparation = DispatchSemaphore(value: 0) + let controlledService = ControllableWalletCoreDataService( + configuration: sourceFacade.databaseService.configuration, + requestExpectations: [saveFetch, savePersist, setupFetch] + ) + let settings = SelectedWalletSettings( + storageFacade: ControllableWalletStorageFacade( + databaseService: controlledService + ), + operationQueue: operationQueue, + savePreparationHook: { + savePrepared.fulfill() + _ = releaseSavePreparation.wait( + timeout: .now() + Constants.defaultExpectationDuration + ) + }, + setupPreparationHook: { + setupPrepared.fulfill() + } + ) + let saveInvocationReturned = expectation(description: "save invocation returns") + let setupInvocationReturned = expectation(description: "setup invocation returns") + let saveCompletion = expectation(description: "save completes") + let setupCompletion = expectation(description: "setup completes") + var saveResult: Result? + var setupResult: Result? + + DispatchQueue.global().async { + settings.save(value: savedWallet, runningCompletionIn: .main) { + saveResult = $0 + saveCompletion.fulfill() + } + saveInvocationReturned.fulfill() + } + wait(for: [savePrepared], timeout: Constants.defaultExpectationDuration) + + DispatchQueue.global().async { + settings.setup(runningCompletionIn: .main) { + setupResult = $0 + setupCompletion.fulfill() + } + setupInvocationReturned.fulfill() + } + wait(for: [setupPrepared], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(controlledService.requestCount, 0) + + releaseSavePreparation.signal() + wait( + for: [saveFetch, saveInvocationReturned, setupInvocationReturned], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual(controlledService.requestCount, 1) + XCTAssertEqual(settings.value, savedWallet) + + try controlledService.resolveRequest( + at: 0, + using: sourceFacade.databaseService + ) + wait(for: [savePersist], timeout: Constants.defaultExpectationDuration) + try controlledService.resolveRequest( + at: 1, + using: sourceFacade.databaseService + ) + wait( + for: [saveCompletion, setupFetch], + timeout: Constants.defaultExpectationDuration + ) + + try controlledService.resolveRequest( + at: 2, + using: sourceFacade.databaseService + ) + wait(for: [setupCompletion], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(try XCTUnwrap(saveResult).get(), savedWallet) + XCTAssertEqual(try XCTUnwrap(setupResult).get(), savedWallet) + XCTAssertEqual(settings.value, savedWallet) + XCTAssertEqual(settings.storeState, .ready) + XCTAssertEqual(controlledService.requestCount, 3) + XCTAssertEqual( + try rawWalletSnapshots(in: sourceFacade) + .filter(\.isSelected) + .map(\.identifier), + [savedWallet.identifier] + ) + } + + func testSetupValueAndStoreStateCommitAtomicallyAgainstSaveRegistration() throws { + let operationQueue = OperationQueue() + operationQueue.maxConcurrentOperationCount = 8 + let sourceFacade = UserDataStorageTestFacade() + let savedWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "saved-wallet" + ) + + try insertTonOnlyWallet( + identifier: "unsupported-ton-wallet", + isSelected: true, + order: 0, + in: sourceFacade + ) + + let setupFetch = expectation(description: "setup fetch starts") + let saveFetch = expectation(description: "save fetch waits for setup commit") + let savePersist = expectation(description: "save persists") + let setupCommitEntered = expectation(description: "setup begins atomic commit") + let releaseSetupCommit = DispatchSemaphore(value: 0) + let savePreparationReached = DispatchSemaphore(value: 0) + let controlledService = ControllableWalletCoreDataService( + configuration: sourceFacade.databaseService.configuration, + requestExpectations: [setupFetch, saveFetch, savePersist] + ) + let settings = SelectedWalletSettings( + storageFacade: ControllableWalletStorageFacade( + databaseService: controlledService + ), + operationQueue: operationQueue, + savePreparationHook: { + savePreparationReached.signal() + }, + setupCommitHook: { + setupCommitEntered.fulfill() + _ = releaseSetupCommit.wait( + timeout: .now() + Constants.defaultExpectationDuration + ) + } + ) + let setupCompletion = expectation(description: "setup completes") + let saveInvocationStarted = expectation(description: "save invocation starts") + let saveCompletion = expectation(description: "save completes") + var setupResult: Result? + var saveResult: Result? + + settings.setup(runningCompletionIn: .main) { + setupResult = $0 + setupCompletion.fulfill() + } + wait(for: [setupFetch], timeout: Constants.defaultExpectationDuration) + try controlledService.resolveRequest( + at: 0, + using: sourceFacade.databaseService + ) + wait(for: [setupCommitEntered], timeout: Constants.defaultExpectationDuration) + + DispatchQueue.global().async { + saveInvocationStarted.fulfill() + settings.save(value: savedWallet, runningCompletionIn: .main) { + saveResult = $0 + saveCompletion.fulfill() + } + } + wait(for: [saveInvocationStarted], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual( + savePreparationReached.wait(timeout: .now() + 0.2), + .timedOut + ) + XCTAssertEqual(controlledService.requestCount, 1) + + releaseSetupCommit.signal() + wait( + for: [setupCompletion, saveFetch], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertNil(try XCTUnwrap(setupResult).get()) + XCTAssertEqual(settings.storeState, .unsupportedOnly) + XCTAssertEqual( + savePreparationReached.wait( + timeout: .now() + Constants.defaultExpectationDuration + ), + .success + ) + + try controlledService.resolveRequest( + at: 1, + using: sourceFacade.databaseService + ) + wait(for: [savePersist], timeout: Constants.defaultExpectationDuration) + try controlledService.resolveRequest( + at: 2, + using: sourceFacade.databaseService + ) + wait(for: [saveCompletion], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(try XCTUnwrap(saveResult).get(), savedWallet) + XCTAssertEqual(settings.value, savedWallet) + XCTAssertEqual(settings.storeState, .ready) + XCTAssertEqual(controlledService.requestCount, 3) + XCTAssertEqual( + try rawWalletSnapshots(in: sourceFacade) + .filter(\.isSelected) + .map(\.identifier), + [savedWallet.identifier] + ) + } + + func testTolerantFactoriesAndStreamsIgnoreCorruptSelectedSiblingAndKeepObservingValidWallet() throws { + try assertTolerantObservableReconcilesEveryObserverGap() + try assertTolerantObservableReconcilesTransientIdentifier() + try assertTolerantObservableAggregatesSameIdentifierHandoffs() + + let facade = UserDataStorageTestFacade() + let repositoryQueue = OperationQueue() + let validWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "provider-valid-wallet", + name: "Provider Valid Wallet" + ) + let transitionWallet = copyWallet( + validWallet, + identifier: "provider-valid-to-corrupt-wallet", + name: "Provider Transition Wallet" + ) + let corruptIdentifier = "provider-corrupt-wallet" + let corruptIdentifiers = Set([corruptIdentifier]) + + try seed( + [ + ManagedMetaAccountModel(info: validWallet, isSelected: true), + ManagedMetaAccountModel(info: transitionWallet, isSelected: true) + ], + in: facade, + using: repositoryQueue + ) + + try performCoreData(in: facade) { context in + let corruptWallet = self.copyWallet( + validWallet, + identifier: corruptIdentifier, + name: "Provider Corrupt Wallet" + ) + let entity = CDMetaAccount(context: context) + try MetaAccountMapper().populate( + entity: entity, + from: corruptWallet, + using: context + ) + entity.isSelected = true + entity.order = 900 + entity.name = "" + let child = try XCTUnwrap( + entity.chainAccounts?.allObjects.first as? CDChainAccount + ) + // The account-ID provider must match this corrupt row through its child + // relationship, not merely through the primary account columns. + child.accountId = validWallet.substrateAccountId.toHex() + + // A structurally corrupt sibling with the same persistent identifier must + // not make the healthy row disappear from tolerant reads. + let duplicateWallet = self.copyWallet( + validWallet, + identifier: validWallet.identifier, + name: "Provider Duplicate Corrupt Wallet" + ) + let duplicateEntity = CDMetaAccount(context: context) + try MetaAccountMapper().populate( + entity: duplicateEntity, + from: duplicateWallet, + using: context + ) + duplicateEntity.isSelected = true + duplicateEntity.order = 899 + duplicateEntity.name = "" + let duplicateChild = try XCTUnwrap( + duplicateEntity.chainAccounts?.allObjects.first as? CDChainAccount + ) + duplicateChild.accountId = validWallet.substrateAccountId.toHex() + try context.save() + } + + let accountRepositoryFactory = AccountRepositoryFactory(storageFacade: facade) + let metaRepository = accountRepositoryFactory.createMetaAccountRepository( + for: nil, + sortDescriptors: [] + ) + let managedRepository = accountRepositoryFactory.createManagedMetaAccountRepository( + for: NSPredicate.selectedMetaAccount(), + sortDescriptors: [] + ) + + XCTAssertEqual( + Set(try execute( + metaRepository.fetchAllOperation( + with: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ), + using: repositoryQueue + ).map(\.identifier)), + Set([validWallet.identifier, transitionWallet.identifier]) + ) + XCTAssertEqual( + Set(try execute( + managedRepository.fetchAllOperation( + with: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ), + using: repositoryQueue + ).map(\.identifier)), + Set([validWallet.identifier, transitionWallet.identifier]) + ) + + let operationManager = OperationManager() + let providerFactory = AccountProviderFactory( + storageFacade: facade, + operationManager: operationManager + ) + let accountProvider = providerFactory.createStreambleProvider( + for: validWallet.substrateAccountId + ) + let managedProvider = providerFactory.createManagedMetaAccountProvider( + for: NSPredicate.selectedMetaAccount(), + sortDescriptors: [] + ) + let accountObserver = NSObject() + let managedObserver = NSObject() + let accountInitial = expectation(description: "account stream returns healthy initial wallet") + let managedInitial = expectation(description: "managed stream returns healthy initial wallet") + let accountUpdate = expectation(description: "account stream observes healthy update") + let managedUpdate = expectation(description: "managed stream observes healthy update") + let accountTransitionDelete = expectation( + description: "account stream removes a wallet that becomes corrupt" + ) + let managedTransitionDelete = expectation( + description: "managed stream removes a wallet that becomes corrupt" + ) + let accountTransitionRestore = expectation( + description: "account stream reinserts a repaired wallet" + ) + let managedTransitionRestore = expectation( + description: "managed stream reinserts a repaired wallet" + ) + let updatedName = "Provider Valid Wallet Updated" + let restoredName = "Provider Transition Wallet Restored" + var accountInitialDelivered = false + var managedInitialDelivered = false + + accountProvider.addObserver( + accountObserver, + deliverOn: .main, + executing: { changes in + let wallets = changes.compactMap { change -> MetaAccountModel? in + switch change { + case let .insert(newItem), let .update(newItem): + return newItem + case let .delete(deletedIdentifier): + if deletedIdentifier == transitionWallet.identifier { + accountTransitionDelete.fulfill() + } + if deletedIdentifier == validWallet.identifier { + XCTFail("A corrupt duplicate deleted the healthy account stream item") + } + return nil + } + } + + XCTAssertTrue( + wallets.allSatisfy { + !corruptIdentifiers.contains($0.identifier) + } + ) + if wallets.contains(where: { $0.name == updatedName }) { + accountUpdate.fulfill() + } else if wallets.contains(where: { $0.name == restoredName }) { + accountTransitionRestore.fulfill() + } else if !accountInitialDelivered { + accountInitialDelivered = true + XCTAssertEqual( + Set(wallets.map(\.identifier)), + Set([validWallet.identifier, transitionWallet.identifier]) + ) + accountInitial.fulfill() + } + }, + failing: { error in + XCTFail("Account stream failed beside a corrupt sibling: \(error)") + }, + options: StreamableProviderObserverOptions(refreshWhenEmpty: false) + ) + managedProvider.addObserver( + managedObserver, + deliverOn: .main, + executing: { changes in + let wallets = changes.compactMap { change -> ManagedMetaAccountModel? in + switch change { + case let .insert(newItem), let .update(newItem): + return newItem + case let .delete(deletedIdentifier): + if deletedIdentifier == transitionWallet.identifier { + managedTransitionDelete.fulfill() + } + if deletedIdentifier == validWallet.identifier { + XCTFail("A corrupt duplicate deleted the healthy managed stream item") + } + return nil + } + } + + XCTAssertTrue( + wallets.allSatisfy { + !corruptIdentifiers.contains($0.identifier) + } + ) + if wallets.contains(where: { $0.info.name == updatedName }) { + managedUpdate.fulfill() + } else if wallets.contains(where: { $0.info.name == restoredName }) { + managedTransitionRestore.fulfill() + } else if !managedInitialDelivered { + managedInitialDelivered = true + XCTAssertEqual( + Set(wallets.map(\.identifier)), + Set([validWallet.identifier, transitionWallet.identifier]) + ) + XCTAssertTrue(wallets.allSatisfy(\.isSelected)) + managedInitial.fulfill() + } + }, + failing: { error in + XCTFail("Managed wallet stream failed beside a corrupt sibling: \(error)") + }, + options: StreamableProviderObserverOptions(refreshWhenEmpty: false) + ) + + wait( + for: [accountInitial, managedInitial], + timeout: Constants.defaultExpectationDuration + ) + + // The observable tracks validity per Core Data object, so invalidating one + // previously valid wallet emits a delete and repairing it emits an insert. + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K == %@", + #keyPath(CDMetaAccount.metaId), + transitionWallet.identifier + ) + let entity = try XCTUnwrap(context.fetch(request).first) + entity.name = " \n\t " + try context.save() + } + wait( + for: [accountTransitionDelete, managedTransitionDelete], + timeout: Constants.defaultExpectationDuration + ) + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K == %@", + #keyPath(CDMetaAccount.metaId), + transitionWallet.identifier + ) + let entity = try XCTUnwrap(context.fetch(request).first) + entity.name = restoredName + try context.save() + } + wait( + for: [accountTransitionRestore, managedTransitionRestore], + timeout: Constants.defaultExpectationDuration + ) + + // Exercise update and delete notifications for a pre-existing corrupt duplicate. + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K == %@", + #keyPath(CDMetaAccount.metaId), + validWallet.identifier + ) + let entity = try XCTUnwrap( + context.fetch(request).first { + ($0.name ?? "").trimmingCharacters( + in: .whitespacesAndNewlines + ).isEmpty + } + ) + entity.name = " \n\t " + try context.save() + context.delete(entity) + try context.save() + } + + try performCoreData(in: facade) { context in + let insertedCorruptWallet = self.copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: validWallet.identifier, + name: "Inserted Corrupt Wallet" + ) + let entity = CDMetaAccount(context: context) + try MetaAccountMapper().populate( + entity: entity, + from: insertedCorruptWallet, + using: context + ) + entity.isSelected = true + entity.order = 901 + entity.name = "" + let child = try XCTUnwrap( + entity.chainAccounts?.allObjects.first as? CDChainAccount + ) + child.accountId = validWallet.substrateAccountId.toHex() + try context.save() + + // Exercise an update notification for the same still-corrupt matching row. + entity.name = " \n\t " + try context.save() + + // A corrupt duplicate was never tracked as valid, so its raw identifier + // must not be emitted as a delete for the healthy sibling. + context.delete(entity) + try context.save() + } + + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K == %@", + #keyPath(CDMetaAccount.metaId), + validWallet.identifier + ) + let entity = try XCTUnwrap( + context.fetch(request).first { + $0.name == validWallet.name + } + ) + entity.name = updatedName + try context.save() + } + + wait( + for: [accountUpdate, managedUpdate], + timeout: Constants.defaultExpectationDuration + ) + accountProvider.removeObserver(accountObserver) + managedProvider.removeObserver(managedObserver) + + let corruptProjections = try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K IN %@", + #keyPath(CDMetaAccount.metaId), + Array(corruptIdentifiers) + ) + return try context.fetch(request).map { + try MetaAccountSelectionMapper().transform(entity: $0) + } + } + XCTAssertEqual(corruptProjections.count, corruptIdentifiers.count) + XCTAssertTrue(corruptProjections.allSatisfy { $0.recordState == .corrupt }) + XCTAssertTrue(corruptProjections.allSatisfy { $0.wallet == nil }) + } + + private func assertTolerantObservableReconcilesEveryObserverGap() throws { + let facade = UserDataStorageTestFacade() + let repositoryQueue = OperationQueue() + let processingQueue = DispatchQueue( + label: "jp.co.fearless.wallet-observable.observer-gap-test" + ) + let wallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "observer-gap-wallet", + name: "Observer Gap Wallet" + ) + try seed( + [ManagedMetaAccountModel(info: wallet, isSelected: true)], + in: facade, + using: repositoryQueue + ) + + let observable = TolerantMetaAccountContextObservable( + service: facade.databaseService, + mapper: AnyCoreDataMapper(ManagedMetaAccountMapper()), + predicate: { _ in true }, + processingQueue: processingQueue + ) + let startExpectation = expectation(description: "gap observable starts") + observable.start { error in + XCTAssertNil(error) + startExpectation.fulfill() + } + wait(for: [startExpectation], timeout: Constants.defaultExpectationDuration) + + func updateWalletName(_ name: String) throws { + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K == %@", + #keyPath(CDMetaAccount.metaId), + wallet.identifier + ) + let entity = try XCTUnwrap(context.fetch(request).first) + entity.name = name + try context.save() + } + processingQueue.sync {} + } + + // Reconcile the exact activation race: valid -> corrupt -> valid completes + // after start but before RobinHood asynchronously registers its observer. + try updateWalletName(" \n\t ") + let restoredName = "Observer Gap Wallet Restored" + try updateWalletName(restoredName) + + let firstObserver = NSObject() + let firstReconciliationExpectation = expectation( + description: "pre-registration final state is reconciled" + ) + var firstBatch: [DataProviderChange] = [] + observable.addObserver( + firstObserver, + deliverOn: .main, + executing: { changes in + firstBatch = changes + firstReconciliationExpectation.fulfill() + } + ) + wait( + for: [firstReconciliationExpectation], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(firstBatch.count, 2) + if case let .delete(identifier)? = firstBatch.first { + XCTAssertEqual(identifier, wallet.identifier) + } else { + XCTFail("Reconciliation must invalidate the provider's stale snapshot") + } + if case let .insert(model)? = firstBatch.last { + XCTAssertEqual(model.identifier, wallet.identifier) + XCTAssertEqual(model.info.name, restoredName) + } else { + XCTFail("Reconciliation must finish with the current healthy wallet") + } + + observable.removeObserver(firstObserver) + processingQueue.sync {} + + let oldDeliveryQueue = DispatchQueue( + label: "jp.co.fearless.wallet-observable.old-delivery-test" + ) + let newDeliveryQueue = DispatchQueue( + label: "jp.co.fearless.wallet-observable.new-delivery-test" + ) + let oldDeliveryBlockStarted = DispatchSemaphore(value: 0) + let newDeliveryBlockStarted = DispatchSemaphore(value: 0) + let releaseOldDelivery = DispatchSemaphore(value: 0) + let releaseNewDelivery = DispatchSemaphore(value: 0) + defer { + releaseOldDelivery.signal() + releaseNewDelivery.signal() + } + oldDeliveryQueue.async { + oldDeliveryBlockStarted.signal() + releaseOldDelivery.wait() + } + newDeliveryQueue.async { + newDeliveryBlockStarted.signal() + releaseNewDelivery.wait() + } + XCTAssertEqual( + oldDeliveryBlockStarted.wait( + timeout: .now() + Constants.defaultExpectationDuration + ), + .success + ) + XCTAssertEqual( + newDeliveryBlockStarted.wait( + timeout: .now() + Constants.defaultExpectationDuration + ), + .success + ) + + let teardownObserver = NSObject() + observable.addObserver( + teardownObserver, + deliverOn: oldDeliveryQueue, + executing: { _ in } + ) + processingQueue.sync {} + + // Model StreamableProvider's teardown race deterministically. The source + // callback is already in flight when the provider loses its last user. + // Removal remains asynchronous, and the repair mutation happens without + // draining that removal first. + try updateWalletName("") + observable.removeObserver(teardownObserver) + let resubscribedName = "Observer Gap Wallet Resubscribed" + try updateWalletName(resubscribedName) + + // Re-add the identical observer while its old-generation callback is + // blocked, then independently block the new-generation reconciliation. + // Finishing the old callback must only acknowledge its unique delivery. + var blockedNewGenerationBatch: [ + DataProviderChange + ] = [] + observable.addObserver( + teardownObserver, + deliverOn: newDeliveryQueue, + executing: { changes in + blockedNewGenerationBatch = changes + } + ) + processingQueue.sync {} + releaseOldDelivery.signal() + oldDeliveryQueue.sync {} + processingQueue.sync {} + + // A second removal must still repend the independently in-flight new + // generation, proving an old completion cannot ABA-clear its state. + observable.removeObserver(teardownObserver) + processingQueue.sync {} + + let abaReconciliationExpectation = expectation( + description: "same observer generation is reconciled independently" + ) + var abaBatch: [DataProviderChange] = [] + observable.addObserver( + teardownObserver, + deliverOn: .main, + executing: { changes in + abaBatch = changes + abaReconciliationExpectation.fulfill() + } + ) + wait( + for: [abaReconciliationExpectation], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(abaBatch.count, 2) + if case let .delete(identifier)? = abaBatch.first { + XCTAssertEqual(identifier, wallet.identifier) + } else { + XCTFail("Resubscription reconciliation must begin with a delete") + } + if case let .insert(model)? = abaBatch.last { + XCTAssertEqual(model.identifier, wallet.identifier) + XCTAssertEqual(model.info.name, resubscribedName) + } else { + XCTFail("Resubscription must finish with the current healthy wallet") + } + + releaseNewDelivery.signal() + newDeliveryQueue.sync {} + processingQueue.sync {} + XCTAssertEqual(blockedNewGenerationBatch.count, 2) + observable.removeObserver(teardownObserver) + processingQueue.sync {} + let stopExpectation = expectation(description: "gap observable stops") + observable.stop { error in + XCTAssertNil(error) + stopExpectation.fulfill() + } + wait(for: [stopExpectation], timeout: Constants.defaultExpectationDuration) + } + + private func assertTolerantObservableReconcilesTransientIdentifier() throws { + let facade = UserDataStorageTestFacade() + let processingQueue = DispatchQueue( + label: "jp.co.fearless.wallet-observable.transient-test" + ) + let wallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "transient-observer-gap-wallet", + name: "Transient Observer Gap Wallet" + ) + let observable = TolerantMetaAccountContextObservable( + service: facade.databaseService, + mapper: AnyCoreDataMapper(ManagedMetaAccountMapper()), + predicate: { _ in true }, + processingQueue: processingQueue + ) + let startExpectation = expectation(description: "transient observable starts") + observable.start { error in + XCTAssertNil(error) + startExpectation.fulfill() + } + wait(for: [startExpectation], timeout: Constants.defaultExpectationDuration) + + // Coalescing is identifier based, so a row created and removed entirely + // within the gap must reconcile as a delete-only terminal state. + try performCoreData(in: facade) { context in + let entity = CDMetaAccount(context: context) + try MetaAccountMapper().populate( + entity: entity, + from: wallet, + using: context + ) + entity.isSelected = true + try context.save() + context.delete(entity) + try context.save() + } + processingQueue.sync {} + + let observer = NSObject() + let reconciliationExpectation = expectation( + description: "transient identifier is reconciled" + ) + var batch: [DataProviderChange] = [] + observable.addObserver( + observer, + deliverOn: .main, + executing: { changes in + batch = changes + reconciliationExpectation.fulfill() + } + ) + wait( + for: [reconciliationExpectation], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(batch.count, 1) + if case let .delete(identifier)? = batch.first { + XCTAssertEqual(identifier, wallet.identifier) + } else { + XCTFail("A transient identifier must reconcile as delete-only") + } + + observable.removeObserver(observer) + processingQueue.sync {} + let stopExpectation = expectation(description: "transient observable stops") + observable.stop { error in + XCTAssertNil(error) + stopExpectation.fulfill() + } + wait( + for: [stopExpectation], + timeout: Constants.defaultExpectationDuration + ) + } + + private func assertTolerantObservableAggregatesSameIdentifierHandoffs() throws { + let facade = UserDataStorageTestFacade() + let repositoryQueue = OperationQueue() + let processingQueue = DispatchQueue( + label: "jp.co.fearless.wallet-observable.identifier-handoff-test" + ) + let identifier = "same-identifier-handoff-wallet" + let firstWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: identifier, + name: "Handoff Wallet A" + ) + let secondWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: identifier, + name: "Handoff Wallet B" + ) + try seed( + [ManagedMetaAccountModel(info: firstWallet, isSelected: true)], + in: facade, + using: repositoryQueue + ) + try performCoreData(in: facade) { context in + let entity = CDMetaAccount(context: context) + try MetaAccountMapper().populate( + entity: entity, + from: secondWallet, + using: context + ) + entity.isSelected = true + entity.order = 900 + entity.name = "" + try context.save() + } + + let observable = TolerantMetaAccountContextObservable( + service: facade.databaseService, + mapper: AnyCoreDataMapper(ManagedMetaAccountMapper()), + predicate: { _ in true }, + processingQueue: processingQueue + ) + let startExpectation = expectation(description: "handoff observable starts") + observable.start { error in + XCTAssertNil(error) + startExpectation.fulfill() + } + wait(for: [startExpectation], timeout: Constants.defaultExpectationDuration) + + let observer = NSObject() + let firstHandoffExpectation = expectation( + description: "healthy role moves from A to B" + ) + let secondHandoffExpectation = expectation( + description: "healthy role moves from B to A" + ) + var receivedBatches: [[DataProviderChange]] = [] + observable.addObserver( + observer, + deliverOn: .main, + executing: { changes in + receivedBatches.append(changes) + if receivedBatches.count == 1 { + firstHandoffExpectation.fulfill() + } else if receivedBatches.count == 2 { + secondHandoffExpectation.fulfill() + } else { + XCTFail("Each same-identifier handoff must emit one terminal batch") + } + } + ) + processingQueue.sync {} + + func moveHealthyRole(from oldName: String, to newName: String) throws { + try performCoreData(in: facade) { context in + let request = NSFetchRequest( + entityName: "CDMetaAccount" + ) + request.predicate = NSPredicate( + format: "%K == %@", + #keyPath(CDMetaAccount.metaId), + identifier + ) + let entities = try context.fetch(request) + XCTAssertEqual(entities.count, 2) + let healthyEntity = try XCTUnwrap( + entities.first { $0.name == oldName } + ) + let corruptEntity = try XCTUnwrap( + entities.first { + ($0.name ?? "").trimmingCharacters( + in: .whitespacesAndNewlines + ).isEmpty + } + ) + healthyEntity.name = "" + corruptEntity.name = newName + try context.save() + } + } + + // Both objects are updated in one save. Core Data exposes notification + // objects as an unordered set, so processing them one-by-one could emit a + // terminal delete even though the identifier remains healthy. + try moveHealthyRole( + from: firstWallet.name, + to: secondWallet.name + ) + wait( + for: [firstHandoffExpectation], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(receivedBatches.count, 1) + XCTAssertEqual(receivedBatches[0].count, 1) + if case let .update(model)? = receivedBatches[0].first { + XCTAssertEqual(model.identifier, identifier) + XCTAssertEqual(model.info.name, secondWallet.name) + } else { + XCTFail("A-to-B handoff must emit one terminal update, never a delete") + } + + try moveHealthyRole( + from: secondWallet.name, + to: firstWallet.name + ) + wait( + for: [secondHandoffExpectation], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(receivedBatches.count, 2) + XCTAssertEqual(receivedBatches[1].count, 1) + if case let .update(model)? = receivedBatches[1].first { + XCTAssertEqual(model.identifier, identifier) + XCTAssertEqual(model.info.name, firstWallet.name) + } else { + XCTFail("B-to-A handoff must emit one terminal update, never a delete") + } + + observable.removeObserver(observer) + processingQueue.sync {} + let stopExpectation = expectation(description: "handoff observable stops") + observable.stop { error in + XCTAssertNil(error) + stopExpectation.fulfill() + } + wait(for: [stopExpectation], timeout: Constants.defaultExpectationDuration) + } + + func testRepositorySaveRejectsEquivalentChainAccountAliasesBeforeMutatingStoredWallet() throws { + let facade = UserDataStorageTestFacade() + let operationQueue = OperationQueue() + let identifier = "duplicate-alias-save-wallet" + let generatedWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 0), + identifier: identifier + ) + let storedWallet = replacingChainAccounts( + in: generatedWallet, + with: [ + ChainAccountModel( + chainId: UniversalWalletRegistry.bitcoinMainnet.chainId, + accountId: Data(repeating: 0x10, count: 32), + publicKey: Data(repeating: 0x20, count: 32), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ) + ] + ) + try seed( + [ManagedMetaAccountModel(info: storedWallet, isSelected: true)], + in: facade, + using: operationQueue + ) + try setRawWalletOrder(identifier: identifier, order: 1_100, in: facade) + let before = try rawStoredWalletSnapshots( + orders: [1_100], + in: facade + ) + + let duplicateModels = [ + replacingChainAccounts( + in: storedWallet, + with: [ + ChainAccountModel( + chainId: "duplicate-remote-chain", + accountId: Data(repeating: 0x11, count: 32), + publicKey: Data(repeating: 0x21, count: 32), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ), + ChainAccountModel( + chainId: "duplicate-remote-chain", + accountId: Data(repeating: 0x12, count: 32), + publicKey: Data(repeating: 0x22, count: 32), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ) + ] + ), + replacingChainAccounts( + in: storedWallet, + with: [ + ChainAccountModel( + chainId: UniversalWalletRegistry.bitcoinMainnet.chainId, + accountId: Data(repeating: 0x13, count: 32), + publicKey: Data(repeating: 0x23, count: 32), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ), + ChainAccountModel( + chainId: UniversalWalletRegistry.bitcoinMainnet.id, + accountId: Data(repeating: 0x14, count: 32), + publicKey: Data(repeating: 0x24, count: 32), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ) + ] + ) + ] + let malformedModels = [ + ChainAccountModel( + chainId: "", + accountId: Data(repeating: 0x31, count: 32), + publicKey: Data(repeating: 0x41, count: 32), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ), + ChainAccountModel( + chainId: " padded-chain-id ", + accountId: Data(repeating: 0x32, count: 32), + publicKey: Data(repeating: 0x42, count: 32), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ), + ChainAccountModel( + chainId: "empty-account-id", + accountId: Data(), + publicKey: Data(repeating: 0x43, count: 32), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ), + ChainAccountModel( + chainId: "short-public-key", + accountId: Data(repeating: 0x34, count: 32), + publicKey: Data(repeating: 0x44, count: 31), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ), + ChainAccountModel( + chainId: "ecdsa-wrong-public-key-width", + accountId: Data(repeating: 0x35, count: 32), + publicKey: Data(repeating: 0x45, count: 32), + cryptoType: CryptoType.ecdsa.rawValue, + ethereumBased: false + ), + ChainAccountModel( + chainId: "invalid-crypto-type", + accountId: Data(repeating: 0x36, count: 32), + publicKey: Data(repeating: 0x46, count: 32), + cryptoType: UInt8.max, + ethereumBased: false + ) + ].map { + replacingChainAccounts(in: storedWallet, with: [$0]) + } + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository(for: nil, sortDescriptors: []) + + for invalidModel in duplicateModels + malformedModels { + let saveOperation = repository.saveOperation( + { [invalidModel] }, + { [] } + ) + XCTAssertThrowsError( + try execute(saveOperation, using: operationQueue) + ) { error in + guard case MetaAccountMapperError.invalidWalletRecord = error else { + return XCTFail( + "Expected duplicate child validation error, got \(error)" + ) + } + } + XCTAssertEqual( + try rawStoredWalletSnapshots(orders: [1_100], in: facade), + before + ) + } + + // Replacing one persisted alias with its canonical equivalent must update + // the existing child rather than append a second equivalent child. + let aliasReplacement = replacingChainAccounts( + in: storedWallet, + with: [ + ChainAccountModel( + chainId: UniversalWalletRegistry.bitcoinMainnet.id, + accountId: Data(repeating: 0x15, count: 32), + publicKey: Data(repeating: 0x25, count: 32), + cryptoType: CryptoType.sr25519.rawValue, + ethereumBased: false + ) + ] + ) + _ = try execute( + repository.saveOperation( + { [aliasReplacement] }, + { [] } + ), + using: operationQueue + ) + + let afterAliasReplacement = try rawStoredWalletSnapshots( + orders: [1_100], + in: facade + ) + XCTAssertEqual(afterAliasReplacement.count, 1) + XCTAssertEqual(afterAliasReplacement[0].chainAccounts.count, 1) + XCTAssertEqual( + afterAliasReplacement[0].chainAccounts[0].chainId, + UniversalWalletRegistry.bitcoinMainnet.id + ) + } + + func testDeleteAndReplaceRejectDuplicateStoredIdentifiersInBothInsertionOrdersWithoutMutation() throws { + for supportedFirst in [true, false] { + let facade = UserDataStorageTestFacade() + let operationQueue = OperationQueue() + let identifier = supportedFirst + ? "collision-supported-first" + : "collision-unsupported-first" + let supportedOrder: Int32 = 1_150 + let unsupportedOrder: Int32 = 1_151 + + let insertSupported = { + try self.insertWallet( + identifier: identifier, + isSelected: true, + order: supportedOrder, + childSpecs: [], + in: facade + ) + } + let insertUnsupported = { + try self.insertTonOnlyWallet( + identifier: identifier, + isSelected: false, + order: unsupportedOrder, + in: facade + ) + } + if supportedFirst { + try insertSupported() + try insertUnsupported() + } else { + try insertUnsupported() + try insertSupported() + } + + let orders = Set([supportedOrder, unsupportedOrder]) + let before = try rawStoredWalletSnapshots( + orders: orders, + in: facade + ) + XCTAssertEqual(before.count, 2) + + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository(for: nil, sortDescriptors: []) + let deleteOperation = repository.saveOperation( + { [] }, + { [identifier] } + ) + XCTAssertThrowsError( + try execute(deleteOperation, using: operationQueue) + ) { error in + guard + let settingsError = error as? SelectedWalletSettingsError, + case .duplicateWalletIdentifier = settingsError + else { + return XCTFail( + "Expected duplicate delete collision, got \(error)" + ) + } + } + XCTAssertEqual( + try rawStoredWalletSnapshots(orders: orders, in: facade), + before + ) + + let replaceOperation = repository.replaceOperation { [] } + XCTAssertThrowsError( + try execute(replaceOperation, using: operationQueue) + ) { error in + guard + let settingsError = error as? SelectedWalletSettingsError, + case .duplicateWalletIdentifier = settingsError + else { + return XCTFail( + "Expected duplicate replace collision, got \(error)" + ) + } + } + XCTAssertEqual( + try rawStoredWalletSnapshots(orders: orders, in: facade), + before + ) + } + } + + func testPersistedDuplicateAndUniversalAliasChainAccountsAreAlwaysQuarantinedWithoutMutation() throws { + typealias ChildSpec = (chainId: String, marker: UInt8) + typealias Fixture = (identifier: String, children: [ChildSpec]) + + let exactForward: [ChildSpec] = [ + ("remote-chain-id", 0x01), + ("remote-chain-id", 0x02) + ] + let exactReverse = Array(exactForward.reversed()) + let aliasPairs: [(String, String)] = [ + ( + UniversalWalletRegistry.bitcoinMainnet.chainId, + UniversalWalletRegistry.bitcoinMainnet.id + ), + ( + UniversalWalletRegistry.bitcoinTestnet.chainId, + UniversalWalletRegistry.bitcoinTestnet.id + ), + ( + UniversalWalletRegistry.solanaMainnet.chainId, + UniversalWalletRegistry.solanaMainnet.id.uppercased() + ), + ( + UniversalWalletRegistry.solanaDevnet.chainId, + UniversalWalletRegistry.solanaDevnet.id + ), + ( + UniversalWalletRegistry.tonMainnetRegistryEntry.chainId, + UniversalWalletRegistry.tonMainnetRegistryEntry.id + ), + ( + TonChainSelection.mainnetChainId, + UniversalWalletRegistry.tonMainnetRegistryEntry.id + ), + ( + UniversalWalletRegistry.taira.chainId, + UniversalWalletRegistry.taira.id + ), + ( + UniversalWalletRegistry.nexus.chainId, + UniversalWalletRegistry.nexus.id + ) + ] + var fixtures: [Fixture] = [ + ("duplicate-exact-forward", exactForward), + ("duplicate-exact-reverse", exactReverse) + ] + + for (index, pair) in aliasPairs.enumerated() { + let forward: [ChildSpec] = [ + (pair.0, UInt8(index * 2 + 10)), + (pair.1, UInt8(index * 2 + 11)) + ] + fixtures.append(("duplicate-alias-\(index)-forward", forward)) + fixtures.append(("duplicate-alias-\(index)-reverse", Array(forward.reversed()))) + } + + let facade = UserDataStorageTestFacade() + let operationQueue = OperationQueue() + let healthyWallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: "duplicate-control-healthy" + ) + try seed( + [ManagedMetaAccountModel(info: healthyWallet, isSelected: true)], + in: facade, + using: operationQueue + ) + + let fixtureOrders = Set( + fixtures.indices.map { Int32(1_200 + $0) } + ) + for (index, fixture) in fixtures.enumerated() { + try insertWallet( + identifier: fixture.identifier, + isSelected: true, + order: Int32(1_200 + index), + childSpecs: fixture.children, + in: facade + ) + } + + let before = try rawStoredWalletSnapshots( + orders: fixtureOrders, + in: facade + ) + let fixtureIdentifiers = Set(fixtures.map(\.identifier)) + let mappingStates = try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K IN %@", + #keyPath(CDMetaAccount.metaId), + Array(fixtureIdentifiers) + ) + return try context.fetch(request).reduce(into: [String: Bool]()) { + result, + entity in + let identifier = try XCTUnwrap(entity.metaId) + do { + _ = try MetaAccountMapper().transform(entity: entity) + result[identifier] = false + } catch MetaAccountMapperError.invalidWalletRecord { + result[identifier] = true + } + } + } + XCTAssertEqual(Set(mappingStates.keys), fixtureIdentifiers) + XCTAssertTrue(mappingStates.values.allSatisfy { $0 }) + + let projectionRepository = facade.createRepository( + mapper: AnyCoreDataMapper(MetaAccountSelectionMapper()) + ) + let projections = try execute( + projectionRepository.fetchAllOperation( + with: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ), + using: operationQueue + ) + let duplicateProjections = projections.filter { + fixtureIdentifiers.contains($0.identifier) + } + XCTAssertEqual(duplicateProjections.count, fixtures.count) + XCTAssertTrue(duplicateProjections.allSatisfy { $0.recordState == .corrupt }) + XCTAssertTrue(duplicateProjections.allSatisfy { $0.wallet == nil }) + + let tolerantRepository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository(for: nil, sortDescriptors: []) + XCTAssertEqual( + try execute( + tolerantRepository.fetchAllOperation( + with: RepositoryFetchOptions( + includesProperties: true, + includesSubentities: true + ) + ), + using: operationQueue + ).map(\.identifier), + [healthyWallet.identifier] + ) + XCTAssertEqual( + try rawStoredWalletSnapshots(orders: fixtureOrders, in: facade), + before + ) + } + + private func setup(_ settings: SelectedWalletSettings) throws -> MetaAccountModel? { + let setupExpectation = expectation(description: "selected wallet setup completes") + var setupResult: Result? + + settings.setup(runningCompletionIn: .main) { result in + setupResult = result + setupExpectation.fulfill() + } + + wait(for: [setupExpectation], timeout: Constants.defaultExpectationDuration) + return try XCTUnwrap(setupResult).get() + } + + private func save( + _ wallet: MetaAccountModel, + in settings: SelectedWalletSettings + ) throws -> MetaAccountModel { + let saveExpectation = expectation(description: "selected wallet save completes") + var saveResult: Result? + + settings.save(value: wallet, runningCompletionIn: .main) { result in + saveResult = result + saveExpectation.fulfill() + } + + wait(for: [saveExpectation], timeout: Constants.defaultExpectationDuration) + return try XCTUnwrap(saveResult).get() + } + + private func execute( + _ operation: BaseOperation, + using operationQueue: OperationQueue + ) throws -> Result { + operationQueue.addOperations([operation], waitUntilFinished: true) + return try XCTUnwrap(operation.result).get() + } + + private func copyWallet( + _ wallet: MetaAccountModel, + identifier: String, + name: String? = nil + ) -> MetaAccountModel { + MetaAccountModel( + metaId: identifier, + name: name ?? wallet.name, + substrateAccountId: wallet.substrateAccountId, + substrateCryptoType: wallet.substrateCryptoType, + substratePublicKey: wallet.substratePublicKey, + ethereumAddress: wallet.ethereumAddress, + ethereumPublicKey: wallet.ethereumPublicKey, + chainAccounts: wallet.chainAccounts, + assetKeysOrder: wallet.assetKeysOrder, + canExportEthereumMnemonic: wallet.canExportEthereumMnemonic, + unusedChainIds: wallet.unusedChainIds, + selectedCurrency: wallet.selectedCurrency, + networkManagmentFilter: wallet.networkManagmentFilter, + assetsVisibility: wallet.assetsVisibility, + hasBackup: wallet.hasBackup, + favouriteChainIds: wallet.favouriteChainIds + ) + } + + private func replacingChainAccounts( + in wallet: MetaAccountModel, + with chainAccounts: Set + ) -> MetaAccountModel { + MetaAccountModel( + metaId: wallet.metaId, + name: wallet.name, + substrateAccountId: wallet.substrateAccountId, + substrateCryptoType: wallet.substrateCryptoType, + substratePublicKey: wallet.substratePublicKey, + ethereumAddress: wallet.ethereumAddress, + ethereumPublicKey: wallet.ethereumPublicKey, + chainAccounts: chainAccounts, + assetKeysOrder: wallet.assetKeysOrder, + canExportEthereumMnemonic: wallet.canExportEthereumMnemonic, + unusedChainIds: wallet.unusedChainIds, + selectedCurrency: wallet.selectedCurrency, + networkManagmentFilter: wallet.networkManagmentFilter, + assetsVisibility: wallet.assetsVisibility, + hasBackup: wallet.hasBackup, + favouriteChainIds: wallet.favouriteChainIds + ) + } + + private func seed( + _ wallets: [ManagedMetaAccountModel], + in facade: UserDataStorageTestFacade, + using operationQueue: OperationQueue + ) throws { + let repository = facade.createRepository( + mapper: AnyCoreDataMapper(ManagedMetaAccountMapper()) + ) + let saveOperation = repository.saveOperation({ wallets }, { [] }) + operationQueue.addOperations([saveOperation], waitUntilFinished: true) + guard let saveResult = saveOperation.result else { + throw WalletCorruptionTestFixtureError( + message: "Managed wallet seed operation completed without a result" + ) + } + _ = try saveResult.get() + } + + private func insertWallet( + identifier: String, + isSelected: Bool, + order: Int32, + childSpecs: [(chainId: String, marker: UInt8)], + in facade: UserDataStorageTestFacade + ) throws { + try performCoreData(in: facade) { context in + let wallet = self.copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 0), + identifier: identifier + ) + let entity = CDMetaAccount(context: context) + try MetaAccountMapper().populate( + entity: entity, + from: wallet, + using: context + ) + entity.isSelected = isSelected + entity.order = order + + for childSpec in childSpecs { + let child = CDChainAccount(context: context) + child.chainId = childSpec.chainId + child.accountId = Data(repeating: childSpec.marker, count: 32).toHex() + child.publicKey = Data( + repeating: childSpec.marker &+ 0x40, + count: 32 + ) + child.cryptoType = Int16(CryptoType.sr25519.rawValue) + child.ethereumBased = false + entity.addToChainAccounts(child) + } + + try context.save() + } + } + + private func insertTonOnlyWallet( + identifier: String, + isSelected: Bool, + order: Int32, + in facade: UserDataStorageTestFacade, + malformedChainAccount: Bool = false + ) throws { + try performCoreData(in: facade) { context in + let wallet = CDMetaAccount(context: context) + wallet.metaId = identifier + wallet.name = "Preserved TON Wallet" + wallet.isSelected = isSelected + wallet.order = order + wallet.canExportEthereumMnemonic = false + wallet.hasBackup = false + wallet.favouriteChainIds = NSArray() + wallet.setValue(false, forKey: "zeroBalanceAssetsHidden") + wallet.setValue(Data(repeating: 0x41, count: 36), forKey: "tonAddress") + wallet.setValue(Data(repeating: 0x42, count: 32), forKey: "tonPublicKey") + wallet.setValue("v5R1", forKey: "tonContractVersion") + + if malformedChainAccount { + let chainAccount = CDChainAccount(context: context) + chainAccount.accountId = "not-valid-hex" + chainAccount.chainId = "foreign-chain" + chainAccount.publicKey = Data(repeating: 0x43, count: 32) + wallet.addToChainAccounts(chainAccount) + } + + try context.save() + } + } + + private func insertCorruptSupportedWallet( + identifier: String, + corruption: PersistedSupportedWalletCorruption, + isSelected: Bool, + order: Int32, + in facade: UserDataStorageTestFacade, + using operationQueue: OperationQueue + ) throws { + let wallet = copyWallet( + AccountGenerator.generateMetaAccount(generatingChainAccounts: 1), + identifier: identifier + ) + try seed( + [ManagedMetaAccountModel(info: wallet, isSelected: isSelected)], + in: facade, + using: operationQueue + ) + + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K == %@", + #keyPath(CDMetaAccount.metaId), + identifier + ) + guard let storedWallet = try context.fetch(request).first else { + throw WalletCorruptionTestFixtureError( + message: "Seeded wallet \(identifier) was not found for corruption \(corruption.identifier)" + ) + } + storedWallet.isSelected = isSelected + storedWallet.order = order + + let chainAccount = { + storedWallet.chainAccounts?.allObjects.first as? CDChainAccount + } + func requiredChainAccount() throws -> CDChainAccount { + guard let chainAccount = chainAccount() else { + throw WalletCorruptionTestFixtureError( + message: "Seeded wallet \(identifier) has no child for corruption \(corruption.identifier)" + ) + } + return chainAccount + } + + switch corruption { + case .malformedSubstrateAccountId: + storedWallet.substrateAccountId = "not-hex" + case .shortSubstrateAccountId: + storedWallet.substrateAccountId = "01" + case .emptySubstratePublicKey: + storedWallet.substratePublicKey = Data() + case .shortSubstratePublicKey: + storedWallet.substratePublicKey = Data(repeating: 0x51, count: 31) + case .ecdsaWithWrongSubstratePublicKeyLength: + storedWallet.substrateCryptoType = Int16(CryptoType.ecdsa.rawValue) + case .invalidSubstrateCryptoType: + storedWallet.substrateCryptoType = Int16.max + case .malformedEthereumAddress: + storedWallet.ethereumAddress = "not-hex" + case .shortEthereumAddress: + storedWallet.ethereumAddress = "01" + case .emptyEthereumPublicKey: + storedWallet.ethereumPublicKey = Data() + case .emptyChainAccountId: + try requiredChainAccount().accountId = "" + case .malformedChainAccountId: + try requiredChainAccount().accountId = "not-hex" + case .emptyChainId: + try requiredChainAccount().chainId = "" + case .whitespaceChainId: + try requiredChainAccount().chainId = " \n\t " + case .paddedChainId: + try requiredChainAccount().chainId = " padded-chain-id " + case .emptyChainPublicKey: + try requiredChainAccount().publicKey = Data() + case .shortChainPublicKey: + try requiredChainAccount().publicKey = Data(repeating: 0x52, count: 31) + case .ecdsaWithWrongChainPublicKeyLength: + try requiredChainAccount().cryptoType = Int16(CryptoType.ecdsa.rawValue) + case .invalidChainCryptoType: + try requiredChainAccount().cryptoType = Int16.max + case .emptyMetaId: + storedWallet.metaId = "" + case .whitespaceMetaId: + storedWallet.metaId = " \n\t " + case .paddedMetaId: + storedWallet.metaId = " \(identifier) " + case .emptyName: + storedWallet.name = "" + case .whitespaceName: + storedWallet.name = " \n\t " + } + + try context.save() + } + } + + private func rawStoredWalletSnapshots( + orders: Set, + in facade: UserDataStorageTestFacade + ) throws -> [RawStoredWalletSnapshot] { + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + let wallets = try context.fetch(request).filter { + orders.contains($0.order) + } + + return wallets.map { wallet in + let chainAccounts = ( + wallet.chainAccounts?.allObjects as? [CDChainAccount] ?? [] + ).map { + RawStoredChainAccountSnapshot( + accountId: $0.accountId, + publicKey: $0.publicKey, + cryptoType: $0.cryptoType, + ethereumBased: $0.ethereumBased, + chainId: $0.chainId, + ecosystem: $0.entity.propertiesByName["ecosystem"] == nil + ? nil + : $0.value(forKey: "ecosystem") as? String + ) + } + .sorted { $0.sortKey < $1.sortKey } + + let currency = wallet.selectedCurrency.map { + RawStoredCurrencySnapshot( + id: $0.id, + symbol: $0.symbol, + name: $0.name, + icon: $0.icon, + isSelected: $0.isSelected + ) + } + let assetsVisibility = ( + wallet.entity.propertiesByName["assetsVisibility"] == nil + ? [] + : (wallet.value(forKey: "assetsVisibility") as? NSSet)? + .allObjects as? [NSManagedObject] ?? [] + ).map { + RawStoredAssetVisibilitySnapshot( + assetId: $0.value(forKey: "assetId") as? String, + hidden: ($0.value(forKey: "hidden") as? Bool) ?? false + ) + } + .sorted { ($0.assetId ?? "") < ($1.assetId ?? "") } + + return RawStoredWalletSnapshot( + objectIdentifier: wallet.objectID.uriRepresentation().absoluteString, + metaId: wallet.metaId, + name: wallet.name, + isSelected: wallet.isSelected, + order: wallet.order, + substrateAccountId: wallet.substrateAccountId, + substratePublicKey: wallet.substratePublicKey, + substrateCryptoType: wallet.substrateCryptoType, + ethereumAddress: wallet.ethereumAddress, + ethereumPublicKey: wallet.ethereumPublicKey, + chainAccounts: chainAccounts, + assetKeysOrder: wallet.assetKeysOrder as? [String], + canExportEthereumMnemonic: wallet.canExportEthereumMnemonic, + unusedChainIds: wallet.unusedChainIds as? [String], + selectedCurrency: currency, + networkManagmentFilter: wallet.networkManagmentFilter, + hasBackup: wallet.hasBackup, + favouriteChainIds: wallet.favouriteChainIds as? [String], + zeroBalanceAssetsHidden: wallet.entity + .propertiesByName["zeroBalanceAssetsHidden"] == nil + ? nil + : wallet.value(forKey: "zeroBalanceAssetsHidden") as? Bool, + tonAddress: wallet.entity.propertiesByName["tonAddress"] == nil + ? nil + : wallet.value(forKey: "tonAddress") as? Data, + tonPublicKey: wallet.entity.propertiesByName["tonPublicKey"] == nil + ? nil + : wallet.value(forKey: "tonPublicKey") as? Data, + tonContractVersion: wallet.entity + .propertiesByName["tonContractVersion"] == nil + ? nil + : wallet.value(forKey: "tonContractVersion") as? String, + assetsVisibility: assetsVisibility + ) + } + .sorted { $0.objectIdentifier < $1.objectIdentifier } + } + } + + private func rawChainAccountSnapshots( + walletIdentifier: String, + in facade: UserDataStorageTestFacade + ) throws -> [RawChainAccountSnapshot] { + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K == %@", + #keyPath(CDMetaAccount.metaId), + walletIdentifier + ) + let wallet = try XCTUnwrap(context.fetch(request).first) + let chainAccounts = wallet.chainAccounts?.allObjects as? [CDChainAccount] ?? [] + + return chainAccounts.map { + RawChainAccountSnapshot( + accountId: $0.accountId, + chainId: $0.chainId, + publicKey: $0.publicKey + ) + } + .sorted { ($0.chainId ?? "") < ($1.chainId ?? "") } + } + } + + private func setRawWalletOrder( + identifier: String, + order: Int32, + in facade: UserDataStorageTestFacade + ) throws { + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate( + format: "%K == %@", + #keyPath(CDMetaAccount.metaId), + identifier + ) + let wallet = try XCTUnwrap(context.fetch(request).first) + wallet.order = order + try context.save() + } + } + + private func rawWalletSnapshots( + in facade: UserDataStorageTestFacade + ) throws -> [RawWalletSnapshot] { + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + let wallets = try context.fetch(request) + + return try wallets.map { wallet in + RawWalletSnapshot( + identifier: try XCTUnwrap(wallet.metaId), + isSelected: wallet.isSelected, + order: wallet.order, + substrateAccountId: wallet.substrateAccountId, + substratePublicKey: wallet.substratePublicKey, + tonAddress: wallet.value(forKey: "tonAddress") as? Data, + tonPublicKey: wallet.value(forKey: "tonPublicKey") as? Data, + tonContractVersion: wallet.value(forKey: "tonContractVersion") as? String + ) + } + .sorted { $0.identifier < $1.identifier } + } + } + + private func performCoreData( + in facade: UserDataStorageTestFacade, + _ body: @escaping (NSManagedObjectContext) throws -> T + ) throws -> T { + let coreDataExpectation = expectation(description: "Core Data operation completes") + var operationResult: Result? + + facade.databaseService.performAsync { context, error in + do { + if let error { + throw error + } + guard let context else { + throw WalletCorruptionTestFixtureError( + message: "Core Data callback completed without a context or error" + ) + } + operationResult = .success(try body(context)) + } catch { + operationResult = .failure(error) + } + + coreDataExpectation.fulfill() + } + + wait(for: [coreDataExpectation], timeout: Constants.defaultExpectationDuration) + guard let operationResult else { + throw WalletCorruptionTestFixtureError( + message: "Core Data callback did not produce a result" + ) + } + return try operationResult.get() + } +} + +private struct WalletCorruptionTestFixtureError: Error, CustomStringConvertible { + let message: String + + var description: String { + message + } +} + +/// Corruptions that the current Core Data model can persist. Required-field `nil` cases are +/// exercised directly against unsaved entities in `MetaAccountMapperTests`. +private enum PersistedSupportedWalletCorruption: CaseIterable { + case malformedSubstrateAccountId + case shortSubstrateAccountId + case emptySubstratePublicKey + case shortSubstratePublicKey + case ecdsaWithWrongSubstratePublicKeyLength + case invalidSubstrateCryptoType + case malformedEthereumAddress + case shortEthereumAddress + case emptyEthereumPublicKey + case emptyChainAccountId + case malformedChainAccountId + case emptyChainId + case whitespaceChainId + case paddedChainId + case emptyChainPublicKey + case shortChainPublicKey + case ecdsaWithWrongChainPublicKeyLength + case invalidChainCryptoType + case emptyMetaId + case whitespaceMetaId + case paddedMetaId + case emptyName + case whitespaceName + + var identifier: String { + switch self { + case .malformedSubstrateAccountId: + return "malformed-substrate-id" + case .shortSubstrateAccountId: + return "short-substrate-id" + case .emptySubstratePublicKey: + return "empty-substrate-public-key" + case .shortSubstratePublicKey: + return "short-substrate-public-key" + case .ecdsaWithWrongSubstratePublicKeyLength: + return "ecdsa-wrong-substrate-public-key-length" + case .invalidSubstrateCryptoType: + return "invalid-substrate-crypto-type" + case .malformedEthereumAddress: + return "malformed-ethereum-address" + case .shortEthereumAddress: + return "short-ethereum-address" + case .emptyEthereumPublicKey: + return "empty-ethereum-public-key" + case .emptyChainAccountId: + return "empty-child-account-id" + case .malformedChainAccountId: + return "malformed-child-account-id" + case .emptyChainId: + return "empty-child-chain-id" + case .whitespaceChainId: + return "whitespace-child-chain-id" + case .paddedChainId: + return "padded-child-chain-id" + case .emptyChainPublicKey: + return "empty-child-public-key" + case .shortChainPublicKey: + return "short-child-public-key" + case .ecdsaWithWrongChainPublicKeyLength: + return "ecdsa-wrong-child-public-key-length" + case .invalidChainCryptoType: + return "invalid-child-crypto-type" + case .emptyMetaId: + return "empty-meta-id" + case .whitespaceMetaId: + return "whitespace-meta-id" + case .paddedMetaId: + return "padded-meta-id" + case .emptyName: + return "empty-name" + case .whitespaceName: + return "whitespace-name" + } + } +} + +private struct RawStoredWalletSnapshot: Equatable { + let objectIdentifier: String + let metaId: String? + let name: String? + let isSelected: Bool + let order: Int32 + let substrateAccountId: String? + let substratePublicKey: Data? + let substrateCryptoType: Int16 + let ethereumAddress: String? + let ethereumPublicKey: Data? + let chainAccounts: [RawStoredChainAccountSnapshot] + let assetKeysOrder: [String]? + let canExportEthereumMnemonic: Bool + let unusedChainIds: [String]? + let selectedCurrency: RawStoredCurrencySnapshot? + let networkManagmentFilter: String? + let hasBackup: Bool + let favouriteChainIds: [String]? + let zeroBalanceAssetsHidden: Bool? + let tonAddress: Data? + let tonPublicKey: Data? + let tonContractVersion: String? + let assetsVisibility: [RawStoredAssetVisibilitySnapshot] +} + +private struct RawStoredChainAccountSnapshot: Equatable { + let accountId: String? + let publicKey: Data? + let cryptoType: Int16 + let ethereumBased: Bool + let chainId: String? + let ecosystem: String? + + var sortKey: String { + [ + chainId ?? "", + accountId ?? "", + publicKey?.base64EncodedString() ?? "", + String(cryptoType), + String(ethereumBased), + ecosystem ?? "" + ].joined(separator: "|") + } +} + +private struct RawStoredCurrencySnapshot: Equatable { + let id: String? + let symbol: String? + let name: String? + let icon: String? + let isSelected: Bool +} + +private struct RawStoredAssetVisibilitySnapshot: Equatable { + let assetId: String? + let hidden: Bool +} + +private struct RawWalletSnapshot: Equatable { + struct Payload: Equatable { + let substrateAccountId: String? + let substratePublicKey: Data? + let tonAddress: Data? + let tonPublicKey: Data? + let tonContractVersion: String? + } + + let identifier: String + let isSelected: Bool + let order: Int32 + let substrateAccountId: String? + let substratePublicKey: Data? + let tonAddress: Data? + let tonPublicKey: Data? + let tonContractVersion: String? + + var payload: Payload { + Payload( + substrateAccountId: substrateAccountId, + substratePublicKey: substratePublicKey, + tonAddress: tonAddress, + tonPublicKey: tonPublicKey, + tonContractVersion: tonContractVersion + ) + } +} + +private struct RawChainAccountSnapshot: Equatable { + let accountId: String? + let chainId: String? + let publicKey: Data? +} + +private enum ControllableWalletCoreDataServiceError: Error { + case missingRequest + case requestAlreadyResolved + case injectedFailure +} + +private final class ControllableWalletCoreDataService: CoreDataServiceProtocol { + let configuration: CoreDataServiceConfigurationProtocol + + private let lock = NSLock() + private let requestExpectations: [XCTestExpectation] + private var requests: [CoreDataContextInvocationBlock] = [] + private var resolvedRequestIndexes = Set() + + var requestCount: Int { + lock.lock() + defer { lock.unlock() } + + return requests.count + } + + init( + configuration: CoreDataServiceConfigurationProtocol, + requestExpectations: [XCTestExpectation] + ) { + self.configuration = configuration + self.requestExpectations = requestExpectations + } + + func performAsync(block: @escaping CoreDataContextInvocationBlock) { + lock.lock() + let requestIndex = requests.count + requests.append(block) + let requestExpectation = requestExpectations[safe: requestIndex] + lock.unlock() + + requestExpectation?.fulfill() + } + + func resolveRequest( + at index: Int, + using sourceService: CoreDataServiceProtocol + ) throws { + lock.lock() + guard requests.indices.contains(index) else { + lock.unlock() + throw ControllableWalletCoreDataServiceError.missingRequest + } + guard resolvedRequestIndexes.insert(index).inserted else { + lock.unlock() + throw ControllableWalletCoreDataServiceError.requestAlreadyResolved + } + let request = requests[index] + lock.unlock() + + sourceService.performAsync(block: request) + } + + func failRequest(at index: Int, with error: Error) throws { + lock.lock() + guard requests.indices.contains(index) else { + lock.unlock() + throw ControllableWalletCoreDataServiceError.missingRequest + } + guard resolvedRequestIndexes.insert(index).inserted else { + lock.unlock() + throw ControllableWalletCoreDataServiceError.requestAlreadyResolved + } + let request = requests[index] + lock.unlock() + + request(nil, error) + } + + func close() throws {} + + func drop() throws {} +} + +private final class ControllableWalletStorageFacade: StorageFacadeProtocol { + let databaseService: CoreDataServiceProtocol + + init(databaseService: CoreDataServiceProtocol) { + self.databaseService = databaseService + } + + func createRepository( + filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor], + mapper: AnyCoreDataMapper + ) -> CoreDataRepository where T: Identifiable, U: NSManagedObject { + CoreDataRepository( + databaseService: databaseService, + mapper: mapper, + filter: filter, + sortDescriptors: sortDescriptors + ) + } + + func createAsyncRepository( + filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor], + mapper: AnyCoreDataMapper + ) -> AsyncCoreDataRepositoryDefault where T: Identifiable, U: NSManagedObject { + AsyncCoreDataRepositoryDefault( + databaseService: databaseService, + mapper: mapper, + filter: filter, + sortDescriptors: sortDescriptors + ) + } } diff --git a/fearlessTests/Common/Storage/TransformableArchiveSafetyTests.swift b/fearlessTests/Common/Storage/TransformableArchiveSafetyTests.swift new file mode 100644 index 0000000000..1bc24f66be --- /dev/null +++ b/fearlessTests/Common/Storage/TransformableArchiveSafetyTests.swift @@ -0,0 +1,846 @@ +import CoreData +import IrohaCrypto +import RobinHood +import SQLite3 +import SSFModels +import XCTest +@testable import fearless + +final class TransformableArchiveSafetyTests: XCTestCase { + private static let invalidArchiveHex = "00FF00" + + func testObjectiveCExceptionBoundaryReturnsOnlySanitizedError() throws { + let secretReason = "archive payload and wallet metadata" + do { + _ = try FearlessObjectiveCExceptionCatcher.performObjectRead { + NSException( + name: .invalidArgumentException, + reason: secretReason, + userInfo: ["private": secretReason] + ).raise() + return nil + } + XCTFail("Raised Objective-C exception must become a Swift error") + } catch { + let sanitizedError = error as NSError + XCTAssertEqual( + sanitizedError.domain, + FearlessObjectiveCExceptionErrorDomain + ) + XCTAssertEqual(sanitizedError.code, 1) + XCTAssertEqual( + Set( + sanitizedError.userInfo.keys.map( + String.init(describing:) + ) + ), + Set([NSLocalizedDescriptionKey]) + ) + XCTAssertFalse( + sanitizedError.localizedDescription.contains(secretReason) + ) + XCTAssertFalse( + String(describing: sanitizedError.userInfo) + .contains(secretReason) + ) + } + } + + func testObjectiveCExceptionBoundaryAllowsSuccessfulVoidOperation() throws { + var didRun = false + + try SafeObjectiveCExceptionBoundary.perform { + didRun = true + } + + XCTAssertTrue(didRun) + } + + func testPersistentCorruptFavouriteChainIdsDefaultsOnlyPreferenceWithoutMutation() throws { + try assertPersistentCorruptWalletTransformable( + attribute: "favouriteChainIds", + column: "ZFAVOURITECHAINIDS" + ) + } + + func testPersistentCorruptAssetKeysOrderDefaultsOnlyPreferenceWithoutMutation() throws { + try assertPersistentCorruptWalletTransformable( + attribute: "assetKeysOrder", + column: "ZASSETKEYSORDER" + ) + } + + func testPersistentCorruptUnusedChainIdsDefaultsOnlyPreferenceWithoutMutation() throws { + try assertPersistentCorruptWalletTransformable( + attribute: "unusedChainIds", + column: "ZUNUSEDCHAINIDS" + ) + } + + func testPersistentWrongStoredTypeDefaultsOnlyPreferenceWithoutMutation() throws { + let wrongTypeArchive = try NSKeyedArchiver.archivedData( + withRootObject: NSString(string: "not-an-array"), + requiringSecureCoding: true + ) + + try assertPersistentCorruptWalletTransformable( + attribute: "assetKeysOrder", + column: "ZASSETKEYSORDER", + archiveHex: wrongTypeArchive.map { + String(format: "%02X", $0) + }.joined() + ) + } + + func testPersistentValidWalletArchivesPreserveEveryPreference() throws { + try withCorruptedUserStore( + updateSQL: + "UPDATE ZCDMETAACCOUNT SET ZORDER = ZORDER" + ) { context, _, facade in + let wallet = try perform(in: context) { + let entity = try fetchSingle(CDMetaAccount.self, in: context) + return try MetaAccountMapper().transform(entity: entity) + } + + XCTAssertEqual(wallet.assetKeysOrder, ["asset-a"]) + XCTAssertEqual(wallet.unusedChainIds, ["unused-chain"]) + XCTAssertEqual(wallet.favouriteChainIds, ["favourite-chain"]) + + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository( + for: nil, + sortDescriptors: [] + ) + let operation = repository.fetchAllOperation( + with: RepositoryFetchOptions() + ) + let queue = OperationQueue() + queue.addOperations([operation], waitUntilFinished: true) + XCTAssertEqual( + try XCTUnwrap(operation.result).get().count, + 1 + ) + } + } + + func testPersistentCorruptChainOptionsDefaultsWithoutMutatingCache() throws { + try withCorruptedSubstrateStore( + updateSQL: + "UPDATE ZCDCHAIN SET ZOPTIONS = X'\(Self.invalidArchiveHex)'" + ) { context, storeURL, facade in + let mappedChain = try perform(in: context) { + let entity = try fetchSingle(CDChain.self, in: context) + return try ChainModelMapper().transform(entity: entity) + } + + XCTAssertNil(mappedChain.options) + XCTAssertEqual(mappedChain.chainId, "transformable-chain") + + let repository: CoreDataRepository = + facade.createRepository( + filter: nil, + sortDescriptors: [], + mapper: AnyCoreDataMapper(ChainModelMapper()) + ) + XCTAssertEqual(try fetchAll(from: repository).count, 1) + try assertBlobAndRowRemain( + storeURL: storeURL, + table: "ZCDCHAIN", + column: "ZOPTIONS" + ) + } + } + + func testPersistentCorruptExternalApiTypesSkipsOnlyExplorerWithoutMutatingCache() throws { + try withCorruptedSubstrateStore( + updateSQL: + "UPDATE ZCDEXTERNALAPI SET ZTYPES = X'\(Self.invalidArchiveHex)'" + ) { context, storeURL, facade in + let mappedChain = try perform(in: context) { + let entity = try fetchSingle(CDChain.self, in: context) + return try ChainModelMapper().transform(entity: entity) + } + + XCTAssertEqual(mappedChain.externalApi?.explorers, []) + XCTAssertEqual(mappedChain.assets.count, 1) + + let repository: CoreDataRepository = + facade.createRepository( + filter: nil, + sortDescriptors: [], + mapper: AnyCoreDataMapper(ChainModelMapper()) + ) + XCTAssertEqual(try fetchAll(from: repository).count, 1) + try assertBlobAndRowRemain( + storeURL: storeURL, + table: "ZCDEXTERNALAPI", + column: "ZTYPES" + ) + } + } + + func testPersistentCorruptAssetPurchaseProvidersDefaultsWithoutMutatingCache() throws { + try withCorruptedSubstrateStore( + updateSQL: + "UPDATE ZCDASSET SET ZPURCHASEPROVIDERS = X'\(Self.invalidArchiveHex)'" + ) { context, storeURL, facade in + let mappedAsset = try perform(in: context) { + let entity = try fetchSingle(CDAsset.self, in: context) + return try AssetModelMapper().transform(entity: entity) + } + XCTAssertNil(mappedAsset.purchaseProviders) + + let repository: CoreDataRepository = + facade.createRepository( + filter: nil, + sortDescriptors: [], + mapper: AnyCoreDataMapper(ChainModelMapper()) + ) + let mappedChain = try XCTUnwrap( + try fetchAll(from: repository).first + ) + XCTAssertEqual(mappedChain.assets.count, 1) + XCTAssertNil(mappedChain.assets.first?.purchaseProviders) + try assertBlobAndRowRemain( + storeURL: storeURL, + table: "ZCDASSET", + column: "ZPURCHASEPROVIDERS" + ) + } + } + + func testPersistentCorruptPolkaswapTransformablesSurfaceCatchableErrorWithoutMutation() throws { + for column in ["ZAVAILABLESOURCES", "ZFORCESMARTIDS"] { + try withCorruptedSubstrateStore( + updateSQL: + "UPDATE ZCDPOLKASWAPREMOTESETTINGS " + + "SET \(column) = X'\(Self.invalidArchiveHex)'" + ) { context, storeURL, _ in + XCTAssertThrowsError( + try perform(in: context) { + let entity = try fetchSingle( + CDPolkaswapRemoteSettings.self, + in: context + ) + return try PolkaswapSettingMapper().transform( + entity: entity + ) + } + ) { error in + guard + case PolkaswapSettingMapperError.requiredFieldsMissing = + error + else { + return XCTFail("Unexpected mapper error: \(error)") + } + } + + try assertBlobAndRowRemain( + storeURL: storeURL, + table: "ZCDPOLKASWAPREMOTESETTINGS", + column: column + ) + } + } + } + + func testProductionRuntimeRegistryRetainsEveryCurrentStoreClass() throws { + XCTAssertEqual( + ManagedObjectRuntimeClassRegistry.substrateV8Classes.count, + 19 + ) + XCTAssertEqual( + ManagedObjectRuntimeClassRegistry.userV11Classes.count, + 7 + ) + XCTAssertEqual( + ManagedObjectRuntimeClassRegistry.classesByRuntimeName.count, + 26 + ) + + for model in [ + try loadUserModel(qualifyClasses: false).model, + try loadSubstrateModel(qualifyClasses: false).model + ] { + for entity in model.entities { + let entityName = try XCTUnwrap(entity.name) + let className = try XCTUnwrap(entity.managedObjectClassName) + let resolvedClass = try XCTUnwrap( + ManagedObjectRuntimeClassRegistry.resolve( + className: className + ), + "Registry must resolve \(entityName)" + ) + + XCTAssertTrue( + ManagedObjectRuntimeClassRegistry.classesByRuntimeName + .values.contains { + ObjectIdentifier($0) == + ObjectIdentifier(resolvedClass) + } + ) + } + } + } + + private func assertPersistentCorruptWalletTransformable( + attribute: String, + column: String, + archiveHex: String = + TransformableArchiveSafetyTests.invalidArchiveHex + ) throws { + try withCorruptedUserStore( + updateSQL: + "UPDATE ZCDMETAACCOUNT " + + "SET \(column) = X'\(archiveHex)'" + ) { context, storeURL, facade in + let wallet = try perform(in: context) { + let entity = try fetchSingle( + CDMetaAccount.self, + in: context + ) + return try MetaAccountMapper().transform(entity: entity) + } + + XCTAssertEqual( + wallet.assetKeysOrder, + attribute == "assetKeysOrder" ? nil : ["asset-a"] + ) + XCTAssertEqual( + wallet.unusedChainIds, + attribute == "unusedChainIds" ? nil : ["unused-chain"] + ) + XCTAssertEqual( + wallet.favouriteChainIds, + attribute == "favouriteChainIds" ? [] : ["favourite-chain"] + ) + + let projection = try perform(in: context) { + let entity = try fetchSingle(CDMetaAccount.self, in: context) + return try MetaAccountSelectionMapper().transform( + entity: entity + ) + } + XCTAssertEqual(projection.recordState, .supported) + XCTAssertNotNil(projection.wallet) + XCTAssertTrue(projection.recordState.allowsStoredRecordUpdates) + + let repository = AccountRepositoryFactory(storageFacade: facade) + .createMetaAccountRepository( + for: nil, + sortDescriptors: [] + ) + let operation = repository.fetchAllOperation( + with: RepositoryFetchOptions() + ) + let queue = OperationQueue() + queue.addOperations([operation], waitUntilFinished: true) + XCTAssertEqual( + try XCTUnwrap(operation.result).get().count, + 1 + ) + + try assertBlobAndRowRemain( + storeURL: storeURL, + table: "ZCDMETAACCOUNT", + column: column, + expectedHex: archiveHex + ) + } + } + + private func withCorruptedUserStore( + updateSQL: String, + body: ( + NSManagedObjectContext, + URL, + PersistentFixtureStorageFacade + ) throws -> Void + ) throws { + let loadedModel = try loadUserModel() + try withCorruptedStore( + modelURL: loadedModel.url, + model: loadedModel.model, + updateSQL: updateSQL, + seed: seedUserStore, + body: body + ) + } + + private func withCorruptedSubstrateStore( + updateSQL: String, + body: ( + NSManagedObjectContext, + URL, + PersistentFixtureStorageFacade + ) throws -> Void + ) throws { + let loadedModel = try loadSubstrateModel() + try withCorruptedStore( + modelURL: loadedModel.url, + model: loadedModel.model, + updateSQL: updateSQL, + seed: seedSubstrateStore, + body: body + ) + } + + private func withCorruptedStore( + modelURL: URL, + model: NSManagedObjectModel, + updateSQL: String, + seed: (NSManagedObjectContext) throws -> Void, + body: ( + NSManagedObjectContext, + URL, + PersistentFixtureStorageFacade + ) throws -> Void + ) throws { + let directoryURL = FileManager.default.temporaryDirectory + .appendingPathComponent( + "TransformableArchiveSafety-\(UUID().uuidString)", + isDirectory: true + ) + let storeURL = directoryURL.appendingPathComponent("Store.sqlite") + try FileManager.default.createDirectory( + at: directoryURL, + withIntermediateDirectories: true + ) + defer { + try? FileManager.default.removeItem(at: directoryURL) + } + + let options: [AnyHashable: Any] = [ + NSSQLitePragmasOption: ["journal_mode": "DELETE"] + ] + let writerCoordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + let writerStore = try writerCoordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: options + ) + let writerContext = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + writerContext.persistentStoreCoordinator = writerCoordinator + try perform(in: writerContext) { + try seed(writerContext) + try writerContext.save() + writerContext.reset() + } + try writerCoordinator.remove(writerStore) + + XCTAssertEqual(try executeSQLiteUpdate(updateSQL, at: storeURL), 1) + + let readerCoordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + let readerStore = try readerCoordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: options + ) + let readerContext = NSManagedObjectContext( + concurrencyType: .privateQueueConcurrencyType + ) + readerContext.persistentStoreCoordinator = readerCoordinator + let facade = PersistentFixtureStorageFacade( + context: readerContext, + modelURL: modelURL + ) + + defer { + try? perform(in: readerContext) { + readerContext.reset() + } + try? readerCoordinator.remove(readerStore) + } + + try body(readerContext, storeURL, facade) + XCTAssertFalse(readerContext.hasChanges) + } + + private func seedUserStore(_ context: NSManagedObjectContext) throws { + let model = MetaAccountModel( + metaId: "transformable-wallet", + name: "Transformable archive fixture", + substrateAccountId: Data(repeating: 0x11, count: 32), + substrateCryptoType: CryptoType.sr25519.rawValue, + substratePublicKey: Data(repeating: 0x22, count: 32), + ethereumAddress: nil, + ethereumPublicKey: nil, + chainAccounts: [], + assetKeysOrder: ["asset-a"], + canExportEthereumMnemonic: false, + unusedChainIds: ["unused-chain"], + selectedCurrency: Currency.defaultCurrency(), + networkManagmentFilter: nil, + assetsVisibility: [], + hasBackup: true, + favouriteChainIds: ["favourite-chain"] + ) + let entity = CDMetaAccount(context: context) + try MetaAccountMapper().populate( + entity: entity, + from: model, + using: context + ) + entity.isSelected = true + entity.order = 1 + } + + private func seedSubstrateStore( + _ context: NSManagedObjectContext + ) throws { + let chain = CDChain(context: context) + chain.chainId = "transformable-chain" + chain.name = "Transformable archive fixture" + chain.addressPrefix = 0 + chain.isEthereumBased = false + chain.isTestnet = false + chain.hasCrowdloans = false + chain.setValue( + NSArray(object: ChainOptions.poolStaking.rawValue), + forKey: "options" + ) + + let node = CDChainNode(context: context) + node.name = "Fixture node" + node.url = try XCTUnwrap(URL(string: "wss://fixture.example")) + node.chain = chain + chain.nodes = NSSet(object: node) + chain.selectedNode = node + + let explorer = CDExternalApi(context: context) + explorer.type = "subscan" + explorer.url = "https://explorer.example" + explorer.setValue(NSArray(object: "extrinsic"), forKey: "types") + explorer.chain = chain + chain.explorers = NSSet(object: explorer) + + let asset = CDAsset(context: context) + asset.id = "fixture-asset" + asset.name = "Fixture Asset" + asset.symbol = "FIX" + asset.precision = 12 + asset.isUtility = true + asset.isNative = true + asset.setValue(NSArray(object: "moonpay"), forKey: "purchaseProviders") + asset.chain = chain + chain.assets = NSSet(object: asset) + + let polkaswap = CDPolkaswapRemoteSettings(context: context) + polkaswap.version = "1" + polkaswap.setValue(NSArray(), forKey: "availableSources") + polkaswap.setValue(NSArray(), forKey: "forceSmartIds") + polkaswap.availableDexIds = NSSet() + polkaswap.xstusdId = "fixture-xstusd" + } + + private func loadUserModel( + qualifyClasses: Bool = true + ) throws -> ( + url: URL, + model: NSManagedObjectModel + ) { + let modelURL = try XCTUnwrap( + [ + Bundle(for: UserDataStorageFacade.self), + Bundle.main + ].lazy.compactMap { + UserStorageParams.modelVersion.modelURL( + in: $0, + legacyModelDirectory: UserStorageParams.modelDirectory + ) + }.first + ) + let loadedModel = try XCTUnwrap( + NSManagedObjectModel(contentsOf: modelURL) + ) + let model = try XCTUnwrap( + loadedModel.copy() as? NSManagedObjectModel + ) + if qualifyClasses { + try qualifyManagedObjectClasses(in: model) + } + return (modelURL, model) + } + + private func loadSubstrateModel( + qualifyClasses: Bool = true + ) throws -> ( + url: URL, + model: NSManagedObjectModel + ) { + let modelURL = try XCTUnwrap( + Bundle(for: SubstrateDataStorageFacade.self).url( + forResource: "SubstrateDataModel", + withExtension: "momd" + ) + ) + let loadedModel = try XCTUnwrap( + NSManagedObjectModel(contentsOf: modelURL) + ) + let model = try XCTUnwrap( + loadedModel.copy() as? NSManagedObjectModel + ) + if qualifyClasses { + try qualifyManagedObjectClasses(in: model) + } + return (modelURL, model) + } + + private func qualifyManagedObjectClasses( + in model: NSManagedObjectModel + ) throws { + for entity in model.entities { + let entityName = try XCTUnwrap(entity.name) + let storedClassName = try XCTUnwrap( + entity.managedObjectClassName + ) + let runtimeClass = try XCTUnwrap( + ManagedObjectRuntimeClassRegistry.resolve( + className: storedClassName + ), + "Missing runtime class for \(entityName)" + ) + entity.managedObjectClassName = NSStringFromClass(runtimeClass) + } + } + + private func perform( + in context: NSManagedObjectContext, + _ block: () throws -> T + ) throws -> T { + var result: Result? + context.performAndWait { + result = Result { + try block() + } + } + return try XCTUnwrap(result).get() + } + + private func fetchSingle( + _: Entity.Type, + in context: NSManagedObjectContext + ) throws -> Entity { + let entityName = try XCTUnwrap(Entity.entity().name) + let request = NSFetchRequest(entityName: entityName) + request.fetchLimit = 2 + request.includesPendingChanges = false + request.includesSubentities = false + let entities = try context.fetch(request) + XCTAssertEqual(entities.count, 1) + return try XCTUnwrap(entities.first) + } + + private func fetchAll( + from repository: CoreDataRepository + ) throws -> [Model] { + let operation = repository.fetchAllOperation( + with: RepositoryFetchOptions() + ) + let queue = OperationQueue() + queue.addOperations([operation], waitUntilFinished: true) + return try XCTUnwrap(operation.result).get() + } + + private func assertBlobAndRowRemain( + storeURL: URL, + table: String, + column: String, + expectedHex: String = + TransformableArchiveSafetyTests.invalidArchiveHex + ) throws { + XCTAssertEqual( + try sqliteText( + "SELECT COUNT(*) FROM \(table)", + at: storeURL + ), + "1" + ) + XCTAssertEqual( + try sqliteText( + "SELECT HEX(\(column)) FROM \(table)", + at: storeURL + ), + expectedHex + ) + } + + private func executeSQLiteUpdate( + _ sql: String, + at storeURL: URL + ) throws -> Int { + let database = try openSQLite(at: storeURL) + defer { + sqlite3_close(database) + } + + var errorMessage: UnsafeMutablePointer? + let result = sqlite3_exec( + database, + sql, + nil, + nil, + &errorMessage + ) + defer { + sqlite3_free(errorMessage) + } + + guard result == SQLITE_OK else { + throw sqliteError( + database: database, + code: result, + fallback: errorMessage.map { String(cString: $0) } + ) + } + + return Int(sqlite3_changes(database)) + } + + private func sqliteText( + _ sql: String, + at storeURL: URL + ) throws -> String? { + let database = try openSQLite(at: storeURL) + defer { + sqlite3_close(database) + } + + var statement: OpaquePointer? + let prepareResult = sqlite3_prepare_v2( + database, + sql, + -1, + &statement, + nil + ) + guard prepareResult == SQLITE_OK, let statement else { + throw sqliteError( + database: database, + code: prepareResult + ) + } + defer { + sqlite3_finalize(statement) + } + + let stepResult = sqlite3_step(statement) + guard stepResult == SQLITE_ROW else { + throw sqliteError(database: database, code: stepResult) + } + guard let text = sqlite3_column_text(statement, 0) else { + return nil + } + let count = Int(sqlite3_column_bytes(statement, 0)) + return String( + decoding: UnsafeBufferPointer(start: text, count: count), + as: UTF8.self + ) + } + + private func openSQLite(at storeURL: URL) throws -> OpaquePointer { + var database: OpaquePointer? + let result = sqlite3_open_v2( + storeURL.path, + &database, + SQLITE_OPEN_READWRITE, + nil + ) + guard result == SQLITE_OK, let database else { + defer { + if let database { + sqlite3_close(database) + } + } + throw sqliteError(database: database, code: result) + } + return database + } + + private func sqliteError( + database: OpaquePointer?, + code: Int32, + fallback: String? = nil + ) -> Error { + let description = fallback ?? + database.flatMap(sqlite3_errmsg).map(String.init(cString:)) ?? + "Unknown SQLite error" + return NSError( + domain: "TransformableArchiveSafetyTests.SQLite", + code: Int(code), + userInfo: [NSLocalizedDescriptionKey: description] + ) + } +} + +private final class PersistentFixtureCoreDataService: + CoreDataServiceProtocol { + let configuration: CoreDataServiceConfigurationProtocol + + private let context: NSManagedObjectContext + + init(context: NSManagedObjectContext, modelURL: URL) { + self.context = context + configuration = CoreDataServiceConfiguration( + modelURL: modelURL, + storageType: .inMemory + ) + } + + func performAsync(block: @escaping CoreDataContextInvocationBlock) { + context.perform { + block(self.context, nil) + } + } + + func close() throws {} + + func drop() throws {} +} + +private final class PersistentFixtureStorageFacade: StorageFacadeProtocol { + let databaseService: CoreDataServiceProtocol + + init(context: NSManagedObjectContext, modelURL: URL) { + databaseService = PersistentFixtureCoreDataService( + context: context, + modelURL: modelURL + ) + } + + func createRepository( + filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor], + mapper: AnyCoreDataMapper + ) -> CoreDataRepository + where T: Identifiable, U: NSManagedObject { + CoreDataRepository( + databaseService: databaseService, + mapper: mapper, + filter: filter, + sortDescriptors: sortDescriptors + ) + } + + func createAsyncRepository( + filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor], + mapper: AnyCoreDataMapper + ) -> AsyncCoreDataRepositoryDefault + where T: Identifiable, U: NSManagedObject { + AsyncCoreDataRepositoryDefault( + databaseService: databaseService, + mapper: mapper, + filter: filter, + sortDescriptors: sortDescriptors + ) + } +} diff --git a/fearlessTests/Helper/UserDataStorageTestFacade.swift b/fearlessTests/Helper/UserDataStorageTestFacade.swift index eac0dc485d..32aee4a1a1 100644 --- a/fearlessTests/Helper/UserDataStorageTestFacade.swift +++ b/fearlessTests/Helper/UserDataStorageTestFacade.swift @@ -86,35 +86,21 @@ class UserDataStorageTestFacade: StorageFacadeProtocol { let databaseService: CoreDataServiceProtocol init() { - let modelName = UserStorageParams.modelVersion.rawValue - let subdirectory = UserStorageParams.modelDirectory - let bundle = Bundle(for: UserDataStorageFacade.self) - - let omoURL = bundle.url( - forResource: modelName, - withExtension: "omo", - subdirectory: subdirectory - ) - - let momURL = bundle.url( - forResource: modelName, - withExtension: "mom", - subdirectory: subdirectory - ) - - let mainOmoURL = Bundle.main.url( - forResource: modelName, - withExtension: "omo", - subdirectory: subdirectory - ) - - let mainMomURL = Bundle.main.url( - forResource: modelName, - withExtension: "mom", - subdirectory: subdirectory - ) - - let modelURL = omoURL ?? momURL ?? mainOmoURL ?? mainMomURL + let modelURL = [ + Bundle(for: UserDataStorageFacade.self), + Bundle.main + ].lazy.compactMap { + UserStorageParams.modelVersion.modelURL( + in: $0, + legacyModelDirectory: UserStorageParams.modelDirectory + ) + }.first + + guard let modelURL else { + preconditionFailure( + "Missing \(UserStorageParams.modelVersion.rawValue) in the unit-test host" + ) + } let managedObjectClassNames: [String: String] = [ "CDAccountInfo": NSStringFromClass(CDAccountInfo.self), @@ -127,7 +113,7 @@ class UserDataStorageTestFacade: StorageFacadeProtocol { ] databaseService = TestCoreDataService( - modelURL: modelURL!, + modelURL: modelURL, managedObjectClassNames: managedObjectClassNames ) } diff --git a/fearlessTests/Mocks/ModuleMocks.swift b/fearlessTests/Mocks/ModuleMocks.swift index e3a640fded..ba5f332963 100644 --- a/fearlessTests/Mocks/ModuleMocks.swift +++ b/fearlessTests/Mocks/ModuleMocks.swift @@ -18928,6 +18928,26 @@ class MockRootInteractorOutputProtocol: RootInteractorOutputProtocol, Cuckoo.Pro cuckoo_manager.enableDefaultStubImplementation() } + func didCompleteSetup() { + return cuckoo_manager.call( + "didCompleteSetup()", + parameters: (), + escapingParameters: (), + superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall(), + defaultCall: __defaultImplStub!.didCompleteSetup() + ) + } + + func didFailSetup() { + return cuckoo_manager.call( + "didFailSetup()", + parameters: (), + escapingParameters: (), + superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall(), + defaultCall: __defaultImplStub!.didFailSetup() + ) + } + struct __StubbingProxy_RootInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager @@ -18935,6 +18955,22 @@ class MockRootInteractorOutputProtocol: RootInteractorOutputProtocol, Cuckoo.Pro init(manager: Cuckoo.MockManager) { self.cuckoo_manager = manager } + + func didCompleteSetup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, + method: "didCompleteSetup()", + parameterMatchers: matchers + )) + } + + func didFailSetup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return .init(stub: cuckoo_manager.createStub(for: MockRootInteractorOutputProtocol.self, + method: "didFailSetup()", + parameterMatchers: matchers + )) + } } struct __VerificationProxy_RootInteractorOutputProtocol: Cuckoo.VerificationProxy { @@ -18947,12 +18983,40 @@ class MockRootInteractorOutputProtocol: RootInteractorOutputProtocol, Cuckoo.Pro self.callMatcher = callMatcher self.sourceLocation = sourceLocation } + + @discardableResult + func didCompleteSetup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify( + "didCompleteSetup()", + callMatcher: callMatcher, + parameterMatchers: matchers, + sourceLocation: sourceLocation + ) + } + + @discardableResult + func didFailSetup() -> Cuckoo.__DoNotUse<(), Void> { + let matchers: [Cuckoo.ParameterMatcher] = [] + return cuckoo_manager.verify( + "didFailSetup()", + callMatcher: callMatcher, + parameterMatchers: matchers, + sourceLocation: sourceLocation + ) + } } } class RootInteractorOutputProtocolStub:RootInteractorOutputProtocol, @unchecked Sendable { + func didCompleteSetup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + func didFailSetup() { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } } @@ -45974,4 +46038,3 @@ class UsernameSetupWireframeProtocolStub:UsernameSetupWireframeProtocol, @unchec return DefaultValueRegistry.defaultValue(for: (Void).self) } } - diff --git a/fearlessTests/Modules/AccountExportPassword/AccountExportPasswordTests.swift b/fearlessTests/Modules/AccountExportPassword/AccountExportPasswordTests.swift index 063cc07bee..ba458041b6 100644 --- a/fearlessTests/Modules/AccountExportPassword/AccountExportPasswordTests.swift +++ b/fearlessTests/Modules/AccountExportPassword/AccountExportPasswordTests.swift @@ -32,17 +32,23 @@ class AccountExportPasswordTests: XCTestCase { let presenter = AccountExportPasswordPresenter( flow: .single(chain: chain, address: walletAddress, wallet: wallet), - localizationManager: LocalizationManager.shared) + localizationManager: LocalizationManager.shared + ) presenter.view = view presenter.wireframe = wireframe let exportWrapper = KeystoreExportWrapper(keystore: keychain) - let interactor = AccountExportPasswordInteractor(exportJsonWrapper: exportWrapper, - accountRepository: AnyDataProviderRepository(accountsRepository), - operationManager: OperationManagerFacade.sharedManager, - extrinsicOperationFactory: nil, - chainRepository: AnyDataProviderRepository(chainRepository)) + let exportOperationQueue = OperationQueue() + exportOperationQueue.qualityOfService = .userInitiated + let exportOperationManager = OperationManager(operationQueue: exportOperationQueue) + let interactor = AccountExportPasswordInteractor( + exportJsonWrapper: exportWrapper, + accountRepository: AnyDataProviderRepository(accountsRepository), + operationManager: exportOperationManager, + extrinsicOperationFactory: nil, + chainRepository: AnyDataProviderRepository(chainRepository) + ) presenter.interactor = interactor interactor.presenter = presenter @@ -63,7 +69,7 @@ class AccountExportPasswordTests: XCTestCase { when(stub.set(error: any(AccountExportPasswordError.self))).thenDoNothing() } - let expectation = XCTestExpectation() + let expectation = expectation(description: "JSON export is presented") stub(wireframe) { stub in when(stub.present(viewModel: any(SheetAlertPresentableViewModel.self), from: any(ControllerBackedProtocol?.self))).thenDoNothing() @@ -90,6 +96,6 @@ class AccountExportPasswordTests: XCTestCase { // then - wait(for: [expectation], timeout: Constants.defaultExpectationDuration) + wait(for: [expectation], timeout: 15) } } diff --git a/fearlessTests/Modules/Root/RootTests.swift b/fearlessTests/Modules/Root/RootTests.swift index 91be77832a..569dc01ea9 100644 --- a/fearlessTests/Modules/Root/RootTests.swift +++ b/fearlessTests/Modules/Root/RootTests.swift @@ -1,225 +1,3568 @@ import XCTest import Foundation +import CoreData @testable import fearless import Cuckoo +import RobinHood import SoraKeystore import SoraFoundation import simd +import SQLite3 class RootTests: XCTestCase { - func testOnboardingDecision() throws { - // given - - let wireframe = MockRootWireframeProtocol() + func testWalletConnectGroupResolverUsesProductionEntitlementForReleaseBundle() { + XCTAssertEqual( + WalletConnectGroupIdentifierResolver.resolve( + bundleIdentifier: "jp.co.soramitsu.fearlesswallet" + ), + "group.jp.co.soramitsu.fearlesswallet" + ) + } - let keystore = InMemoryKeychain() + func testWalletConnectGroupResolverUsesDevelopmentEntitlementForDevBundle() { + XCTAssertEqual( + WalletConnectGroupIdentifierResolver.resolve( + bundleIdentifier: "jp.co.soramitsu.fearlesswallet.dev" + ), + "group.jp.co.soramitsu.fearlesswallet.walletconnect" + ) + } - let expectedPincode = "123456" - try keystore.saveKey(expectedPincode.data(using: .utf8)!, - with: KeystoreTag.pincode.rawValue) + func testWalletConnectGroupResolverRejectsUnsupportedApplicationIdentities() { + let unsupportedIdentifiers: [String?] = [ + nil, + "", + "jp.co.soramitsu.fearless", + "jp.co.soramitsu.fearlesswallet.debug", + "jp.co.soramitsu.fearlesswallet.dev.attacker", + "evil.jp.co.soramitsu.fearlesswallet" + ] - let settings = SelectedWalletSettings( - storageFacade: UserDataStorageTestFacade(), - operationQueue: OperationQueue() - ) - let userDefaultsStorage = InMemorySettingsManager() + for identifier in unsupportedIdentifiers { + XCTAssertNil( + WalletConnectGroupIdentifierResolver.resolve( + bundleIdentifier: identifier + ), + "Unexpected WalletConnect group for \(identifier ?? "nil")" + ) + } + } - let onboardingService = StubOnboardingService( - result: .success(Self.makeOnboardingPlatform()) + func testHostedUnitTestsUseIsolatedApplicationLaunch() { + XCTAssertTrue( + ProcessInfo.processInfo.arguments.contains("-UNITTEST"), + "Hosted unit tests must not launch the production startup path or open persistent stores" ) + } - let presenter = createPresenter( - wireframe: wireframe, - settings: settings, - keystore: keystore, - userDefaultsStorage: userDefaultsStorage, - onboardingService: onboardingService + func testCoreDataPreflightForwardsStoreOpenError() throws { + let configuration = try makeSubstrateInMemoryConfiguration() + let preflight = RootCoreDataStoragePreflight( + databaseService: FailingCoreDataService( + configuration: configuration, + error: RootSetupTestError.substrateStorageOpenFailed + ) ) - let splashExpectation = XCTestExpectation() - - stub(wireframe) { stub in - stub.showSplash(splashView: any(), on: any()).then { _ in - splashExpectation.fulfill() - } - } - - let onboardingExpectation = XCTestExpectation() - - stub(wireframe) { stub in - stub.showOnboarding(on: any(), with: any()).then { _ in - onboardingExpectation.fulfill() + XCTAssertThrowsError(try performStoragePreflight(preflight).get()) { error in + guard case RootSetupTestError.substrateStorageOpenFailed = error else { + return XCTFail("Unexpected forwarded open error: \(error)") } } + } - // when + func testCoreDataPreflightRejectsUnresolvableEntityClassBeforeFetch() throws { + let entity = NSEntityDescription() + entity.name = "BrokenSubstrateEntity" + entity.managedObjectClassName = "MissingSubstrateManagedObjectClass" - presenter.loadOnLaunch() + let model = NSManagedObjectModel() + model.entities = [entity] - // then + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + try coordinator.addPersistentStore( + ofType: NSInMemoryStoreType, + configurationName: nil, + at: nil + ) - wait(for: [splashExpectation, onboardingExpectation], timeout: Constants.defaultExpectationDuration) - XCTAssertTrue(try keystore.checkKey(for: KeystoreTag.pincode.rawValue)) + let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + let preflight = RootCoreDataStoragePreflight( + databaseService: ContextProvidingCoreDataService( + configuration: try makeSubstrateInMemoryConfiguration(), + context: context + ) + ) + + XCTAssertThrowsError(try performStoragePreflight(preflight).get()) { error in + guard + let preflightError = error as? RootStoragePreflightError, + case let .managedObjectClassUnavailable(entityName, className) = + preflightError + else { + return XCTFail("Expected a class-resolution failure, got \(error)") + } + + XCTAssertEqual(entityName, "BrokenSubstrateEntity") + XCTAssertEqual(className, "MissingSubstrateManagedObjectClass") + } } - func testPincodeSetupDecision() { - // given + func testCoreDataPreflightQueriesObjectIdsWithoutDecodingCorruptTransformables() throws { + let entity = NSEntityDescription() + entity.name = "PreflightArchive" + entity.managedObjectClassName = NSStringFromClass(NSManagedObject.self) - let wireframe = MockRootWireframeProtocol() + let payload = NSAttributeDescription() + payload.name = "payload" + payload.attributeType = .transformableAttributeType + payload.attributeValueClassName = NSStringFromClass(NSData.self) + payload.valueTransformerName = + NSValueTransformerName.secureUnarchiveFromDataTransformerName.rawValue + payload.isOptional = true + entity.properties = [payload] - let settings = SelectedWalletSettings( - storageFacade: UserDataStorageTestFacade(), - operationQueue: OperationQueue() - ) + let model = NSManagedObjectModel() + model.entities = [entity] - let selectedAccount = AccountGenerator.generateMetaAccount() - let saveExpectation = XCTestExpectation() - settings.save(value: selectedAccount, runningCompletionIn: .main) { result in - if case let .failure(error) = result { - XCTFail("Unexpected save error: \(error)") - } - saveExpectation.fulfill() + let directoryURL = FileManager.default.temporaryDirectory.appendingPathComponent( + "RootStoragePreflight-\(UUID().uuidString)", + isDirectory: true + ) + let storeURL = directoryURL.appendingPathComponent("Preflight.sqlite") + try FileManager.default.createDirectory( + at: directoryURL, + withIntermediateDirectories: true + ) + defer { + try? FileManager.default.removeItem(at: directoryURL) } - wait(for: [saveExpectation], timeout: Constants.defaultExpectationDuration) - let keystore = InMemoryKeychain() - let userDefaultsStorage = InMemorySettingsManager() + let writerCoordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + let storeOptions: [AnyHashable: Any] = [ + NSSQLitePragmasOption: ["journal_mode": "DELETE"] + ] + let writerStore = try writerCoordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: storeOptions + ) + let writerContext = NSManagedObjectContext( + concurrencyType: .mainQueueConcurrencyType + ) + writerContext.persistentStoreCoordinator = writerCoordinator + let object = NSManagedObject(entity: entity, insertInto: writerContext) + object.setValue(Data("valid archive".utf8), forKey: payload.name) + try writerContext.save() + writerContext.reset() + try writerCoordinator.remove(writerStore) - let presenter = createPresenter(wireframe: wireframe, - settings: settings, - keystore: keystore, - userDefaultsStorage: userDefaultsStorage) - - let splashExpectation = XCTestExpectation() + XCTAssertEqual( + try executeSQLiteUpdate( + "UPDATE ZPREFLIGHTARCHIVE SET ZPAYLOAD = X'00FF00'", + at: storeURL + ), + 1 + ) - stub(wireframe) { stub in - stub.showSplash(splashView: any(), on: any()).then { _ in - splashExpectation.fulfill() - } + let readerCoordinator = NSPersistentStoreCoordinator( + managedObjectModel: model + ) + let readerStore = try readerCoordinator.addPersistentStore( + ofType: NSSQLiteStoreType, + configurationName: nil, + at: storeURL, + options: storeOptions + ) + defer { + try? readerCoordinator.remove(readerStore) } + let readerContext = NSManagedObjectContext( + concurrencyType: .mainQueueConcurrencyType + ) + readerContext.persistentStoreCoordinator = readerCoordinator + let preflight = RootCoreDataStoragePreflight( + databaseService: ContextProvidingCoreDataService( + configuration: try makeSubstrateInMemoryConfiguration(), + context: readerContext + ) + ) - let pincodeExpectation = XCTestExpectation() + XCTAssertNoThrow(try performStoragePreflight(preflight).get()) + XCTAssertFalse(readerContext.hasChanges) + } - stub(wireframe) { stub in - stub.showPincodeSetup(on: any()).then { _ in - pincodeExpectation.fulfill() - } - stub.showMain(on: any()).thenDoNothing() + func testUserStorageFacadeMissingModelReturnsControlledFailure() throws { + let directoryURL = FileManager.default.temporaryDirectory.appendingPathComponent( + "MissingUserModel-\(UUID().uuidString)", + isDirectory: true + ) + defer { + try? FileManager.default.removeItem(at: directoryURL) } - // when + let facade = UserDataStorageFacade( + modelURL: nil, + databaseDirectory: directoryURL + ) + let completionExpectation = expectation( + description: "missing User model returns an error" + ) - presenter.loadOnLaunch() + facade.databaseService.performAsync { context, error in + XCTAssertNil(context) - // then + guard + let serviceError = error as? CoreDataServiceError, + case .modelInitializationFailed = serviceError + else { + XCTFail("Expected modelInitializationFailed, got \(String(describing: error))") + completionExpectation.fulfill() + return + } - wait(for: [splashExpectation, pincodeExpectation], timeout: Constants.defaultExpectationDuration) + completionExpectation.fulfill() + } + + wait( + for: [completionExpectation], + timeout: Constants.defaultExpectationDuration + ) } - func testMainScreenDecision() throws { - // given + func testSubstrateStorageFacadeMissingModelFailsPreflightWithoutTrap() throws { + let directoryURL = FileManager.default.temporaryDirectory.appendingPathComponent( + "MissingSubstrateModel-\(UUID().uuidString)", + isDirectory: true + ) + defer { + try? FileManager.default.removeItem(at: directoryURL) + } - let wireframe = MockRootWireframeProtocol() + let facade = SubstrateDataStorageFacade( + modelURL: nil, + databaseDirectory: directoryURL, + databaseName: "MissingSubstrateModel.sqlite" + ) + let preflight = RootCoreDataStoragePreflight( + databaseService: facade.databaseService + ) - let keystore = InMemoryKeychain() + XCTAssertThrowsError(try performStoragePreflight(preflight).get()) { error in + guard + let serviceError = error as? CoreDataServiceError, + case .modelInitializationFailed = serviceError + else { + return XCTFail("Expected modelInitializationFailed, got \(error)") + } + } + } + func testStartViewHelperDoesNotResolveWalletSettingsDuringConstruction() { let settings = SelectedWalletSettings( storageFacade: UserDataStorageTestFacade(), operationQueue: OperationQueue() ) + var providerInvocationCount = 0 + let helper = StartViewHelper( + keystore: InMemoryKeychain(), + selectedWalletSettingsProvider: { + providerInvocationCount += 1 + return settings + }, + userDefaultsStorage: InMemorySettingsManager() + ) - let selectedAccount = AccountGenerator.generateMetaAccount() - let saveExpectation = XCTestExpectation() - settings.save(value: selectedAccount, runningCompletionIn: .main) { result in - if case let .failure(error) = result { - XCTFail("Unexpected save error: \(error)") + XCTAssertEqual(providerInvocationCount, 0) + + _ = helper.startView(onboardingConfig: nil) + + XCTAssertEqual(providerInvocationCount, 1) + } + + func testMigrationFailureDoesNotResolveStorePreflightRegistryOrWalletSettings() { + let recorder = RootSetupEventRecorder() + let settings = RecordingImmediateRootSelectedWalletSettings( + recorder: recorder, + result: .success(nil) + ) + let chainRegistry = MockChainRegistryProtocol() + let output = MockRootInteractorOutputProtocol() + let failureExpectation = expectation( + description: "migration failure is reported" + ) + + stub(output) { stub in + stub.didFailSetup().then { + failureExpectation.fulfill() } - saveExpectation.fulfill() } - wait(for: [saveExpectation], timeout: Constants.defaultExpectationDuration) - let expectedPincode = "123456" - try keystore.saveKey(expectedPincode.data(using: .utf8)!, - with: KeystoreTag.pincode.rawValue) - let userDefaultsStorage = InMemorySettingsManager() + let interactor = RootInteractor( + chainRegistryProvider: { + recorder.record(.chainRegistry) + return chainRegistry + }, + storagePreflightProvider: { + recorder.record(.storagePreflightProvider) + return ImmediateRootStoragePreflight(result: .success(())) + }, + settingsProvider: { + recorder.record(.walletSettingsProvider) + return settings + }, + applicationConfig: ApplicationConfig.shared, + eventCenter: MockEventCenterProtocol(), + migrators: [ + RecordingRootMigrator( + recorder: recorder, + error: RootSetupTestError.migrationFailed + ) + ], + onboardingService: StubOnboardingService( + result: .failure(OnboardingServiceError.empty) + ), + onboardingConfigResolver: OnboardingConfigVersionResolver( + userDefaultsStorage: InMemorySettingsManager() + ) + ) + interactor.presenter = output - let presenter = createPresenter(wireframe: wireframe, - settings: settings, - keystore: keystore, - userDefaultsStorage: userDefaultsStorage) - - let splashExpectation = XCTestExpectation() + interactor.setup(runMigrations: true) - stub(wireframe) { stub in - stub.showSplash(splashView: any(), on: any()).then { _ in - splashExpectation.fulfill() + wait( + for: [failureExpectation], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual(recorder.snapshot, [.migration]) + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(0)).performColdBoot() + verify(output, times(0)).didCompleteSetup() + verify(output, times(1)).didFailSetup() + } + + func testMigrationFailureBlocksNoMigrationBypassAndRequiredRetryRerunsMigration() { + let recorder = RootSetupEventRecorder() + let settings = RecordingImmediateRootSelectedWalletSettings( + recorder: recorder, + result: .success(nil) + ) + let chainRegistry = MockChainRegistryProtocol() + let output = MockRootInteractorOutputProtocol() + let firstFailureExpectation = expectation( + description: "first migration attempt fails" + ) + let blockedBypassExpectation = expectation( + description: "no-migration retry cannot bypass failed migration" + ) + let retryCompletionExpectation = expectation( + description: "migration retry completes setup" + ) + var failureCallbackCount = 0 + let migrator = SequencedRootMigrator( + recorder: recorder, + results: [ + .failure(RootSetupTestError.migrationFailed), + .success(()) + ] + ) + + stub(chainRegistry) { stub in + stub.performColdBoot().then { + recorder.record(.coldBoot) } } + stub(output) { stub in + stub.didFailSetup().then { + failureCallbackCount += 1 - let mainScreenExpectation = XCTestExpectation() - - stub(wireframe) { stub in - stub.showLocalAuthentication(on: any()).then { _ in - mainScreenExpectation.fulfill() + if failureCallbackCount == 1 { + firstFailureExpectation.fulfill() + } else if failureCallbackCount == 2 { + blockedBypassExpectation.fulfill() + } + } + stub.didCompleteSetup().then { + retryCompletionExpectation.fulfill() } - stub.showMain(on: any()).thenDoNothing() } - // when + let interactor = RootInteractor( + chainRegistryProvider: { + recorder.record(.chainRegistry) + return chainRegistry + }, + storagePreflightProvider: { + recorder.record(.storagePreflightProvider) + return RecordingRootStoragePreflight( + recorder: recorder, + result: .success(()) + ) + }, + settingsProvider: { + recorder.record(.walletSettingsProvider) + return settings + }, + applicationConfig: ApplicationConfig.shared, + eventCenter: MockEventCenterProtocol(), + migrators: [migrator], + onboardingService: StubOnboardingService( + result: .failure(OnboardingServiceError.empty) + ), + onboardingConfigResolver: OnboardingConfigVersionResolver( + userDefaultsStorage: InMemorySettingsManager() + ) + ) + interactor.presenter = output - presenter.loadOnLaunch() + interactor.setup(runMigrations: true) + wait( + for: [firstFailureExpectation], + timeout: Constants.defaultExpectationDuration + ) - // then + XCTAssertEqual(recorder.snapshot, [.migration]) - wait(for: [splashExpectation, mainScreenExpectation], timeout: Constants.defaultExpectationDuration) + interactor.setup(runMigrations: false) + wait( + for: [blockedBypassExpectation], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual(recorder.snapshot, [.migration]) + + interactor.setup(runMigrations: true) + wait( + for: [retryCompletionExpectation], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual( + recorder.snapshot, + [ + .migration, + .migration, + .storagePreflightProvider, + .storagePreflight, + .chainRegistry, + .walletSettingsProvider, + .walletSetup, + .coldBoot + ] + ) + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(1)).performColdBoot() + verify(output, times(1)).didCompleteSetup() + verify(output, times(2)).didFailSetup() } - private func createPresenter( - wireframe: MockRootWireframeProtocol, - settings: SelectedWalletSettings, - keystore: KeystoreProtocol, - userDefaultsStorage: SettingsManagerProtocol, - migrators: [Migrating] = [], - onboardingService: OnboardingServiceProtocol = StubOnboardingService(result: .failure(OnboardingServiceError.empty)) - ) -> RootPresenter { - let resolver = OnboardingConfigVersionResolver(userDefaultsStorage: userDefaultsStorage) + func testMigrationDeadlineFailsClosedAndRetriesReuseSingleRunningAttempt() { + let recorder = RootSetupEventRecorder() + let settings = RecordingImmediateRootSelectedWalletSettings( + recorder: recorder, + result: .success(nil) + ) + let chainRegistry = MockChainRegistryProtocol() + let output = MockRootInteractorOutputProtocol() + let migrationStartedExpectation = expectation( + description: "migration attempt starts" + ) + let firstDeadlineScheduledExpectation = expectation( + description: "first migration deadline is scheduled" + ) + let retryDeadlineScheduledExpectation = expectation( + description: "retry waits on the same migration attempt" + ) + let timeoutFailureExpectation = expectation( + description: "migration timeout fails setup" + ) + let bypassFailureExpectation = expectation( + description: "no-migration request cannot bypass running migration" + ) + let completionExpectation = expectation( + description: "required retry completes after original migration" + ) + let deadlineScheduler = ManualRootSetupDeadlineScheduler( + scheduledExpectations: [ + firstDeadlineScheduledExpectation, + retryDeadlineScheduledExpectation + ] + ) + let migrator = BlockingRootMigrator( + recorder: recorder, + startedExpectation: migrationStartedExpectation + ) + var failureCount = 0 + + stub(chainRegistry) { stub in + stub.performColdBoot().then { + recorder.record(.coldBoot) + } + } + stub(output) { stub in + stub.didFailSetup().then { + failureCount += 1 + if failureCount == 1 { + timeoutFailureExpectation.fulfill() + } else if failureCount == 2 { + bypassFailureExpectation.fulfill() + } + } + stub.didCompleteSetup().then { + completionExpectation.fulfill() + } + } let interactor = RootInteractor( - chainRegistry: ChainRegistryFacade.sharedRegistry, - settings: settings, + chainRegistryProvider: { + recorder.record(.chainRegistry) + return chainRegistry + }, + storagePreflightProvider: { + recorder.record(.storagePreflightProvider) + return RecordingRootStoragePreflight( + recorder: recorder, + result: .success(()) + ) + }, + settingsProvider: { + recorder.record(.walletSettingsProvider) + return settings + }, applicationConfig: ApplicationConfig.shared, eventCenter: MockEventCenterProtocol(), - migrators: migrators, - onboardingService: onboardingService, - onboardingConfigResolver: resolver + migrators: [migrator], + onboardingService: StubOnboardingService( + result: .failure(OnboardingServiceError.empty) + ), + onboardingConfigResolver: OnboardingConfigVersionResolver( + userDefaultsStorage: InMemorySettingsManager() + ), + migrationDeadline: 7, + setupDeadline: 42, + setupDeadlineScheduler: deadlineScheduler.schedule ) + interactor.presenter = output + defer { + migrator.release() + } - let startViewHelper = StartViewHelper(keystore: keystore, - selectedWalletSettings: settings, - userDefaultsStorage: userDefaultsStorage) - let presenter = RootPresenter(localizationManager: LocalizationManager.shared, startViewHelper: startViewHelper) + interactor.setup(runMigrations: true) + wait( + for: [ + migrationStartedExpectation, + firstDeadlineScheduledExpectation + ], + timeout: Constants.defaultExpectationDuration + ) - let view = MockControllerBackedProtocol() + XCTAssertEqual(deadlineScheduler.delays, [7]) + deadlineScheduler.fire(at: 0) + wait( + for: [timeoutFailureExpectation], + timeout: Constants.defaultExpectationDuration + ) - presenter.view = view - presenter.window = UIWindow() - presenter.wireframe = wireframe - presenter.interactor = interactor - interactor.presenter = presenter + interactor.setup(runMigrations: false) + wait( + for: [bypassFailureExpectation], + timeout: Constants.defaultExpectationDuration + ) - return presenter + interactor.setup(runMigrations: true) + wait( + for: [retryDeadlineScheduledExpectation], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual(migrator.invocationCount, 1) + XCTAssertEqual(migrator.maximumConcurrentInvocationCount, 1) + XCTAssertEqual(deadlineScheduler.delays, [7, 7]) + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(0)).performColdBoot() + + migrator.release() + wait( + for: [completionExpectation], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual( + recorder.snapshot, + [ + .migration, + .storagePreflightProvider, + .storagePreflight, + .chainRegistry, + .walletSettingsProvider, + .walletSetup, + .coldBoot + ] + ) + XCTAssertEqual(migrator.invocationCount, 1) + XCTAssertEqual(migrator.maximumConcurrentInvocationCount, 1) + XCTAssertEqual(deadlineScheduler.delays, [7, 7, 42, 42]) + verify(output, times(2)).didFailSetup() + verify(output, times(1)).didCompleteSetup() + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(1)).performColdBoot() } -} -private final class StubOnboardingService: OnboardingServiceProtocol { - var result: Result + func testPreflightFailureDoesNotResolveRegistryOrWalletSettings() { + let recorder = RootSetupEventRecorder() + let settings = RecordingImmediateRootSelectedWalletSettings( + recorder: recorder, + result: .success(nil) + ) + let chainRegistry = MockChainRegistryProtocol() + let output = MockRootInteractorOutputProtocol() + let failureExpectation = expectation( + description: "preflight failure is reported" + ) - init(result: Result) { - self.result = result + stub(output) { stub in + stub.didFailSetup().then { + failureExpectation.fulfill() + } + } + + let interactor = RootInteractor( + chainRegistryProvider: { + recorder.record(.chainRegistry) + return chainRegistry + }, + storagePreflightProvider: { + recorder.record(.storagePreflightProvider) + return RecordingRootStoragePreflight( + recorder: recorder, + result: .failure(RootSetupTestError.substrateStorageOpenFailed) + ) + }, + settingsProvider: { + recorder.record(.walletSettingsProvider) + return settings + }, + applicationConfig: ApplicationConfig.shared, + eventCenter: MockEventCenterProtocol(), + migrators: [RecordingRootMigrator(recorder: recorder)], + onboardingService: StubOnboardingService( + result: .failure(OnboardingServiceError.empty) + ), + onboardingConfigResolver: OnboardingConfigVersionResolver( + userDefaultsStorage: InMemorySettingsManager() + ) + ) + interactor.presenter = output + + interactor.setup(runMigrations: true) + + wait( + for: [failureExpectation], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual( + recorder.snapshot, + [.migration, .storagePreflightProvider, .storagePreflight] + ) + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(0)).performColdBoot() + verify(output, times(0)).didCompleteSetup() + verify(output, times(1)).didFailSetup() } - func fetchConfigs() async throws -> OnboardingConfigPlatform { - try result.get() + func testWalletFailureRetryDoesNotRerunMigrationsAgainstResolvedStores() { + let recorder = RootSetupEventRecorder() + let settings = SequencedRootSelectedWalletSettings( + recorder: recorder, + results: [ + .failure(RootSetupTestError.walletRepositoryFailed), + .success(nil) + ] + ) + let chainRegistry = MockChainRegistryProtocol() + let output = MockRootInteractorOutputProtocol() + let firstFailureExpectation = expectation( + description: "wallet setup fails after migrations" + ) + let retryCompletionExpectation = expectation( + description: "wallet setup retry completes" + ) + + stub(chainRegistry) { stub in + stub.performColdBoot().then { + recorder.record(.coldBoot) + } + } + stub(output) { stub in + stub.didFailSetup().then { + firstFailureExpectation.fulfill() + } + stub.didCompleteSetup().then { + retryCompletionExpectation.fulfill() + } + } + + let interactor = RootInteractor( + chainRegistryProvider: { + recorder.record(.chainRegistry) + return chainRegistry + }, + storagePreflightProvider: { + recorder.record(.storagePreflightProvider) + return RecordingRootStoragePreflight( + recorder: recorder, + result: .success(()) + ) + }, + settingsProvider: { + recorder.record(.walletSettingsProvider) + return settings + }, + applicationConfig: ApplicationConfig.shared, + eventCenter: MockEventCenterProtocol(), + migrators: [RecordingRootMigrator(recorder: recorder)], + onboardingService: StubOnboardingService( + result: .failure(OnboardingServiceError.empty) + ), + onboardingConfigResolver: OnboardingConfigVersionResolver( + userDefaultsStorage: InMemorySettingsManager() + ) + ) + interactor.presenter = output + + interactor.setup(runMigrations: false) + wait( + for: [firstFailureExpectation], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual( + recorder.snapshot, + [ + .storagePreflightProvider, + .storagePreflight, + .chainRegistry, + .walletSettingsProvider, + .walletSetup + ] + ) + + interactor.setup(runMigrations: true) + wait( + for: [retryCompletionExpectation], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual( + recorder.snapshot, + [ + .storagePreflightProvider, + .storagePreflight, + .chainRegistry, + .walletSettingsProvider, + .walletSetup, + .storagePreflightProvider, + .storagePreflight, + .walletSetup, + .coldBoot + ] + ) + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(1)).performColdBoot() + verify(output, times(1)).didCompleteSetup() + verify(output, times(1)).didFailSetup() + } + + func testMigrationFailureDoesNotLoadWalletOrRouteAndPreservesPincode() throws { + // given + + let recorder = RootSetupEventRecorder() + let storageFacade = RecordingUserDataStorageTestFacade(recorder: recorder) + let settings = SelectedWalletSettings( + storageFacade: storageFacade, + operationQueue: OperationQueue() + ) + let keystore = InMemoryKeychain() + let expectedPincode = "123456" + try keystore.saveKey( + Data(expectedPincode.utf8), + with: KeystoreTag.pincode.rawValue + ) + + let migrator = RecordingRootMigrator(recorder: recorder, error: RootSetupTestError.migrationFailed) + let wireframe = MockRootWireframeProtocol() + let alertController = AlertCapturingViewController() + let readinessReporter = RecordingRootStartupReadinessReporter() + let failureExpectation = XCTestExpectation(description: "setup failure is presented") + + alertController.onPresent = { presentedController in + XCTAssertTrue(presentedController is UIAlertController) + failureExpectation.fulfill() + } + + stub(wireframe) { stub in + stub.showSplash(splashView: any(), on: any()).thenDoNothing() + } + + let presenter = createPresenter( + wireframe: wireframe, + settings: settings, + keystore: keystore, + userDefaultsStorage: InMemorySettingsManager(), + migrators: [migrator], + view: alertController, + chainRegistryProvider: { + recorder.record(.chainRegistry) + return ChainRegistryFacade.sharedRegistry + }, + storagePreflightProvider: { + RecordingRootStoragePreflight( + recorder: recorder, + result: .success(()) + ) + }, + startupReadinessReporter: readinessReporter + ) + + // when + + presenter.loadOnLaunch() + + // then + + wait(for: [failureExpectation], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(recorder.snapshot, [.migration]) + XCTAssertEqual(readinessReporter.readyCount, 0) + XCTAssertEqual(readinessReporter.failureCount, 1) + XCTAssertTrue(try keystore.checkKey(for: KeystoreTag.pincode.rawValue)) + verify(wireframe, times(0)).showLocalAuthentication(on: any()) + verify(wireframe, times(0)).showPincodeSetup(on: any()) + verify(wireframe, times(0)).showMain(on: any()) + verify(wireframe, times(0)).showBroken(on: any()) + verify(wireframe, times(0)).showOnboarding(on: any(), with: any()) + } + + func testSubstratePreflightFailureDoesNotCreateRegistryOrOpenWalletAndPreservesData() throws { + let recorder = RootSetupEventRecorder() + let storageFacade = RecordingUserDataStorageTestFacade(recorder: recorder) + let settings = SelectedWalletSettings( + storageFacade: storageFacade, + operationQueue: OperationQueue() + ) + try insertTonOnlyWallet(in: storageFacade) + let walletBefore = try tonOnlyWalletSnapshot(in: storageFacade) + recorder.reset() + + let keystore = InMemoryKeychain() + try keystore.saveKey( + Data("123456".utf8), + with: KeystoreTag.pincode.rawValue + ) + + let chainRegistry = MockChainRegistryProtocol() + let wireframe = MockRootWireframeProtocol() + let alertController = AlertCapturingViewController() + let failureExpectation = expectation( + description: "Substrate preflight failure is presented" + ) + + stub(wireframe) { stub in + stub.showSplash(splashView: any(), on: any()).thenDoNothing() + } + alertController.onPresent = { presentedController in + XCTAssertTrue(presentedController is UIAlertController) + failureExpectation.fulfill() + } + + let presenter = createPresenter( + wireframe: wireframe, + settings: settings, + keystore: keystore, + userDefaultsStorage: InMemorySettingsManager(), + migrators: [RecordingRootMigrator(recorder: recorder)], + view: alertController, + chainRegistryProvider: { + recorder.record(.chainRegistry) + return chainRegistry + }, + storagePreflightProvider: { + RecordingRootStoragePreflight( + recorder: recorder, + result: .failure(RootSetupTestError.substrateStorageOpenFailed) + ) + } + ) + + presenter.loadOnLaunch() + + wait(for: [failureExpectation], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(recorder.snapshot, [.migration, .storagePreflight]) + XCTAssertEqual(try tonOnlyWalletSnapshot(in: storageFacade), walletBefore) + XCTAssertTrue(try keystore.checkKey(for: KeystoreTag.pincode.rawValue)) + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(0)).performColdBoot() + verify(wireframe, times(0)).showLocalAuthentication(on: any()) + verify(wireframe, times(0)).showPincodeSetup(on: any()) + verify(wireframe, times(0)).showMain(on: any()) + verify(wireframe, times(0)).showBroken(on: any()) + verify(wireframe, times(0)).showOnboarding(on: any(), with: any()) + } + + func testWalletRepositoryFailureDoesNotBootOrRouteAndPreservesPincode() throws { + // given + + let storageFacade = FailingUserDataStorageTestFacade( + error: RootSetupTestError.walletRepositoryFailed + ) + let settings = SelectedWalletSettings( + storageFacade: storageFacade, + operationQueue: OperationQueue() + ) + let keystore = InMemoryKeychain() + try keystore.saveKey( + Data("123456".utf8), + with: KeystoreTag.pincode.rawValue + ) + + let chainRegistry = MockChainRegistryProtocol() + let wireframe = MockRootWireframeProtocol() + let alertController = AlertCapturingViewController() + let failureExpectation = XCTestExpectation(description: "wallet-load failure is presented") + let onboardingService = StubOnboardingService( + result: .success(Self.makeOnboardingPlatform()) + ) + + stub(wireframe) { stub in + stub.showSplash(splashView: any(), on: any()).thenDoNothing() + } + alertController.onPresent = { presentedController in + XCTAssertTrue(presentedController is UIAlertController) + failureExpectation.fulfill() + } + + let presenter = createPresenter( + wireframe: wireframe, + settings: settings, + keystore: keystore, + userDefaultsStorage: InMemorySettingsManager(), + onboardingService: onboardingService, + view: alertController, + chainRegistryProvider: { chainRegistry } + ) + + // when + + presenter.loadOnLaunch() + + // then + + wait(for: [failureExpectation], timeout: Constants.defaultExpectationDuration) + + XCTAssertTrue(try keystore.checkKey(for: KeystoreTag.pincode.rawValue)) + XCTAssertEqual(settings.storeState, .unavailable) + XCTAssertEqual(onboardingService.fetchCallCount, 0) + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(0)).performColdBoot() + verify(wireframe, times(0)).showLocalAuthentication(on: any()) + verify(wireframe, times(0)).showPincodeSetup(on: any()) + verify(wireframe, times(0)).showMain(on: any()) + verify(wireframe, times(0)).showBroken(on: any()) + verify(wireframe, times(0)).showOnboarding(on: any(), with: any()) + } + + func testOutOfOrderDualSetupRejectsStaleCallbackBeforeBootOrPresenterMutation() { + let firstRequestStarted = expectation(description: "first wallet request starts") + let secondRequestStarted = expectation(description: "retry wallet request starts") + let newestSetupCompleted = expectation(description: "newest setup completes") + let staleSuccessDelivered = expectation(description: "stale success callback returns") + let staleFailureDelivered = expectation(description: "stale failure callback returns") + let settings = ControllableRootSelectedWalletSettings( + requestStartedExpectations: [ + firstRequestStarted, + secondRequestStarted + ] + ) + let recorder = RootGenerationEventRecorder() + let chainRegistry = MockChainRegistryProtocol() + let output = MockRootInteractorOutputProtocol() + + stub(chainRegistry) { stub in + stub.performHotBoot().then { + recorder.record(.hotBoot) + } + stub.performColdBoot().then { + recorder.record(.coldBoot) + } + } + stub(output) { stub in + stub.didCompleteSetup().then { + recorder.record(.completed) + newestSetupCompleted.fulfill() + } + stub.didFailSetup().then { + recorder.record(.failed) + } + } + + let interactor = RootInteractor( + chainRegistryProvider: { chainRegistry }, + storagePreflightProvider: { + ImmediateRootStoragePreflight(result: .success(())) + }, + settings: settings, + applicationConfig: ApplicationConfig.shared, + eventCenter: MockEventCenterProtocol(), + migrators: [], + onboardingService: StubOnboardingService( + result: .failure(OnboardingServiceError.empty) + ), + onboardingConfigResolver: OnboardingConfigVersionResolver( + userDefaultsStorage: InMemorySettingsManager() + ) + ) + interactor.presenter = output + + interactor.setup(runMigrations: false) + wait(for: [firstRequestStarted], timeout: Constants.defaultExpectationDuration) + + interactor.setup(runMigrations: false) + wait(for: [secondRequestStarted], timeout: Constants.defaultExpectationDuration) + + settings.resolveRequest( + at: 1, + with: .success(nil) + ) + wait(for: [newestSetupCompleted], timeout: Constants.defaultExpectationDuration) + + XCTAssertEqual(recorder.snapshot, [.coldBoot, .completed]) + XCTAssertEqual(recorder.routeState, .completed) + + settings.resolveRequest( + at: 0, + with: .success(AccountGenerator.generateMetaAccount()), + deliveryExpectation: staleSuccessDelivered + ) + settings.resolveRequest( + at: 0, + with: .failure(RootSetupTestError.staleWalletLoadFailed), + deliveryExpectation: staleFailureDelivered + ) + wait( + for: [staleSuccessDelivered, staleFailureDelivered], + timeout: Constants.defaultExpectationDuration + ) + + XCTAssertEqual(recorder.snapshot, [.coldBoot, .completed]) + XCTAssertEqual(recorder.routeState, .completed) + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(1)).performColdBoot() + verify(output, times(1)).didCompleteSetup() + verify(output, times(0)).didFailSetup() + } + + func testPreflightTimeoutIgnoresLateResultAndRetryUsesFreshAttempt() { + let firstRequestStarted = expectation(description: "first preflight starts") + let secondRequestStarted = expectation(description: "retry preflight starts") + let firstTimedOut = expectation(description: "first preflight times out") + let retryCompleted = expectation(description: "retry completes") + let staleResultDelivered = expectation(description: "late preflight returns") + let preflight = ControllableRootStoragePreflight( + requestStartedExpectations: [ + firstRequestStarted, + secondRequestStarted + ] + ) + let deadlineScheduler = ManualRootSetupDeadlineScheduler() + let settings = RecordingImmediateRootSelectedWalletSettings( + recorder: RootSetupEventRecorder(), + result: .success(nil) + ) + let chainRegistry = MockChainRegistryProtocol() + let output = MockRootInteractorOutputProtocol() + + stub(chainRegistry) { stub in + stub.performColdBoot().thenDoNothing() + } + stub(output) { stub in + stub.didFailSetup().then { + firstTimedOut.fulfill() + } + stub.didCompleteSetup().then { + retryCompleted.fulfill() + } + } + + let interactor = RootInteractor( + chainRegistryProvider: { chainRegistry }, + storagePreflightProvider: { preflight }, + settings: settings, + applicationConfig: ApplicationConfig.shared, + eventCenter: MockEventCenterProtocol(), + migrators: [], + onboardingService: StubOnboardingService( + result: .failure(OnboardingServiceError.empty) + ), + onboardingConfigResolver: OnboardingConfigVersionResolver( + userDefaultsStorage: InMemorySettingsManager() + ), + setupDeadline: 42, + setupDeadlineScheduler: deadlineScheduler.schedule + ) + interactor.presenter = output + + interactor.setup(runMigrations: false) + wait( + for: [firstRequestStarted], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(deadlineScheduler.delays, [42]) + deadlineScheduler.fire(at: 0) + wait( + for: [firstTimedOut], + timeout: Constants.defaultExpectationDuration + ) + + interactor.setup(runMigrations: false) + wait( + for: [secondRequestStarted], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(deadlineScheduler.delays, [42, 42]) + preflight.resolveRequest( + at: 0, + with: .success(()), + deliveryExpectation: staleResultDelivered + ) + preflight.resolveRequest(at: 1, with: .success(())) + + wait( + for: [staleResultDelivered, retryCompleted], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(deadlineScheduler.delays, [42, 42, 42]) + deadlineScheduler.fire(at: 1) + deadlineScheduler.fire(at: 2) + + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(1)).performColdBoot() + verify(output, times(1)).didFailSetup() + verify(output, times(1)).didCompleteSetup() + } + + func testSynchronouslyBlockedPreflightTimesOutAndDoesNotBlockRetry() { + let blockedRequestStarted = expectation( + description: "blocking preflight starts" + ) + let firstRequestTimedOut = expectation( + description: "blocking preflight times out" + ) + firstRequestTimedOut.assertForOverFulfill = true + let retryCompleted = expectation( + description: "retry completes while first preflight remains blocked" + ) + retryCompleted.assertForOverFulfill = true + let lateCallbacksDelivered = expectation( + description: "blocked preflight delivers late success and failure" + ) + let blockedPreflight = SynchronouslyBlockingRootStoragePreflight( + requestStartedExpectation: blockedRequestStarted, + lateCallbacksDeliveredExpectation: lateCallbacksDelivered + ) + defer { + blockedPreflight.release() + } + + let preflightSequence = RootStoragePreflightSequence( + preflights: [ + blockedPreflight, + ImmediateRootStoragePreflight(result: .success(())) + ] + ) + let settings = RecordingImmediateRootSelectedWalletSettings( + recorder: RootSetupEventRecorder(), + result: .success(nil) + ) + let chainRegistry = MockChainRegistryProtocol() + let output = MockRootInteractorOutputProtocol() + + stub(chainRegistry) { stub in + stub.performColdBoot().thenDoNothing() + } + stub(output) { stub in + stub.didFailSetup().then { + XCTAssertTrue(Thread.isMainThread) + firstRequestTimedOut.fulfill() + } + stub.didCompleteSetup().then { + XCTAssertTrue(Thread.isMainThread) + retryCompleted.fulfill() + } + } + + let setupDeadline: TimeInterval = 0.25 + let interactor = RootInteractor( + chainRegistryProvider: { chainRegistry }, + storagePreflightProvider: preflightSequence.next, + settings: settings, + applicationConfig: ApplicationConfig.shared, + eventCenter: MockEventCenterProtocol(), + migrators: [], + onboardingService: StubOnboardingService( + result: .failure(OnboardingServiceError.empty) + ), + onboardingConfigResolver: OnboardingConfigVersionResolver( + userDefaultsStorage: InMemorySettingsManager() + ), + setupDeadline: setupDeadline + ) + interactor.presenter = output + + interactor.setup(runMigrations: false) + wait( + for: [blockedRequestStarted], + timeout: Constants.defaultExpectationDuration + ) + + // The preflight invocation is still synchronously blocked. The default + // deadline must run independently and report failure before release. + wait( + for: [firstRequestTimedOut], + timeout: Constants.defaultExpectationDuration + ) + + interactor.setup(runMigrations: false) + wait( + for: [retryCompleted], + timeout: Constants.defaultExpectationDuration + ) + + // Both late outcomes from the timed-out generation must lose the same + // completion gate and must not mutate the successful retry's route. + blockedPreflight.release() + wait( + for: [lateCallbacksDelivered], + timeout: Constants.defaultExpectationDuration + ) + + let pendingDeadlinesDrained = expectation( + description: "retry deadlines have had time to lose their gates" + ) + DispatchQueue.global().asyncAfter( + deadline: .now() + setupDeadline * 2 + ) { + pendingDeadlinesDrained.fulfill() + } + wait( + for: [pendingDeadlinesDrained], + timeout: Constants.defaultExpectationDuration + ) + + verify(chainRegistry, times(0)).performHotBoot() + verify(chainRegistry, times(1)).performColdBoot() + verify(output, times(1)).didFailSetup() + verify(output, times(1)).didCompleteSetup() + } + + func testTwoBlockedPreflightsFailFurtherRetriesFastWithoutUnboundedInvocation() { + let firstRequestStarted = expectation( + description: "first blocking preflight starts" + ) + let secondRequestStarted = expectation( + description: "second blocking preflight starts" + ) + let firstLateCallbacksDelivered = expectation( + description: "first blocked preflight delivers conflicting callbacks" + ) + let secondLateCallbacksDelivered = expectation( + description: "second blocked preflight delivers conflicting callbacks" + ) + let firstBlockedPreflight = SynchronouslyBlockingRootStoragePreflight( + requestStartedExpectation: firstRequestStarted, + lateCallbacksDeliveredExpectation: firstLateCallbacksDelivered + ) + let secondBlockedPreflight = SynchronouslyBlockingRootStoragePreflight( + requestStartedExpectation: secondRequestStarted, + lateCallbacksDeliveredExpectation: secondLateCallbacksDelivered + ) + defer { + firstBlockedPreflight.release() + secondBlockedPreflight.release() + } + + let preflightSequence = RootStoragePreflightSequence( + preflights: [ + firstBlockedPreflight, + secondBlockedPreflight, + ImmediateRootStoragePreflight(result: .success(())) + ] + ) + let deadlineScheduler = ManualRootSetupDeadlineScheduler() + let settingsRecorder = RootSetupEventRecorder() + let settings = RecordingImmediateRootSelectedWalletSettings( + recorder: settingsRecorder, + result: .success(nil) + ) + let chainRegistry = MockChainRegistryProtocol() + let output = MockRootInteractorOutputProtocol() + let saturatedRetryCount = 16 + let failureExpectations = (0..<(saturatedRetryCount + 2)).map { + expectation(description: "setup failure \($0)") + } + let failureLock = NSLock() + var failureCount = 0 + + stub(chainRegistry) { stub in + stub.performHotBoot().thenDoNothing() + stub.performColdBoot().thenDoNothing() + } + stub(output) { stub in + stub.didFailSetup().then { + XCTAssertTrue(Thread.isMainThread) + + failureLock.lock() + let failureIndex = failureCount + failureCount += 1 + failureLock.unlock() + + guard failureExpectations.indices.contains(failureIndex) else { + return XCTFail("Received an unexpected setup failure") + } + + failureExpectations[failureIndex].fulfill() + } + stub.didCompleteSetup().then { + XCTFail("A saturated preflight must not complete setup") + } + } + + let interactor = RootInteractor( + chainRegistryProvider: { chainRegistry }, + storagePreflightProvider: preflightSequence.next, + settings: settings, + applicationConfig: ApplicationConfig.shared, + eventCenter: MockEventCenterProtocol(), + migrators: [], + onboardingService: StubOnboardingService( + result: .failure(OnboardingServiceError.empty) + ), + onboardingConfigResolver: OnboardingConfigVersionResolver( + userDefaultsStorage: InMemorySettingsManager() + ), + setupDeadline: 42, + setupDeadlineScheduler: deadlineScheduler.schedule + ) + interactor.presenter = output + + interactor.setup(runMigrations: false) + wait( + for: [firstRequestStarted], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(deadlineScheduler.delays, [42]) + deadlineScheduler.fire(at: 0) + wait( + for: [failureExpectations[0]], + timeout: Constants.defaultExpectationDuration + ) + + interactor.setup(runMigrations: false) + wait( + for: [secondRequestStarted], + timeout: Constants.defaultExpectationDuration + ) + XCTAssertEqual(deadlineScheduler.delays, [42, 42]) + deadlineScheduler.fire(at: 1) + wait( + for: [failureExpectations[1]], + timeout: Constants.defaultExpectationDuration + ) + + for retryIndex in 0.. ChainRegistryProtocol = { + ChainRegistryFacade.sharedRegistry + }, + storagePreflightProvider: @escaping RootStoragePreflightProvider = { + ImmediateRootStoragePreflight(result: .success(())) + }, + startupReadinessReporter: RootStartupReadinessReporting = + RootStartupReadinessReporter.shared + ) -> RootPresenter { + let resolver = OnboardingConfigVersionResolver(userDefaultsStorage: userDefaultsStorage) + + let interactor = RootInteractor( + chainRegistryProvider: chainRegistryProvider, + storagePreflightProvider: storagePreflightProvider, + settings: settings, + applicationConfig: ApplicationConfig.shared, + eventCenter: MockEventCenterProtocol(), + migrators: migrators, + onboardingService: onboardingService, + onboardingConfigResolver: resolver + ) + + let startViewHelper = StartViewHelper(keystore: keystore, + selectedWalletSettings: settings, + userDefaultsStorage: userDefaultsStorage) + let presenter = RootPresenter( + localizationManager: LocalizationManager.shared, + startViewHelper: startViewHelper, + onboardingConfigTimeoutNanoseconds: onboardingConfigTimeoutNanoseconds, + startupReadinessReporter: startupReadinessReporter + ) + + let presenterView = view ?? MockControllerBackedProtocol() + + presenter.view = presenterView + presenter.window = UIWindow() + presenter.wireframe = wireframe + presenter.interactor = interactor + interactor.presenter = presenter + + return presenter + } + + private func makeSubstrateInMemoryConfiguration() throws + -> CoreDataServiceConfiguration { + let modelURL = try XCTUnwrap( + Bundle(for: SubstrateDataStorageFacade.self).url( + forResource: "SubstrateDataModel", + withExtension: "momd" + ) + ) + + return CoreDataServiceConfiguration( + modelURL: modelURL, + storageType: .inMemory + ) + } + + private func executeSQLiteUpdate( + _ sql: String, + at storeURL: URL + ) throws -> Int { + var database: OpaquePointer? + let openResult = sqlite3_open_v2( + storeURL.path, + &database, + SQLITE_OPEN_READWRITE, + nil + ) + + guard openResult == SQLITE_OK, let database else { + defer { + if let database { + sqlite3_close(database) + } + } + + let message = database + .flatMap(sqlite3_errmsg) + .map { String(cString: $0) } ?? "unknown SQLite open error" + throw NSError( + domain: "RootStoragePreflightTests.SQLite", + code: Int(openResult), + userInfo: [NSLocalizedDescriptionKey: message] + ) + } + defer { + sqlite3_close(database) + } + + var errorMessage: UnsafeMutablePointer? + let executionResult = sqlite3_exec( + database, + sql, + nil, + nil, + &errorMessage + ) + defer { + sqlite3_free(errorMessage) + } + + guard executionResult == SQLITE_OK else { + let message = errorMessage + .map { String(cString: $0) } ?? "unknown SQLite update error" + throw NSError( + domain: "RootStoragePreflightTests.SQLite", + code: Int(executionResult), + userInfo: [NSLocalizedDescriptionKey: message] + ) + } + + return Int(sqlite3_changes(database)) + } + + private func performStoragePreflight( + _ preflight: RootStoragePreflighting + ) throws -> Result { + let completionExpectation = expectation( + description: "storage preflight completes" + ) + var result: Result? + + preflight.preflight { + result = $0 + completionExpectation.fulfill() + } + + wait( + for: [completionExpectation], + timeout: Constants.defaultExpectationDuration + ) + + return try XCTUnwrap(result) + } + + private func insertTonOnlyWallet(in facade: UserDataStorageTestFacade) throws { + try performCoreData(in: facade) { context in + let wallet = CDMetaAccount(context: context) + wallet.metaId = "root-ton-only-wallet" + wallet.name = "Preserved TON Wallet" + wallet.isSelected = true + wallet.order = 1 + wallet.canExportEthereumMnemonic = false + wallet.hasBackup = false + wallet.favouriteChainIds = NSArray() + wallet.setValue(false, forKey: "zeroBalanceAssetsHidden") + wallet.setValue(Data(repeating: 0x51, count: 36), forKey: "tonAddress") + wallet.setValue(Data(repeating: 0x52, count: 32), forKey: "tonPublicKey") + wallet.setValue("v5R1", forKey: "tonContractVersion") + try context.save() + } + } + + private func tonOnlyWalletSnapshot( + in facade: UserDataStorageTestFacade + ) throws -> RootTonOnlyWalletSnapshot { + try performCoreData(in: facade) { context in + let request = NSFetchRequest(entityName: "CDMetaAccount") + request.predicate = NSPredicate(format: "metaId == %@", "root-ton-only-wallet") + let wallet = try XCTUnwrap(context.fetch(request).first) + + return RootTonOnlyWalletSnapshot( + identifier: try XCTUnwrap(wallet.metaId), + name: try XCTUnwrap(wallet.name), + isSelected: wallet.isSelected, + order: wallet.order, + tonAddress: wallet.value(forKey: "tonAddress") as? Data, + tonPublicKey: wallet.value(forKey: "tonPublicKey") as? Data, + tonContractVersion: wallet.value(forKey: "tonContractVersion") as? String + ) + } + } + + private func performCoreData( + in facade: UserDataStorageTestFacade, + _ body: @escaping (NSManagedObjectContext) throws -> T + ) throws -> T { + let operationExpectation = expectation(description: "Core Data operation completes") + var operationResult: Result? + + facade.databaseService.performAsync { context, error in + do { + if let error { + throw error + } + operationResult = .success(try body(XCTUnwrap(context))) + } catch { + operationResult = .failure(error) + } + + operationExpectation.fulfill() + } + + wait(for: [operationExpectation], timeout: Constants.defaultExpectationDuration) + return try XCTUnwrap(operationResult).get() + } +} + +private struct RootTonOnlyWalletSnapshot: Equatable { + let identifier: String + let name: String + let isSelected: Bool + let order: Int32 + let tonAddress: Data? + let tonPublicKey: Data? + let tonContractVersion: String? +} + +private enum RootSetupTestError: Error { + case migrationFailed + case protectedDataUnavailable + case staleWalletLoadFailed + case substrateStorageOpenFailed + case walletRepositoryFailed +} + +private enum RootSetupEvent: Equatable { + case migration + case storagePreflightProvider + case storagePreflight + case chainRegistry + case walletSettingsProvider + case walletSetup + case walletRepository + case hotBoot + case coldBoot +} + +private final class RootSetupEventRecorder { + private let lock = NSLock() + private var events: [RootSetupEvent] = [] + + var snapshot: [RootSetupEvent] { + lock.lock() + defer { lock.unlock() } + + return events + } + + func record(_ event: RootSetupEvent) { + lock.lock() + events.append(event) + lock.unlock() + } + + func reset() { + lock.lock() + events.removeAll() + lock.unlock() + } +} + +private enum RootGenerationEvent: Equatable { + case hotBoot + case coldBoot + case completed + case failed +} + +private enum RootGenerationRouteState: Equatable { + case unresolved + case completed + case failed +} + +private final class RootGenerationEventRecorder { + private let lock = NSLock() + private var events: [RootGenerationEvent] = [] + private var state = RootGenerationRouteState.unresolved + + var snapshot: [RootGenerationEvent] { + lock.lock() + defer { lock.unlock() } + + return events + } + + var routeState: RootGenerationRouteState { + lock.lock() + defer { lock.unlock() } + + return state + } + + func record(_ event: RootGenerationEvent) { + lock.lock() + events.append(event) + + switch event { + case .completed: + state = .completed + case .failed: + state = .failed + case .hotBoot, .coldBoot: + break + } + + lock.unlock() + } +} + +private final class ManualRootSetupDeadlineScheduler { + private let lock = NSLock() + private let scheduledExpectations: [XCTestExpectation] + private var scheduledDelays: [TimeInterval] = [] + private var actions: [() -> Void] = [] + + init(scheduledExpectations: [XCTestExpectation] = []) { + self.scheduledExpectations = scheduledExpectations + } + + var delays: [TimeInterval] { + lock.lock() + defer { lock.unlock() } + + return scheduledDelays + } + + func schedule( + after delay: TimeInterval, + action: @escaping () -> Void + ) { + lock.lock() + let scheduledIndex = actions.count + scheduledDelays.append(delay) + actions.append(action) + lock.unlock() + + if scheduledExpectations.indices.contains(scheduledIndex) { + scheduledExpectations[scheduledIndex].fulfill() + } + } + + func fire(at index: Int) { + lock.lock() + let action = actions[index] + lock.unlock() + + action() + } +} + +private final class ControllableRootSelectedWalletSettings: RootSelectedWalletSettingsProtocol { + private struct Request { + let queue: DispatchQueue? + let completion: (Result) -> Void + } + + private let lock = NSLock() + private let requestStartedExpectations: [XCTestExpectation] + private var requests: [Request] = [] + + init(requestStartedExpectations: [XCTestExpectation]) { + self.requestStartedExpectations = requestStartedExpectations + } + + func setup( + runningCompletionIn queue: DispatchQueue?, + completionClosure: ((Result) -> Void)? + ) { + guard let completionClosure else { + return + } + + lock.lock() + let requestIndex = requests.count + requests.append( + Request( + queue: queue, + completion: completionClosure + ) + ) + lock.unlock() + + if requestStartedExpectations.indices.contains(requestIndex) { + requestStartedExpectations[requestIndex].fulfill() + } + } + + func resolveRequest( + at index: Int, + with result: Result, + deliveryExpectation: XCTestExpectation? = nil + ) { + lock.lock() + let request = requests[index] + lock.unlock() + + let deliver = { + request.completion(result) + deliveryExpectation?.fulfill() + } + + if let queue = request.queue { + queue.async(execute: deliver) + } else { + deliver() + } + } +} + +private final class RecordingImmediateRootSelectedWalletSettings: + RootSelectedWalletSettingsProtocol { + private let recorder: RootSetupEventRecorder + private let result: Result + + init( + recorder: RootSetupEventRecorder, + result: Result + ) { + self.recorder = recorder + self.result = result + } + + func setup( + runningCompletionIn queue: DispatchQueue?, + completionClosure: ((Result) -> Void)? + ) { + recorder.record(.walletSetup) + + guard let completionClosure else { + return + } + + if let queue { + queue.async { + completionClosure(self.result) + } + } else { + completionClosure(result) + } + } +} + +private final class SequencedRootSelectedWalletSettings: + RootSelectedWalletSettingsProtocol { + private let lock = NSLock() + private let recorder: RootSetupEventRecorder + private var results: [Result] + + init( + recorder: RootSetupEventRecorder, + results: [Result] + ) { + self.recorder = recorder + self.results = results + } + + func setup( + runningCompletionIn queue: DispatchQueue?, + completionClosure: ((Result) -> Void)? + ) { + recorder.record(.walletSetup) + + guard let completionClosure else { + return + } + + lock.lock() + let result = results.isEmpty + ? Result.failure( + RootSetupTestError.walletRepositoryFailed + ) + : results.removeFirst() + lock.unlock() + + if let queue { + queue.async { + completionClosure(result) + } + } else { + completionClosure(result) + } + } +} + +private final class RecordingRootMigrator: Migrating { + private let recorder: RootSetupEventRecorder + private let error: Error? + + init(recorder: RootSetupEventRecorder, error: Error? = nil) { + self.recorder = recorder + self.error = error + } + + func migrate() throws { + recorder.record(.migration) + + if let error { + throw error + } + } +} + +private final class BlockingRootMigrator: Migrating { + private let condition = NSCondition() + private let recorder: RootSetupEventRecorder + private let startedExpectation: XCTestExpectation + private var isReleased = false + private var invocationCountStorage = 0 + private var activeInvocationCount = 0 + private var maximumConcurrentInvocationCountStorage = 0 + + init( + recorder: RootSetupEventRecorder, + startedExpectation: XCTestExpectation + ) { + self.recorder = recorder + self.startedExpectation = startedExpectation + } + + var invocationCount: Int { + condition.lock() + defer { condition.unlock() } + + return invocationCountStorage + } + + var maximumConcurrentInvocationCount: Int { + condition.lock() + defer { condition.unlock() } + + return maximumConcurrentInvocationCountStorage + } + + func migrate() throws { + condition.lock() + invocationCountStorage += 1 + activeInvocationCount += 1 + maximumConcurrentInvocationCountStorage = max( + maximumConcurrentInvocationCountStorage, + activeInvocationCount + ) + condition.unlock() + + recorder.record(.migration) + startedExpectation.fulfill() + + condition.lock() + while !isReleased { + condition.wait() + } + activeInvocationCount -= 1 + condition.unlock() + } + + func release() { + condition.lock() + isReleased = true + condition.broadcast() + condition.unlock() + } +} + +private final class SequencedRootMigrator: Migrating { + private let lock = NSLock() + private let recorder: RootSetupEventRecorder + private var results: [Result] + + init( + recorder: RootSetupEventRecorder, + results: [Result] + ) { + self.recorder = recorder + self.results = results + } + + func migrate() throws { + recorder.record(.migration) + + lock.lock() + let result = results.isEmpty + ? Result.failure(RootSetupTestError.migrationFailed) + : results.removeFirst() + lock.unlock() + + try result.get() + } +} + +private final class ControllableRootStoragePreflight: RootStoragePreflighting { + private let lock = NSLock() + private let requestStartedExpectations: [XCTestExpectation] + private var completions: [(Result) -> Void] = [] + + init(requestStartedExpectations: [XCTestExpectation]) { + self.requestStartedExpectations = requestStartedExpectations + } + + func preflight( + completion: @escaping (Result) -> Void + ) { + lock.lock() + let requestIndex = completions.count + completions.append(completion) + lock.unlock() + + if requestStartedExpectations.indices.contains(requestIndex) { + requestStartedExpectations[requestIndex].fulfill() + } + } + + func resolveRequest( + at index: Int, + with result: Result, + deliveryExpectation: XCTestExpectation? = nil + ) { + lock.lock() + let completion = completions[index] + lock.unlock() + + DispatchQueue.global().async { + completion(result) + deliveryExpectation?.fulfill() + } + } +} + +private final class SynchronouslyBlockingRootStoragePreflight: + RootStoragePreflighting { + private let releaseSemaphore = DispatchSemaphore(value: 0) + private let releaseLock = NSLock() + private let requestStartedExpectation: XCTestExpectation + private let lateCallbacksDeliveredExpectation: XCTestExpectation + private var isReleased = false + + init( + requestStartedExpectation: XCTestExpectation, + lateCallbacksDeliveredExpectation: XCTestExpectation + ) { + self.requestStartedExpectation = requestStartedExpectation + self.lateCallbacksDeliveredExpectation = + lateCallbacksDeliveredExpectation + } + + func preflight( + completion: @escaping (Result) -> Void + ) { + requestStartedExpectation.fulfill() + releaseSemaphore.wait() + + completion(.success(())) + completion(.failure(RootSetupTestError.substrateStorageOpenFailed)) + lateCallbacksDeliveredExpectation.fulfill() + } + + func release() { + releaseLock.lock() + defer { releaseLock.unlock() } + + guard !isReleased else { + return + } + + isReleased = true + releaseSemaphore.signal() + } +} + +private final class RootStoragePreflightSequence { + private let lock = NSLock() + private var preflights: [RootStoragePreflighting] + private var invocationCountStorage = 0 + + init(preflights: [RootStoragePreflighting]) { + self.preflights = preflights + } + + var invocationCount: Int { + lock.lock() + defer { lock.unlock() } + + return invocationCountStorage + } + + func next() -> RootStoragePreflighting { + lock.lock() + defer { lock.unlock() } + + invocationCountStorage += 1 + + guard preflights.isNotEmpty else { + return ImmediateRootStoragePreflight( + result: .failure( + RootSetupTestError.substrateStorageOpenFailed + ) + ) + } + + return preflights.removeFirst() + } +} + +private final class ImmediateRootStoragePreflight: RootStoragePreflighting { + private let result: Result + + init(result: Result) { + self.result = result + } + + func preflight( + completion: @escaping (Result) -> Void + ) { + completion(result) + } +} + +private final class RecordingRootStoragePreflight: RootStoragePreflighting { + private let recorder: RootSetupEventRecorder + private let result: Result + + init( + recorder: RootSetupEventRecorder, + result: Result + ) { + self.recorder = recorder + self.result = result + } + + func preflight( + completion: @escaping (Result) -> Void + ) { + recorder.record(.storagePreflight) + completion(result) + } +} + +private final class AdversarialRootStoragePreflight: RootStoragePreflighting { + private let recorder: RootSetupEventRecorder + + init(recorder: RootSetupEventRecorder) { + self.recorder = recorder + } + + func preflight( + completion: @escaping (Result) -> Void + ) { + recorder.record(.storagePreflight) + completion(.success(())) + completion(.success(())) + completion(.failure(RootSetupTestError.substrateStorageOpenFailed)) + } +} + +private final class SequencedRootStoragePreflight: RootStoragePreflighting { + private let lock = NSLock() + private let recorder: RootSetupEventRecorder + private var results: [Result] + + init( + recorder: RootSetupEventRecorder, + results: [Result] + ) { + self.recorder = recorder + self.results = results + } + + func preflight( + completion: @escaping (Result) -> Void + ) { + recorder.record(.storagePreflight) + + lock.lock() + let result = results.isEmpty + ? Result.failure(RootSetupTestError.substrateStorageOpenFailed) + : results.removeFirst() + lock.unlock() + + completion(result) + } +} + +private final class RecordingCoreDataService: CoreDataServiceProtocol { + var configuration: CoreDataServiceConfigurationProtocol { + service.configuration + } + + private let service: CoreDataServiceProtocol + private let recorder: RootSetupEventRecorder + + init( + service: CoreDataServiceProtocol, + recorder: RootSetupEventRecorder + ) { + self.service = service + self.recorder = recorder + } + + func performAsync(block: @escaping CoreDataContextInvocationBlock) { + recorder.record(.storagePreflight) + service.performAsync(block: block) + } + + func close() throws { + try service.close() + } + + func drop() throws { + try service.drop() + } +} + +private final class RecordingUserDataStorageTestFacade: UserDataStorageTestFacade { + private let recorder: RootSetupEventRecorder + + init(recorder: RootSetupEventRecorder) { + self.recorder = recorder + super.init() + } + + override func createRepository( + filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor], + mapper: AnyCoreDataMapper + ) -> CoreDataRepository where T: Identifiable, U: NSManagedObject { + recorder.record(.walletRepository) + + return super.createRepository( + filter: filter, + sortDescriptors: sortDescriptors, + mapper: mapper + ) + } +} + +private final class FailingUserDataStorageTestFacade: UserDataStorageTestFacade { + private let error: Error + + init(error: Error) { + self.error = error + super.init() + } + + override func createRepository( + filter: NSPredicate?, + sortDescriptors: [NSSortDescriptor], + mapper: AnyCoreDataMapper + ) -> CoreDataRepository where T: Identifiable, U: NSManagedObject { + let failingService = FailingCoreDataService( + configuration: databaseService.configuration, + error: error + ) + + return CoreDataRepository( + databaseService: failingService, + mapper: mapper, + filter: filter, + sortDescriptors: sortDescriptors + ) + } +} + +private final class FailingCoreDataService: CoreDataServiceProtocol { + let configuration: CoreDataServiceConfigurationProtocol + private let error: Error + + init(configuration: CoreDataServiceConfigurationProtocol, error: Error) { + self.configuration = configuration + self.error = error + } + + func performAsync(block: @escaping CoreDataContextInvocationBlock) { + block(nil, error) + } + + func close() throws {} + + func drop() throws {} +} + +private final class ContextProvidingCoreDataService: CoreDataServiceProtocol { + let configuration: CoreDataServiceConfigurationProtocol + private let context: NSManagedObjectContext? + private let error: Error? + + init( + configuration: CoreDataServiceConfigurationProtocol, + context: NSManagedObjectContext?, + error: Error? = nil + ) { + self.configuration = configuration + self.context = context + self.error = error + } + + func performAsync(block: @escaping CoreDataContextInvocationBlock) { + block(context, error) + } + + func close() throws {} + + func drop() throws {} +} + +private final class AlertCapturingViewController: UIViewController, ControllerBackedProtocol { + var onPresent: ((UIViewController) -> Void)? + + override func present( + _ viewControllerToPresent: UIViewController, + animated flag: Bool, + completion: (() -> Void)? = nil + ) { + onPresent?(viewControllerToPresent) + completion?() + } +} + +private final class RecordingRootStartupReadinessReporter: + RootStartupReadinessReporting { + private let lock = NSLock() + private var readyEvents = 0 + private var failureEvents = 0 + + var readyCount: Int { + lock.lock() + defer { lock.unlock() } + + return readyEvents + } + + var failureCount: Int { + lock.lock() + defer { lock.unlock() } + + return failureEvents + } + + func reportReady() { + lock.lock() + readyEvents += 1 + lock.unlock() + } + + func reportFailure() { + lock.lock() + failureEvents += 1 + lock.unlock() + } +} + +private final class StubOnboardingService: OnboardingServiceProtocol { + private let lock = NSLock() + private let result: Result + private var callCount = 0 + + var fetchCallCount: Int { + lock.lock() + defer { lock.unlock() } + + return callCount + } + + init(result: Result) { + self.result = result + } + + private func recordFetch() { + lock.lock() + callCount += 1 + lock.unlock() + } + + func fetchConfigs() async throws -> OnboardingConfigPlatform { + recordFetch() + + return try result.get() + } +} + +private final class LateCompletingOnboardingService: OnboardingServiceProtocol { + private let lock = NSLock() + private let startedExpectation: XCTestExpectation + private var continuation: CheckedContinuation? + + init(startedExpectation: XCTestExpectation) { + self.startedExpectation = startedExpectation + } + + func fetchConfigs() async throws -> OnboardingConfigPlatform { + try await withCheckedThrowingContinuation { continuation in + lock.lock() + self.continuation = continuation + lock.unlock() + + startedExpectation.fulfill() + } + } + + func succeed(with platform: OnboardingConfigPlatform) { + lock.lock() + let continuation = continuation + self.continuation = nil + lock.unlock() + + continuation?.resume(returning: platform) } } diff --git a/scripts/audit-codecov-coverage-contract.sh b/scripts/audit-codecov-coverage-contract.sh new file mode 100755 index 0000000000..487b226ccc --- /dev/null +++ b/scripts/audit-codecov-coverage-contract.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +WORKFLOW="${1:-$ROOT_DIR/.github/workflows/codecov.yml}" + +fail() { + echo "[codecov-coverage-contract][error] $*" >&2 + exit 1 +} + +[[ -f "$WORKFLOW" && ! -L "$WORKFLOW" ]] || + fail "Codecov workflow must be a regular, non-symlink file." + +require_text() { + local text="$1" + grep -Fq -- "$text" "$WORKFLOW" || + fail "Codecov workflow is missing required coverage control: $text" +} + +require_text "persist-credentials: false" +require_text "-enableCodeCoverage YES" +require_text '-resultBundlePath "$RESULT_BUNDLE"' +require_text "-type f -name '*.profdata' -print -quit" +require_text 'xcrun llvm-profdata show "$COVERAGE_PROFILE"' +require_text 'test -d "$RESULT_BUNDLE"' +require_text "plugins: xcode" +require_text "swift_project: fearless" +require_text "fail_ci_if_error: true" +require_text "use_oidc: true" + +if grep -Eq 'codecov/codecov-action@(main|master|v[0-9]+)[[:space:]#]' "$WORKFLOW"; then + fail "Codecov action must use an immutable full commit SHA." +fi + +echo "[codecov-coverage-contract] executable coverage and upload contract passed" diff --git a/scripts/audit-testflight-publication-readiness.sh b/scripts/audit-testflight-publication-readiness.sh new file mode 100755 index 0000000000..083cd4d7ad --- /dev/null +++ b/scripts/audit-testflight-publication-readiness.sh @@ -0,0 +1,480 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="${TESTFLIGHT_PUBLICATION_AUDIT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +MANIFEST="$ROOT_DIR/config/testflight-publication-readiness.json" +DOC="$ROOT_DIR/docs/testflight-publication-readiness.md" +RELEASE_CHECKLIST="$ROOT_DIR/docs/release-checklist.md" +RUN_PR="$ROOT_DIR/scripts/ci/run-pr.sh" +WORKFLOW="$ROOT_DIR/.github/workflows/codecov.yml" +AUDIT_CONTRACT="$ROOT_DIR/scripts/audit-testflight-publication-readiness.sh" +SELF_TEST="$ROOT_DIR/scripts/test-testflight-publication-readiness-audit.sh" +EXPECTED_MANIFEST_SHA256="${TESTFLIGHT_PUBLICATION_AUDIT_EXPECTED_MANIFEST_SHA256:-d66634ec2fce2305e2cc64e18e55c273dcc802bc82e074f658bef72ad8d53b26}" + +fail() { + echo "[testflight-publication][ios][error] $*" >&2 + exit 1 +} + +sha256_file() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$1" | awk '{print $1}' + else + shasum -a 256 "$1" | awk '{print $1}' + fi +} + +require_regular_file() { + local path="$1" + [[ -f "$path" && ! -L "$path" ]] || + fail "required regular file is missing or is a symlink: ${path#"$ROOT_DIR/"}" +} + +require_executable_file() { + local path="$1" + [[ -x "$path" ]] || fail "required script is not executable: ${path#"$ROOT_DIR/"}" +} + +require_bounded_file() { + local path="$1" + local maximum="$2" + local label="$3" + local bytes + bytes="$(wc -c < "$path" | tr -d '[:space:]')" + [[ "$bytes" =~ ^[0-9]+$ && "$bytes" -gt 0 && "$bytes" -le "$maximum" ]] || + fail "$label must be nonempty and no larger than $maximum bytes" +} + +require_fixed() { + local path="$1" + local marker="$2" + local label="$3" + grep -Fq -- "$marker" "$path" || fail "$label is missing from ${path#"$ROOT_DIR/"}" +} + +require_active_line() { + local path="$1" + local expected="$2" + local label="$3" + awk -v expected="$expected" ' + { + line = $0 + sub(/^[[:space:]]*/, "", line) + sub(/[[:space:]]*$/, "", line) + if (line == expected) found = 1 + } + END { exit found ? 0 : 1 } + ' "$path" || fail "$label is missing from ${path#"$ROOT_DIR/"}" +} + +command -v node >/dev/null 2>&1 || fail "node is required for canonical JSON validation" + +for path in \ + "$MANIFEST" "$DOC" "$RELEASE_CHECKLIST" "$RUN_PR" "$WORKFLOW" \ + "$AUDIT_CONTRACT" "$SELF_TEST"; do + require_regular_file "$path" +done + +require_executable_file "$AUDIT_CONTRACT" +require_executable_file "$SELF_TEST" +require_bounded_file "$MANIFEST" 32768 "TestFlight publication manifest" +require_bounded_file "$DOC" 65536 "TestFlight publication document" +require_bounded_file "$RELEASE_CHECKLIST" 262144 "release checklist" +require_bounded_file "$RUN_PR" 131072 "PR runner" +require_bounded_file "$WORKFLOW" 262144 "GitHub workflow" +require_bounded_file "$AUDIT_CONTRACT" 131072 "TestFlight publication audit" +require_bounded_file "$SELF_TEST" 262144 "TestFlight publication adversarial self-test" + +[[ "$EXPECTED_MANIFEST_SHA256" =~ ^[0-9a-f]{64}$ ]] || + fail "expected manifest digest must be exactly 64 lowercase hexadecimal characters" +actual_manifest_sha256="$(sha256_file "$MANIFEST")" +[[ "$actual_manifest_sha256" == "$EXPECTED_MANIFEST_SHA256" ]] || + fail "publication manifest digest mismatch: expected $EXPECTED_MANIFEST_SHA256, got $actual_manifest_sha256" + +node - "$MANIFEST" <<'NODE' +const crypto = require('node:crypto'); +const fs = require('node:fs'); +const path = process.argv[2]; +const raw = fs.readFileSync(path, 'utf8'); +let manifest; + +function fail(message) { + console.error(`[testflight-publication][ios][error] ${message}`); + process.exit(1); +} + +function assert(condition, message) { + if (!condition) fail(message); +} + +try { + manifest = JSON.parse(raw); +} catch (error) { + fail(`invalid publication JSON: ${error.message}`); +} + +assert( + raw === `${JSON.stringify(manifest, null, 2)}\n`, + 'publication manifest must use canonical two-space JSON without duplicate keys or trailing data' +); + +function exactKeys(value, expected, label) { + assert(value && typeof value === 'object' && !Array.isArray(value), `${label} must be an object`); + const actual = Object.keys(value).sort(); + const wanted = [...expected].sort(); + assert(JSON.stringify(actual) === JSON.stringify(wanted), `${label} keys drifted`); +} + +function exactArray(value, expected, label) { + assert(Array.isArray(value), `${label} must be an array`); + assert(JSON.stringify(value) === JSON.stringify(expected), `${label} drifted`); + assert(new Set(value).size === value.length, `${label} must not contain duplicates`); +} + +function exactInteger(value, expected, label) { + assert(Number.isSafeInteger(value), `${label} must be a safe integer`); + assert(value === expected, `${label} drifted`); +} + +function exactDigest(value, expected, label) { + assert(typeof value === 'string' && /^[0-9a-f]{64}$/.test(value), `${label} must be a lowercase SHA-256`); + assert(value === expected, `${label} drifted`); +} + +exactKeys(manifest, [ + 'schemaVersion', 'platform', 'distributionChannel', 'assessedAtUTC', + 'evidenceBoundary', 'artifact', 'upload', 'testFlight', 'symbolication', + 'readiness' +], 'top-level manifest'); +assert(manifest.schemaVersion === 1, 'schemaVersion must be 1'); +assert(manifest.platform === 'ios', 'platform must be ios'); +assert( + manifest.distributionChannel === 'testflight-external-public-link', + 'distribution channel drifted' +); +assert(manifest.assessedAtUTC === '2026-07-26T13:26:11Z', 'assessment timestamp drifted'); + +const boundary = manifest.evidenceBoundary; +exactKeys(boundary, [ + 'contract', 'observationMethod', 'rawAttestationsTracked', + 'rawAttestationsLocation', 'currentStateRevalidationRequired' +], 'evidenceBoundary'); +assert( + boundary.contract === 'tracked-sanitized-publication-snapshot', + 'evidence boundary contract drifted' +); +assert( + boundary.observationMethod === + 'authenticated-app-store-connect-and-unauthenticated-public-link-in-safari', + 'observation method drifted' +); +assert(boundary.rawAttestationsTracked === false, 'ignored raw attestations must not be claimed as tracked'); +assert( + boundary.rawAttestationsLocation === 'ignored-build-output', + 'raw attestation location drifted' +); +assert( + boundary.currentStateRevalidationRequired === true, + 'mutable App Store Connect state must require revalidation' +); + +const artifact = manifest.artifact; +exactKeys(artifact, [ + 'sourceCommit', 'bundleIdentifier', 'marketingVersion', 'buildNumber', + 'preUploadArchiveTreeSHA256', 'executableSHA256', + 'signedArchiveAuditReceiptSHA256', + 'preservedDataArchiveRehearsalResultSHA256' +], 'artifact'); +assert( + artifact.sourceCommit === 'f56b7b896344cfded39456217097747ef9efeacf', + 'artifact source commit drifted' +); +assert( + artifact.bundleIdentifier === 'jp.co.soramitsu.fearlesswallet', + 'artifact bundle identifier drifted' +); +assert(artifact.marketingVersion === '4.2.0', 'artifact marketing version drifted'); +assert(artifact.buildNumber === '2026.7.26', 'artifact build number drifted'); +exactDigest( + artifact.preUploadArchiveTreeSHA256, + '301f19a4f1232fb05719d85b825ac081196fa5fb6988b58011b7569a4bd9e6fa', + 'pre-upload archive tree SHA-256' +); +exactDigest( + artifact.executableSHA256, + 'cf0318792fc361bbd8704b21b6e1a08c4d81897f23492e4a807eab7f22403568', + 'executable SHA-256' +); +exactDigest( + artifact.signedArchiveAuditReceiptSHA256, + '1dbf38740b38403dde9cc7d4b1710cd28fdd5dc6f6f25990a7102020f11d1abc', + 'signed archive audit receipt SHA-256' +); +exactDigest( + artifact.preservedDataArchiveRehearsalResultSHA256, + '418d22cdd9e673ddfa1f47a49c666df11a740aac6737f6ef2b0328fa1b6a8641', + 'preserved-data archive rehearsal result SHA-256' +); + +const upload = manifest.upload; +exactKeys(upload, [ + 'status', 'uploadedAtUTC', 'postUploadArchiveTreeSHA256', + 'postUploadArchiveInfoPlistSHA256', 'postUploadAttestationSHA256', + 'xcodeMutation', 'reconstructedPreUploadArchiveTreeMatched', + 'embeddedAppSignatureVerified' +], 'upload'); +assert(upload.status === 'success', 'upload status must remain success'); +assert(upload.uploadedAtUTC === '2026-07-26T13:16:00Z', 'upload timestamp drifted'); +exactDigest( + upload.postUploadArchiveTreeSHA256, + 'a483a372fe8fd19761d3b0324427c4cf55a4553b4ed7433b34b78517f292cea7', + 'post-upload archive tree SHA-256' +); +exactDigest( + upload.postUploadArchiveInfoPlistSHA256, + 'e82ff42b4b47713d1094c420dd7d1abfbfdfe7e7b80c972909936ad64e1e4756', + 'post-upload archive Info.plist SHA-256' +); +exactDigest( + upload.postUploadAttestationSHA256, + '6ede1d8fb981be149a82d69313be0ebc1838291e27d0ecf1c1576c95350b1af9', + 'post-upload attestation SHA-256' +); +assert(upload.xcodeMutation === 'Distributions-only', 'Xcode post-upload mutation scope drifted'); +assert( + upload.reconstructedPreUploadArchiveTreeMatched === true, + 'reconstructed pre-upload archive tree match must remain true' +); +assert( + upload.embeddedAppSignatureVerified === true, + 'embedded app signature verification must remain true' +); + +const testFlight = manifest.testFlight; +exactKeys(testFlight, [ + 'processingStatus', 'externalTestingActive', 'externalGroup', 'publicLink', + 'whatToTestSHA256', 'automaticTesterNotification', + 'publicationAttestationSHA256' +], 'testFlight'); +assert(testFlight.processingStatus === 'testing', 'TestFlight processing status must remain testing'); +assert(testFlight.externalTestingActive === true, 'external TestFlight testing must remain active'); + +const group = testFlight.externalGroup; +exactKeys(group, [ + 'name', 'id', 'testerCount', 'buildCount', 'containsBuild', + 'publicLinkTesterCount', 'publicLinkTesterLimit' +], 'externalGroup'); +assert(group.name === 'Public Beta Test', 'external group name drifted'); +assert( + group.id === '9410949d-b468-40e5-b2f4-24055e65d270', + 'external group identifier drifted' +); +exactInteger(group.testerCount, 122, 'external group tester count snapshot'); +exactInteger(group.buildCount, 2, 'external group build count snapshot'); +assert(group.containsBuild === true, 'external group must contain build 2026.7.26'); +exactInteger(group.publicLinkTesterCount, 120, 'public-link tester count snapshot'); +exactInteger(group.publicLinkTesterLimit, 500, 'public-link tester limit'); +assert( + group.publicLinkTesterCount <= group.testerCount, + 'public-link tester count cannot exceed the external group tester count' +); +assert( + group.publicLinkTesterCount <= group.publicLinkTesterLimit, + 'public-link tester count cannot exceed its limit' +); + +const publicLink = testFlight.publicLink; +exactKeys(publicLink, [ + 'enabled', 'shareableToAnyoneWithLink', 'url', 'urlSHA256', + 'landingPageResolved', 'landingPageApplicationName', + 'testFlightDeepLinkPresent' +], 'publicLink'); +assert(publicLink.enabled === true, 'public TestFlight link must remain enabled'); +assert( + publicLink.shareableToAnyoneWithLink === true, + 'public TestFlight link must remain shareable to anyone with the link' +); +assert( + publicLink.url === 'https://testflight.apple.com/join/012KzFyD', + 'public TestFlight URL drifted' +); +exactDigest( + publicLink.urlSHA256, + 'd6599b1b9c0f7e77d9dd80d9185da67c1d864be5df9a7bbf360f245b099a000c', + 'public TestFlight URL SHA-256' +); +assert( + crypto.createHash('sha256').update(publicLink.url, 'utf8').digest('hex') === + publicLink.urlSHA256, + 'public TestFlight URL does not match its SHA-256' +); +let parsedPublicLink; +try { + parsedPublicLink = new URL(publicLink.url); +} catch (error) { + fail(`public TestFlight URL is invalid: ${error.message}`); +} +assert(parsedPublicLink.protocol === 'https:', 'public TestFlight URL must use HTTPS'); +assert(parsedPublicLink.hostname === 'testflight.apple.com', 'public TestFlight URL host drifted'); +assert(parsedPublicLink.port === '', 'public TestFlight URL must not specify a port'); +assert( + parsedPublicLink.username === '' && parsedPublicLink.password === '', + 'public TestFlight URL must not contain userinfo' +); +assert( + parsedPublicLink.search === '' && parsedPublicLink.hash === '', + 'public TestFlight URL must not contain a query or fragment' +); +assert(parsedPublicLink.pathname === '/join/012KzFyD', 'public TestFlight URL path drifted'); +assert(publicLink.landingPageResolved === true, 'public landing page resolution must remain true'); +assert( + publicLink.landingPageApplicationName === 'Fearless Wallet: DeFi Wallet', + 'public landing-page application identity drifted' +); +assert( + publicLink.testFlightDeepLinkPresent === true, + 'public landing page must retain the TestFlight deep link' +); +exactDigest( + testFlight.whatToTestSHA256, + 'd5d0c2063934c4ca7dd8bb82af038d79909738c93cf96c11ab63bca8c0b7f272', + 'What to Test text SHA-256' +); +assert( + testFlight.automaticTesterNotification === true, + 'automatic tester notification must remain recorded as enabled' +); +exactDigest( + testFlight.publicationAttestationSHA256, + '84e53d78316cf46cc1956d04e86782241d6e575da90fef109acaaf44cb368d4c', + 'publication attestation SHA-256' +); + +const symbolication = manifest.symbolication; +exactKeys(symbolication, [ + 'status', 'runtimeInstallLaunchOrMigrationImpact', 'mainApplicationDSYMPresent', + 'runtimeFrameworkMissingVendorDSYM', 'staticStubFrameworkWarnings', + 'productionFollowUpRequired' +], 'symbolication'); +assert( + symbolication.status === 'degraded-third-party-symbolication', + 'symbolication status drifted' +); +assert( + symbolication.runtimeInstallLaunchOrMigrationImpact === false, + 'dSYM warnings must not be classified as an install, launch, or migration runtime failure' +); +assert( + symbolication.mainApplicationDSYMPresent === true, + 'main application dSYM presence must remain recorded' +); +assert( + symbolication.runtimeFrameworkMissingVendorDSYM === 'MPQRCoreSDK.framework', + 'runtime framework vendor-dSYM gap drifted' +); +exactArray(symbolication.staticStubFrameworkWarnings, [ + 'blake2lib.framework', + 'libed25519.framework', + 'sr25519lib.framework' +], 'static stub framework warning inventory'); +assert( + symbolication.productionFollowUpRequired === true, + 'third-party production symbolication follow-up must remain required' +); + +const readiness = manifest.readiness; +exactKeys(readiness, [ + 'status', 'publicationVerified', 'externalTestingActive', + 'exactAppleDeliveredInstallVerified', + 'preservedDataPostInstallRehearsalVerified', 'releaseEnabled', + 'blockerCode', 'requiredAction' +], 'readiness'); +assert(readiness.status === 'blocked', 'TestFlight readiness must remain blocked'); +assert(readiness.publicationVerified === true, 'publicationVerified must remain true'); +assert(readiness.externalTestingActive === true, 'readiness externalTestingActive must remain true'); +assert( + readiness.exactAppleDeliveredInstallVerified === false, + 'exact Apple-delivered TestFlight installation must not be claimed' +); +assert( + readiness.preservedDataPostInstallRehearsalVerified === false, + 'post-install preserved-data rehearsal must not be claimed' +); +assert(readiness.releaseEnabled === false, 'releaseEnabled must remain false'); +assert( + readiness.blockerCode === 'testflight-exact-build-preserved-data-install-pending', + 'TestFlight blocker code drifted' +); +assert( + readiness.requiredAction === + 'Update in place through TestFlight without deleting or clearing app data, then repeat the five-cold-launch and store-integrity rehearsal.', + 'TestFlight required action drifted' +); +assert( + readiness.publicationVerified === + ( + upload.status === 'success' && + testFlight.processingStatus === 'testing' && + testFlight.externalTestingActive === true && + group.containsBuild === true && + publicLink.enabled === true && + publicLink.shareableToAnyoneWithLink === true && + publicLink.landingPageResolved === true && + publicLink.testFlightDeepLinkPresent === true + ), + 'publicationVerified disagrees with upload, group, or public-link evidence' +); +assert( + readiness.externalTestingActive === testFlight.externalTestingActive, + 'readiness externalTestingActive disagrees with TestFlight state' +); +assert( + readiness.releaseEnabled === false || + ( + readiness.publicationVerified === true && + readiness.exactAppleDeliveredInstallVerified === true && + readiness.preservedDataPostInstallRehearsalVerified === true && + symbolication.productionFollowUpRequired === false + ), + 'releaseEnabled requires publication, exact Apple-delivered install, preserved-data rehearsal, and symbolication closure' +); +NODE + +require_fixed "$DOC" 'Status: **BLOCKED only on exact Apple-delivered install/rehearsal and symbolication follow-up**' \ + "documented current TestFlight readiness status" +require_fixed "$DOC" '`4.2.0 (2026.7.26)` is `Testing`' \ + "documented current TestFlight build status" +require_fixed "$DOC" '`9410949d-b468-40e5-b2f4-24055e65d270`' \ + "documented external group identifier" +require_fixed "$DOC" '`122` testers, `2` builds' \ + "documented external group snapshot" +require_fixed "$DOC" '`120/500` public-link places used' \ + "documented public-link occupancy snapshot" +require_fixed "$DOC" 'https://testflight.apple.com/join/012KzFyD' \ + "documented public TestFlight link" +require_fixed "$DOC" 'must not be treated as canonical release source' \ + "documented ignored raw-attestation boundary" +require_fixed "$DOC" 'MPQRCoreSDK.framework' \ + "documented runtime framework symbolication gap" +require_fixed "$DOC" 'Do not uninstall the app or clear its container.' \ + "documented preserved-data install constraint" +require_fixed "$RELEASE_CHECKLIST" \ + 'bash ./scripts/test-testflight-publication-readiness-audit.sh && bash ./scripts/audit-testflight-publication-readiness.sh' \ + "release-checklist TestFlight publication gate" +require_fixed "$RELEASE_CHECKLIST" \ + 'build release-enabled until an in-place TestFlight update preserves the' \ + "release-checklist exact Apple-delivered install gate" +require_active_line "$RUN_PR" \ + 'bash "$WORKSPACE_DIR/scripts/test-testflight-publication-readiness-audit.sh"' \ + "PR TestFlight publication adversarial self-test" +require_active_line "$RUN_PR" \ + 'bash "$WORKSPACE_DIR/scripts/audit-testflight-publication-readiness.sh"' \ + "PR TestFlight publication audit" +require_active_line "$WORKFLOW" \ + 'bash ./scripts/test-testflight-publication-readiness-audit.sh' \ + "CI TestFlight publication adversarial self-test" +require_active_line "$WORKFLOW" \ + 'bash ./scripts/audit-testflight-publication-readiness.sh' \ + "CI TestFlight publication audit" + +echo "[testflight-publication][ios] tracked publication evidence is valid; exact Apple-delivered install remains blocked" diff --git a/scripts/ci/audit-ios-release-identity.sh b/scripts/ci/audit-ios-release-identity.sh new file mode 100755 index 0000000000..1285915e76 --- /dev/null +++ b/scripts/ci/audit-ios-release-identity.sh @@ -0,0 +1,311 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +readonly EXPECTED_DEVELOPMENT_TEAM="YLWWUD25VZ" +readonly EXPECTED_SIGNING_IDENTITY="Apple Distribution: Soramitsu Co., Ltd. (YLWWUD25VZ)" +readonly EXPECTED_PROFILE_NAME="Fearless App Store 2026.7.26" +readonly AUDIT_TEST_HARNESS="${IOS_RELEASE_AUDIT_TEST_HARNESS:-0}" + +fail() { + printf '[ios-release-identity] FAIL: %s\n' "$*" >&2 + exit 1 +} + +readonly TEST_HARNESS_OVERRIDE_NAMES=( + IOS_RELEASE_SCHEME_FILE + IOS_RELEASE_ENTITLEMENTS_FILE + IOS_DEBUG_ENTITLEMENTS_FILE + IOS_RELEASE_INFO_PLIST_FILE + IOS_RELEASE_WALLET_CONNECT_SERVICE_FILE + IOS_RELEASE_SETTINGS_JSON + IOS_DEBUG_SETTINGS_JSON + IOS_EXPECTED_BUNDLE_ID + IOS_EXPECTED_DEBUG_BUNDLE_ID + IOS_EXPECTED_MARKETING_VERSION +) +if [[ "$AUDIT_TEST_HARNESS" != "1" ]]; then + for override_name in "${TEST_HARNESS_OVERRIDE_NAMES[@]}"; do + [[ -z "${!override_name:-}" ]] || + fail "$override_name is accepted only with IOS_RELEASE_AUDIT_TEST_HARNESS=1" + done +fi + +readonly SCHEME_FILE="${IOS_RELEASE_SCHEME_FILE:-$REPO_ROOT/fearless.xcodeproj/xcshareddata/xcschemes/fearless.xcscheme}" +readonly ENTITLEMENTS_FILE="${IOS_RELEASE_ENTITLEMENTS_FILE:-$REPO_ROOT/fearless/WalletConnect.entitlements}" +readonly DEBUG_ENTITLEMENTS_FILE="${IOS_DEBUG_ENTITLEMENTS_FILE:-$REPO_ROOT/fearless/WalletConnect.dev.entitlements}" +readonly INFO_PLIST_FILE="${IOS_RELEASE_INFO_PLIST_FILE:-$REPO_ROOT/fearless/Info.plist}" +readonly WALLET_CONNECT_SERVICE_FILE="${IOS_RELEASE_WALLET_CONNECT_SERVICE_FILE:-$REPO_ROOT/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift}" +readonly EXPECTED_BUNDLE_ID="${IOS_EXPECTED_BUNDLE_ID:-jp.co.soramitsu.fearlesswallet}" +readonly EXPECTED_DEBUG_BUNDLE_ID="${IOS_EXPECTED_DEBUG_BUNDLE_ID:-jp.co.soramitsu.fearlesswallet.dev}" +readonly EXPECTED_VERSION="${IOS_EXPECTED_MARKETING_VERSION:-4.2.0}" +readonly EXPECTED_BUILD="${IOS_EXPECTED_BUILD_NUMBER:-}" +[[ "$EXPECTED_BUILD" =~ ^[1-9][0-9]{0,3}(\.[0-9]{1,2}){0,2}$ ]] || + fail "IOS_EXPECTED_BUILD_NUMBER must be an explicit canonical CFBundleVersion" + +require_regular_file() { + local path="$1" + local label="$2" + + [[ -f "$path" ]] || fail "$label is missing: $path" + [[ ! -L "$path" ]] || fail "$label must not be a symbolic link: $path" +} + +require_regular_file "$SCHEME_FILE" "shared scheme" +require_regular_file "$ENTITLEMENTS_FILE" "production entitlements" +require_regular_file "$DEBUG_ENTITLEMENTS_FILE" "development entitlements" +require_regular_file "$INFO_PLIST_FILE" "application Info.plist" +require_regular_file "$WALLET_CONNECT_SERVICE_FILE" "WalletConnect service" + +bundle_version="$( + plutil -extract CFBundleVersion raw "$INFO_PLIST_FILE" 2>/dev/null +)" || fail "application Info.plist has no CFBundleVersion" +[[ "$bundle_version" == '$(CURRENT_PROJECT_VERSION)' ]] || + fail "CFBundleVersion must expand CURRENT_PROJECT_VERSION" + +short_version="$( + plutil -extract CFBundleShortVersionString raw "$INFO_PLIST_FILE" 2>/dev/null +)" || fail "application Info.plist has no CFBundleShortVersionString" +[[ "$short_version" == '$(MARKETING_VERSION)' ]] || + fail "CFBundleShortVersionString must expand MARKETING_VERSION" + +git_commit="$( + plutil -extract FearlessGitCommit raw "$INFO_PLIST_FILE" 2>/dev/null +)" || fail "application Info.plist has no FearlessGitCommit" +[[ "$git_commit" == '$(FEARLESS_GIT_COMMIT)' ]] || + fail "FearlessGitCommit must expand FEARLESS_GIT_COMMIT" + +archive_action_count="$( + xmllint --xpath 'count(/Scheme/ArchiveAction)' "$SCHEME_FILE" 2>/dev/null +)" || fail "shared scheme is not valid XML" +[[ "$archive_action_count" == "1" ]] || + fail "shared scheme must contain exactly one ArchiveAction" + +archive_configuration="$( + xmllint --xpath 'string(/Scheme/ArchiveAction/@buildConfiguration)' \ + "$SCHEME_FILE" 2>/dev/null +)" || fail "cannot read ArchiveAction configuration" +[[ "$archive_configuration" == "Release" ]] || + fail "shared scheme archives $archive_configuration instead of Release" + +settings_json="${IOS_RELEASE_SETTINGS_JSON:-}" +generated_settings="" +if [[ -z "$settings_json" ]]; then + generated_settings="$(mktemp "${TMPDIR:-/tmp}/fearless-release-settings.XXXXXX")" + settings_json="$generated_settings" + + xcodebuild_args=( + -workspace "$REPO_ROOT/fearless.xcworkspace" + -scheme fearless + -configuration Release + -destination "generic/platform=iOS" + -showBuildSettings + -json + ) + + if [[ -n "${IOS_RELEASE_SOURCE_PACKAGES_DIR:-}" ]]; then + xcodebuild_args+=( + -clonedSourcePackagesDirPath "$IOS_RELEASE_SOURCE_PACKAGES_DIR" + -disableAutomaticPackageResolution + -skipPackageUpdates + ) + fi + + xcodebuild "${xcodebuild_args[@]}" > "$settings_json" || + fail "xcodebuild could not resolve Release settings" +else + require_regular_file "$settings_json" "Release settings JSON" +fi + +debug_settings_json="${IOS_DEBUG_SETTINGS_JSON:-}" +generated_debug_settings="" +if [[ -z "$debug_settings_json" ]]; then + generated_debug_settings="$( + mktemp "${TMPDIR:-/tmp}/fearless-debug-settings.XXXXXX" + )" + debug_settings_json="$generated_debug_settings" + + debug_xcodebuild_args=( + -workspace "$REPO_ROOT/fearless.xcworkspace" + -scheme fearless + -configuration Debug + -destination "generic/platform=iOS" + -showBuildSettings + -json + ) + + if [[ -n "${IOS_RELEASE_SOURCE_PACKAGES_DIR:-}" ]]; then + debug_xcodebuild_args+=( + -clonedSourcePackagesDirPath "$IOS_RELEASE_SOURCE_PACKAGES_DIR" + -disableAutomaticPackageResolution + -skipPackageUpdates + ) + fi + + xcodebuild "${debug_xcodebuild_args[@]}" > "$debug_settings_json" || + fail "xcodebuild could not resolve Debug settings" +else + require_regular_file "$debug_settings_json" "Debug settings JSON" +fi + +jq -e ' + type == "array" and + ([.[] | select(.target == "fearless")] | length == 1) +' "$settings_json" >/dev/null || + fail "Release settings must contain exactly one fearless target" + +jq -e ' + type == "array" and + ([.[] | select(.target == "fearless")] | length == 1) +' "$debug_settings_json" >/dev/null || + fail "Debug settings must contain exactly one fearless target" + +read_setting() { + local key="$1" + + jq -er --arg key "$key" ' + [.[] | select(.target == "fearless")][0].buildSettings[$key] // + error("missing setting") + ' "$settings_json" 2>/dev/null || + fail "Release setting is missing: $key" +} + +read_debug_setting() { + local key="$1" + + jq -er --arg key "$key" ' + [.[] | select(.target == "fearless")][0].buildSettings[$key] // + error("missing setting") + ' "$debug_settings_json" 2>/dev/null || + fail "Debug setting is missing: $key" +} + +require_setting() { + local key="$1" + local expected="$2" + local actual + + actual="$(read_setting "$key")" + [[ "$actual" == "$expected" ]] || + fail "$key is '$actual', expected '$expected'" +} + +require_debug_setting() { + local key="$1" + local expected="$2" + local actual + + actual="$(read_debug_setting "$key")" + [[ "$actual" == "$expected" ]] || + fail "Debug $key is '$actual', expected '$expected'" +} + +require_setting PRODUCT_BUNDLE_IDENTIFIER "$EXPECTED_BUNDLE_ID" +require_setting MARKETING_VERSION "$EXPECTED_VERSION" +require_setting CURRENT_PROJECT_VERSION "$EXPECTED_BUILD" +require_setting CODE_SIGN_ENTITLEMENTS "fearless/WalletConnect.entitlements" +require_setting CODE_SIGN_STYLE "Manual" +require_setting CODE_SIGN_IDENTITY "$EXPECTED_SIGNING_IDENTITY" +require_setting DEVELOPMENT_TEAM "$EXPECTED_DEVELOPMENT_TEAM" +require_setting PROVISIONING_PROFILE_SPECIFIER "$EXPECTED_PROFILE_NAME" +require_setting SWIFT_OPTIMIZATION_LEVEL "-O" +require_setting ENABLE_TESTABILITY "NO" + +require_debug_setting PRODUCT_BUNDLE_IDENTIFIER "$EXPECTED_DEBUG_BUNDLE_ID" +require_debug_setting \ + CODE_SIGN_ENTITLEMENTS \ + "fearless/WalletConnect.dev.entitlements" +require_debug_setting CODE_SIGN_STYLE "Automatic" +require_debug_setting DEVELOPMENT_TEAM "$EXPECTED_DEVELOPMENT_TEAM" + +entitlements_json="$( + plutil -convert json -o - "$ENTITLEMENTS_FILE" 2>/dev/null +)" || fail "production entitlements are not a valid property list" + +jq -e ' + type == "object" and + (keys | sort) == ( + [ + "com.apple.developer.associated-domains", + "com.apple.developer.icloud-container-identifiers", + "com.apple.developer.icloud-services", + "com.apple.security.application-groups" + ] | sort + ) and + .["com.apple.developer.associated-domains"] == [ + "applinks:fearlesswallet.io", + "webcredentials:fearlesswallet.io" + ] and + .["com.apple.developer.icloud-container-identifiers"] == [ + "iCloud.jp.co.soramitsu.fearlesswallet" + ] and + .["com.apple.developer.icloud-services"] == ["CloudKit"] and + .["com.apple.security.application-groups"] == [ + "group.jp.co.soramitsu.fearlesswallet" + ] and + (has("keychain-access-groups") | not) +' <<<"$entitlements_json" >/dev/null || + fail "production entitlements do not match the Fearless App Store identity" + +debug_entitlements_json="$( + plutil -convert json -o - "$DEBUG_ENTITLEMENTS_FILE" 2>/dev/null +)" || fail "development entitlements are not a valid property list" + +jq -e ' + type == "object" and + (keys | sort) == ( + [ + "com.apple.developer.associated-domains", + "com.apple.developer.icloud-container-identifiers", + "com.apple.developer.icloud-services", + "com.apple.security.application-groups" + ] | sort + ) and + .["com.apple.developer.associated-domains"] == [ + "webcredentials:fearlesswallet.io" + ] and + .["com.apple.developer.icloud-container-identifiers"] == [ + "iCloud.jp.co.soramitsu.fearless", + "iCloud.jp.co.soramitsu.fearlesswallet.dev" + ] and + .["com.apple.developer.icloud-services"] == ["CloudKit"] and + .["com.apple.security.application-groups"] == [ + "group.jp.co.soramitsu.fearlesswallet.walletconnect" + ] and + (has("keychain-access-groups") | not) +' <<<"$debug_entitlements_json" >/dev/null || + fail "Debug entitlements do not match the isolated development identity" + +grep -Fq \ + 'static let productionGroupIdentifier = "group.jp.co.soramitsu.fearlesswallet"' \ + "$WALLET_CONNECT_SERVICE_FILE" || + fail "WalletConnect production consumer does not use the entitled app group" +grep -Fq \ + 'static let developmentGroupIdentifier = "group.jp.co.soramitsu.fearlesswallet.walletconnect"' \ + "$WALLET_CONNECT_SERVICE_FILE" || + fail "WalletConnect development consumer does not use the registered Debug app group" +grep -Fq \ + 'WalletConnectGroupIdentifierResolver.resolve(' \ + "$WALLET_CONNECT_SERVICE_FILE" || + fail "WalletConnect setup does not resolve its group from the application identity" +grep -Fq \ + 'groupIdentifier: groupIdentifier' \ + "$WALLET_CONNECT_SERVICE_FILE" || + fail "WalletConnect networking does not consume the resolved group" +if grep -Fq \ + 'groupIdentifier: Self.walletConnectGroupIdentifier' \ + "$WALLET_CONNECT_SERVICE_FILE"; then + fail "WalletConnect setup still consumes a hard-coded app group" +fi + +if [[ -n "$generated_settings" ]]; then + rm -f "$generated_settings" +fi +if [[ -n "$generated_debug_settings" ]]; then + rm -f "$generated_debug_settings" +fi + +printf '%s\n' \ + "[ios-release-identity] PASS: Release archives $EXPECTED_BUNDLE_ID $EXPECTED_VERSION ($EXPECTED_BUILD)" diff --git a/scripts/ci/audit-ios-signed-release-artifact.sh b/scripts/ci/audit-ios-signed-release-artifact.sh new file mode 100755 index 0000000000..a0c1ee7077 --- /dev/null +++ b/scripts/ci/audit-ios-signed-release-artifact.sh @@ -0,0 +1,662 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Fail-closed audit of the exact production .xcarchive proposed for TestFlight. +# The caller must supply independently recorded digests from the archive build +# step; this script never infers provenance from the current checkout. + +umask 077 + +readonly LOG_PREFIX="[ios-signed-release-audit]" +readonly EXPECTED_TEAM="YLWWUD25VZ" +readonly EXPECTED_BUNDLE="jp.co.soramitsu.fearlesswallet" +readonly EXPECTED_VERSION="4.2.0" +readonly EXPECTED_APPLICATION_ID="${EXPECTED_TEAM}.${EXPECTED_BUNDLE}" +readonly EXPECTED_ASSOCIATED_DOMAINS_JSON='["applinks:fearlesswallet.io","webcredentials:fearlesswallet.io"]' +readonly EXPECTED_ICLOUD_CONTAINERS_JSON='["iCloud.jp.co.soramitsu.fearlesswallet"]' +readonly EXPECTED_ICLOUD_SERVICES_JSON='["CloudKit"]' +readonly EXPECTED_APP_GROUPS_JSON='["group.jp.co.soramitsu.fearlesswallet"]' +readonly EXPECTED_PROFILE_KEYCHAIN_GROUPS_JSON='["YLWWUD25VZ.*","com.apple.token"]' +readonly MINIMUM_PROFILE_VALIDITY_DAYS=14 +readonly TEST_HARNESS="${FEARLESS_SIGNED_AUDIT_TEST_HARNESS:-0}" + +fail() { + printf '%s ERROR: %s\n' "$LOG_PREFIX" "$*" >&2 + exit 1 +} + +usage() { + cat <<'USAGE' +Usage: + bash scripts/ci/audit-ios-signed-release-artifact.sh \ + --archive /absolute/path/to/fearless.xcarchive \ + --expected-git-sha 40_HEX_SHA \ + --expected-build CANONICAL_CF_BUNDLE_VERSION \ + --expected-executable-sha256 64_HEX_SHA256 \ + --expected-archive-sha256 64_HEX_SHA256 \ + --expected-signing-certificate-sha1 40_HEX_SHA1 \ + --expected-profile-uuid UUID \ + --expected-profile-name PROFILE_NAME \ + --receipt /absolute/path/to/new-receipt.json + +The archive digest is the canonical tree digest emitted by: + bash scripts/ci/hash-ios-archive.sh /absolute/path/to/fearless.xcarchive + +Tool overrides are accepted only when +FEARLESS_SIGNED_AUDIT_TEST_HARNESS=1: + FEARLESS_SIGNED_AUDIT_CODESIGN_BIN + FEARLESS_SIGNED_AUDIT_SECURITY_BIN + FEARLESS_SIGNED_AUDIT_PYTHON_BIN + FEARLESS_SIGNED_AUDIT_SHASUM_BIN +USAGE +} + +require_option_value() { + local option="$1" + local remaining="$2" + [[ "$remaining" -ge 2 ]] || fail "$option requires a value" +} + +require_executable() { + local executable="$1" + local label="$2" + + if [[ "$executable" == */* ]]; then + [[ -x "$executable" ]] || fail "$label is not executable" + else + command -v "$executable" >/dev/null 2>&1 || + fail "$label is unavailable" + fi +} + +lowercase() { + printf '%s' "$1" | tr '[:upper:]' '[:lower:]' +} + +if [[ "$TEST_HARNESS" != "1" ]]; then + for override_name in \ + FEARLESS_SIGNED_AUDIT_CODESIGN_BIN \ + FEARLESS_SIGNED_AUDIT_SECURITY_BIN \ + FEARLESS_SIGNED_AUDIT_PYTHON_BIN \ + FEARLESS_SIGNED_AUDIT_SHASUM_BIN; do + [[ -z "${!override_name:-}" ]] || + fail "$override_name is accepted only in the explicit test harness" + done +fi + +readonly CODESIGN_BIN="${FEARLESS_SIGNED_AUDIT_CODESIGN_BIN:-codesign}" +readonly SECURITY_BIN="${FEARLESS_SIGNED_AUDIT_SECURITY_BIN:-security}" +readonly PYTHON_BIN="${FEARLESS_SIGNED_AUDIT_PYTHON_BIN:-python3}" +readonly SHASUM_BIN="${FEARLESS_SIGNED_AUDIT_SHASUM_BIN:-shasum}" + +archive="" +expected_git_sha="" +expected_build="" +expected_executable_sha="" +expected_archive_sha="" +expected_signing_certificate_sha1="" +expected_profile_uuid="" +expected_profile_name="" +receipt="" + +while [[ "$#" -gt 0 ]]; do + case "$1" in + --archive) + require_option_value "$1" "$#" + archive="$2" + shift 2 + ;; + --expected-git-sha) + require_option_value "$1" "$#" + expected_git_sha="$2" + shift 2 + ;; + --expected-build) + require_option_value "$1" "$#" + expected_build="$2" + shift 2 + ;; + --expected-executable-sha256) + require_option_value "$1" "$#" + expected_executable_sha="$2" + shift 2 + ;; + --expected-archive-sha256) + require_option_value "$1" "$#" + expected_archive_sha="$2" + shift 2 + ;; + --expected-signing-certificate-sha1) + require_option_value "$1" "$#" + expected_signing_certificate_sha1="$2" + shift 2 + ;; + --expected-profile-uuid) + require_option_value "$1" "$#" + expected_profile_uuid="$2" + shift 2 + ;; + --expected-profile-name) + require_option_value "$1" "$#" + expected_profile_name="$2" + shift 2 + ;; + --receipt) + require_option_value "$1" "$#" + receipt="$2" + shift 2 + ;; + --help|-h) + usage + exit 0 + ;; + *) + fail "unknown argument: $1" + ;; + esac +done + +[[ "$archive" == /* ]] || fail "--archive must be an absolute path" +[[ "$archive" == *.xcarchive ]] || fail "--archive must name an .xcarchive" +[[ -d "$archive" && ! -L "$archive" ]] || + fail "--archive must name a real, non-symlink directory" +[[ "$expected_git_sha" =~ ^[0-9A-Fa-f]{40}$ ]] || + fail "--expected-git-sha must be an exact 40-hex commit" +[[ "$expected_build" =~ ^[1-9][0-9]{0,3}(\.[0-9]{1,2}){0,2}$ ]] || + fail "--expected-build must be an explicit canonical CFBundleVersion" +[[ "$expected_executable_sha" =~ ^[0-9A-Fa-f]{64}$ ]] || + fail "--expected-executable-sha256 must be 64 hex" +[[ "$expected_archive_sha" =~ ^[0-9A-Fa-f]{64}$ ]] || + fail "--expected-archive-sha256 must be 64 hex" +[[ "$expected_signing_certificate_sha1" =~ ^[0-9A-Fa-f]{40}$ ]] || + fail "--expected-signing-certificate-sha1 must be 40 hex" +[[ "$expected_profile_uuid" =~ ^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$ ]] || + fail "--expected-profile-uuid must be a UUID" +[[ -n "$expected_profile_name" && "$expected_profile_name" != *$'\n'* ]] || + fail "--expected-profile-name must be a nonempty single line" +[[ "$receipt" == /* ]] || fail "--receipt must be an absolute path" +[[ ! -e "$receipt" && ! -L "$receipt" ]] || + fail "--receipt must not already exist" +[[ -d "$(dirname "$receipt")" && ! -L "$(dirname "$receipt")" ]] || + fail "--receipt parent must be a real existing directory" + +require_executable "$CODESIGN_BIN" "codesign" +require_executable "$SECURITY_BIN" "security" +require_executable "$PYTHON_BIN" "Python" +require_executable "$SHASUM_BIN" "shasum" + +archive="$(cd "$archive" && pwd -P)" +readonly archive + +readonly ARCHIVE_INFO="$archive/Info.plist" +[[ -f "$ARCHIVE_INFO" && ! -L "$ARCHIVE_INFO" ]] || + fail "archive Info.plist is missing or unsafe" + +readonly APP_ROOT="$archive/Products/Applications" +[[ -d "$APP_ROOT" && ! -L "$APP_ROOT" ]] || + fail "archive Products/Applications directory is missing or unsafe" + +app_inventory="$( + find "$APP_ROOT" -mindepth 1 -maxdepth 1 -type d -name '*.app' -print +)" +app_count="$(printf '%s\n' "$app_inventory" | awk 'NF { count += 1 } END { print count + 0 }')" +[[ "$app_count" == "1" ]] || + fail "archive must contain exactly one top-level application" +readonly APP_PATH="$app_inventory" +[[ ! -L "$APP_PATH" ]] || fail "archived application must not be a symlink" + +readonly APP_INFO="$APP_PATH/Info.plist" +[[ -f "$APP_INFO" && ! -L "$APP_INFO" ]] || + fail "archived application Info.plist is missing or unsafe" + +read_plist_string() { + local plist="$1" + local key_path="$2" + + "$PYTHON_BIN" - "$plist" "$key_path" <<'PY' +import plistlib +import sys + +path, key_path = sys.argv[1:] +try: + with open(path, "rb") as source: + value = plistlib.load(source) + for component in key_path.split("."): + value = value[component] +except (OSError, KeyError, TypeError, plistlib.InvalidFileException): + raise SystemExit(2) +if not isinstance(value, str) or not value: + raise SystemExit(3) +print(value) +PY +} + +bundle_id="$(read_plist_string "$APP_INFO" CFBundleIdentifier)" || + fail "archived app lacks CFBundleIdentifier" +version="$(read_plist_string "$APP_INFO" CFBundleShortVersionString)" || + fail "archived app lacks CFBundleShortVersionString" +build="$(read_plist_string "$APP_INFO" CFBundleVersion)" || + fail "archived app lacks CFBundleVersion" +embedded_git_sha="$(read_plist_string "$APP_INFO" FearlessGitCommit)" || + fail "archived app lacks FearlessGitCommit provenance" +configuration="$(read_plist_string "$APP_INFO" FearlessBuildConfiguration)" || + fail "archived app lacks Release configuration attestation" +optimization="$(read_plist_string "$APP_INFO" FearlessSwiftOptimizationLevel)" || + fail "archived app lacks Swift optimization attestation" +testability="$(read_plist_string "$APP_INFO" FearlessEnableTestability)" || + fail "archived app lacks testability attestation" +executable_name="$(read_plist_string "$APP_INFO" CFBundleExecutable)" || + fail "archived app lacks CFBundleExecutable" + +[[ "$bundle_id" == "$EXPECTED_BUNDLE" ]] || + fail "archived bundle identifier is not the production identity" +[[ "$version" == "$EXPECTED_VERSION" ]] || + fail "archived marketing version is not $EXPECTED_VERSION" +[[ "$build" == "$expected_build" ]] || + fail "archived build number is not the expected fresh build" +[[ "$(lowercase "$embedded_git_sha")" == "$(lowercase "$expected_git_sha")" ]] || + fail "embedded git commit does not match the expected build commit" +[[ "$configuration" == "Release" ]] || + fail "archived app was not built with Release configuration" +[[ "$optimization" == "-O" ]] || + fail "archived app was not built with Swift -O" +[[ "$testability" == "NO" ]] || + fail "archived app has testability enabled" +[[ "$executable_name" =~ ^[A-Za-z0-9._-]+$ ]] || + fail "archived executable name is unsafe" + +readonly EXECUTABLE="$APP_PATH/$executable_name" +[[ -f "$EXECUTABLE" && ! -L "$EXECUTABLE" && -x "$EXECUTABLE" ]] || + fail "archived executable is missing, unsafe, or not executable" +actual_executable_sha="$("$SHASUM_BIN" -a 256 "$EXECUTABLE" | awk '{print $1}')" +[[ "$actual_executable_sha" =~ ^[0-9A-Fa-f]{64}$ ]] || + fail "could not compute archived executable SHA-256" +[[ "$(lowercase "$actual_executable_sha")" == "$(lowercase "$expected_executable_sha")" ]] || + fail "archived executable SHA-256 does not match build provenance" + +readonly HASH_SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)/hash-ios-archive.sh" +[[ -x "$HASH_SCRIPT" ]] || fail "canonical archive hash helper is unavailable" +actual_archive_sha="$("$HASH_SCRIPT" "$archive")" || + fail "could not compute canonical archive SHA-256" +[[ "$(lowercase "$actual_archive_sha")" == "$(lowercase "$expected_archive_sha")" ]] || + fail "archive SHA-256 does not match build provenance" + +"$PYTHON_BIN" - "$ARCHIVE_INFO" "$APP_PATH" "$EXPECTED_BUNDLE" "$EXPECTED_TEAM" <<'PY' || +import os +import plistlib +import sys + +path, app_path, expected_bundle, expected_team = sys.argv[1:] +try: + with open(path, "rb") as source: + payload = plistlib.load(source) +except (OSError, plistlib.InvalidFileException): + raise SystemExit(2) +properties = payload.get("ApplicationProperties") +if not isinstance(properties, dict): + raise SystemExit(3) +products_root = os.path.join(os.path.dirname(path), "Products") +expected_relative = os.path.relpath(app_path, products_root) +if properties.get("ApplicationPath") != expected_relative: + raise SystemExit(4) +if properties.get("CFBundleIdentifier") != expected_bundle: + raise SystemExit(5) +if properties.get("Team") != expected_team: + raise SystemExit(6) +identity = properties.get("SigningIdentity") +if not isinstance(identity, str) or not ( + identity.startswith("Apple Distribution:") or + identity.startswith("iPhone Distribution:") +): + raise SystemExit(7) +PY + fail "xcarchive metadata does not bind the production app, team, and distribution identity" + +temporary_dir="$(mktemp -d "${TMPDIR:-/private/tmp}/fearless-signed-audit.XXXXXX")" +cleanup() { + rm -rf "$temporary_dir" +} +trap cleanup EXIT + +if ! "$CODESIGN_BIN" --verify --deep --strict "$APP_PATH" \ + >"$temporary_dir/codesign-verify" 2>&1; then + fail "archived app failed strict code-signature verification" +fi + +if ! "$CODESIGN_BIN" -d --entitlements :- --xml "$APP_PATH" \ + >"$temporary_dir/signed-entitlements.plist" \ + 2>"$temporary_dir/codesign-diagnostics"; then + fail "could not extract signed application entitlements" +fi +[[ -s "$temporary_dir/signed-entitlements.plist" ]] || + fail "signed application entitlements were empty" +if ! "$CODESIGN_BIN" -d \ + --extract-certificates="$temporary_dir/signing-certificate" \ + "$APP_PATH" >"$temporary_dir/certificate-output" \ + 2>"$temporary_dir/certificate-diagnostics"; then + fail "could not extract the application signing certificate" +fi +readonly SIGNING_CERTIFICATE="$temporary_dir/signing-certificate0" +[[ -f "$SIGNING_CERTIFICATE" && ! -L "$SIGNING_CERTIFICATE" ]] || + fail "application signature has no regular leaf certificate" +signing_certificate_sha1="$( + "$SHASUM_BIN" -a 1 "$SIGNING_CERTIFICATE" | awk '{print $1}' +)" +[[ "$signing_certificate_sha1" =~ ^[0-9A-Fa-f]{40}$ ]] || + fail "could not compute the application signing certificate SHA-1" +[[ "$(lowercase "$signing_certificate_sha1")" == "$(lowercase "$expected_signing_certificate_sha1")" ]] || + fail "application signing certificate does not match the expected release identity" + +readonly EMBEDDED_PROFILE="$APP_PATH/embedded.mobileprovision" +[[ -f "$EMBEDDED_PROFILE" && ! -L "$EMBEDDED_PROFILE" ]] || + fail "archived app has no regular embedded provisioning profile" +if ! "$SECURITY_BIN" cms -D -i "$EMBEDDED_PROFILE" \ + >"$temporary_dir/profile.plist" 2>"$temporary_dir/security-diagnostics"; then + fail "embedded provisioning profile could not be decoded" +fi + +"$PYTHON_BIN" - \ + "$temporary_dir/signed-entitlements.plist" \ + "$temporary_dir/profile.plist" \ + "$EXPECTED_TEAM" \ + "$EXPECTED_APPLICATION_ID" \ + "$EXPECTED_ASSOCIATED_DOMAINS_JSON" \ + "$EXPECTED_ICLOUD_CONTAINERS_JSON" \ + "$EXPECTED_ICLOUD_SERVICES_JSON" \ + "$EXPECTED_APP_GROUPS_JSON" \ + "$EXPECTED_PROFILE_KEYCHAIN_GROUPS_JSON" \ + "$MINIMUM_PROFILE_VALIDITY_DAYS" \ + "$signing_certificate_sha1" \ + "$expected_profile_uuid" \ + "$expected_profile_name" <<'PY' || +import datetime +import hashlib +import json +import plistlib +import sys + +( + entitlements_path, + profile_path, + expected_team, + expected_application_id, + associated_json, + containers_json, + services_json, + groups_json, + profile_keychain_groups_json, + minimum_validity_days_text, + signing_certificate_sha1, + expected_profile_uuid, + expected_profile_name, +) = sys.argv[1:] + +def load(path): + try: + with open(path, "rb") as source: + return plistlib.load(source) + except (OSError, plistlib.InvalidFileException): + raise SystemExit(2) + +signed = load(entitlements_path) +profile = load(profile_path) +if not isinstance(signed, dict) or not isinstance(profile, dict): + raise SystemExit(3) + +expected = { + "com.apple.developer.associated-domains": json.loads(associated_json), + "com.apple.developer.icloud-container-identifiers": json.loads(containers_json), + "com.apple.developer.icloud-services": json.loads(services_json), + "com.apple.security.application-groups": json.loads(groups_json), +} +for key, value in expected.items(): + if signed.get(key) != value: + raise SystemExit(4) +if signed.get("application-identifier") != expected_application_id: + raise SystemExit(5) +if signed.get("com.apple.developer.team-identifier") != expected_team: + raise SystemExit(6) +if signed.get("get-task-allow") is True: + raise SystemExit(7) + +allowed_signed_keys = set(expected) | { + "application-identifier", + "beta-reports-active", + "com.apple.developer.icloud-container-environment", + "com.apple.developer.team-identifier", + "get-task-allow", +} +if set(signed) - allowed_signed_keys: + raise SystemExit(8) +if ( + "beta-reports-active" in signed + and signed["beta-reports-active"] is not True +): + raise SystemExit(8) +if ( + "com.apple.developer.icloud-container-environment" in signed + and signed["com.apple.developer.icloud-container-environment"] != "Production" +): + raise SystemExit(8) + +def scalar_values(value): + if isinstance(value, dict): + for nested in value.values(): + yield from scalar_values(nested) + elif isinstance(value, (list, tuple)): + for nested in value: + yield from scalar_values(nested) + elif isinstance(value, str): + yield value + +for value in scalar_values(signed): + if value in { + "group.jp.co.soramitsu.fearlesswallet", + "group.com.walletconnect.sdk", + "group.jp.co.soramitsu.fearlesswallet.dev", + "iCloud.jp.co.soramitsu.fearless", + "iCloud.jp.co.soramitsu.fearlesswallet.dev", + }: + if value != "group.jp.co.soramitsu.fearlesswallet": + raise SystemExit(9) + +team_identifiers = profile.get("TeamIdentifier") +if team_identifiers != [expected_team]: + raise SystemExit(10) +if profile.get("TeamName") is not None and not isinstance(profile.get("TeamName"), str): + raise SystemExit(11) +if ( + not isinstance(profile.get("UUID"), str) + or profile["UUID"].lower() != expected_profile_uuid.lower() +): + raise SystemExit(12) +if profile.get("Name") != expected_profile_name: + raise SystemExit(13) +profile_certificates = profile.get("DeveloperCertificates") +if ( + not isinstance(profile_certificates, list) + or not profile_certificates + or not all(isinstance(certificate, bytes) for certificate in profile_certificates) +): + raise SystemExit(13) +profile_certificate_fingerprints = { + hashlib.sha1(certificate).hexdigest() + for certificate in profile_certificates +} +if signing_certificate_sha1.lower() not in profile_certificate_fingerprints: + raise SystemExit(13) +creation = profile.get("CreationDate") +expiration = profile.get("ExpirationDate") +if not isinstance(creation, datetime.datetime) or not isinstance(expiration, datetime.datetime): + raise SystemExit(14) +now = datetime.datetime.now(datetime.timezone.utc) +if creation.tzinfo is None: + creation = creation.replace(tzinfo=datetime.timezone.utc) +if expiration.tzinfo is None: + expiration = expiration.replace(tzinfo=datetime.timezone.utc) +try: + minimum_validity_days = int(minimum_validity_days_text) +except ValueError: + raise SystemExit(15) +minimum_expiration = now + datetime.timedelta(days=minimum_validity_days) +if creation >= expiration or expiration < minimum_expiration: + raise SystemExit(15) + +# App Store/TestFlight profiles do not enumerate development devices and are +# never enterprise profiles. +if "ProvisionedDevices" in profile or profile.get("ProvisionsAllDevices") is True: + raise SystemExit(16) +profile_entitlements = profile.get("Entitlements") +if not isinstance(profile_entitlements, dict): + raise SystemExit(17) +if profile_entitlements.get("application-identifier") != expected_application_id: + raise SystemExit(18) +if profile_entitlements.get("com.apple.developer.team-identifier") != expected_team: + raise SystemExit(19) +if profile_entitlements.get("get-task-allow") is not False: + raise SystemExit(20) +if profile_entitlements.get("beta-reports-active") is not True: + raise SystemExit(20) + +# The signed app must contain the exact least-privilege values above. Apple's +# App Store profile is an authorization envelope: associated domains and iCloud +# services are represented as "*" in the real production profile, while the +# container and app-group identities remain explicit. Validate that distinction +# instead of requiring the profile payload to be byte-shaped like the app's +# signed entitlements. +associated_authorization = profile_entitlements.get( + "com.apple.developer.associated-domains" +) +if associated_authorization not in ( + "*", + expected["com.apple.developer.associated-domains"], +): + raise SystemExit(21) +services_authorization = profile_entitlements.get( + "com.apple.developer.icloud-services" +) +if services_authorization not in ( + "*", + expected["com.apple.developer.icloud-services"], +): + raise SystemExit(21) +for key in ( + "com.apple.developer.icloud-container-identifiers", + "com.apple.security.application-groups", +): + if profile_entitlements.get(key) != expected[key]: + raise SystemExit(21) + +expected_containers = expected[ + "com.apple.developer.icloud-container-identifiers" +] +if profile_entitlements.get( + "com.apple.developer.icloud-container-development-container-identifiers" +) != expected_containers: + raise SystemExit(21) +if profile_entitlements.get( + "com.apple.developer.ubiquity-container-identifiers" +) != expected_containers: + raise SystemExit(21) +if profile_entitlements.get( + "com.apple.developer.ubiquity-kvstore-identifier" +) != f"{expected_team}.*": + raise SystemExit(21) + +profile_cloud_environments = profile_entitlements.get( + "com.apple.developer.icloud-container-environment" +) +if isinstance(profile_cloud_environments, str): + profile_cloud_environments = [profile_cloud_environments] +if ( + not isinstance(profile_cloud_environments, list) + or "Production" not in profile_cloud_environments + or not set(profile_cloud_environments).issubset({"Development", "Production"}) +): + raise SystemExit(21) +if profile_entitlements.get("keychain-access-groups") != json.loads( + profile_keychain_groups_json +): + raise SystemExit(21) +allowed_profile_keys = allowed_signed_keys | { + "com.apple.developer.icloud-container-development-container-identifiers", + "com.apple.developer.ubiquity-container-identifiers", + "com.apple.developer.ubiquity-kvstore-identifier", + "keychain-access-groups", +} +if set(profile_entitlements) - allowed_profile_keys: + raise SystemExit(22) +if ( + "beta-reports-active" in profile_entitlements + and profile_entitlements["beta-reports-active"] is not True +): + raise SystemExit(23) +PY + fail "signed entitlements or embedded distribution profile violate the production contract" + +# Recompute the canonical tree digest after every signature/profile read and +# immediately before publishing the receipt. This prevents a concurrently +# mutated archive from retaining the digest accepted at the start of the audit. +final_archive_sha="$("$HASH_SCRIPT" "$archive")" || + fail "could not recompute canonical archive SHA-256 before receipt publication" +[[ "$(lowercase "$final_archive_sha")" == "$(lowercase "$actual_archive_sha")" ]] || + fail "archive changed while signed identity and profile were audited" + +receipt_pending="${receipt}.pending.$$" +"$PYTHON_BIN" - \ + "$receipt_pending" \ + "$expected_git_sha" \ + "$bundle_id" \ + "$version" \ + "$build" \ + "$actual_executable_sha" \ + "$actual_archive_sha" \ + "$EXPECTED_TEAM" \ + "$signing_certificate_sha1" \ + "$expected_profile_uuid" \ + "$expected_profile_name" <<'PY' +import datetime +import json +import os +import sys + +( + path, + git_sha, + bundle_id, + version, + build, + executable_sha, + archive_sha, + team, + signing_certificate_sha1, + profile_uuid, + profile_name, +) = sys.argv[1:] +payload = { + "schemaVersion": 1, + "audit": "fearless-ios-signed-production-archive", + "auditedAtUTC": datetime.datetime.now(datetime.timezone.utc).isoformat(), + "gitCommit": git_sha.lower(), + "bundleIdentifier": bundle_id, + "marketingVersion": version, + "buildNumber": build, + "developmentTeam": team, + "executableSHA256": executable_sha.lower(), + "archiveTreeSHA256": archive_sha.lower(), + "signingCertificateSHA1": signing_certificate_sha1.lower(), + "provisioningProfileUUID": profile_uuid.lower(), + "provisioningProfileName": profile_name, + "distributionProfile": "valid-app-store", + "signedEntitlements": "exact-production-contract", +} +with open(path, "x", encoding="utf-8") as destination: + json.dump(payload, destination, indent=2, sort_keys=True) + destination.write("\n") + destination.flush() + os.fsync(destination.fileno()) +PY +mv "$receipt_pending" "$receipt" + +printf '%s\n' \ + "$LOG_PREFIX PASS: exact commit, bundle/version/build, executable/archive hashes, distribution profile, and signed production entitlements verified" diff --git a/scripts/ci/build-audited-ios-release-archive.sh b/scripts/ci/build-audited-ios-release-archive.sh new file mode 100644 index 0000000000..2f8531c8f0 --- /dev/null +++ b/scripts/ci/build-audited-ios-release-archive.sh @@ -0,0 +1,175 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Builds and audits the only archive eligible for the 4.2.0 hotfix handoff. +# It derives provenance from an exact clean HEAD and never uploads anything. + +umask 077 + +readonly LOG_PREFIX="[ios-release-archive]" +readonly EXPECTED_BUNDLE="jp.co.soramitsu.fearlesswallet" +readonly EXPECTED_VERSION="4.2.0" +readonly EXPECTED_SIGNING_IDENTITY="Apple Distribution: Soramitsu Co., Ltd. (YLWWUD25VZ)" +readonly EXPECTED_SIGNING_CERTIFICATE_SHA1="84AB95335BE14CAE9B050A353910F86FF2F9539B" +readonly EXPECTED_PROFILE_NAME="Fearless App Store 2026.7.26" +readonly EXPECTED_PROFILE_UUID="0d51265e-4b53-4a1f-814a-436dc9ca087b" +# Read-only App Store Connect inspection on 2026-07-26 found 2026.7.27 as the +# newest 4.2.0 build. This candidate number was unused at inspection time. +readonly EXPECTED_BUILD="2026.7.28" +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +readonly REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd -P)" + +fail() { + printf '%s ERROR: %s\n' "$LOG_PREFIX" "$*" >&2 + exit 1 +} + +usage() { + cat <<'USAGE' +Usage: + bash scripts/ci/build-audited-ios-release-archive.sh \ + --archive /absolute/new/path/fearless.xcarchive \ + --receipt /absolute/new/path/signed-archive-audit.json + +Preconditions: + - exact clean git HEAD, including no untracked files; + - App Store Connect read-only uniqueness check for 4.2.0 (2026.7.28); + - App Store distribution profile for the production App ID, with + group.jp.co.soramitsu.fearlesswallet and Apple default keychain groups. + +This command creates a local archive and receipt. It does not export, upload, +publish, tag, commit, or push. +USAGE +} + +require_option_value() { + local option="$1" + local remaining="$2" + [[ "$remaining" -ge 2 ]] || fail "$option requires a value" +} + +archive="" +receipt="" +while [[ "$#" -gt 0 ]]; do + case "$1" in + --archive) + require_option_value "$1" "$#" + archive="$2" + shift 2 + ;; + --receipt) + require_option_value "$1" "$#" + receipt="$2" + shift 2 + ;; + --help|-h) + usage + exit 0 + ;; + *) + fail "unknown argument: $1" + ;; + esac +done + +[[ "$archive" == /* && "$archive" == *.xcarchive ]] || + fail "--archive must be an absolute .xcarchive path" +[[ ! -e "$archive" && ! -L "$archive" ]] || + fail "--archive must not already exist" +[[ -d "$(dirname "$archive")" && ! -L "$(dirname "$archive")" ]] || + fail "--archive parent must be a real existing directory" +[[ "$receipt" == /* ]] || fail "--receipt must be an absolute path" +[[ ! -e "$receipt" && ! -L "$receipt" ]] || + fail "--receipt must not already exist" +[[ -d "$(dirname "$receipt")" && ! -L "$(dirname "$receipt")" ]] || + fail "--receipt parent must be a real existing directory" + +command -v git >/dev/null 2>&1 || fail "git is unavailable" +command -v xcodebuild >/dev/null 2>&1 || fail "xcodebuild is unavailable" +command -v shasum >/dev/null 2>&1 || fail "shasum is unavailable" +command -v security >/dev/null 2>&1 || fail "security is unavailable" +security find-identity -v -p codesigning 2>/dev/null | + grep -Fq "$EXPECTED_SIGNING_CERTIFICATE_SHA1 \"$EXPECTED_SIGNING_IDENTITY\"" || + fail "the exact reviewed Apple Distribution signing identity is not installed" + +cd "$REPO_ROOT" +[[ -z "$(git status --porcelain=v1 --untracked-files=all)" ]] || + fail "release archive requires an exact clean worktree, including no untracked files" +git diff --quiet --ignore-submodules -- || + fail "release archive source differs from HEAD" +git diff --cached --quiet --ignore-submodules -- || + fail "release archive index differs from HEAD" + +source_commit="$(git rev-parse --verify HEAD)" +[[ "$source_commit" =~ ^[0-9A-Fa-f]{40}$ ]] || + fail "could not derive an exact source commit" +git cat-file -e "${source_commit}^{commit}" || + fail "derived source provenance is not a commit" + +IOS_EXPECTED_BUILD_NUMBER="$EXPECTED_BUILD" \ +IOS_RELEASE_SOURCE_PACKAGES_DIR="${IOS_RELEASE_SOURCE_PACKAGES_DIR:-}" \ + bash "$SCRIPT_DIR/audit-ios-release-identity.sh" + +xcodebuild_arguments=( + -workspace "$REPO_ROOT/fearless.xcworkspace" + -scheme fearless + -configuration Release + -destination "generic/platform=iOS" + -archivePath "$archive" +) +if [[ -n "${IOS_RELEASE_SOURCE_PACKAGES_DIR:-}" ]]; then + xcodebuild_arguments+=( + -clonedSourcePackagesDirPath "$IOS_RELEASE_SOURCE_PACKAGES_DIR" + -disableAutomaticPackageResolution + -skipPackageUpdates + ) +fi +xcodebuild_arguments+=( + "CURRENT_PROJECT_VERSION=$EXPECTED_BUILD" + "MARKETING_VERSION=$EXPECTED_VERSION" + "FEARLESS_GIT_COMMIT=$source_commit" + # Signing is intentionally target-scoped in the application's Release build + # configuration. Any signing setting passed here would apply to every Pod, + # Swift package, and resource bundle in the workspace. The source identity + # audit above and signed-artifact audit below fail closed on the exact team, + # distribution identity, App Store profile, and production entitlements. + clean + archive +) + +printf '%s\n' \ + "$LOG_PREFIX building local Release archive from clean commit $source_commit" +xcodebuild "${xcodebuild_arguments[@]}" + +[[ "$(git rev-parse --verify HEAD)" == "$source_commit" ]] || + fail "HEAD changed while the release archive was built" +[[ -z "$(git status --porcelain=v1 --untracked-files=all)" ]] || + fail "tracked or untracked source state changed while the archive was built" + +app_path="$archive/Products/Applications/fearless.app" +[[ -d "$app_path" && ! -L "$app_path" ]] || + fail "archive did not produce exactly the expected application path" +executable_name="$( + /usr/libexec/PlistBuddy -c "Print :CFBundleExecutable" \ + "$app_path/Info.plist" 2>/dev/null +)" || fail "archive app has no executable identity" +[[ "$executable_name" =~ ^[A-Za-z0-9._-]+$ ]] || + fail "archive executable identity is unsafe" +executable_sha="$( + shasum -a 256 "$app_path/$executable_name" | awk '{print $1}' +)" +archive_sha="$(bash "$SCRIPT_DIR/hash-ios-archive.sh" "$archive")" + +bash "$SCRIPT_DIR/audit-ios-signed-release-artifact.sh" \ + --archive "$archive" \ + --expected-git-sha "$source_commit" \ + --expected-build "$EXPECTED_BUILD" \ + --expected-executable-sha256 "$executable_sha" \ + --expected-archive-sha256 "$archive_sha" \ + --expected-signing-certificate-sha1 "$EXPECTED_SIGNING_CERTIFICATE_SHA1" \ + --expected-profile-uuid "$EXPECTED_PROFILE_UUID" \ + --expected-profile-name "$EXPECTED_PROFILE_NAME" \ + --receipt "$receipt" + +printf '%s\n' \ + "$LOG_PREFIX PASS: local 4.2.0 ($EXPECTED_BUILD) archive is bound to clean HEAD $source_commit" diff --git a/scripts/ci/hash-ios-archive.sh b/scripts/ci/hash-ios-archive.sh new file mode 100755 index 0000000000..5e38004b68 --- /dev/null +++ b/scripts/ci/hash-ios-archive.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -euo pipefail + +umask 077 + +[[ "$#" == "1" ]] || { + printf '%s\n' "Usage: bash scripts/ci/hash-ios-archive.sh /absolute/path/to/archive.xcarchive" >&2 + exit 64 +} + +archive="$1" +[[ "$archive" == /* && "$archive" == *.xcarchive ]] || { + printf '%s\n' "archive path must be an absolute .xcarchive path" >&2 + exit 64 +} +[[ -d "$archive" && ! -L "$archive" ]] || { + printf '%s\n' "archive path must be a real non-symlink directory" >&2 + exit 1 +} + +python3 - "$archive" <<'PY' +import hashlib +import os +import stat +import sys + +root = os.path.realpath(sys.argv[1]) +digest = hashlib.sha256() + +def frame(value): + digest.update(str(len(value)).encode("ascii")) + digest.update(b":") + digest.update(value) + digest.update(b";") + +for directory, names, filenames in os.walk(root, topdown=True, followlinks=False): + names.sort() + filenames.sort() + relative_directory = os.path.relpath(directory, root) + for name in names + filenames: + path = os.path.join(directory, name) + relative = os.path.normpath(os.path.join(relative_directory, name)) + if relative.startswith("../") or relative == "..": + raise SystemExit(2) + encoded_path = relative.encode("utf-8") + metadata = os.lstat(path) + if stat.S_ISDIR(metadata.st_mode): + kind = b"d" + payload = b"" + elif stat.S_ISREG(metadata.st_mode): + kind = b"f" + with open(path, "rb") as source: + content_digest = hashlib.sha256() + for chunk in iter(lambda: source.read(1024 * 1024), b""): + content_digest.update(chunk) + payload = content_digest.digest() + elif stat.S_ISLNK(metadata.st_mode): + kind = b"l" + payload = os.readlink(path).encode("utf-8") + else: + raise SystemExit(3) + frame(kind) + frame(encoded_path) + frame(oct(stat.S_IMODE(metadata.st_mode)).encode("ascii")) + frame(payload) + +print(digest.hexdigest()) +PY diff --git a/scripts/ci/manifests/coredata-release-copied-phone-tests.txt b/scripts/ci/manifests/coredata-release-copied-phone-tests.txt new file mode 100644 index 0000000000..72d906fd12 --- /dev/null +++ b/scripts/ci/manifests/coredata-release-copied-phone-tests.txt @@ -0,0 +1,3 @@ +# Exact XCTest identities required by the copied-phone Release/-O gate. +fearlessTests/SubstrateStorageClassResolutionTests/testCopiedPhoneV8Store_whenAvailable_thenAllRowsHaveExpectedClassesAndStoreIsUnchanged +fearlessTests/SubstrateStorageClassResolutionTests/testCopiedPhoneV8Store_whenFetchedThroughProductionRepositories_thenMapsEveryRuntimeAndChain diff --git a/scripts/ci/manifests/coredata-release-core-tests.txt b/scripts/ci/manifests/coredata-release-core-tests.txt new file mode 100644 index 0000000000..e8a03b7a7f --- /dev/null +++ b/scripts/ci/manifests/coredata-release-core-tests.txt @@ -0,0 +1,414 @@ +# Exact XCTest identities required by the Release/-O Core Data gate. +# Generated from, and reviewed against, the 13 explicitly selected test classes. +fearlessTests/SingleToMultiassetUserMigrationTests/testMigrationForCreatedAccountWithoutDerivPath +fearlessTests/SingleToMultiassetUserMigrationTests/testMigrationForCreatedAccountWithDerivPath +fearlessTests/SingleToMultiassetUserMigrationTests/testMigrationForImportedWithSeedAccountWithoutDerivPath +fearlessTests/SingleToMultiassetUserMigrationTests/testMigrationForImportedWithSeedAccountWithDerivPath +fearlessTests/SingleToMultiassetUserMigrationTests/testMigrationForImportedWithJSONAccountWithoutDerivPath +fearlessTests/SingleToMultiassetUserMigrationTests/testMigrationForImportedWithJSONAccountWithDerivPath +fearlessTests/SingleToMultiassetUserMigrationTests/testMigrationFromV1ToCurrentForCreatedAccountWithDerivationPath +fearlessTests/SingleToMultiassetUserMigrationTests/testMigrationFromV1ToCurrentForImportedJSONAccount +fearlessTests/SingleToMultiassetUserMigrationTests/testDuplicateAccountMigration_whenWatchOnlyRowIsInsertedFirst_thenSigningSecretsArePreserved +fearlessTests/SingleToMultiassetUserMigrationTests/testDuplicateAccountMigration_whenSigningRowIsInsertedFirst_thenSigningSecretsArePreserved +fearlessTests/SingleToMultiassetUserMigrationTests/testDuplicateAccountMigration_whenFirstAliasHasConflictingSecret_thenFailsWithoutReplacingStore +fearlessTests/SingleToMultiassetUserMigrationTests/testDuplicateAccountMigration_whenSecondAliasHasConflictingSecret_thenFailsWithoutReplacingStore +fearlessTests/SingleToMultiassetUserMigrationTests/testKeystoreResourceLimits_atEveryExactBoundary_prepareSucceeds +fearlessTests/SingleToMultiassetUserMigrationTests/testKeystoreResourceLimits_whenLegacyRowLimitExceeded_freezesAndFailsBeforePrepareWrites +fearlessTests/SingleToMultiassetUserMigrationTests/testKeystoreResourceLimits_whenStagedKeyCountExceeded_freezesAndFailsBeforePrepareWrites +fearlessTests/SingleToMultiassetUserMigrationTests/testKeystoreResourceLimits_whenIdentifierBytesExceeded_freezesAndFailsBeforePrepareWrites +fearlessTests/SingleToMultiassetUserMigrationTests/testKeystoreResourceLimits_whenStagedKeyBytesExceeded_freezesAndFailsBeforePrepareWrites +fearlessTests/SingleToMultiassetUserMigrationTests/testKeystoreResourceLimits_whenDeletionCountExceeded_freezesAndFailsBeforePrepareWrites +fearlessTests/SingleToMultiassetUserMigrationTests/testKeystoreResourceLimits_whenEncodedJournalExceeded_failsBeforeJournalOrDestinationWrites +fearlessTests/SingleToMultiassetUserMigrationTests/testCleanupRecovery_whenEncodedJournalExceedsProductionLimit_rejectsBeforeDecodeOrMutation +fearlessTests/SingleToMultiassetUserMigrationTests/testV1Migration_whenLegacyRowLimitExceeded_preservesLiveStoreAndKeychain +fearlessTests/SingleToMultiassetUserMigrationTests/testV1Migration_whenNonthrowingStagingLimitExceeded_preservesLiveStoreAndMakesNoKeychainWrites +fearlessTests/SingleToMultiassetUserMigrationTests/testV1Migration_whenEntropyExceedsStagedByteLimit_abortsBeforeCryptographicDerivation +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenProcessDiesAtEveryCommitBoundary_thenBothStoreFamiliesRecoverExactly +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenProcessDiesAtEveryRollbackFileBoundary_thenBothStoreFamiliesRestoreExactly +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenProcessDiesDuringEveryCleanupDeletion_thenPreparingRollbackAndCommittedStatesConverge +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenProcessDiesDuringEachLowLevelFamilyMutation_thenBothStoreFamiliesRestoreExactly +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenFirstMarkerWriteIsInterrupted_thenOnlyExactSafePendingTreeIsCleaned +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenPreparingBackupCopyIsPartial_thenCleansOnlyWithExactOriginalLiveFamily +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenMarkerIsAdversarial_thenFailsClosedWithoutChangingLiveFamily +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenTransactionTreeContainsUnknownFileOrDirectory_thenFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenCommittedFamilyOrSemanticValidationChanges_thenRestoresOriginalFamily +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenCommittedValidationMutatesItsStoreAndCleanupIsInterrupted_thenLiveCommitStillConverges +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenMarkerBackupOrLiveMemberIsSymlink_thenFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenLiveFamilyIsUnsafeOrOrphaned_thenNeverReportsAnEmptyStore +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenStagedFamilyIsUnsafeOrAliasesProtectedPaths_thenRejectsBeforeMutation +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenPreMarkerDirectoryIsEmpty_thenSafelyCleansItOnlyAfterValidatingLiveFamily +fearlessTests/UserStorageCompatibilityMigrationTests/testCrashConsistentReplacement_whenPathsShareDirectory_thenUserAndSubstrateTransactionsCannotCollide +fearlessTests/UserStorageCompatibilityMigrationTests/testCompatibilityModels_whenBundled_thenHaveExactFingerprintsAndMigrationEdges +fearlessTests/UserStorageCompatibilityMigrationTests/testCurrentModel_whenLoaded_thenEveryEntityResolvesToTheAppRuntimeClass +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenVersion2PersistentFixture_thenPreservesWalletsAndAccountsAndRoutesExistingPincodeToPinOnRepeatedLaunch +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenIntermediateV3StoreDropsWallet_thenPerHopCountFailsClosedAndRetryPreservesFixture +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenIntermediateV3StoreDropsChainAccountButWalletCountIsUnchanged_thenPerHopIntegrityFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenIntermediateV3StoreMutatesWalletFieldWithoutChangingCount_thenPerHopIntegrityFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenLegacyFieldsAreIntentionallyDerived_thenPreservesExactAssetVisibilityAndNetworkFilterSemantics +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenIntentionalDerivedFieldsAreDroppedOrMutatedInStaging_thenSemanticIntegrityFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenV1ToV2DropsDestinationAccount_thenLegacyAccountSemanticIntegrityFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenLegacyEcosystemStore_thenPreservesWalletTonAssetAndChainData +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenPublicV11Store_thenPreservesWalletAssetAndEthereumChainData +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenV11OrLegacyV12PreferenceArchiveIsInvalid_thenDefaultsOnlyDamagedField +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenPreferenceArchiveHasWrongDecodedType_thenDefaultsOnlyDamagedField +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenPreferenceArchivesAreValid_thenPreservesEveryValue +fearlessTests/UserStorageCompatibilityMigrationTests/testRawArchivePreflight_whenValuesCrossByteBoundary_thenRepairsOnlyOversizedArchivesAndIsIdempotent +fearlessTests/UserStorageCompatibilityMigrationTests/testRawArchivePreflight_whenRequiredReplacementExceedsLimit_thenRollsBackWithoutMutation +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenRawPreferenceArchiveExceedsProductionLimit_thenRepairsBeforeCoreDataDecode +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenDecodedPreferenceLimitsAreCrossed_thenRepairsOverLimitAndPreservesExactBoundaries +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenCurrentVersionRequiredArchiveExceedsRawLimit_thenAtomicallyRepairsAndSubsequentRunIsNoOp +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenCurrentVersionOptionalArchiveHasWrongSQLiteType_thenAtomicallyRepairsToNullAndSubsequentRunIsNoOp +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenCurrentVersionDecodedPreferenceExceedsLimit_thenCountsRepairAndSubsequentRunIsNoOp +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenCurrentVersionRepairFitsCopyLimitButFinalBackupCapacityIsInsufficient_thenPreservesLiveStore +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenCurrentVersionRepairValidationHookDropsWallet_thenRejectsMutatedBaselineBeforeReplacement +fearlessTests/UserStorageCompatibilityMigrationTests/testRelationshipCountPreflight_whenRelationshipIsFaulted_thenCountsWithoutMaterializingIt +fearlessTests/UserStorageCompatibilityMigrationTests/testRelationshipAggregateCounter_whenCountReachesExactBoundary_thenAcceptsIt +fearlessTests/UserStorageCompatibilityMigrationTests/testRelationshipAggregateCounter_whenLimitOrIntegerRangeIsExceeded_thenFailsWithoutChangingTotal +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenAggregateRelationshipDestinationsExceedStoreLimit_thenFailsBeforeStoreReplacement +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenRelationshipExceedsDestinationLimit_thenFailsBeforeStoreReplacement +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenVersion1AccountRowLimitIsExceeded_thenFailsBeforeKeyOrStoreReplacement +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenVersion1RowsExceedKeystoreProductionCap_thenFailsBeforeMigrationPolicyOrKeyStaging +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenVersion1SourceFamilyExceedsCopyLimit_thenFailsBeforeCapacityKeyOrStoreReplacement +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenPrivateRepairSucceedsButReplacementFails_thenOnlyStagedFieldChangesAndSourceRemainsByteIdentical +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenPrivateRepairRowCapIsExceeded_thenRejectsBeforePagingOrReplacement +fearlessTests/UserStorageCompatibilityMigrationTests/testMigration_whenPrivateRepairRowsSpanSingleIDPages_thenEnumeratesEveryWalletExactlyOnce +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenStagedStoreDropsChainAccount_thenRefusesReplacementAndLeavesSourceUnchanged +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenIntegrityRowBudgetIsExceeded_thenFailsBeforeReplacementAndLeavesSourceUnchanged +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenCanonicalIdentityByteBudgetIsExceeded_thenFailsBeforeReplacementAndLeavesSourceUnchanged +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenStagedStoreMutatesSameCountGlobalContentOrRelationships_thenRefusesReplacementAndLeavesSourceUnchanged +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenWALSourceReplacementFails_thenOriginalDurableFilesAreByteForByteUnchanged +fearlessTests/UserStorageCompatibilityMigrationTests/testCopyStoreFamily_whenRollbackJournalExists_thenCopiesRecoveryStateWithoutSourceShmOrMutation +fearlessTests/UserStorageCompatibilityMigrationTests/testMetadataProbe_whenObjectiveCExceptionIsRaised_thenFailsClosedOnPrivateCopiesAndNeverMutatesSource +fearlessTests/UserStorageCompatibilityMigrationTests/testMetadataProbe_whenSourceHasHotRollbackJournal_thenRecoversOnlyPrivateCopyAndLeavesSourceFamilyByteIdentical +fearlessTests/UserStorageCompatibilityMigrationTests/testSynchronousMigration_whenStoreIsCurrent_thenUsesSinglePrivateMetadataProbe +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenStoreAlreadyCurrent_thenRepeatedCallsAreByteForByteIdempotent +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenStoreIsCorrupt_thenThrowsAndDoesNotModifyFiles +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenStoreModelIsUnknown_thenThrowsAndDoesNotModifyFiles +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenProcessDiesAfterRemovingLiveMainStore_thenRelaunchRestoresAndMigratesProtectedWallets +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenStoreReplacementFails_thenProtectedDataIsNeverFinalized +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenStoreReplacementSucceeds_thenProtectedDataFinalizesAfterward +fearlessTests/UserStorageCompatibilityMigrationTests/testSettingsCleanup_whenReplacementFailsBeforeCommit_thenRelaunchRollsBackJournalWithoutDeletingLegacySelections +fearlessTests/UserStorageCompatibilityMigrationTests/testSettingsCleanup_whenProcessStopsAfterDatabaseReplacement_thenCurrentVersionRelaunchFinishesCleanup +fearlessTests/UserStorageCompatibilityMigrationTests/testSettingsCleanup_whenFinalizeFails_thenErrorPropagatesAndCurrentVersionRelaunchRetriesIdempotently +fearlessTests/UserStorageCompatibilityMigrationTests/testSettingsCleanup_whenJournalIsValid_thenDeletesOnlyExactLegacySelections +fearlessTests/UserStorageCompatibilityMigrationTests/testSettingsCleanup_whenJournalTargetsUnrelatedKey_thenFailsClosedAndPreservesEverything +fearlessTests/UserStorageCompatibilityMigrationTests/testSettingsCleanup_whenJournalHasDuplicateField_thenFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testSettingsCleanup_whenJournalHasUnknownField_thenFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testSettingsCleanup_whenJournalIsOversized_thenFailsBeforeDeletingAnything +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenKeychainReadFails_thenPropagatesAndLeavesLegacyStoreUntouched +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenReplacementKeySaveFails_thenNeverReplacesStoreOrDeletesLegacyKey +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenStoreReplacementFails_thenKeepsOldAndStagedKeysUntilSafeRollback +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenPostReplacementCleanupFails_thenFailsAndRelaunchFinishesCleanupWithoutLosingNewKey +fearlessTests/UserStorageCompatibilityMigrationTests/testMigrate_whenDestinationSecretVerificationFails_thenReturnsFailureAndRetryConvergesOnlyAfterRepair +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenCurrentStoreCleanupJournalIsCorrupt_thenLaunchFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenCurrentStoreCleanupJournalCannotBeRead_thenBlocksAndRetriesWithoutDeletingKeys +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenCurrentStoreDestinationKeyIsMissing_thenBlocksUntilKeyIsRestored +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenCurrentStoreDestinationProofIsTampered_thenBlocksUntilJournalIsRestored +fearlessTests/UserStorageCompatibilityMigrationTests/testPerformMigration_whenSourceStoreHasLegacyCleanupJournal_thenRerunsWithExistingStagedKey +fearlessTests/UserStorageCompatibilityMigrationTests/testMigrate_whenDestinationStoreHasLegacyCleanupJournal_thenClearsOnlyJournal +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenLegacyJournalContainsReservedIdentifier_thenFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenVerifiedJournalDoesNotBracketDatabaseVersion_thenFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenLegacyJournalDoesNotBracketDatabaseVersion_thenFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testMigrate_whenStoreDoesNotExist_thenReturnsWithoutReadingKeychain +fearlessTests/UserStorageCompatibilityMigrationTests/testKeystoreMigrator_whenLegacyKeyReadFails_thenErrorIsNotTreatedAsMissingKey +fearlessTests/UserStorageCompatibilityMigrationTests/testKeystoreMigrator_whenReplacementIdentifierContainsDifferentKey_thenRefusesToOverwriteIt +fearlessTests/UserStorageCompatibilityMigrationTests/testKeystoreMigrator_whenJournalDeletionFails_thenRecoveryCanRepeatWithoutDeletingNewKey +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenDestinationKeyIsMissing_thenRetainsLegacyKeyAndJournal +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenDestinationKeyHasDrifted_thenRetainsLegacyKeyAndJournal +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenDestinationDigestIsTampered_thenRetainsAllKeysAndJournal +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenDeletionListContainsReservedJournalIdentifier_thenFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenDeletionListContainsDestinationIdentifier_thenFailsClosed +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenDeletionListContainsPincode_thenFailsClosedWithoutDeletingIt +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenDeletionListContainsUnrelatedAppKey_thenFailsClosedWithoutDeletingIt +fearlessTests/UserStorageCompatibilityMigrationTests/testCleanupRecovery_whenRollbackStagesPincodeWithMatchingProof_thenFailsClosedWithoutDeletingIt +fearlessTests/UserStorageCompatibilityMigrationTests/testMetaAccountMapper_whenMigratedRecordHasOnlyTonFields_thenThrowsRecoverableError +fearlessTests/UserStorageCompatibilityMigrationTests/testMetaAccountMapper_whenEvmAccount_thenWritesCanonicalIdentifierAndReadsCanonicalAndLegacyAliases +fearlessTests/SubstrateStorageClassResolutionTests/testBundledV8Model_whenLoaded_thenEveryEntityResolvesToExactRuntimeClass +fearlessTests/SubstrateStorageClassResolutionTests/testBundledV8Model_whenObjectsInsertedAndFetched_thenUsesExactRuntimeClasses +fearlessTests/SubstrateStorageClassResolutionTests/testRuntimeMetadata_whenPersisted_thenCodableMapperRoundTripsBoundaryVersions +fearlessTests/SubstrateStorageClassResolutionTests/testRuntimeMetadataStartupMapper_whenGetterRaises_thenReturnsSanitizedSwiftError +fearlessTests/SubstrateStorageClassResolutionTests/testRuntimeMetadataStartupMapper_whenSetterRaises_thenReturnsSanitizedSwiftError +fearlessTests/SubstrateStorageClassResolutionTests/testFallbackCodableEntities_whenPersisted_thenTypedAccessorsAndMappersRoundTrip +fearlessTests/SubstrateStorageClassResolutionTests/testFallbackCodableEntities_whenRequiredFieldsAreMissing_thenMappersRejectRows +fearlessTests/SubstrateStorageClassResolutionTests/testBundledV8Model_whenStoreCreated_thenSchemaFingerprintsAndCompatibilityStayCanonical +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenStoreDoesNotExist_thenDoesNotCreateOrModifyAnything +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenStoreIsCurrent_thenRepeatedCallsAreByteForByteIdempotent +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentStoreHasOversizedRawArchive_thenRepairsPrivateCopyAtomicallyAndPreservesProtectedGraph +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentStoreHasDecodedWrongTypeArchive_thenRepairsPrivateCopyAndPreservesOtherValues +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCleanCurrentStartupGraphIsExactlyAtEveryRelationshipLimit_thenAuditsWithoutHookReplacementOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCleanCurrentStartupRootsAreExactlyAtRowLimits_thenAuditsWithoutHookReplacementOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCleanCurrentRuntimeRootExceedsRowLimit_thenRejectsBeforeHookReplacementOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCleanCurrentRootPayloadIsExactlyAtByteLimit_thenAuditsWithoutHookReplacementOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCleanCurrentRootPayloadExceedsByteLimit_thenRejectsBeforeHookReplacementOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentPriceStringIsExactlyAtStartupChildValueLimit_thenAuditsWithoutMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentPriceStringExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentAssetNameExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentCustomNodeNameExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentExplorerURLExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentXcmConfigVersionExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentXcmDestinationChainIdExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentXcmAssetIdentifierExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentPriceProviderIdentifierExceedsStartupChildValueLimit_thenRejectsBeforeCoreDataOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentChildPayloadAggregateIsExactlyAtLimit_thenAuditsWithoutMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentChildPayloadAggregateExceedsLimitByOne_thenRejectsBeforeCoreDataOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCleanCurrentNodesExceedRelationshipLimit_thenRejectsWhileFaultedBeforeHookReplacementOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCleanCurrentPriceDataExceedsRelationshipLimit_thenRejectsWhileFaultedBeforeHookReplacementOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCleanCurrentXcmRelationshipsExceedAggregateLimit_thenRejectsBeforeHookReplacementOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenRepairedCurrentStageIntroducesOversizedPriceDataRelationship_thenRejectsBeforeReplacement +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenCurrentStoreHasLargeSharedMemorySidecar_thenUsesOneDisposableCopyAndCleansIt +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenSourceFamilyExceedsPrivateCopyLimit_thenRejectsBeforeCapacityInspectionOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenPrivateCopyCapacityIsInsufficient_thenRejectsBeforeCopyOrMutation +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenStoreIsCorrupt_thenThrowsAndPreservesEveryStoreFile +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenStoreIsCorrupt_thenFailsClosedAndPreservesEverySidecar +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenStoreVersionIsUnknown_thenThrowsAndPreservesEveryStoreFile +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenStoreVersionIsUnknown_thenFailsClosedAndPreservesEveryStoreFile +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenKnownStoreCannotBeInspected_thenFailsClosedAndPreservesEveryStoreFile +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenTargetModelIsMissing_thenThrowsBeforeCheckpointAndPreservesSource +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenAskedToDowngrade_thenThrowsBeforeCheckpointAndPreservesSource +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenVersion7Store_thenStagesValidVersion8AndPreservesRows +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenEverySupportedLegacyVersion_thenReachesV8AndPreservesRows +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenOldestLegacyStore_thenNeverRetainsCompletedIntermediates +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenTemporaryInputCleanupFails_thenAbortsAndCleansEveryPrivateStore +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenVersion1ChainHasNoSelectedNode_thenSelectsStableNode +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenVersion3ContainsChainGraph_thenUsesCustomV4Policy +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenV3ChainOptionsArchiveIsRawGarbage_thenDefaultsOnlyThatCache +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenV3ExternalTypesArchiveIsEmpty_thenDefaultsOnlyThatCache +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenV3PurchaseProvidersArchiveIsTruncated_thenV4PolicyStillPreservesGraph +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenV4AssetPurchaseProvidersArchiveIsRawGarbage_thenDefaultsOnlyAssetCache +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenBothV3PolkaswapArchivesHaveWrongTypes_thenDefaultsBothRequiredArrays +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenV4LegacyXcmArchiveContainsDisallowedClass_thenDefaultsConfigAndPreservesDestination +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenV3LegacyDestinationAssetsArchiveIsInvalid_thenDefaultsDestinationAndPreservesConfig +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenAllV3TransformableArchivesAreValid_thenPreservesEveryValueAndProtectedRelationship +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenEveryV3TransformableArchiveIsDamagedTogether_thenRepairsEveryKeyAndPreservesProtectedGraph +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenTransformableElementCountIsExactlyAtLimit_thenPreservesArray +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenTransformableElementCountExceedsLimit_thenRepairsArray +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenTransformableUTF8BytesAreExactlyAtLimit_thenPreservesArray +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenTransformableUTF8BytesExceedLimit_thenRepairsArray +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenRawTransformableArchiveIsExactlyAtLimit_thenPreservesArray +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenRawTransformableArchiveExceedsLimit_thenRepairsBeforeCoreDataDecode +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenOptionalTransformableUsesWrongSQLiteStorageClass_thenRepairsBeforeDecode +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenRequiredTransformableUsesWrongSQLiteStorageClass_thenWritesValidEmptyArchive +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigrationWithRecovery_whenTransformableEntityExceedsRowCap_thenRejectsBeforePagingReplacementOrQuarantine +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenBatchRepairsResetContext_thenImmutableIDCohortRepairsEveryRowExactlyOnce +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenFinalReplacementFails_thenSourceFamilyAndRelationshipsRemainExact +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenProcessDiesAfterRemovingLiveMainStore_thenRelaunchRestoresAndMigratesProtectedGraph +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenStagedProtectedValuesAndSelectedNodeAreSwappedWithoutRowLoss_thenRejectsStageAndPreservesSource +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenProtectedEntityExceedsRowLimit_thenFailsClosedBeforeMigration +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenProtectedEntitiesExceedTotalRowLimit_thenFailsClosedBeforePaging +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenChainRelationshipExceedsMemberLimit_thenFailsClosedBeforeDigestingTopology +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenNoInverseRelationshipExceedsMemberLimit_thenRejectsWhileRelationshipRemainsFaulted +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenAggregateRelationshipLimitIsExceeded_thenRejectsBeforeEitherRelationshipMaterializes +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenProtectedValueExceedsByteLimit_thenFailsClosedWithoutReplacingStore +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenBoundedRelationshipMemberExceedsByteLimit_thenFailsBeforeReplacement +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenProtectedRowsSpanSingleItemPages_thenDigestPreservesEveryRecord +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenLegacyAssetHasNoSymbolAndWrapperHasNoAsset_thenPreservesGraph +fearlessTests/SubstrateStorageMigrationSafetyTests/testChainV4Policy_whenSourceAssetHasNoDestinationAssociation_thenMigrationFails +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenVersion3ContainsOrphanAsset_thenPreservesItUnattached +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenRequiredCustomMappingIsMissing_thenThrowsBeforeCheckpoint +fearlessTests/SubstrateStorageMigrationSafetyTests/testBundledRequiredCustomMappings_matchCurrentModelsAndPolicies +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenKnownStoreHasZeroProtectedFootprint_thenQuarantinesOnlySubstrateFamily +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenCheckpointFailsWithZeroProtectedData_thenQuarantinesExactSourceFamily +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenCheckpointFailsWithProtectedData_thenBlocksRecoveryAndPreservesSource +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenCheckpointFails_thenFinalRecoveryInspectionNeverCheckpointsAgain +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenInterruptedAtEveryDurableBoundary_thenRelaunchConvergesExactly +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenPreparationIsMarkerlessOrOnlyPending_thenRelaunchCleansItWithoutMovingLiveFamily +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigrationWithRecovery_whenCacheQuarantineLostMainStore_thenReconcilesBeforeLiveStoreSafetyCheck +fearlessTests/SubstrateStorageMigrationSafetyTests/testPerformMigration_whenDeployedLegacyRecoveryMovedRealSQLiteMain_thenRestoresBeforeStoreSafetyAndPreservesRowsAndWAL +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenActiveTreeContainsUnknownFile_thenFailsClosedWithoutMovingFamily +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenLiveFamilyChangesAfterMarker_thenFailsClosedWithoutMovingAnything +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenMovedMemberChanges_thenFailsClosedAndKeepsDurableMarker +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenSourceContainsSymlinkOrHardlink_thenRejectsBeforeCreatingMarker +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenMarkerIsNoncanonicalOrOversized_thenFailsClosedAndPreservesLiveFamily +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenLegacyMarkerlessMoveStoppedAtEveryBoundary_thenAdoptsDurablyAndConverges +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenLegacyAdoptionMarkerWriteWasInterrupted_thenRemovesOnlyPendingMarkerAndConverges +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenLegacyRestorationIsInterruptedAtEveryDurableBoundary_thenRelaunchConverges +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenLegacyTemporaryFileSynchronizationFails_thenRelaunchResynchronizesBeforeInstall +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenFinalQuarantineDirectorySynchronizationFails_thenRetryResynchronizesBothDirectoriesBeforeCommit +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenFinalLegacyRestoreDirectorySynchronizationFails_thenRetryResynchronizesBothDirectoriesBeforeCommit +fearlessTests/SubstrateStorageMigrationSafetyTests/testRequiresMigration_whenCacheRecoveryMarkerIsPendingBeforeFirstMove_thenReturnsTrueForCurrentStore +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenCompletedLegacyArchiveExistsBesideRebuiltLiveStore_thenLeavesBothUntouched +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryRetention_whenQuarantineCompletes_thenExcludesRootAndArchiveFromBackup +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryRetention_whenBackupExclusionFails_thenPreservesLiveFamilyBeforeMarker +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryRetention_whenCountLimitExceeded_thenDeletesOnlyOldestCompleteFamily +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryRetention_whenByteBudgetCannotHoldArchive_thenDeletesWholeFamilyAndPreservesLiveStore +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryRetention_whenAnyArchiveTreeIsUnrecognized_thenFailsClosedBeforeDeletingValidArchive +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryRetention_whenArchiveMemberHardlinksLiveStore_thenFailsClosedWithoutUnlinkingEitherPath +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryRetention_whenDeletionIsInterruptedAtEveryDurableBoundary_thenRelaunchConvergesWithoutTouchingNewestOrLiveFamily +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenLegacySplitHasMultipleCandidates_thenFailsClosedWithoutChoosingArchive +fearlessTests/SubstrateStorageMigrationSafetyTests/testCacheRecoveryTransaction_whenLegacySplitIsTamperedOrOverlapping_thenFailsClosed +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenKnownStoreHasContact_thenBlocksRecovery +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenKnownStoreHasContactItem_thenBlocksRecovery +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenKnownStoreHasTransactionHistory_thenBlocksRecovery +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenKnownStoreHasCustomNode_thenBlocksRecovery +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenKnownStoreHasSelectedDefaultNode_thenBlocksRecovery +fearlessTests/SubstrateStorageMigrationSafetyTests/testSyncMigration_whenKnownStoreHasOrphanNode_thenBlocksRecovery +fearlessTests/SubstrateStorageMigrationSafetyTests/testCallbackMigration_whenStoreIsCorrupt_thenDoesNotCompleteOrQuarantine +fearlessTests/TransformableArchiveSafetyTests/testObjectiveCExceptionBoundaryReturnsOnlySanitizedError +fearlessTests/TransformableArchiveSafetyTests/testObjectiveCExceptionBoundaryAllowsSuccessfulVoidOperation +fearlessTests/TransformableArchiveSafetyTests/testPersistentCorruptFavouriteChainIdsDefaultsOnlyPreferenceWithoutMutation +fearlessTests/TransformableArchiveSafetyTests/testPersistentCorruptAssetKeysOrderDefaultsOnlyPreferenceWithoutMutation +fearlessTests/TransformableArchiveSafetyTests/testPersistentCorruptUnusedChainIdsDefaultsOnlyPreferenceWithoutMutation +fearlessTests/TransformableArchiveSafetyTests/testPersistentWrongStoredTypeDefaultsOnlyPreferenceWithoutMutation +fearlessTests/TransformableArchiveSafetyTests/testPersistentValidWalletArchivesPreserveEveryPreference +fearlessTests/TransformableArchiveSafetyTests/testPersistentCorruptChainOptionsDefaultsWithoutMutatingCache +fearlessTests/TransformableArchiveSafetyTests/testPersistentCorruptExternalApiTypesSkipsOnlyExplorerWithoutMutatingCache +fearlessTests/TransformableArchiveSafetyTests/testPersistentCorruptAssetPurchaseProvidersDefaultsWithoutMutatingCache +fearlessTests/TransformableArchiveSafetyTests/testPersistentCorruptPolkaswapTransformablesSurfaceCatchableErrorWithoutMutation +fearlessTests/TransformableArchiveSafetyTests/testProductionRuntimeRegistryRetainsEveryCurrentStoreClass +fearlessTests/MetaAccountMapperTests/testTransformConvertsMandatoryGetterExceptionToSanitizedSwiftError +fearlessTests/MetaAccountMapperTests/testMalformedChildRelationshipFailsClosedThroughDirectAndSelectionMappers +fearlessTests/MetaAccountMapperTests/testSelectionStartupWrapperQuarantinesOwnIdentifierGetterException +fearlessTests/MetaAccountMapperTests/testSaveAndFetch +fearlessTests/MetaAccountMapperTests/testCanonicalEcdsaSubstratePublicKeyIsAccepted +fearlessTests/MetaAccountMapperTests/testNonPersistableNilRequiredFieldsAreQuarantinedByMappersWithoutSaving +fearlessTests/MetaAccountMapperTests/testRepositorySliceDecoderAcceptsExactShapeAndFailsClosedOtherwise +fearlessTests/SelectedAccountSettingsTests/testSelectFirst +fearlessTests/SelectedAccountSettingsTests/testChangeSelectedAccount +fearlessTests/SelectedAccountSettingsTests/testSetupWhenWalletsExistWithoutSelectionRepairsDeterministicFallback +fearlessTests/SelectedAccountSettingsTests/testSetupToleratesTonOnlyRowAlongsideSelectedValidWalletWithoutChangingEitherPayload +fearlessTests/SelectedAccountSettingsTests/testSetupWithOnlyTonOnlyWalletReportsUnsupportedWithoutMutatingRow +fearlessTests/SelectedAccountSettingsTests/testStartupQuarantinesMixedCorruptSupportedRowsAndPreservesEveryStoredField +fearlessTests/SelectedAccountSettingsTests/testCorruptOnlyStoreReportsUnavailableAndPreservesEveryStoredField +fearlessTests/SelectedAccountSettingsTests/testStructurallyValidUnsupportedWalletKeepsUnsupportedOnlyWithCorruptSibling +fearlessTests/SelectedAccountSettingsTests/testSetupReplacesSelectedTonOnlyRowWithDeterministicValidFallbackAndPreservesPayloads +fearlessTests/SelectedAccountSettingsTests/testSaveAfterUnsupportedOnlyAddsValidWalletWithoutOverwritingTonPayload +fearlessTests/SelectedAccountSettingsTests/testSaveRejectsIdentifierCollisionWithUnsupportedWalletWithoutMutatingStore +fearlessTests/SelectedAccountSettingsTests/testAccountRepositoryDeleteAllRemovesSupportedAndUnsupportedWalletsForLogout +fearlessTests/SelectedAccountSettingsTests/testFilteredAccountRepositoryDeleteAllRemainsScopedAndIncludesUnsupportedMatches +fearlessTests/SelectedAccountSettingsTests/testAccountRepositoriesProjectMixedStoreBeforePagingAndSupportAsyncReads +fearlessTests/SelectedAccountSettingsTests/testRepositoryPagingSlicesHealthyProjectionAcrossPersistedCorruptRows +fearlessTests/SelectedAccountSettingsTests/testAccountRepositoryUpdatePreservesUnsupportedPayloadAndWalletMetadata +fearlessTests/SelectedAccountSettingsTests/testAccountRepositoryReplacePreservesUnsupportedRowsAndDeletesOnlySupportedRows +fearlessTests/SelectedAccountSettingsTests/testAccountRepositoryRejectsUnsupportedIdentifierCollisionWithoutMutation +fearlessTests/SelectedAccountSettingsTests/testManagedMapperFailsSafelyWhenWalletOrderHasReachedInt32Max +fearlessTests/SelectedAccountSettingsTests/testSelectionMapperFailsSafelyWhenUnsupportedWalletOrderHasReachedInt32Max +fearlessTests/SelectedAccountSettingsTests/testOutOfOrderSetupCannotOverwriteLatestValueStateOrPersistStaleRepair +fearlessTests/SelectedAccountSettingsTests/testSetupGenerationCannotChangeInsideAtomicValueAndStateCommit +fearlessTests/SelectedAccountSettingsTests/testConcurrentSavesAreSerializedAndOlderFailureCannotRollbackLatestSelection +fearlessTests/SelectedAccountSettingsTests/testSaveInvalidatesOlderSetupBeforeItCanCommitOrRepairSelection +fearlessTests/SelectedAccountSettingsTests/testSetupStartedDuringSaveWaitsForPersistenceAndCannotReadStaleSelection +fearlessTests/SelectedAccountSettingsTests/testSaveRegistrationIsAtomicAgainstSetupAtPreparationBoundary +fearlessTests/SelectedAccountSettingsTests/testSetupValueAndStoreStateCommitAtomicallyAgainstSaveRegistration +fearlessTests/SelectedAccountSettingsTests/testTolerantFactoriesAndStreamsIgnoreCorruptSelectedSiblingAndKeepObservingValidWallet +fearlessTests/SelectedAccountSettingsTests/testRepositorySaveRejectsEquivalentChainAccountAliasesBeforeMutatingStoredWallet +fearlessTests/SelectedAccountSettingsTests/testDeleteAndReplaceRejectDuplicateStoredIdentifiersInBothInsertionOrdersWithoutMutation +fearlessTests/SelectedAccountSettingsTests/testPersistedDuplicateAndUniversalAliasChainAccountsAreAlwaysQuarantinedWithoutMutation +fearlessTests/RootTests/testWalletConnectGroupResolverUsesProductionEntitlementForReleaseBundle +fearlessTests/RootTests/testWalletConnectGroupResolverUsesDevelopmentEntitlementForDevBundle +fearlessTests/RootTests/testWalletConnectGroupResolverRejectsUnsupportedApplicationIdentities +fearlessTests/RootTests/testHostedUnitTestsUseIsolatedApplicationLaunch +fearlessTests/RootTests/testCoreDataPreflightForwardsStoreOpenError +fearlessTests/RootTests/testCoreDataPreflightRejectsUnresolvableEntityClassBeforeFetch +fearlessTests/RootTests/testCoreDataPreflightQueriesObjectIdsWithoutDecodingCorruptTransformables +fearlessTests/RootTests/testUserStorageFacadeMissingModelReturnsControlledFailure +fearlessTests/RootTests/testSubstrateStorageFacadeMissingModelFailsPreflightWithoutTrap +fearlessTests/RootTests/testStartViewHelperDoesNotResolveWalletSettingsDuringConstruction +fearlessTests/RootTests/testMigrationFailureDoesNotResolveStorePreflightRegistryOrWalletSettings +fearlessTests/RootTests/testMigrationFailureBlocksNoMigrationBypassAndRequiredRetryRerunsMigration +fearlessTests/RootTests/testMigrationDeadlineFailsClosedAndRetriesReuseSingleRunningAttempt +fearlessTests/RootTests/testPreflightFailureDoesNotResolveRegistryOrWalletSettings +fearlessTests/RootTests/testWalletFailureRetryDoesNotRerunMigrationsAgainstResolvedStores +fearlessTests/RootTests/testMigrationFailureDoesNotLoadWalletOrRouteAndPreservesPincode +fearlessTests/RootTests/testSubstratePreflightFailureDoesNotCreateRegistryOrOpenWalletAndPreservesData +fearlessTests/RootTests/testWalletRepositoryFailureDoesNotBootOrRouteAndPreservesPincode +fearlessTests/RootTests/testOutOfOrderDualSetupRejectsStaleCallbackBeforeBootOrPresenterMutation +fearlessTests/RootTests/testPreflightTimeoutIgnoresLateResultAndRetryUsesFreshAttempt +fearlessTests/RootTests/testSynchronouslyBlockedPreflightTimesOutAndDoesNotBlockRetry +fearlessTests/RootTests/testTwoBlockedPreflightsFailFurtherRetriesFastWithoutUnboundedInvocation +fearlessTests/RootTests/testSynchronouslyBlockedPreflightDoesNotRetainInteractorAfterDeinit +fearlessTests/RootTests/testTwoSynchronouslyBlockedPreflightsDoNotRetainInteractorAfterDeinit +fearlessTests/RootTests/testWalletSetupTimeoutIgnoresLateResultAndRetryUsesFreshAttempt +fearlessTests/RootTests/testSubstratePreflightFailureCanRetryWithoutRemigrationOrPrematureBoot +fearlessTests/RootTests/testAdversarialPreflightMultipleCallbacksCanOnlyOpenWalletAndBootOnce +fearlessTests/RootTests/testOnlyTonWalletAllowsLoginWithoutPincodeButFailsClosedAndPreservesRowWithPincode +fearlessTests/RootTests/testMigrationThenRealSubstrateOpenThenWalletOpenThenBootRoutesSelectedWalletToPin +fearlessTests/RootTests/testLateOnboardingResultAfterTimeoutCannotReplaceLogin +fearlessTests/RootTests/testProtectedDataFailureIsVisibleAndNeverBypassesAuthentication +fearlessTests/RootTests/testUnselectedWalletIsRecoveredWithoutDeletingPincodeOrBypassingAuthentication +fearlessTests/RootTests/testConfirmedEmptyWalletStoreReturnsLoginAndDeletesPincode +fearlessTests/RootTests/testConfirmedEmptyWalletStoreFailsClosedWhenPincodeDeletionFails +fearlessTests/RootTests/testOnboardingDecision +fearlessTests/RootTests/testPincodeSetupDecision +fearlessTests/RootTests/testMainScreenDecision +fearlessTests/ChainModelMapperTests/testStartupWrapperConvertsMandatoryGetterExceptionToSanitizedSwiftError +fearlessTests/ChainModelMapperTests/testThrowingNodeRelationshipFailsClosedAsSwiftError +fearlessTests/ChainModelMapperTests/testSaveAndFetchPreservesParaIdAndIdentityChain +fearlessTests/ChainModelMapperTests/testTransformQuarantinesChainWithoutIdentifier +fearlessTests/ChainModelMapperTests/testTransformQuarantinesNoncanonicalIdentifierUntilCleanup +fearlessTests/ChainModelMapperTests/testTransformQuarantinesNameButKeepsIdentifierAndPreferences +fearlessTests/ChainModelMapperTests/testTransformSkipsDefaultNodeWithoutURL +fearlessTests/ChainModelMapperTests/testTransformSkipsSelectedNodeWithoutName +fearlessTests/ChainModelMapperTests/testTransformSkipsSelectedNodeWithUnusableURL +fearlessTests/ChainModelMapperTests/testTransformAcceptsSubstrateWebSocketNodeURLs +fearlessTests/ChainModelMapperTests/testTransformKeepsCompatibleCustomNodeAsOnlyRuntimeEndpoint +fearlessTests/ChainModelMapperTests/testTransformDisablesChainWithOnlyIncompatibleCustomNode +fearlessTests/ChainModelMapperTests/testTransformRejectsHTTPNodesForSubstrateRuntime +fearlessTests/ChainModelMapperTests/testTransformAcceptsOnlySecureEthereumRuntimeSchemes +fearlessTests/ChainModelMapperTests/testTransformAppliesStrictTonServerShape +fearlessTests/ChainModelMapperTests/testTransformKeepsValidNodesWhileSkippingMalformedOnes +fearlessTests/ChainModelMapperTests/testPopulateRoundTripPreservesValidStandaloneSelectedNode +fearlessTests/ChainModelMapperTests/testTransformDropsUnsupportedStandaloneSelectionButKeepsHealthyChain +fearlessTests/ChainModelMapperTests/testTransformSkipsMalformedCachedAsset +fearlessTests/ChainModelMapperTests/testTransformIgnoresRelationshipWithOnlyMalformedPrices +fearlessTests/ChainModelMapperTests/testCachedPriceExtractionRejectsUnexpectedEntityBeforeReadingUndefinedKeys +fearlessTests/ChainModelMapperTests/testCachedPriceExtractionSkipsRowWhenAttributeReadRaisesException +fearlessTests/ChainModelMapperTests/testCachedPriceExtractionPreservesLegacyDecimalWithoutOptionalFields +fearlessTests/ChainModelMapperTests/testTransformUsesSingleValidUnmatchedCachedPrice +fearlessTests/ChainModelMapperTests/testTransformDeterministicallyChoosesCanonicalUnmatchedCachedPrice +fearlessTests/ChainModelMapperTests/testTransformUsesValidCachedPriceAmongMalformedRows +fearlessTests/ChainModelMapperTests/testTransformRejectsMalformedNonfiniteAndNegativeCachedPrices +fearlessTests/ChainModelMapperTests/testTransformPreservesSupportedCachedPriceStringFormats +fearlessTests/ChainModelMapperTests/testPopulateDeletesMalformedStaleNodesInsteadOfForceUnwrapping +fearlessTests/ChainModelMapperTests/testMalformedChainCleanup_whenGetterRaisesDuringQuarantine_thenFailsSafelyAndRollsBack +fearlessTests/ChainModelMapperTests/testMalformedChainCleanupQuarantinesBlankIdentifiersWithoutDataLoss +fearlessTests/ChainModelMapperTests/testMalformedChainQuarantineCannotCollideWithStoredIdentifier +fearlessTests/ChainModelMapperTests/testCleanupCanonicalizesIdentifiersAndMergesPreferencesWithoutLoss +fearlessTests/ChainModelMapperTests/testCleanupCollisionPreservesCustomSelectionWhenDefaultRetires +fearlessTests/ChainModelMapperTests/testCleanupQuarantinesConflictingCollisionWithoutDeletingItsData +fearlessTests/ChainSyncServiceCompatibilityTests/testCoerceChainsPayloadForCompatibilityNormalizesBlockscoutTypes +fearlessTests/ChainSyncServiceCompatibilityTests/testPreservingLocalNodePreferencesKeepsCustomAndSelectedNodes +fearlessTests/ChainSyncServiceCompatibilityTests/testPreservingLocalNodePreferencesDoesNotApplyPreferencesToAnotherChain +fearlessTests/ChainSyncServiceCompatibilityTests/testPreservingLocalNodePreferencesRejectsRemoteCustomNodeInjection +fearlessTests/ChainSyncServiceCompatibilityTests/testPreservingLocalNodePreferencesDropsRetiredDefaultSelection +fearlessTests/ChainSyncServiceCompatibilityTests/testPreservingLocalNodePreferencesRefreshesSelectedDefaultByURL +fearlessTests/ChainSyncServiceCompatibilityTests/testRepositoryWriteFailureEmitsFailureWithoutFalseCompletion +fearlessTests/ChainSyncServiceCompatibilityTests/testRepositoryFetchFailureDoesNotWriteOrReplaceCache +fearlessTests/ChainSyncServiceCompatibilityTests/testEmptyRemotePayloadNeverDeletesReadableCache +fearlessTests/ChainSyncServiceCompatibilityTests/testActiveRemoteChainWithOnlyUnusableNodesPreservesWorkingCache +fearlessTests/ChainSyncServiceCompatibilityTests/testMixedRemoteNodesPersistOnlyUsableUniqueEndpoints +fearlessTests/ChainSyncServiceCompatibilityTests/testPartialRemotePayloadDisablesOmittedChainWithoutDeletingPreferences +fearlessTests/ChainSyncServiceCompatibilityTests/testReappearingRemoteChainRestoresDisabledPreferences +fearlessTests/ChainSyncServiceCompatibilityTests/testQuarantinedLocalChainDoesNotDiscardHealthyNodePreferences +fearlessTests/ChainSyncServiceCompatibilityTests/testMalformedChainCleanupFailurePreventsRepositoryMutation +fearlessTests/ChainSyncServiceCompatibilityTests/testConcurrentSyncRequestsStartSingleDeterministicPipeline +fearlessTests/ChainSyncServiceCompatibilityTests/testCooldownExpiryDoesNotReleaseBlockedPipeline +fearlessTests/ChainSyncServiceCompatibilityTests/testSuccessBeforeTimerStartRetainsCooldownUntilExpiry +fearlessTests/ChainSyncServiceCompatibilityTests/testSuccessDuringCooldownRemainsBlockedUntilExpiry +fearlessTests/ChainSyncServiceCompatibilityTests/testFailureBeforeTimerStartInvalidatesOnlyFailedReservation +fearlessTests/ChainSyncServiceCompatibilityTests/testFailureDuringCooldownStopsOldTimerAndAllowsOneReplacement +fearlessTests/ChainSyncServiceCompatibilityTests/testFailureAfterCooldownExpiryAllowsReplacementWithoutOverlap +fearlessTests/ChainSyncServiceCompatibilityTests/testStaleStopCallbackCannotClearNewerCooldown +fearlessTests/ChainSyncServiceCompatibilityTests/testSanitizerRejectsDuplicateRemoteIdentifiers +fearlessTests/ChainSyncServiceCompatibilityTests/testSanitizerRejectsBlankNoncanonicalAndReservedIdentifiers +fearlessTests/ChainSyncServiceCompatibilityTests/testSanitizerRejectsBlankRemoteName +fearlessTests/ChainSyncServiceCompatibilityTests/testSanitizerAllowsDisabledChainWithoutNodes +fearlessTests/ChainSyncServiceCompatibilityTests/testSanitizerDeterministicallyDeduplicatesNodeCredentialMetadata +fearlessTests/ChainSyncServiceCompatibilityTests/testSanitizerRejectsEthereumChainWithOnlyIncompatibleSchemes +fearlessTests/ChainSyncServiceCompatibilityTests/testSanitizerKeepsOnlyRuntimeCompatibleEthereumNodes +fearlessTests/ChainSyncServiceCompatibilityTests/testPreservingPreferencesDropsRuntimeIncompatibleCustomSelection +fearlessTests/ChainSyncServiceCompatibilityTests/testSanitizerStripsRemotePreferencesForBrandNewChain +fearlessTests/ChainRegistryTests/testDisabledThenReenabledChainDisconnectsAndUsesNewNode +fearlessTests/ChainRegistryTests/testUpdatedEthereumChainUsesReplacementNodeImmediately +fearlessTests/ConnectionPoolTests/testSetupCreatesNewConnections +fearlessTests/ConnectionPoolTests/testEthereumConnectionPoolResetRemovesConnectionForChainId +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testReplaceStore_whenMainFileExceedsLimit_rejectsBeforeCapacityOrMutation +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testReplaceStore_whenAggregateFamilyExceedsLimit_rejectsBeforeMutation +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testReplaceStore_whenCapacityIsOneByteShort_rejectsBeforeTransactionMutation +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testReplaceStore_whenFamilyAndCapacityAreExactBoundaries_succeeds +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testReplaceStore_whenCapacityRequirementOverflows_rejectsBeforeMutation +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testCommittedRecovery_whenValidationCopyLacksSpace_preservesTransactionForRetry +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testPrivateCopy_whenSparseSourceExceedsLimit_rejectsBeforeCapacityOrCopy +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testPrivateCopy_whenCapacityIsInsufficient_rejectsBeforeFirstMember +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testPrivateCopy_whenSourceMainIsSymlink_rejectsWithoutFollowingIt +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testPrivateCopy_whenDestinationHasOrphanSidecar_rejectsBeforeMainCopy +fearlessTests/CrashConsistentStoreReplacerResourceLimitTests/testPrivateCopy_atExactAggregateAndCapacityBoundary_copiesDurableMembersButNotSharedMemory diff --git a/scripts/ci/run-coredata-release-gate.sh b/scripts/ci/run-coredata-release-gate.sh new file mode 100644 index 0000000000..193f54ec2f --- /dev/null +++ b/scripts/ci/run-coredata-release-gate.sh @@ -0,0 +1,754 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Runs the migration/startup Core Data unit-test gate with Release optimization. +# +# The normal stage deliberately excludes the two copied-phone fixture tests. Run +# those separately with: +# +# FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE=/absolute/path/to/SubstrateDataModel.sqlite \ +# bash scripts/ci/run-coredata-release-gate.sh --stage copied-phone \ +# --simulator-udid +# +# This script never accepts a physical-device destination, never opens the source +# fixture itself, and keeps xcodebuild output in a private local log. + +umask 077 + +readonly LOG_PREFIX="[coredata-release-gate]" +readonly SCHEME="fearless.tests" +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +readonly MANIFEST_DIR="$SCRIPT_DIR/manifests" +readonly CDMETAACCOUNT_CODABLE_AUDIT="$SCRIPT_DIR/../storage/audit-cdmetaaccount-codable-contract.sh" +readonly UUID_PATTERN='^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$' +readonly SIMULATOR_DESTINATION_PATTERN='^platform=iOS Simulator,id=([0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12})(,arch=(arm64|x86_64))?$' +SIMULATOR_INVENTORY_FILE="" + +log() { + printf '%s %s\n' "$LOG_PREFIX" "$*" +} + +fail() { + printf '%s ERROR: %s\n' "$LOG_PREFIX" "$*" >&2 + exit 1 +} + +readonly CORE_DATA_TEST_HARNESS="${FEARLESS_CORE_DATA_TEST_HARNESS:-0}" +if [[ "$CORE_DATA_TEST_HARNESS" != "1" ]]; then + for override_name in \ + FEARLESS_CORE_DATA_ROOT_DIR \ + FEARLESS_CORE_DATA_WORKSPACE \ + FEARLESS_CORE_DATA_XCODEBUILD_BIN \ + FEARLESS_CORE_DATA_XCRUN_BIN \ + FEARLESS_CORE_DATA_PYTHON_BIN \ + FEARLESS_CORE_DATA_SHASUM_BIN; do + [[ -z "${!override_name:-}" ]] || + fail "$override_name is accepted only with FEARLESS_CORE_DATA_TEST_HARNESS=1" + done +fi + +cleanup() { + if [[ -n "${SIMULATOR_INVENTORY_FILE:-}" && -e "$SIMULATOR_INVENTORY_FILE" ]]; then + rm "$SIMULATOR_INVENTORY_FILE" + fi +} + +usage() { + cat <<'USAGE' +Usage: + bash scripts/ci/run-coredata-release-gate.sh [options] + +Options: + --stage core|copied-phone|all + Run the hermetic class gate (default), the two copied-phone tests, or both. + --simulator-udid UUID + Use an available iPhone simulator. If omitted, exactly one booted, + available iPhone simulator must be discoverable. + --destination DESTINATION + Accepted only in the exact form "platform=iOS Simulator,id=UUID", with an + optional ",arch=arm64" or ",arch=x86_64". Physical/generic destinations + are refused. + --fixture ABSOLUTE_SQLITE_PATH + Source fixture for --stage copied-phone/all. The environment variable + FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE is also accepted. + --output-dir DIRECTORY + New result/log directory. Defaults beneath build/test-results. + --derived-data DIRECTORY + DerivedData directory. Defaults beneath build. + --help + +Environment overrides intended for controlled CI/test harnesses: + FEARLESS_CORE_DATA_ROOT_DIR + FEARLESS_CORE_DATA_SOURCE_PACKAGES_DIR + FEARLESS_CORE_DATA_XCODEBUILD_BIN + FEARLESS_CORE_DATA_XCRUN_BIN + FEARLESS_CORE_DATA_PYTHON_BIN + FEARLESS_CORE_DATA_SHASUM_BIN +USAGE +} + +require_option_value() { + local option="$1" + local remaining="$2" + [[ "$remaining" -ge 2 ]] || fail "$option requires a value" +} + +require_executable() { + local executable="$1" + local label="$2" + + if [[ "$executable" == */* ]]; then + [[ -x "$executable" ]] || fail "$label is not executable" + else + command -v "$executable" >/dev/null 2>&1 || fail "$label is unavailable" + fi +} + +canonical_directory() { + local directory="$1" + (cd "$directory" && pwd -P) +} + +resolve_simulator_from_json() { + local mode="$1" + local requested_udid="${2:-}" + local json_file="$3" + + "$PYTHON_BIN" - "$mode" "$requested_udid" "$json_file" <<'PY' +import json +import re +import sys + +mode, requested, json_path = sys.argv[1:] +uuid_pattern = re.compile( + r"^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-" + r"[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$" +) + +try: + with open(json_path, "r", encoding="utf-8") as source: + payload = json.load(source) +except (OSError, json.JSONDecodeError): + print("simulator inventory was not valid JSON", file=sys.stderr) + sys.exit(2) + +runtime_devices = payload.get("devices") +if not isinstance(runtime_devices, dict): + print("simulator inventory did not contain a devices object", file=sys.stderr) + sys.exit(2) + +eligible = [] +for devices in runtime_devices.values(): + if not isinstance(devices, list): + continue + for device in devices: + if not isinstance(device, dict): + continue + udid = device.get("udid") + name = device.get("name") + is_available = device.get("isAvailable", True) + if ( + isinstance(udid, str) + and uuid_pattern.fullmatch(udid) + and isinstance(name, str) + and name.startswith("iPhone") + and is_available is True + ): + eligible.append(device) + +if mode == "explicit": + matches = [device for device in eligible if device.get("udid", "").lower() == requested.lower()] + if len(matches) != 1: + print("requested UDID is not one available iPhone simulator", file=sys.stderr) + sys.exit(3) + print(matches[0]["udid"]) + sys.exit(0) + +booted = [device for device in eligible if device.get("state") == "Booted"] +if len(booted) == 0: + print("no booted available iPhone simulator was found; pass --simulator-udid", file=sys.stderr) + sys.exit(4) +if len(booted) > 1: + print("multiple booted iPhone simulators were found; pass --simulator-udid", file=sys.stderr) + sys.exit(5) + +print(booted[0]["udid"]) +PY +} + +fixture_fingerprint() { + local fixture="$1" + local suffix + local candidate + local digest + + for suffix in "" "-wal" "-shm"; do + candidate="${fixture}${suffix}" + if [[ -e "$candidate" ]]; then + [[ -f "$candidate" && ! -L "$candidate" ]] || + fail "copied-phone fixture components must be regular, non-symlink files" + digest="$("$SHASUM_BIN" -a 256 "$candidate" | awk '{print $1}')" + [[ "$digest" =~ ^[0-9A-Fa-f]{64}$ ]] || + fail "unable to fingerprint copied-phone fixture safely" + printf '%s=%s\n' "$suffix" "$digest" + else + printf '%s=%s\n' "$suffix" "absent" + fi + done +} + +validate_result_summary() { + local result_bundle="$1" + local expected_total="$2" + local summary_file="$3" + + [[ -d "$result_bundle" && -f "$result_bundle/Info.plist" ]] || + fail "xcodebuild succeeded without a complete xcresult bundle" + + if ! "$XCRUN_BIN" xcresulttool get test-results summary \ + --path "$result_bundle" --compact >"$summary_file" 2>/dev/null; then + fail "xcresulttool could not read the test summary" + fi + + if ! "$PYTHON_BIN" - "$summary_file" "$expected_total" "$SIMULATOR_UDID" <<'PY' +import json +import sys + +summary_path, expected_total_text, expected_device_id = sys.argv[1:] + +def reject(message): + print(f"invalid xcresult summary: {message}", file=sys.stderr) + raise SystemExit(1) + +try: + with open(summary_path, "r", encoding="utf-8") as source: + summary = json.load(source) +except (OSError, json.JSONDecodeError): + reject("malformed or missing JSON") + +if not isinstance(summary, dict): + reject("root is not an object") + +def count(container, key): + value = container.get(key) + if type(value) is not int or value < 0: + reject(f"{key} is missing or is not a nonnegative integer") + return value + +if summary.get("result") != "Passed": + reject("result is not Passed") + +total = count(summary, "totalTestCount") +passed = count(summary, "passedTests") +failed = count(summary, "failedTests") +skipped = count(summary, "skippedTests") +expected = count(summary, "expectedFailures") + +if total <= 0: + reject("no tests executed") +if failed != 0: + reject("failedTests is not zero") +if skipped != 0: + reject("skippedTests is not zero") +if expected != 0: + reject("expectedFailures is not zero") +if passed != total: + reject("passedTests does not equal totalTestCount") + +failures = summary.get("testFailures") +if not isinstance(failures, list) or failures: + reject("testFailures is missing or nonempty") + +configurations = summary.get("devicesAndConfigurations") +if not isinstance(configurations, list) or not configurations: + reject("devicesAndConfigurations is missing or empty") + +configuration_passed = 0 +configuration_failed = 0 +configuration_skipped = 0 +configuration_expected = 0 +for configuration in configurations: + if not isinstance(configuration, dict): + reject("configuration entry is not an object") + device = configuration.get("device") + if not isinstance(device, dict): + reject("configuration device is missing") + if device.get("platform") != "iOS Simulator": + reject("a test destination was not iOS Simulator") + device_id = device.get("deviceId") + if not isinstance(device_id, str) or device_id.lower() != expected_device_id.lower(): + reject("test destination does not match the selected simulator") + configuration_passed += count(configuration, "passedTests") + configuration_failed += count(configuration, "failedTests") + configuration_skipped += count(configuration, "skippedTests") + configuration_expected += count(configuration, "expectedFailures") + +if configuration_passed != passed: + reject("configuration passed count disagrees with summary") +if configuration_failed != failed: + reject("configuration failed count disagrees with summary") +if configuration_skipped != skipped: + reject("configuration skipped count disagrees with summary") +if configuration_expected != expected: + reject("configuration expected-failure count disagrees with summary") + +if expected_total_text != "any": + try: + required_total = int(expected_total_text) + except ValueError: + reject("internal expected total is invalid") + if total != required_total: + reject(f"expected exactly {required_total} tests, found {total}") +PY + then + fail "test result did not satisfy the zero-failure/zero-skip Release contract" + fi +} + +validate_test_inventory() { + local result_bundle="$1" + local manifest="$2" + local tests_json="$3" + local executed_manifest="$4" + + [[ -f "$manifest" && ! -L "$manifest" ]] || + fail "expected test identity manifest is missing or unsafe" + + if ! "$XCRUN_BIN" xcresulttool get test-results tests \ + --path "$result_bundle" --compact >"$tests_json" 2>/dev/null; then + fail "xcresulttool could not read the executed test identities" + fi + + if ! "$PYTHON_BIN" - "$manifest" "$tests_json" "$executed_manifest" <<'PY' +import json +import re +import sys + +manifest_path, tests_path, output_path = sys.argv[1:] +identity_pattern = re.compile( + r"^fearlessTests/([A-Za-z_][A-Za-z0-9_]*)/(test[A-Za-z0-9_]+)$" +) + +def reject(message): + print(f"invalid xcresult test inventory: {message}", file=sys.stderr) + raise SystemExit(1) + +try: + with open(manifest_path, "r", encoding="utf-8") as source: + expected = [ + line.strip() + for line in source + if line.strip() and not line.lstrip().startswith("#") + ] +except OSError: + reject("expected manifest is unreadable") + +if not expected: + reject("expected manifest is empty") +if len(expected) != len(set(expected)): + reject("expected manifest contains duplicate identities") +for identity in expected: + if not identity_pattern.fullmatch(identity): + reject("expected manifest contains a noncanonical identity") + +try: + with open(tests_path, "r", encoding="utf-8") as source: + payload = json.load(source) +except (OSError, json.JSONDecodeError): + reject("test tree is malformed or missing") +if not isinstance(payload, (dict, list)): + reject("test tree root has an unexpected type") + +executed = [] +statuses = [] + +def canonical_direct(value): + if not isinstance(value, str): + return None + value = value.strip() + value = re.sub(r"\(\)$", "", value) + match = re.search( + r"(?:^|/)(fearlessTests/[A-Za-z_][A-Za-z0-9_]*/" + r"test[A-Za-z0-9_]+)$", + value, + ) + return match.group(1) if match else None + +def class_name(value): + if not isinstance(value, str): + return None + value = value.strip().rstrip("/") + value = value.split("/")[-1] + return value if re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*Tests", value) else None + +def method_name(value): + if not isinstance(value, str): + return None + value = re.sub(r"\(\)$", "", value.strip().split("/")[-1]) + return value if re.fullmatch(r"test[A-Za-z0-9_]+", value) else None + +def visit(node, ancestors): + if isinstance(node, list): + for child in node: + visit(child, ancestors) + return + if not isinstance(node, dict): + return + + identifiers = [ + node.get("nodeIdentifier"), + node.get("identifier"), + node.get("name"), + node.get("testName"), + ] + node_type = str(node.get("nodeType", node.get("type", ""))).lower() + direct = next( + (value for value in (canonical_direct(item) for item in identifiers) if value), + None, + ) + method = next( + (value for value in (method_name(item) for item in identifiers) if value), + None, + ) + is_test_case = ( + "test case" in node_type + or node_type in {"test", "testcase"} + or direct is not None + or method is not None + ) + if is_test_case: + identity = direct + if identity is None and method is not None: + test_class = next( + ( + value + for value in ( + class_name(item) + for ancestor in reversed(ancestors) + for item in ancestor + ) + if value + ), + None, + ) + if test_class is not None: + identity = f"fearlessTests/{test_class}/{method}" + if identity is None: + reject("a test case has no canonical XCTest identity") + status = node.get("result", node.get("testStatus", node.get("status"))) + if status != "Passed": + reject(f"{identity} did not have Passed status") + executed.append(identity) + statuses.append(status) + + next_ancestors = ancestors + [identifiers] + for value in node.values(): + if isinstance(value, (dict, list)): + visit(value, next_ancestors) + +visit(payload, []) + +if not executed: + reject("no test case identities were found") +if len(executed) != len(set(executed)): + reject("executed test tree contains duplicate identities") +if len(statuses) != len(executed): + reject("executed test status inventory is incomplete") + +expected_set = set(expected) +executed_set = set(executed) +if executed_set != expected_set: + missing = len(expected_set - executed_set) + unexpected = len(executed_set - expected_set) + reject( + f"exact identity set differs (missing={missing}, unexpected={unexpected})" + ) +if len(executed) != len(expected): + reject("executed identity cardinality differs from the expected manifest") + +with open(output_path + ".pending", "x", encoding="utf-8") as destination: + for identity in sorted(executed): + destination.write(identity + "\n") +import os +os.replace(output_path + ".pending", output_path) +PY + then + fail "executed tests did not match the exact reviewed identity manifest" + fi +} + +run_stage() { + local stage="$1" + local result_name + local expected_total + local expected_manifest + local fixture_before="" + local fixture_after="" + local xcodebuild_status + local -a selectors + + if [[ "$stage" == "core" ]]; then + result_name="core" + # The simulator core cohort must execute exactly 412 tests. Copied-phone + # fixtures are intentionally verified by the separate device/store stage. + expected_total="412" + expected_manifest="$MANIFEST_DIR/coredata-release-core-tests.txt" + selectors=( + "-only-testing:fearlessTests/SingleToMultiassetUserMigrationTests" + "-only-testing:fearlessTests/UserStorageCompatibilityMigrationTests" + "-only-testing:fearlessTests/SubstrateStorageClassResolutionTests" + "-only-testing:fearlessTests/SubstrateStorageMigrationSafetyTests" + "-only-testing:fearlessTests/TransformableArchiveSafetyTests" + "-only-testing:fearlessTests/MetaAccountMapperTests" + "-only-testing:fearlessTests/SelectedAccountSettingsTests" + "-only-testing:fearlessTests/RootTests" + "-only-testing:fearlessTests/ChainModelMapperTests" + "-only-testing:fearlessTests/ChainSyncServiceCompatibilityTests" + "-only-testing:fearlessTests/ChainRegistryTests" + "-only-testing:fearlessTests/ConnectionPoolTests" + "-only-testing:fearlessTests/CrashConsistentStoreReplacerResourceLimitTests" + "-skip-testing:fearlessTests/SubstrateStorageClassResolutionTests/testCopiedPhoneV8Store_whenAvailable_thenAllRowsHaveExpectedClassesAndStoreIsUnchanged" + "-skip-testing:fearlessTests/SubstrateStorageClassResolutionTests/testCopiedPhoneV8Store_whenFetchedThroughProductionRepositories_thenMapsEveryRuntimeAndChain" + ) + else + result_name="copied-phone" + expected_total="2" + expected_manifest="$MANIFEST_DIR/coredata-release-copied-phone-tests.txt" + selectors=( + "-only-testing:fearlessTests/SubstrateStorageClassResolutionTests/testCopiedPhoneV8Store_whenAvailable_thenAllRowsHaveExpectedClassesAndStoreIsUnchanged" + "-only-testing:fearlessTests/SubstrateStorageClassResolutionTests/testCopiedPhoneV8Store_whenFetchedThroughProductionRepositories_thenMapsEveryRuntimeAndChain" + ) + fixture_before="$(fixture_fingerprint "$PHONE_FIXTURE")" + fi + + local result_bundle="$OUTPUT_DIR/${result_name}.xcresult" + local xcodebuild_log="$OUTPUT_DIR/${result_name}.xcodebuild.log" + local summary_file="$OUTPUT_DIR/${result_name}.summary.json" + local tests_json="$OUTPUT_DIR/${result_name}.tests.json" + local executed_manifest="$OUTPUT_DIR/${result_name}.executed-tests.txt" + [[ ! -e "$result_bundle" ]] || + fail "refusing to overwrite an existing xcresult bundle" + actual_manifest_total="$( + awk 'NF && $1 !~ /^#/ { count += 1 } END { print count + 0 }' \ + "$expected_manifest" + )" + [[ "$actual_manifest_total" == "$expected_total" ]] || + fail "reviewed test manifest cardinality does not match the stage contract" + + local -a xcodebuild_arguments=( + -workspace "$WORKSPACE" + -scheme "$SCHEME" + -configuration Release + -destination "$SIMULATOR_DESTINATION" + -derivedDataPath "$DERIVED_DATA_DIR" + -clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" + -disableAutomaticPackageResolution + -skipPackageUpdates + -parallel-testing-enabled NO + -maximum-parallel-testing-workers 1 + -resultBundlePath "$result_bundle" + "SWIFT_OPTIMIZATION_LEVEL=-O" + "ENABLE_TESTABILITY=YES" + "ONLY_ACTIVE_ARCH=YES" + "${selectors[@]}" + test + ) + + log "Running ${stage} Release test stage; detailed output is private in the gate log" + set +e + if [[ "$stage" == "core" ]]; then + env -u FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE \ + "$XCODEBUILD_BIN" "${xcodebuild_arguments[@]}" >"$xcodebuild_log" 2>&1 + xcodebuild_status=$? + else + FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE="$PHONE_FIXTURE" \ + "$XCODEBUILD_BIN" "${xcodebuild_arguments[@]}" >"$xcodebuild_log" 2>&1 + xcodebuild_status=$? + fi + set -e + + if [[ "$stage" == "copied-phone" ]]; then + fixture_after="$(fixture_fingerprint "$PHONE_FIXTURE")" + [[ "$fixture_after" == "$fixture_before" ]] || + fail "copied-phone source fixture changed during the test stage" + fi + + [[ "$xcodebuild_status" -eq 0 ]] || + fail "xcodebuild failed for the ${stage} stage; inspect the private gate log" + + validate_result_summary "$result_bundle" "$expected_total" "$summary_file" + validate_test_inventory \ + "$result_bundle" \ + "$expected_manifest" \ + "$tests_json" \ + "$executed_manifest" + if [[ "$stage" == "copied-phone" ]]; then + log "PASSED copied-phone fixture stage: exactly 2 tests, source fixture unchanged" + else + log "PASSED core stage: exactly 412 Release -O tests, zero failures, skips, or expected failures" + fi +} + +main() { + local stage="core" + local requested_udid="${FEARLESS_CORE_DATA_SIMULATOR_UDID:-}" + local requested_destination="" + local fixture_argument="" + local output_argument="" + local derived_data_argument="" + + while [[ "$#" -gt 0 ]]; do + case "$1" in + --stage) + require_option_value "$1" "$#" + stage="$2" + shift 2 + ;; + --simulator-udid) + require_option_value "$1" "$#" + requested_udid="$2" + shift 2 + ;; + --destination) + require_option_value "$1" "$#" + requested_destination="$2" + shift 2 + ;; + --fixture) + require_option_value "$1" "$#" + fixture_argument="$2" + shift 2 + ;; + --output-dir) + require_option_value "$1" "$#" + output_argument="$2" + shift 2 + ;; + --derived-data) + require_option_value "$1" "$#" + derived_data_argument="$2" + shift 2 + ;; + --help|-h) + usage + exit 0 + ;; + *) + fail "unknown argument: $1" + ;; + esac + done + + case "$stage" in + core|copied-phone|all) ;; + *) fail "--stage must be core, copied-phone, or all" ;; + esac + + if [[ -n "$requested_udid" && -n "$requested_destination" ]]; then + fail "pass either --simulator-udid or --destination, not both" + fi + + if [[ -n "$requested_destination" ]]; then + if [[ "$requested_destination" =~ $SIMULATOR_DESTINATION_PATTERN ]]; then + requested_udid="${BASH_REMATCH[1]}" + else + fail "refusing physical, generic, named, or otherwise non-canonical simulator destination" + fi + fi + + if [[ -n "$requested_udid" && ! "$requested_udid" =~ $UUID_PATTERN ]]; then + fail "simulator UDID must be a canonical UUID" + fi + + readonly ROOT_DIR="$( + cd "${FEARLESS_CORE_DATA_ROOT_DIR:-$(dirname "${BASH_SOURCE[0]}")/../..}" && + pwd -P + )" + readonly WORKSPACE_INPUT="${FEARLESS_CORE_DATA_WORKSPACE:-$ROOT_DIR/fearless.xcworkspace}" + [[ -d "$WORKSPACE_INPUT" && -f "$WORKSPACE_INPUT/contents.xcworkspacedata" ]] || + fail "fearless.xcworkspace is missing or incomplete" + [[ "$(basename "$WORKSPACE_INPUT")" == "fearless.xcworkspace" ]] || + fail "the Core Data gate requires fearless.xcworkspace" + readonly WORKSPACE="$(canonical_directory "$WORKSPACE_INPUT")" + + readonly SOURCE_PACKAGES_INPUT="${FEARLESS_CORE_DATA_SOURCE_PACKAGES_DIR:-$ROOT_DIR/SourcePackages}" + [[ -d "$SOURCE_PACKAGES_INPUT" && -d "$SOURCE_PACKAGES_INPUT/checkouts" ]] || + fail "prepared canonical SourcePackages/checkouts is required" + readonly SOURCE_PACKAGES_DIR="$(canonical_directory "$SOURCE_PACKAGES_INPUT")" + + readonly XCODEBUILD_BIN="${FEARLESS_CORE_DATA_XCODEBUILD_BIN:-xcodebuild}" + readonly XCRUN_BIN="${FEARLESS_CORE_DATA_XCRUN_BIN:-xcrun}" + readonly PYTHON_BIN="${FEARLESS_CORE_DATA_PYTHON_BIN:-python3}" + readonly SHASUM_BIN="${FEARLESS_CORE_DATA_SHASUM_BIN:-shasum}" + require_executable "$XCODEBUILD_BIN" "xcodebuild" + require_executable "$XCRUN_BIN" "xcrun" + require_executable "$PYTHON_BIN" "python3" + if [[ "$stage" == "copied-phone" || "$stage" == "all" ]]; then + require_executable "$SHASUM_BIN" "shasum" + fi + [[ -f "$CDMETAACCOUNT_CODABLE_AUDIT" && ! -L "$CDMETAACCOUNT_CODABLE_AUDIT" ]] || + fail "CDMetaAccount Codable contract audit is missing or unsafe" + FEARLESS_CDMETAACCOUNT_CODABLE_ROOT="$ROOT_DIR" \ + FEARLESS_CDMETAACCOUNT_CODABLE_PYTHON_BIN="$PYTHON_BIN" \ + bash "$CDMETAACCOUNT_CODABLE_AUDIT" + + SIMULATOR_INVENTORY_FILE="$( + mktemp "${TMPDIR:-/private/tmp}/fearless-coredata-simulators.XXXXXX" + )" + trap cleanup EXIT + + if [[ -n "$requested_udid" ]]; then + if ! "$XCRUN_BIN" simctl list devices available -j \ + >"$SIMULATOR_INVENTORY_FILE" 2>/dev/null; then + fail "unable to query available iOS simulators" + fi + if ! SIMULATOR_UDID="$( + resolve_simulator_from_json "explicit" "$requested_udid" "$SIMULATOR_INVENTORY_FILE" + )"; then + fail "the requested simulator could not be verified" + fi + else + if ! "$XCRUN_BIN" simctl list devices booted -j \ + >"$SIMULATOR_INVENTORY_FILE" 2>/dev/null; then + fail "unable to query booted iOS simulators" + fi + if ! SIMULATOR_UDID="$( + resolve_simulator_from_json "automatic" "" "$SIMULATOR_INVENTORY_FILE" + )"; then + fail "a unique booted simulator is required" + fi + fi + readonly SIMULATOR_UDID + readonly SIMULATOR_DESTINATION="platform=iOS Simulator,id=${SIMULATOR_UDID}" + + local timestamp + timestamp="$(date -u +%Y%m%dT%H%M%SZ)" + readonly OUTPUT_DIR_INPUT="${output_argument:-$ROOT_DIR/build/test-results/CoreDataReleaseGate-$timestamp}" + [[ ! -e "$OUTPUT_DIR_INPUT" ]] || + fail "output directory must not already exist" + mkdir -p "$OUTPUT_DIR_INPUT" + readonly OUTPUT_DIR="$(canonical_directory "$OUTPUT_DIR_INPUT")" + + readonly DERIVED_DATA_DIR="${derived_data_argument:-$ROOT_DIR/build/DerivedData-CoreDataReleaseGate}" + + readonly PHONE_FIXTURE="${fixture_argument:-${FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE:-}}" + if [[ "$stage" == "copied-phone" || "$stage" == "all" ]]; then + [[ -n "$PHONE_FIXTURE" ]] || + fail "copied-phone stage requires --fixture or FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE" + [[ "$PHONE_FIXTURE" == /* ]] || + fail "copied-phone fixture path must be absolute" + [[ -r "$PHONE_FIXTURE" && -f "$PHONE_FIXTURE" && ! -L "$PHONE_FIXTURE" ]] || + fail "copied-phone fixture must be a readable, regular, non-symlink file" + fi + + log "Using fearless.xcworkspace, scheme fearless.tests, Release optimization -O" + if [[ "$stage" == "core" || "$stage" == "all" ]]; then + run_stage "core" + fi + if [[ "$stage" == "copied-phone" || "$stage" == "all" ]]; then + run_stage "copied-phone" + fi + log "PASSED requested Core Data Release gate" +} + +main "$@" diff --git a/scripts/ci/run-coredata-simulator-rehearsal.sh b/scripts/ci/run-coredata-simulator-rehearsal.sh new file mode 100755 index 0000000000..b520ddb57c --- /dev/null +++ b/scripts/ci/run-coredata-simulator-rehearsal.sh @@ -0,0 +1,1646 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Rehearses first launch and relaunch of a standalone Release simulator app +# against a disposable, offline copy of the three Fearless Core Data stores. +# +# Safety properties: +# - requires an explicit, booted iPhone Simulator UDID; +# - verifies the .app contains an iOS Simulator binary; +# - rejects unsigned or linker-only Simulator app bundles; +# - requires artifact-embedded Release, Swift -O, and disabled-testability attestations; +# - refuses a simulator where this bundle is already installed; +# - never opens, deletes, renames, chmods, or otherwise writes the source fixture; +# - runs SQLite inspection only against additional private copies; +# - never prints database rows or application log messages; +# - never uninstalls an app or erases a simulator. + +umask 077 + +readonly LOG_PREFIX="[coredata-simulator-rehearsal]" +readonly UUID_PATTERN='^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$' +readonly BUNDLE_ID_PATTERN='^[A-Za-z0-9][A-Za-z0-9.-]*[A-Za-z0-9]$' +readonly DEFAULT_ALIVE_SECONDS=8 +readonly EXPECTED_BUNDLE_ID="jp.co.soramitsu.fearlesswallet" +readonly EXPECTED_VERSION="4.2.0" + +readonly STORE_FILES=( + "CacheDataModel.sqlite" + "CacheDataModel.sqlite-shm" + "CacheDataModel.sqlite-wal" + "SubstrateDataModel.sqlite" + "SubstrateDataModel.sqlite-shm" + "SubstrateDataModel.sqlite-wal" + "UserDataModel.sqlite" + "UserDataModel.sqlite-shm" + "UserDataModel.sqlite-wal" +) + +readonly REQUIRED_MANAGED_OBJECT_CLASSES=( + "CDAsset" + "CDChain" + "CDChainNode" + "CDChainStorageItem" + "CDChainXcmConfig" + "CDContact" + "CDContactItem" + "CDExternalApi" + "CDPhishingItem" + "CDPolkaswapDex" + "CDPolkaswapRemoteSettings" + "CDPriceData" + "CDPriceProvider" + "CDRuntimeMetadataItem" + "CDScamInfo" + "CDStashItem" + "CDTransactionHistoryItem" + "CDXcmAvailableAsset" + "CDXcmAvailableDestination" + "CDAccountInfo" + "CDAssetVisibility" + "CDChainAccount" + "CDChainSettings" + "CDCurrency" + "CDCustomChainNode" + "CDMetaAccount" +) + +readonly REQUIRED_CORE_DATA_RESOURCES=( + "CompatibleUserDataModel_v13.mom" + "LegacyEcosystemUserDataModel_v12.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/UserDataModel.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v2.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v3.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v4.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v5.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v6.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v7.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v8.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v9.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v10.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v11.mom" + "SubstrateDataModel.momd/SubstrateDataModel.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v2.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v3.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v4.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v5.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v6.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v7.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v8.mom" + "SingleToMultiasset.cdm" + "MultiassetV2.cdm" + "MultiassetV9.cdm" + "UserDataModelV10toV11.cdm" + "SubstrateV2Mapping.cdm" + "SubstrateV2toV4.cdm" + "SubstrateV3toV4.cdm" +) + +SIMULATOR_UDID="" +APP_PATH="" +BUNDLE_ID="" +FIXTURE_DIR="" +ARTIFACTS_DIR="" +CRASH_REPORT_DIR="${HOME}/Library/Logs/DiagnosticReports" +ALIVE_SECONDS="$DEFAULT_ALIVE_SECONDS" +DISPOSABLE_FIXTURE_CONFIRMED=0 +DRY_RUN=0 +EXPECTED_GIT_SHA="" +EXPECTED_EXECUTABLE_SHA256="" +EXPECTED_BUILD="" + +readonly REHEARSAL_TEST_HARNESS="${FEARLESS_REHEARSAL_TEST_HARNESS:-0}" +if [[ "$REHEARSAL_TEST_HARNESS" != "1" ]]; then + for override_name in \ + FEARLESS_REHEARSAL_XCRUN_BIN \ + FEARLESS_REHEARSAL_CODESIGN_BIN \ + FEARLESS_REHEARSAL_PYTHON_BIN \ + FEARLESS_REHEARSAL_SHASUM_BIN \ + FEARLESS_REHEARSAL_PS_BIN \ + FEARLESS_REHEARSAL_SLEEP_BIN \ + FEARLESS_REHEARSAL_PROCESS_CHECK_BIN; do + if [[ -n "${!override_name:-}" ]]; then + printf '%s ERROR: %s\n' \ + "[coredata-simulator-rehearsal]" \ + "$override_name is accepted only with FEARLESS_REHEARSAL_TEST_HARNESS=1" >&2 + exit 1 + fi + done +fi + +XCRUN_BIN="${FEARLESS_REHEARSAL_XCRUN_BIN:-xcrun}" +CODESIGN_BIN="${FEARLESS_REHEARSAL_CODESIGN_BIN:-codesign}" +PYTHON_BIN="${FEARLESS_REHEARSAL_PYTHON_BIN:-python3}" +SHASUM_BIN="${FEARLESS_REHEARSAL_SHASUM_BIN:-shasum}" +PS_BIN="${FEARLESS_REHEARSAL_PS_BIN:-ps}" +SLEEP_BIN="${FEARLESS_REHEARSAL_SLEEP_BIN:-sleep}" +PROCESS_CHECK_BIN="${FEARLESS_REHEARSAL_PROCESS_CHECK_BIN:-}" + +APP_EXECUTABLE_NAME="" +APP_EXECUTABLE_PATH="" +DATA_CONTAINER="" +CORE_DATA_TARGET="" +APP_RUNNING=0 + +log() { + printf '%s %s\n' "$LOG_PREFIX" "$*" +} + +fail() { + printf '%s ERROR: %s\n' "$LOG_PREFIX" "$*" >&2 + exit 1 +} + +cleanup() { + if [[ "$APP_RUNNING" == "1" && -n "$SIMULATOR_UDID" && -n "$BUNDLE_ID" ]]; then + "$XCRUN_BIN" simctl terminate "$SIMULATOR_UDID" "$BUNDLE_ID" \ + >/dev/null 2>&1 || true + fi +} + +trap cleanup EXIT + +usage() { + cat <<'USAGE' +Usage: + bash scripts/ci/run-coredata-simulator-rehearsal.sh \ + --simulator-udid UUID \ + --app /absolute/path/to/fearless.app \ + --bundle-id jp.co.soramitsu.fearlesswallet \ + --expected-git-sha 40_HEX_SHA \ + --expected-build CANONICAL_CF_BUNDLE_VERSION \ + --expected-executable-sha256 64_HEX_SHA256 \ + --fixture-dir /absolute/path/to/disposable/offline/CoreData \ + --artifacts-dir /absolute/path/to/new/artifacts \ + --confirm-disposable-fixture + +Required safety acknowledgement: + --confirm-disposable-fixture + Confirms that --fixture-dir is an offline disposable copy, not a phone + container, device backup, or sole recovery copy. The directory is still + treated as immutable and is checksum-verified throughout the run. + +Options: + --alive-seconds N + Require the launched process to remain alive for N seconds per launch + (1...30, default 8). + --crash-report-dir ABSOLUTE_DIRECTORY + DiagnosticReports directory to inspect for new matching crash reports. + --dry-run + Perform fail-closed input, Simulator, binary, checksum, and copied-SQLite + validation without installing or launching the app. + --expected-git-sha SHA + Exact 40-hex source commit embedded in the Simulator artifact. + --expected-build BUILD + Exact fresh CFBundleVersion selected after the App Store Connect check. + --expected-executable-sha256 SHA + Exact 64-hex executable digest recorded by the build step. + --help + +Controlled test-harness overrides: + FEARLESS_REHEARSAL_XCRUN_BIN + FEARLESS_REHEARSAL_CODESIGN_BIN + FEARLESS_REHEARSAL_PYTHON_BIN + FEARLESS_REHEARSAL_SHASUM_BIN + FEARLESS_REHEARSAL_PS_BIN + FEARLESS_REHEARSAL_SLEEP_BIN + FEARLESS_REHEARSAL_PROCESS_CHECK_BIN +USAGE +} + +require_option_value() { + local option="$1" + local remaining="$2" + [[ "$remaining" -ge 2 ]] || fail "$option requires a value" +} + +require_executable() { + local executable="$1" + local description="$2" + + if [[ "$executable" == */* ]]; then + [[ -x "$executable" ]] || fail "$description is not executable" + else + command -v "$executable" >/dev/null 2>&1 || + fail "$description is unavailable" + fi +} + +validate_release_app_contract() { + local symbols_file="$ARTIFACTS_DIR/managed-object-symbols.pending" + local class_name + local resource + local build_configuration + local optimization_level + local enable_testability + local embedded_git_sha + local marketing_version + local build_number + local executable_digest + + build_configuration="$( + plist_string "$APP_PATH/Info.plist" "FearlessBuildConfiguration" + )" || fail "Release app lacks its build-configuration attestation" + optimization_level="$( + plist_string "$APP_PATH/Info.plist" "FearlessSwiftOptimizationLevel" + )" || fail "Release app lacks its Swift-optimization attestation" + enable_testability="$( + plist_string "$APP_PATH/Info.plist" "FearlessEnableTestability" + )" || fail "Release app lacks its testability attestation" + embedded_git_sha="$( + plist_string "$APP_PATH/Info.plist" "FearlessGitCommit" + )" || fail "Release app lacks its git-commit attestation" + marketing_version="$( + plist_string "$APP_PATH/Info.plist" "CFBundleShortVersionString" + )" || fail "Release app lacks its marketing version" + build_number="$( + plist_string "$APP_PATH/Info.plist" "CFBundleVersion" + )" || fail "Release app lacks its build number" + + [[ "$build_configuration" == "Release" ]] || + fail "app was not built with the Release configuration" + [[ "$optimization_level" == "-O" ]] || + fail "app was not built with Swift -O optimization" + [[ "$enable_testability" == "NO" ]] || + fail "app was built with testability enabled" + [[ "$embedded_git_sha" == "$EXPECTED_GIT_SHA" ]] || + fail "app git commit does not match --expected-git-sha" + [[ "$marketing_version" == "$EXPECTED_VERSION" ]] || + fail "app marketing version is not $EXPECTED_VERSION" + [[ "$build_number" == "$EXPECTED_BUILD" ]] || + fail "app build number is not --expected-build" + executable_digest="$("$SHASUM_BIN" -a 256 "$APP_EXECUTABLE_PATH" | awk '{print $1}')" + [[ "$executable_digest" =~ ^[0-9A-Fa-f]{64}$ ]] || + fail "unable to compute the Simulator executable SHA-256" + [[ "$executable_digest" == "$EXPECTED_EXECUTABLE_SHA256" ]] || + fail "Simulator executable SHA-256 does not match the build record" + + if ! "$XCRUN_BIN" nm -gj "$APP_EXECUTABLE_PATH" >"$symbols_file" 2>/dev/null; then + : >"$symbols_file" + fail "unable to inspect managed-object symbols in the app executable" + fi + + for class_name in "${REQUIRED_MANAGED_OBJECT_CLASSES[@]}"; do + if ! grep -Fqx -- "_OBJC_CLASS_\$_${class_name}" "$symbols_file"; then + : >"$symbols_file" + fail "Release app is missing a required managed-object runtime class" + fi + done + : >"$symbols_file" + + for resource in "${REQUIRED_CORE_DATA_RESOURCES[@]}"; do + [[ -f "$APP_PATH/$resource" && ! -L "$APP_PATH/$resource" ]] || + fail "Release app is missing or symlinking a required Core Data migration resource" + done + + printf '%s\n' \ + "Release, Swift -O, testability disabled; exact commit/version/build/executable SHA-256; 26 managed-object runtime classes and 29 Core Data resources verified" \ + >"$ARTIFACTS_DIR/coredata-app-contract.txt" +} + +validate_app_signature_contract() { + local verification_file="$ARTIFACTS_DIR/app-signature-verification.pending" + local diagnostics_file="$ARTIFACTS_DIR/app-signature-diagnostics.pending" + + if ! "$CODESIGN_BIN" --verify --deep --strict "$APP_PATH" \ + >"$verification_file" 2>&1; then + : >"$verification_file" + fail "app failed strict code-signature verification" + fi + : >"$verification_file" + + if ! "$CODESIGN_BIN" -dv --verbose=4 "$APP_PATH" \ + >"$diagnostics_file" 2>&1; then + : >"$diagnostics_file" + fail "unable to inspect app code-signing identity" + fi + + if ! "$PYTHON_BIN" - "$diagnostics_file" "$BUNDLE_ID" <<'PY' +import re +import sys + +path, bundle_id = sys.argv[1:] +try: + with open(path, "r", encoding="utf-8", errors="replace") as source: + lines = source.readlines() +except OSError: + sys.exit(2) + +pattern = re.compile(r"^Identifier=(.+)$") +identifiers = [ + match.group(1) + for line in lines + if (match := pattern.fullmatch(line.rstrip("\r\n"))) +] +if identifiers != [bundle_id]: + sys.exit(3) +PY + then + : >"$diagnostics_file" + fail "app code-signing identifier does not exactly match the requested bundle" + fi + : >"$diagnostics_file" + + printf '%s\n' \ + "strict bundle signature and exact bundle-bound code-signing identifier verified" \ + >"$ARTIFACTS_DIR/app-signature-contract.txt" +} + +canonical_directory() { + local directory="$1" + (cd "$directory" && pwd -P) +} + +path_is_within() { + local child="$1" + local parent="$2" + + [[ "$child" == "$parent" || "$child" == "$parent/"* ]] +} + +plist_string() { + local plist="$1" + local key="$2" + + "$PYTHON_BIN" - "$plist" "$key" <<'PY' +import plistlib +import sys + +path, key = sys.argv[1:] +try: + with open(path, "rb") as source: + value = plistlib.load(source).get(key) +except (OSError, plistlib.InvalidFileException): + sys.exit(2) + +if not isinstance(value, str) or not value: + sys.exit(3) +print(value) +PY +} + +validate_fixture_directory() { + local directory="$1" + + "$PYTHON_BIN" - "$directory" <<'PY' +import os +import stat +import sys + +directory = sys.argv[1] +expected = { + "CacheDataModel.sqlite", + "CacheDataModel.sqlite-shm", + "CacheDataModel.sqlite-wal", + "SubstrateDataModel.sqlite", + "SubstrateDataModel.sqlite-shm", + "SubstrateDataModel.sqlite-wal", + "UserDataModel.sqlite", + "UserDataModel.sqlite-shm", + "UserDataModel.sqlite-wal", +} + +try: + directory_stat = os.lstat(directory) + names = set(os.listdir(directory)) +except OSError: + print("fixture directory cannot be inspected", file=sys.stderr) + sys.exit(2) + +if not stat.S_ISDIR(directory_stat.st_mode) or stat.S_ISLNK(directory_stat.st_mode): + print("fixture directory must be a real directory, not a symlink", file=sys.stderr) + sys.exit(3) +if names != expected: + print("fixture directory must contain exactly the nine expected store-family files", file=sys.stderr) + sys.exit(4) + +for name in sorted(expected): + path = os.path.join(directory, name) + try: + item_stat = os.lstat(path) + except OSError: + print("fixture component cannot be inspected", file=sys.stderr) + sys.exit(5) + if not stat.S_ISREG(item_stat.st_mode) or stat.S_ISLNK(item_stat.st_mode): + print("fixture components must be regular non-symlink files", file=sys.stderr) + sys.exit(6) + if name.endswith(".sqlite") and item_stat.st_size <= 0: + print("primary SQLite stores must be nonempty", file=sys.stderr) + sys.exit(7) +PY +} + +write_family_manifest() { + local directory="$1" + local output="$2" + local require_every_file="$3" + local filename + local digest_output + local digest + + : >"$output" + for filename in "${STORE_FILES[@]}"; do + if [[ ! -e "$directory/$filename" ]]; then + if [[ "$require_every_file" == "1" ]]; then + fail "a required store-family component is missing" + fi + printf '%s %s\n' "absent" "$filename" >>"$output" + continue + fi + + [[ -f "$directory/$filename" && ! -L "$directory/$filename" ]] || + fail "store-family components must be regular non-symlink files" + digest_output="$("$SHASUM_BIN" -a 256 "$directory/$filename")" || + fail "unable to checksum a store-family component" + digest="${digest_output%%[[:space:]]*}" + [[ "$digest" =~ ^[0-9A-Fa-f]{64}$ ]] || + fail "a store-family checksum was malformed" + printf '%s %s\n' "$digest" "$filename" >>"$output" + done +} + +require_no_unexpected_files() { + local directory="$1" + + "$PYTHON_BIN" - "$directory" <<'PY' +import os +import sys + +expected = { + "CacheDataModel.sqlite", + "CacheDataModel.sqlite-shm", + "CacheDataModel.sqlite-wal", + "SubstrateDataModel.sqlite", + "SubstrateDataModel.sqlite-shm", + "SubstrateDataModel.sqlite-wal", + "UserDataModel.sqlite", + "UserDataModel.sqlite-shm", + "UserDataModel.sqlite-wal", +} +try: + names = set(os.listdir(sys.argv[1])) +except OSError: + sys.exit(2) + +if not names.issubset(expected): + print("Core Data directory contains an unexpected file", file=sys.stderr) + sys.exit(3) +for name in names: + path = os.path.join(sys.argv[1], name) + if os.path.islink(path) or not os.path.isfile(path): + print("Core Data components must be regular non-symlink files", file=sys.stderr) + sys.exit(4) +PY +} + +copy_family() { + local source="$1" + local destination="$2" + local require_every_file="$3" + local filename + + [[ -d "$destination" && ! -L "$destination" ]] || + fail "copy destination is not a real directory" + if [[ -n "$(find "$destination" -mindepth 1 -maxdepth 1 -print -quit)" ]]; then + fail "copy destination must be empty" + fi + + for filename in "${STORE_FILES[@]}"; do + if [[ -e "$source/$filename" ]]; then + [[ -f "$source/$filename" && ! -L "$source/$filename" ]] || + fail "copy source contains a non-regular component" + cp -p "$source/$filename" "$destination/$filename" + elif [[ "$require_every_file" == "1" ]]; then + fail "copy source is missing a required store-family component" + fi + done +} + +inspect_sqlite_copies() { + local directory="$1" + local output="$2" + + "$PYTHON_BIN" - "$directory" "$output" <<'PY' +import json +import hashlib +import os +import sqlite3 +import sys + +directory, output = sys.argv[1:] +stores = ( + "CacheDataModel.sqlite", + "SubstrateDataModel.sqlite", + "UserDataModel.sqlite", +) +result = {} + +def quote_identifier(value): + return '"' + value.replace('"', '""') + '"' + +def encode_value(value): + if value is None: + return b"n;" + if isinstance(value, bytes): + return b"b" + str(len(value)).encode("ascii") + b":" + value + b";" + if isinstance(value, str): + encoded = value.encode("utf-8") + return b"s" + str(len(encoded)).encode("ascii") + b":" + encoded + b";" + if isinstance(value, int): + return b"i" + str(value).encode("ascii") + b";" + if isinstance(value, float): + return b"f" + value.hex().encode("ascii") + b";" + raise RuntimeError("unsupported protected SQLite value type") + +def rows_digest(rows): + encoded_rows = [] + for row in rows: + encoded_rows.append(b"".join(encode_value(value) for value in row)) + encoded_rows.sort() + + digest = hashlib.sha256() + for row in encoded_rows: + digest.update(str(len(row)).encode("ascii")) + digest.update(b":") + digest.update(row) + digest.update(b";") + return digest.hexdigest() + +def table_columns(connection, table_name): + return { + row[1] + for row in connection.execute( + f"PRAGMA table_info({quote_identifier(table_name)})" + ).fetchall() + } + +def protected_user_fingerprints(connection, table_names): + meta_table = "ZCDMETAACCOUNT" + chain_table = "ZCDCHAINACCOUNT" + if meta_table not in table_names or chain_table not in table_names: + raise RuntimeError("User store lacks protected wallet tables") + + meta_columns = table_columns(connection, meta_table) + core_meta_columns = ( + "ZMETAID", + "ZSUBSTRATEACCOUNTID", + "ZSUBSTRATEPUBLICKEY", + "ZSUBSTRATECRYPTOTYPE", + "ZETHEREUMADDRESS", + "ZETHEREUMPUBLICKEY", + ) + missing_meta = set(core_meta_columns) - meta_columns + if missing_meta: + raise RuntimeError("User store lacks protected wallet identity columns") + + quoted_core_meta = ", ".join(quote_identifier(value) for value in core_meta_columns) + fingerprints = { + "wallet-core-identities-and-keys": rows_digest( + connection.execute( + f"SELECT {quoted_core_meta} FROM {quote_identifier(meta_table)}" + ).fetchall() + ) + } + + optional_wallet_groups = { + "wallet-ton-identities-and-keys": ( + "ZTONADDRESS", + "ZTONPUBLICKEY", + ), + } + for label, columns in optional_wallet_groups.items(): + if set(columns).issubset(meta_columns): + selected = ("ZMETAID",) + columns + quoted = ", ".join(quote_identifier(value) for value in selected) + fingerprints[label] = rows_digest( + connection.execute( + f"SELECT {quoted} FROM {quote_identifier(meta_table)}" + ).fetchall() + ) + + chain_columns = table_columns(connection, chain_table) + core_chain_columns = ( + "ZACCOUNTID", + "ZCHAINID", + "ZPUBLICKEY", + "ZCRYPTOTYPE", + "ZMETAACCOUNT", + ) + missing_chain = set(core_chain_columns) - chain_columns + if missing_chain: + raise RuntimeError("User store lacks protected child-account columns") + + fingerprints["child-identities-keys-and-wallet-links"] = rows_digest( + connection.execute( + f""" + SELECT + child.ZACCOUNTID, + child.ZCHAINID, + child.ZPUBLICKEY, + child.ZCRYPTOTYPE, + parent.ZMETAID + FROM {quote_identifier(chain_table)} AS child + LEFT JOIN {quote_identifier(meta_table)} AS parent + ON child.ZMETAACCOUNT = parent.Z_PK + """ + ).fetchall() + ) + return fingerprints + +def protected_substrate_topology(connection, table_names): + chain_table = "ZCDCHAIN" + node_table = "ZCDCHAINNODE" + primary_key_table = "Z_PRIMARYKEY" + required_tables = {chain_table, node_table, primary_key_table} + if not required_tables.issubset(table_names): + raise RuntimeError("Substrate store lacks chain/node topology tables") + + chain_columns = table_columns(connection, chain_table) + node_columns = table_columns(connection, node_table) + required_chain_columns = {"Z_PK", "ZCHAINID", "ZSELECTEDNODE"} + required_node_columns = {"Z_PK", "ZCHAIN", "ZNAME", "ZURL"} + if not required_chain_columns.issubset(chain_columns): + raise RuntimeError("Substrate store lacks protected chain topology columns") + if not required_node_columns.issubset(node_columns): + raise RuntimeError("Substrate store lacks protected node topology columns") + + entity_numbers = { + str(name).upper(): number + for number, name in connection.execute( + f"SELECT Z_ENT, Z_NAME FROM {quote_identifier(primary_key_table)}" + ).fetchall() + } + chain_entity = entity_numbers.get("CDCHAIN") + node_entity = entity_numbers.get("CDCHAINNODE") + if not isinstance(chain_entity, int) or not isinstance(node_entity, int): + raise RuntimeError("Substrate store lacks Core Data entity-number metadata") + + inline_custom_column = f"Z{chain_entity}CUSTOMNODES" + if inline_custom_column not in node_columns: + raise RuntimeError("Substrate store lacks the canonical customNodes relationship column") + custom_tables = [] + for table_name in sorted(table_names): + if table_name in {chain_table, node_table, primary_key_table}: + continue + columns = table_columns(connection, table_name) + if "CUSTOMNODES" in table_name or any( + "CUSTOMNODES" in column for column in columns + ): + custom_tables.append((table_name, columns)) + if custom_tables: + raise RuntimeError("Substrate store has an unexpected customNodes join table") + + chains = {} + for primary_key, chain_id, selected_node in connection.execute( + f""" + SELECT Z_PK, ZCHAINID, ZSELECTEDNODE + FROM {quote_identifier(chain_table)} + """ + ).fetchall(): + if ( + not isinstance(primary_key, int) + or not isinstance(chain_id, str) + or not chain_id.strip() + ): + raise RuntimeError("Substrate chain topology contains an invalid identity") + chains[primary_key] = (chain_id, selected_node) + if not chains: + raise RuntimeError("Substrate chain topology is vacuous") + + optional_node_columns = tuple( + column + for column in ("ZAPIKEYNAME", "ZAPIQUERYNAME") + if column in node_columns + ) + selected_node_columns = ( + "Z_PK", + "ZCHAIN", + inline_custom_column, + "ZNAME", + "ZURL", + ) + optional_node_columns + node_query_columns = ", ".join( + quote_identifier(column) for column in selected_node_columns + ) + nodes = {} + for row in connection.execute( + f"SELECT {node_query_columns} FROM {quote_identifier(node_table)}" + ).fetchall(): + primary_key, default_chain, custom_chain, name, url, *credentials = row + if not isinstance(primary_key, int): + raise RuntimeError("Substrate node topology contains an invalid primary key") + nodes[primary_key] = ( + default_chain, + custom_chain, + name, + url, + *credentials, + ) + if not nodes: + raise RuntimeError("Substrate node topology is vacuous") + + custom_edges = set() + for node_key, node in nodes.items(): + custom_chain = node[1] + if custom_chain is not None: + if custom_chain not in chains: + raise RuntimeError("Substrate customNodes relationship is dangling") + custom_edges.add((custom_chain, node_key)) + if not custom_edges: + raise RuntimeError("Substrate fixture has no custom-node relationships") + + selected_edges = set() + for chain_key, (_, selected_node) in chains.items(): + if selected_node is not None: + if selected_node not in nodes: + raise RuntimeError("Substrate selected-node relationship is dangling") + selected_edges.add((chain_key, selected_node)) + + default_edges = set() + for node_key, node in nodes.items(): + default_chain = node[0] + if default_chain is not None: + if default_chain not in chains: + raise RuntimeError("Substrate default-node relationship is dangling") + default_edges.add((default_chain, node_key)) + + has_custom_selected = bool(custom_edges & selected_edges) + has_custom_only = any( + any(source == chain_key for source, _ in custom_edges) + and not any(source == chain_key for source, _ in default_edges) + for chain_key in chains + ) + if not has_custom_selected: + raise RuntimeError("Substrate fixture lacks a selected custom-node topology") + if not has_custom_only: + raise RuntimeError("Substrate fixture lacks a custom-only chain topology") + + topology_rows = [] + for chain_key, (chain_id, selected_node) in chains.items(): + topology_rows.append(("chain", chain_id, selected_node)) + for relationship, edges in ( + ("default", default_edges), + ("custom", custom_edges), + ("selected", selected_edges), + ): + for source, node_key in sorted(edges): + if source == chain_key: + topology_rows.append( + (relationship, chain_id, node_key, *nodes[node_key][2:]) + ) + + referenced_nodes = { + node_key + for _, node_key in default_edges | custom_edges | selected_edges + } + orphan_rows = [ + ("orphan", node_key, *node[2:]) + for node_key, node in nodes.items() + if node_key not in referenced_nodes + ] + return { + "fingerprints": { + "chain-default-custom-selected-topology": rows_digest(topology_rows), + "orphan-node-topology": rows_digest(orphan_rows), + }, + "coverage": { + "customOnlyChain": has_custom_only, + "selectedCustomNode": has_custom_selected, + }, + } + +try: + for store_name in stores: + store_path = os.path.join(directory, store_name) + if not os.path.isfile(store_path) or os.path.islink(store_path): + raise RuntimeError(f"{store_name}: copied primary store is missing") + + connection = sqlite3.connect(store_path, timeout=5.0) + try: + connection.execute("PRAGMA query_only = ON") + integrity_rows = [ + row[0] for row in connection.execute("PRAGMA integrity_check").fetchall() + ] + if integrity_rows != ["ok"]: + raise RuntimeError(f"{store_name}: integrity check failed") + + table_names = [ + row[0] + for row in connection.execute( + """ + SELECT name + FROM sqlite_master + WHERE type = 'table' AND name GLOB 'Z*' + ORDER BY name + """ + ).fetchall() + ] + table_counts = {} + for table_name in table_names: + quoted_name = quote_identifier(table_name) + count = connection.execute( + f"SELECT COUNT(*) FROM {quoted_name}" + ).fetchone()[0] + if not isinstance(count, int) or count < 0: + raise RuntimeError(f"{store_name}: invalid table count") + table_counts[table_name] = count + + store_result = { + "integrity": "ok", + "applicationRowCount": sum(table_counts.values()), + "tables": table_counts, + } + if store_name == "UserDataModel.sqlite": + store_result["protectedFingerprints"] = ( + protected_user_fingerprints(connection, set(table_names)) + ) + if store_name == "SubstrateDataModel.sqlite": + topology = protected_substrate_topology( + connection, set(table_names) + ) + store_result["protectedTopologyFingerprints"] = ( + topology["fingerprints"] + ) + store_result["topologyCoverage"] = topology["coverage"] + result[store_name] = store_result + finally: + connection.close() +except (OSError, sqlite3.Error, RuntimeError) as error: + print(f"copied SQLite inspection failed: {error}", file=sys.stderr) + sys.exit(2) + +temporary_output = output + ".pending" +with open(temporary_output, "w", encoding="utf-8") as destination: + json.dump(result, destination, indent=2, sort_keys=True) + destination.write("\n") +os.replace(temporary_output, output) +PY +} + +log_count_summary() { + local counts_file="$1" + local phase="$2" + + "$PYTHON_BIN" - "$counts_file" "$phase" <<'PY' +import json +import sys + +path, phase = sys.argv[1:] +with open(path, "r", encoding="utf-8") as source: + payload = json.load(source) +for store_name in sorted(payload): + count = payload[store_name]["applicationRowCount"] + print(f"[coredata-simulator-rehearsal] {phase} {store_name}: {count} aggregate rows") +PY +} + +validate_preservation() { + local before="$1" + local after_first="$2" + local after_second="$3" + + "$PYTHON_BIN" - "$before" "$after_first" "$after_second" <<'PY' +import json +import sys + +payloads = [] +for path in sys.argv[1:]: + with open(path, "r", encoding="utf-8") as source: + payloads.append(json.load(source)) + +before, first, second = payloads +for phase_name, payload in (("prelaunch", before), ("first launch", first), ("relaunch", second)): + for store_name in ("CacheDataModel.sqlite", "SubstrateDataModel.sqlite", "UserDataModel.sqlite"): + store = payload.get(store_name) + if not isinstance(store, dict) or store.get("integrity") != "ok": + print(f"{phase_name} lacks an intact {store_name}", file=sys.stderr) + sys.exit(2) + +user_critical_tables = ("ZCDMETAACCOUNT", "ZCDCHAINACCOUNT") +before_user = before["UserDataModel.sqlite"]["tables"] +for table_name in user_critical_tables: + if table_name not in before_user: + print(f"prelaunch User store lacks required {table_name} count", file=sys.stderr) + sys.exit(3) + expected_count = before_user[table_name] + for phase_name, payload in (("first launch", first), ("relaunch", second)): + actual_count = payload["UserDataModel.sqlite"]["tables"].get(table_name) + if actual_count != expected_count: + print(f"{phase_name} changed the protected {table_name} row count", file=sys.stderr) + sys.exit(4) + +before_fingerprints = before["UserDataModel.sqlite"].get("protectedFingerprints") +if not isinstance(before_fingerprints, dict) or not before_fingerprints: + print("prelaunch User store lacks protected wallet fingerprints", file=sys.stderr) + sys.exit(5) +for fingerprint_name, expected_fingerprint in before_fingerprints.items(): + if ( + not isinstance(fingerprint_name, str) + or not isinstance(expected_fingerprint, str) + or len(expected_fingerprint) != 64 + ): + print("prelaunch User store has malformed protected fingerprints", file=sys.stderr) + sys.exit(6) + for phase_name, payload in (("first launch", first), ("relaunch", second)): + actual_fingerprint = ( + payload["UserDataModel.sqlite"] + .get("protectedFingerprints", {}) + .get(fingerprint_name) + ) + if actual_fingerprint != expected_fingerprint: + print( + f"{phase_name} changed protected wallet identities, keys, or relationships", + file=sys.stderr, + ) + sys.exit(7) + +substrate_critical_tables = ("ZCDCHAIN", "ZCDRUNTIMEMETADATAITEM") +before_substrate = before["SubstrateDataModel.sqlite"]["tables"] +for table_name in substrate_critical_tables: + expected_count = before_substrate.get(table_name) + if not isinstance(expected_count, int) or expected_count <= 0: + print(f"prelaunch Substrate store lacks populated {table_name}", file=sys.stderr) + sys.exit(8) + for phase_name, payload in (("first launch", first), ("relaunch", second)): + actual_count = payload["SubstrateDataModel.sqlite"]["tables"].get(table_name) + if actual_count != expected_count: + print(f"{phase_name} changed the protected {table_name} row count", file=sys.stderr) + sys.exit(9) + +before_topology_store = before["SubstrateDataModel.sqlite"] +before_coverage = before_topology_store.get("topologyCoverage") +if before_coverage != { + "customOnlyChain": True, + "selectedCustomNode": True, +}: + print( + "prelaunch Substrate fixture lacks required custom-node topology coverage", + file=sys.stderr, + ) + sys.exit(10) +before_topology = before_topology_store.get("protectedTopologyFingerprints") +if not isinstance(before_topology, dict) or not before_topology: + print("prelaunch Substrate store lacks topology fingerprints", file=sys.stderr) + sys.exit(11) +for fingerprint_name, expected_fingerprint in before_topology.items(): + if ( + not isinstance(fingerprint_name, str) + or not isinstance(expected_fingerprint, str) + or len(expected_fingerprint) != 64 + ): + print("prelaunch Substrate topology fingerprint is malformed", file=sys.stderr) + sys.exit(12) + for phase_name, payload in (("first launch", first), ("relaunch", second)): + topology_store = payload["SubstrateDataModel.sqlite"] + if topology_store.get("topologyCoverage") != before_coverage: + print( + f"{phase_name} changed required custom-node topology coverage", + file=sys.stderr, + ) + sys.exit(13) + actual_fingerprint = ( + topology_store + .get("protectedTopologyFingerprints", {}) + .get(fingerprint_name) + ) + if actual_fingerprint != expected_fingerprint: + print( + f"{phase_name} changed protected default/custom/selected/orphan node topology", + file=sys.stderr, + ) + sys.exit(14) +PY +} + +validate_simulator_inventory() { + local inventory_file="$1" + + "$PYTHON_BIN" - "$inventory_file" "$SIMULATOR_UDID" <<'PY' +import json +import re +import sys + +inventory_path, requested = sys.argv[1:] +uuid_pattern = re.compile( + r"^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-" + r"[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$" +) +if not uuid_pattern.fullmatch(requested): + print("requested Simulator UDID is not a canonical UUID", file=sys.stderr) + sys.exit(2) + +try: + with open(inventory_path, "r", encoding="utf-8") as source: + payload = json.load(source) +except (OSError, json.JSONDecodeError): + print("simctl returned malformed device inventory", file=sys.stderr) + sys.exit(3) + +matches = [] +devices_by_runtime = payload.get("devices") +if not isinstance(devices_by_runtime, dict): + print("simctl device inventory has no devices object", file=sys.stderr) + sys.exit(4) + +for runtime, devices in devices_by_runtime.items(): + if not isinstance(runtime, str) or ".SimRuntime.iOS-" not in runtime: + continue + if not isinstance(devices, list): + continue + for device in devices: + if ( + isinstance(device, dict) + and str(device.get("udid", "")).lower() == requested.lower() + ): + matches.append(device) + +if len(matches) != 1: + print("requested UDID is not exactly one iOS Simulator", file=sys.stderr) + sys.exit(5) + +device = matches[0] +if device.get("isAvailable", True) is not True: + print("requested iOS Simulator is unavailable", file=sys.stderr) + sys.exit(6) +if device.get("state") != "Booted": + print("requested iOS Simulator must already be Booted", file=sys.stderr) + sys.exit(7) +name = device.get("name") +if not isinstance(name, str) or not name.startswith("iPhone"): + print("requested Simulator must be an iPhone", file=sys.stderr) + sys.exit(8) +PY +} + +process_is_expected_and_alive() { + local pid="$1" + local process_command + + if [[ -n "$PROCESS_CHECK_BIN" ]]; then + "$PROCESS_CHECK_BIN" "$pid" "$APP_EXECUTABLE_NAME" + return + fi + + kill -0 "$pid" 2>/dev/null || return 1 + process_command="$("$PS_BIN" -p "$pid" -o command= 2>/dev/null)" || return 1 + [[ "$process_command" == *"/$APP_EXECUTABLE_NAME"* || + "$process_command" == "$APP_EXECUTABLE_NAME" || + "$process_command" == "$APP_EXECUTABLE_NAME "* ]] +} + +assert_process_stays_alive() { + local pid="$1" + local elapsed=0 + + while [[ "$elapsed" -lt "$ALIVE_SECONDS" ]]; do + process_is_expected_and_alive "$pid" || + fail "launched app did not remain alive for the required interval" + "$SLEEP_BIN" 1 + elapsed=$((elapsed + 1)) + done + process_is_expected_and_alive "$pid" || + fail "launched app exited at the end of the required interval" +} + +parse_launch_pid() { + local launch_output="$1" + + "$PYTHON_BIN" - "$launch_output" "$BUNDLE_ID" <<'PY' +import re +import sys + +path, bundle_id = sys.argv[1:] +try: + with open(path, "r", encoding="utf-8", errors="replace") as source: + lines = source.readlines() +except OSError: + sys.exit(2) + +pattern = re.compile(r"^\s*" + re.escape(bundle_id) + r":\s*([1-9][0-9]*)\s*$") +matches = [pattern.match(line).group(1) for line in lines if pattern.match(line)] +if len(matches) != 1: + sys.exit(3) +print(matches[0]) +PY +} + +scan_for_new_crash_reports() { + local marker="$1" + local phase="$2" + local result_file="$ARTIFACTS_DIR/crash-scan-${phase}.txt" + + if "$PYTHON_BIN" - \ + "$CRASH_REPORT_DIR" \ + "$marker" \ + "$SIMULATOR_UDID" \ + "$BUNDLE_ID" \ + "$APP_EXECUTABLE_NAME" \ + "$result_file" <<'PY' +import os +import sys + +root, marker_path, _udid, bundle_id, executable, output = sys.argv[1:] +marker_ns = os.stat(marker_path).st_mtime_ns +matches = [] + +for directory, _, filenames in os.walk(root): + for filename in filenames: + if not (filename.endswith(".ips") or filename.endswith(".crash")): + continue + path = os.path.join(directory, filename) + try: + if os.stat(path).st_mtime_ns < marker_ns: + continue + with open(path, "r", encoding="utf-8", errors="ignore") as source: + content = source.read() + except OSError: + continue + lowered = content.lower() + has_app = bundle_id.lower() in lowered or executable.lower() in lowered + if has_app: + matches.append(filename) + +with open(output, "w", encoding="utf-8") as destination: + if matches: + destination.write("matching crash report detected\n") + else: + destination.write("clean\n") + +sys.exit(1 if matches else 0) +PY + then + return + fi + + fail "a new crash report matched the requested Simulator app during $phase" +} + +scan_unified_log_markers() { + local start_time="$1" + local phase="$2" + local raw_file="$ARTIFACTS_DIR/unified-log-filtered-${phase}.pending" + local scan_file="$ARTIFACTS_DIR/unified-log-scan-${phase}.txt" + local predicate + + predicate="process == \"$APP_EXECUTABLE_NAME\" AND (eventMessage CONTAINS[c] \"FEARLESS_STARTUP_\" OR eventMessage CONTAINS[c] \"CoreData\" OR eventMessage CONTAINS[c] \"migration\" OR eventMessage CONTAINS[c] \"persistent store\" OR eventMessage CONTAINS[c] \"fatal\" OR eventMessage CONTAINS[c] \"exception\" OR eventMessage CONTAINS[c] \"abort\")" + + if ! "$XCRUN_BIN" simctl spawn "$SIMULATOR_UDID" log show \ + --style compact \ + --start "$start_time" \ + --predicate "$predicate" >"$raw_file" 2>/dev/null; then + : >"$raw_file" + fail "unable to inspect the Simulator unified log" + fi + + if "$PYTHON_BIN" - "$raw_file" "$scan_file" <<'PY' +import re +import sys + +source_path, output_path = sys.argv[1:] +patterns = { + "fatal-error": re.compile(r"\bfatal error\b", re.IGNORECASE), + "uncaught-exception": re.compile(r"\buncaught (?:objective-c )?exception\b", re.IGNORECASE), + "abort": re.compile(r"\b(?:abort|aborted|sigabrt)\b", re.IGNORECASE), + "migration-failure": re.compile( + r"\b(?:migration|migrate|mapping model)\b.{0,120}\b(?:fail|error|incompatible|missing|abort)\b", + re.IGNORECASE, + ), + "persistent-store-failure": re.compile( + r"\b(?:persistent store|addPersistentStore|NSPersistentStore)\b.{0,120}\b(?:fail|error|incompatible|missing|abort)\b", + re.IGNORECASE, + ), + "core-data-failure": re.compile( + r"\b(?:CoreData|NSCocoaErrorDomain)\b.{0,120}\b(?:fatal|fail|error|exception|abort|incompatible)\b", + re.IGNORECASE, + ), +} + +with open(source_path, "r", encoding="utf-8", errors="ignore") as source: + content = source.read() +matched = sorted(name for name, pattern in patterns.items() if pattern.search(content)) +ready_count = content.count("FEARLESS_STARTUP_READY") +failure_count = content.count("FEARLESS_STARTUP_FAILED") +if ready_count != 1: + matched.append("startup-ready-count") +if failure_count != 0: + matched.append("startup-failure") +matched = sorted(set(matched)) + +with open(output_path, "w", encoding="utf-8") as destination: + if matched: + for name in matched: + destination.write(name + "\n") + else: + destination.write("clean\n") + +sys.exit(1 if matched else 0) +PY + then + : >"$raw_file" + return + fi + + : >"$raw_file" + fail "startup readiness failed or fatal migration/Core Data marker detected during $phase" +} + +terminate_running_app() { + local pid="$1" + local attempts=0 + + "$XCRUN_BIN" simctl terminate "$SIMULATOR_UDID" "$BUNDLE_ID" \ + >/dev/null 2>&1 || + fail "simctl could not terminate the rehearsed app" + APP_RUNNING=0 + + while process_is_expected_and_alive "$pid"; do + attempts=$((attempts + 1)) + [[ "$attempts" -le 5 ]] || + fail "rehearsed app process remained alive after termination" + "$SLEEP_BIN" 1 + done +} + +capture_target_state() { + local phase="$1" + local manifest="$ARTIFACTS_DIR/${phase}-target.sha256" + local audit_directory="$ARTIFACTS_DIR/audits/$phase" + local counts_file="$ARTIFACTS_DIR/${phase}-counts.json" + + require_no_unexpected_files "$CORE_DATA_TARGET" || + fail "target Core Data directory failed strict file validation" + write_family_manifest "$CORE_DATA_TARGET" "$manifest" "0" + mkdir "$audit_directory" + copy_family "$CORE_DATA_TARGET" "$audit_directory" "0" + inspect_sqlite_copies "$audit_directory" "$counts_file" + log_count_summary "$counts_file" "$phase" +} + +run_launch_phase() { + local phase="$1" + local marker="$ARTIFACTS_DIR/${phase}-launch.marker" + local launch_output="$ARTIFACTS_DIR/${phase}-launch-output.pending" + local launch_error="$ARTIFACTS_DIR/${phase}-launch-error.pending" + local start_time + local pid + + : >"$marker" + start_time="$(date -u '+%Y-%m-%d %H:%M:%S%z')" + if ! "$XCRUN_BIN" simctl launch "$SIMULATOR_UDID" "$BUNDLE_ID" \ + >"$launch_output" 2>"$launch_error"; then + : >"$launch_output" + : >"$launch_error" + fail "simctl could not launch the app during $phase" + fi + pid="$(parse_launch_pid "$launch_output")" || + fail "simctl launch did not return one valid app PID" + : >"$launch_output" + : >"$launch_error" + APP_RUNNING=1 + + assert_process_stays_alive "$pid" + scan_for_new_crash_reports "$marker" "${phase}-while-running" + scan_unified_log_markers "$start_time" "$phase" + terminate_running_app "$pid" + scan_for_new_crash_reports "$marker" "${phase}-after-termination" + capture_target_state "$phase" +} + +while [[ "$#" -gt 0 ]]; do + case "$1" in + --simulator-udid) + require_option_value "$1" "$#" + SIMULATOR_UDID="$2" + shift 2 + ;; + --app) + require_option_value "$1" "$#" + APP_PATH="$2" + shift 2 + ;; + --bundle-id) + require_option_value "$1" "$#" + BUNDLE_ID="$2" + shift 2 + ;; + --expected-git-sha) + require_option_value "$1" "$#" + EXPECTED_GIT_SHA="$2" + shift 2 + ;; + --expected-build) + require_option_value "$1" "$#" + EXPECTED_BUILD="$2" + shift 2 + ;; + --expected-executable-sha256) + require_option_value "$1" "$#" + EXPECTED_EXECUTABLE_SHA256="$2" + shift 2 + ;; + --fixture-dir) + require_option_value "$1" "$#" + FIXTURE_DIR="$2" + shift 2 + ;; + --artifacts-dir) + require_option_value "$1" "$#" + ARTIFACTS_DIR="$2" + shift 2 + ;; + --crash-report-dir) + require_option_value "$1" "$#" + CRASH_REPORT_DIR="$2" + shift 2 + ;; + --alive-seconds) + require_option_value "$1" "$#" + ALIVE_SECONDS="$2" + shift 2 + ;; + --confirm-disposable-fixture) + DISPOSABLE_FIXTURE_CONFIRMED=1 + shift + ;; + --dry-run) + DRY_RUN=1 + shift + ;; + --help|-h) + usage + exit 0 + ;; + *) + fail "unknown argument: $1" + ;; + esac +done + +[[ -n "$SIMULATOR_UDID" ]] || fail "--simulator-udid is required" +[[ "$SIMULATOR_UDID" =~ $UUID_PATTERN ]] || + fail "--simulator-udid must be a canonical UUID" +[[ -n "$APP_PATH" ]] || fail "--app is required" +[[ "$APP_PATH" == /* ]] || fail "--app must be an absolute path" +[[ -n "$BUNDLE_ID" ]] || fail "--bundle-id is required" +[[ "$BUNDLE_ID" =~ $BUNDLE_ID_PATTERN ]] || + fail "--bundle-id is malformed" +[[ "$BUNDLE_ID" == "$EXPECTED_BUNDLE_ID" ]] || + fail "--bundle-id must be the production Fearless identity" +[[ "$EXPECTED_GIT_SHA" =~ ^[0-9A-Fa-f]{40}$ ]] || + fail "--expected-git-sha must be an exact 40-hex commit" +[[ "$EXPECTED_BUILD" =~ ^[1-9][0-9]{0,3}(\.[0-9]{1,2}){0,2}$ ]] || + fail "--expected-build must be an explicit canonical CFBundleVersion" +[[ "$EXPECTED_EXECUTABLE_SHA256" =~ ^[0-9A-Fa-f]{64}$ ]] || + fail "--expected-executable-sha256 must be 64 hex" +[[ -n "$FIXTURE_DIR" ]] || fail "--fixture-dir is required" +[[ "$FIXTURE_DIR" == /* ]] || fail "--fixture-dir must be an absolute path" +[[ -n "$ARTIFACTS_DIR" ]] || fail "--artifacts-dir is required" +[[ "$ARTIFACTS_DIR" == /* ]] || fail "--artifacts-dir must be an absolute path" +[[ "$CRASH_REPORT_DIR" == /* ]] || + fail "--crash-report-dir must be an absolute path" +[[ "$ALIVE_SECONDS" =~ ^[0-9]+$ ]] || + fail "--alive-seconds must be an integer" +[[ "$ALIVE_SECONDS" -ge 1 && "$ALIVE_SECONDS" -le 30 ]] || + fail "--alive-seconds must be between 1 and 30" +[[ "$DISPOSABLE_FIXTURE_CONFIRMED" == "1" ]] || + fail "--confirm-disposable-fixture is required" + +require_executable "$XCRUN_BIN" "xcrun" +require_executable "$CODESIGN_BIN" "codesign" +require_executable "$PYTHON_BIN" "Python" +require_executable "$SHASUM_BIN" "shasum" +require_executable "$PS_BIN" "ps" +require_executable "$SLEEP_BIN" "sleep" +if [[ -n "$PROCESS_CHECK_BIN" ]]; then + require_executable "$PROCESS_CHECK_BIN" "process checker" +fi + +[[ -d "$APP_PATH" && ! -L "$APP_PATH" ]] || + fail "--app must name a real .app directory, not a symlink" +[[ "${APP_PATH##*/}" == *.app ]] || + fail "--app must end in .app" +APP_PATH="$(canonical_directory "$APP_PATH")" + +[[ -d "$FIXTURE_DIR" && ! -L "$FIXTURE_DIR" ]] || + fail "--fixture-dir must name a real directory, not a symlink" +FIXTURE_DIR="$(canonical_directory "$FIXTURE_DIR")" + +[[ -d "$CRASH_REPORT_DIR" && ! -L "$CRASH_REPORT_DIR" ]] || + fail "--crash-report-dir must name a real directory" +CRASH_REPORT_DIR="$(canonical_directory "$CRASH_REPORT_DIR")" + +[[ ! -e "$ARTIFACTS_DIR" && ! -L "$ARTIFACTS_DIR" ]] || + fail "--artifacts-dir must not already exist" +artifacts_parent="$(dirname "$ARTIFACTS_DIR")" +artifacts_name="$(basename "$ARTIFACTS_DIR")" +[[ "$artifacts_name" != "." && "$artifacts_name" != ".." ]] || + fail "--artifacts-dir has an unsafe basename" +[[ -d "$artifacts_parent" && ! -L "$artifacts_parent" ]] || + fail "--artifacts-dir parent must be a real existing directory" +artifacts_parent="$(canonical_directory "$artifacts_parent")" +ARTIFACTS_DIR="$artifacts_parent/$artifacts_name" + +if path_is_within "$ARTIFACTS_DIR" "$FIXTURE_DIR" || + path_is_within "$FIXTURE_DIR" "$ARTIFACTS_DIR"; then + fail "artifacts and fixture directories must not overlap" +fi +if path_is_within "$ARTIFACTS_DIR" "$APP_PATH" || + path_is_within "$APP_PATH" "$ARTIFACTS_DIR"; then + fail "artifacts and app directories must not overlap" +fi + +mkdir "$ARTIFACTS_DIR" +mkdir "$ARTIFACTS_DIR/staging" +mkdir "$ARTIFACTS_DIR/audits" + +[[ -f "$APP_PATH/Info.plist" && ! -L "$APP_PATH/Info.plist" ]] || + fail "app Info.plist is missing or unsafe" +actual_bundle_id="$(plist_string "$APP_PATH/Info.plist" "CFBundleIdentifier")" || + fail "unable to read CFBundleIdentifier from the app" +[[ "$actual_bundle_id" == "$BUNDLE_ID" ]] || + fail "explicit bundle ID does not match the app" + +APP_EXECUTABLE_NAME="$(plist_string "$APP_PATH/Info.plist" "CFBundleExecutable")" || + fail "unable to read CFBundleExecutable from the app" +[[ "$APP_EXECUTABLE_NAME" =~ ^[A-Za-z0-9._-]+$ ]] || + fail "app executable name is unsafe" +APP_EXECUTABLE_PATH="$APP_PATH/$APP_EXECUTABLE_NAME" +[[ -f "$APP_EXECUTABLE_PATH" && ! -L "$APP_EXECUTABLE_PATH" && + -x "$APP_EXECUTABLE_PATH" ]] || + fail "app executable is missing, non-regular, symlinked, or not executable" + +build_platform="$("$XCRUN_BIN" vtool -show-build "$APP_EXECUTABLE_PATH" 2>/dev/null)" || + fail "unable to inspect app binary platform" +if ! grep -Eq \ + 'platform[[:space:]]+(IOSSIMULATOR|7)([[:space:]]|$)|LC_VERSION_MIN_IPHONESIMULATOR' \ + <<<"$build_platform"; then + fail "app binary is not an iOS Simulator binary; refusing device app" +fi +if grep -Eq 'platform[[:space:]]+IOS([[:space:]]|$)' <<<"$build_platform"; then + fail "app binary includes an iOS device platform; refusing it" +fi +printf '%s\n' "iOS Simulator binary verified" \ + >"$ARTIFACTS_DIR/app-platform-verification.txt" +validate_app_signature_contract +validate_release_app_contract + +if ! "$XCRUN_BIN" simctl list devices --json \ + >"$ARTIFACTS_DIR/simulator-inventory.pending" 2>/dev/null; then + fail "unable to obtain Simulator inventory" +fi +validate_simulator_inventory "$ARTIFACTS_DIR/simulator-inventory.pending" || + fail "requested destination failed Simulator-only validation" +: >"$ARTIFACTS_DIR/simulator-inventory.pending" +printf '%s\n' "explicit booted iPhone Simulator verified" \ + >"$ARTIFACTS_DIR/simulator-verification.txt" + +validate_fixture_directory "$FIXTURE_DIR" || + fail "fixture failed exact immutable-family validation" +write_family_manifest \ + "$FIXTURE_DIR" \ + "$ARTIFACTS_DIR/source-before.sha256" \ + "1" + +seed_directory="$ARTIFACTS_DIR/staging/seed" +mkdir "$seed_directory" +copy_family "$FIXTURE_DIR" "$seed_directory" "1" +write_family_manifest \ + "$FIXTURE_DIR" \ + "$ARTIFACTS_DIR/source-after-copy.sha256" \ + "1" +cmp -s \ + "$ARTIFACTS_DIR/source-before.sha256" \ + "$ARTIFACTS_DIR/source-after-copy.sha256" || + fail "source fixture changed while it was copied" +write_family_manifest \ + "$seed_directory" \ + "$ARTIFACTS_DIR/seed.sha256" \ + "1" +cmp -s "$ARTIFACTS_DIR/source-before.sha256" "$ARTIFACTS_DIR/seed.sha256" || + fail "private seed copy does not match the source fixture" + +if [[ "$DRY_RUN" == "1" ]]; then + dry_audit="$ARTIFACTS_DIR/audits/dry-run" + mkdir "$dry_audit" + copy_family "$seed_directory" "$dry_audit" "1" + inspect_sqlite_copies "$dry_audit" "$ARTIFACTS_DIR/dry-run-counts.json" + log_count_summary "$ARTIFACTS_DIR/dry-run-counts.json" "dry-run" + write_family_manifest \ + "$FIXTURE_DIR" \ + "$ARTIFACTS_DIR/source-after-run.sha256" \ + "1" + cmp -s \ + "$ARTIFACTS_DIR/source-before.sha256" \ + "$ARTIFACTS_DIR/source-after-run.sha256" || + fail "source fixture changed during dry-run validation" + log "DRY RUN PASSED: inputs are simulator-only, copied stores are intact, source is unchanged" + exit 0 +fi + +if "$XCRUN_BIN" simctl get_app_container \ + "$SIMULATOR_UDID" "$BUNDLE_ID" data \ + >"$ARTIFACTS_DIR/preexisting-data-container.pending" 2>&1; then + : >"$ARTIFACTS_DIR/preexisting-data-container.pending" + fail "bundle already has Simulator data; use a fresh dedicated Simulator" +fi +: >"$ARTIFACTS_DIR/preexisting-data-container.pending" + +if "$XCRUN_BIN" simctl get_app_container \ + "$SIMULATOR_UDID" "$BUNDLE_ID" app \ + >"$ARTIFACTS_DIR/preexisting-app-container.pending" 2>&1; then + : >"$ARTIFACTS_DIR/preexisting-app-container.pending" + fail "bundle is already installed; use a fresh dedicated Simulator" +fi +: >"$ARTIFACTS_DIR/preexisting-app-container.pending" + +if ! "$XCRUN_BIN" simctl install "$SIMULATOR_UDID" "$APP_PATH" \ + >"$ARTIFACTS_DIR/install.pending" 2>&1; then + : >"$ARTIFACTS_DIR/install.pending" + fail "simctl could not install the app" +fi +: >"$ARTIFACTS_DIR/install.pending" + +if ! "$XCRUN_BIN" simctl get_app_container \ + "$SIMULATOR_UDID" "$BUNDLE_ID" data \ + >"$ARTIFACTS_DIR/data-container.pending" 2>/dev/null; then + fail "unable to obtain the installed app data container" +fi +DATA_CONTAINER="$(tr -d '\r\n' <"$ARTIFACTS_DIR/data-container.pending")" +: >"$ARTIFACTS_DIR/data-container.pending" +[[ "$DATA_CONTAINER" == /* && -d "$DATA_CONTAINER" && ! -L "$DATA_CONTAINER" ]] || + fail "simctl returned an unsafe data container" +DATA_CONTAINER="$(canonical_directory "$DATA_CONTAINER")" +[[ "$DATA_CONTAINER" == *"/CoreSimulator/Devices/$SIMULATOR_UDID/data/Containers/Data/Application/"* ]] || + fail "data container is not rooted in the requested Simulator" + +# A newly installed app is not expected to be running. A successful terminate +# is accepted, as is simctl's documented-style "not running" response. +if ! "$XCRUN_BIN" simctl terminate "$SIMULATOR_UDID" "$BUNDLE_ID" \ + >"$ARTIFACTS_DIR/preseed-terminate.pending" 2>&1; then + if ! grep -Eqi 'not running|nothing to terminate|no such process' \ + "$ARTIFACTS_DIR/preseed-terminate.pending"; then + : >"$ARTIFACTS_DIR/preseed-terminate.pending" + fail "could not establish a terminated preseed app state" + fi +fi +: >"$ARTIFACTS_DIR/preseed-terminate.pending" + +write_family_manifest \ + "$FIXTURE_DIR" \ + "$ARTIFACTS_DIR/source-before-injection.sha256" \ + "1" +cmp -s \ + "$ARTIFACTS_DIR/source-before.sha256" \ + "$ARTIFACTS_DIR/source-before-injection.sha256" || + fail "source fixture changed before Simulator injection" + +CORE_DATA_TARGET="$DATA_CONTAINER/Documents/CoreData" +if [[ -e "$CORE_DATA_TARGET" || -L "$CORE_DATA_TARGET" ]]; then + [[ -d "$CORE_DATA_TARGET" && ! -L "$CORE_DATA_TARGET" ]] || + fail "target CoreData path is not a real directory" + if [[ -n "$(find "$CORE_DATA_TARGET" -mindepth 1 -maxdepth 1 -print -quit)" ]]; then + fail "new Simulator app unexpectedly has existing Core Data files" + fi +else + mkdir -p "$CORE_DATA_TARGET" +fi +CORE_DATA_TARGET="$(canonical_directory "$CORE_DATA_TARGET")" +path_is_within "$CORE_DATA_TARGET" "$DATA_CONTAINER" || + fail "target CoreData directory escaped the Simulator data container" + +copy_family "$seed_directory" "$CORE_DATA_TARGET" "1" +require_no_unexpected_files "$CORE_DATA_TARGET" || + fail "injected Core Data family failed strict validation" +write_family_manifest \ + "$CORE_DATA_TARGET" \ + "$ARTIFACTS_DIR/prelaunch-target.sha256" \ + "1" +cmp -s \ + "$ARTIFACTS_DIR/source-before.sha256" \ + "$ARTIFACTS_DIR/prelaunch-target.sha256" || + fail "injected Simulator store family does not match the source" +capture_target_state "prelaunch" + +run_launch_phase "first-launch" +run_launch_phase "relaunch" + +validate_preservation \ + "$ARTIFACTS_DIR/prelaunch-counts.json" \ + "$ARTIFACTS_DIR/first-launch-counts.json" \ + "$ARTIFACTS_DIR/relaunch-counts.json" || + fail "protected Core Data counts were not preserved" + +write_family_manifest \ + "$FIXTURE_DIR" \ + "$ARTIFACTS_DIR/source-after-run.sha256" \ + "1" +cmp -s \ + "$ARTIFACTS_DIR/source-before.sha256" \ + "$ARTIFACTS_DIR/source-after-run.sha256" || + fail "source fixture changed during the rehearsal" + +log "PASSED: first launch and relaunch each reached a usable startup route with no crash or fatal migration/Core Data marker" +log "PASSED: copied stores remain intact; protected wallet and custom-node topology fingerprints are preserved" +log "PASSED: signed Simulator Release/-O/non-testable artifact, exact commit/version/build/executable hash, 26 managed-object classes, and 29 migration resources verified; source fixture is unchanged" +log "NOTE: device distribution profile, production entitlements, and TestFlight Keychain capability require audit-ios-signed-release-artifact.sh against the exact .xcarchive" diff --git a/scripts/ci/run-pr.sh b/scripts/ci/run-pr.sh index 9ecdc79809..d85ea4efbc 100755 --- a/scripts/ci/run-pr.sh +++ b/scripts/ci/run-pr.sh @@ -23,6 +23,10 @@ if [[ -f "$WORKSPACE_DIR/scripts/audit-todo-debt.sh" ]]; then bash "$WORKSPACE_DIR/scripts/audit-todo-debt.sh" fi +echo "[run-pr] Verifying tracked TestFlight publication evidence" +bash "$WORKSPACE_DIR/scripts/test-testflight-publication-readiness-audit.sh" +bash "$WORKSPACE_DIR/scripts/audit-testflight-publication-readiness.sh" + if [[ -f "$WORKSPACE_DIR/scripts/check-iroha-mobile-sdk-release-assets.sh" ]]; then echo "[run-pr] Checking Iroha mobile SDK release asset contract" bash "$WORKSPACE_DIR/scripts/check-iroha-mobile-sdk-release-assets.sh" --self-test diff --git a/scripts/storage/audit-cdmetaaccount-codable-contract.sh b/scripts/storage/audit-cdmetaaccount-codable-contract.sh new file mode 100755 index 0000000000..4fda28bb6f --- /dev/null +++ b/scripts/storage/audit-cdmetaaccount-codable-contract.sh @@ -0,0 +1,261 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +readonly ROOT_DIR="${FEARLESS_CDMETAACCOUNT_CODABLE_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd -P)}" +readonly SOURCE_DIR="$ROOT_DIR/fearless" +readonly PYTHON_BIN="${FEARLESS_CDMETAACCOUNT_CODABLE_PYTHON_BIN:-python3}" +readonly LOG_PREFIX="[cdmetaaccount-codable-audit]" + +fail() { + printf '%s ERROR: %s\n' "$LOG_PREFIX" "$*" >&2 + exit 1 +} + +if [[ "$PYTHON_BIN" == */* ]]; then + [[ -x "$PYTHON_BIN" ]] || fail "python interpreter is not executable" +else + command -v "$PYTHON_BIN" >/dev/null 2>&1 || + fail "python3 is required" +fi + +[[ -d "$SOURCE_DIR" && ! -L "$SOURCE_DIR" ]] || + fail "fearless source directory is missing or unsafe" + +"$PYTHON_BIN" - "$SOURCE_DIR" <<'PY' +import bisect +import os +import re +import sys +from dataclasses import dataclass +from pathlib import Path +from typing import Optional + +source_dir = Path(sys.argv[1]).resolve() +token_pattern = re.compile(r"[A-Za-z_][A-Za-z0-9_]*|[<>{}:,.()\[\]]") +declaration_keywords = {"extension", "class", "struct", "enum", "actor"} + + +@dataclass(frozen=True) +class Token: + value: str + offset: int + + +def mask_comments(source: str) -> str: + """Remove line and nested block comments while preserving source offsets.""" + masked = list(source) + index = 0 + size = len(source) + + def blank(start: int, end: int) -> None: + for position in range(start, end): + if masked[position] not in "\r\n": + masked[position] = " " + + while index < size: + if source.startswith("//", index): + end = source.find("\n", index + 2) + if end == -1: + end = size + blank(index, end) + index = end + continue + + if source.startswith("/*", index): + start = index + depth = 1 + index += 2 + while index < size and depth: + if source.startswith("/*", index): + depth += 1 + index += 2 + elif source.startswith("*/", index): + depth -= 1 + index += 2 + else: + index += 1 + blank(start, index) + continue + + index += 1 + + return "".join(masked) + + +def line_number(line_offsets: list[int], offset: int) -> int: + return bisect.bisect_right(line_offsets, offset) + + +def direct_conformance(tokens: list[Token], start: int) -> Optional[Token]: + angle_depth = 0 + top_level_identifiers: list[Token] = [] + colon_index = None + + for index in range(start + 1, len(tokens)): + token = tokens[index] + if token.value == "<": + angle_depth += 1 + elif token.value == ">": + angle_depth = max(0, angle_depth - 1) + elif angle_depth == 0 and token.value in {"{", "where"}: + break + elif angle_depth == 0 and token.value == ":": + colon_index = index + break + elif angle_depth == 0 and token.value[0].isalpha(): + top_level_identifiers.append(token) + + if colon_index is None or not top_level_identifiers: + return None + if top_level_identifiers[-1].value != "CDMetaAccount": + return None + + angle_depth = 0 + for token in tokens[colon_index + 1:]: + if token.value == "<": + angle_depth += 1 + elif token.value == ">": + angle_depth = max(0, angle_depth - 1) + elif angle_depth == 0 and token.value in {"{", "where"}: + break + elif token.value == "CoreDataCodable": + return token + + return None + + +def mapper_second_argument(tokens: list[Token], start: int) -> Optional[Token]: + if start + 1 >= len(tokens) or tokens[start + 1].value != "<": + return None + + angle_depth = 1 + parenthesis_depth = 0 + bracket_depth = 0 + argument_index = 0 + + for token in tokens[start + 2:]: + if token.value == "<": + angle_depth += 1 + elif token.value == ">": + angle_depth -= 1 + if angle_depth == 0: + break + elif token.value == "(": + parenthesis_depth += 1 + elif token.value == ")": + parenthesis_depth = max(0, parenthesis_depth - 1) + elif token.value == "[": + bracket_depth += 1 + elif token.value == "]": + bracket_depth = max(0, bracket_depth - 1) + elif ( + token.value == "," + and angle_depth == 1 + and parenthesis_depth == 0 + and bracket_depth == 0 + ): + argument_index += 1 + continue + + if argument_index == 1 and token.value == "CDMetaAccount": + return token + + return None + + +violations: list[tuple[str, int, str]] = [] +swift_files: list[Path] = [] + +for directory, directory_names, file_names in os.walk(source_dir, followlinks=False): + directory_names.sort() + file_names.sort() + for directory_name in directory_names: + candidate = Path(directory, directory_name) + if candidate.is_symlink(): + relative = candidate.relative_to(source_dir) + print( + f"[cdmetaaccount-codable-audit] ERROR: " + f"symlinked source directory is forbidden: fearless/{relative}", + file=sys.stderr, + ) + raise SystemExit(1) + for file_name in file_names: + if not file_name.endswith(".swift"): + continue + candidate = Path(directory, file_name) + if candidate.is_symlink() or not candidate.is_file(): + relative = candidate.relative_to(source_dir) + print( + f"[cdmetaaccount-codable-audit] ERROR: " + f"unsafe Swift source is forbidden: fearless/{relative}", + file=sys.stderr, + ) + raise SystemExit(1) + swift_files.append(candidate) + +if not swift_files: + print( + "[cdmetaaccount-codable-audit] ERROR: no Swift source files were found", + file=sys.stderr, + ) + raise SystemExit(1) + +for path in swift_files: + try: + source = path.read_text(encoding="utf-8") + except (OSError, UnicodeError) as error: + print( + f"[cdmetaaccount-codable-audit] ERROR: unreadable Swift source " + f"{path}: {error}", + file=sys.stderr, + ) + raise SystemExit(1) + + code = mask_comments(source) + tokens = [ + Token(match.group(0), match.start()) + for match in token_pattern.finditer(code) + ] + line_offsets = [0] + line_offsets.extend( + index + 1 + for index, character in enumerate(source) + if character == "\n" + ) + relative = f"fearless/{path.relative_to(source_dir)}" + + for index, token in enumerate(tokens): + if token.value in declaration_keywords: + violation = direct_conformance(tokens, index) + if violation is not None: + violations.append( + ( + relative, + line_number(line_offsets, violation.offset), + "CDMetaAccount must not directly conform to CoreDataCodable", + ) + ) + elif token.value == "CodableCoreDataMapper": + violation = mapper_second_argument(tokens, index) + if violation is not None: + violations.append( + ( + relative, + line_number(line_offsets, violation.offset), + "CodableCoreDataMapper must not target CDMetaAccount", + ) + ) + +if violations: + for path, line, message in sorted(set(violations)): + print( + f"[cdmetaaccount-codable-audit] ERROR: {path}:{line}: {message}", + file=sys.stderr, + ) + raise SystemExit(1) + +print( + "[cdmetaaccount-codable-audit] PASS: explicit MetaAccountMapper boundary preserved" +) +PY diff --git a/scripts/storage/audit-user-storage-compatibility-models.sh b/scripts/storage/audit-user-storage-compatibility-models.sh new file mode 100755 index 0000000000..567ba5c345 --- /dev/null +++ b/scripts/storage/audit-user-storage-compatibility-models.sh @@ -0,0 +1,137 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +MODELS_ROOT="${FEARLESS_COMPATIBILITY_MODELS_ROOT:-$ROOT_DIR/fearless/Common/Storage/CompatibilityModels}" +SOURCE_DIR="$MODELS_ROOT/Source" +COMPILED_DIR="$MODELS_ROOT/Compiled" +COMPILER="$SCRIPT_DIR/compile-user-storage-compatibility-models.sh" +CHECKSUM_SOURCE="$SCRIPT_DIR/core-data-model-checksum.swift" + +LEGACY_MODEL="LegacyEcosystemUserDataModel_v12" +TARGET_MODEL="CompatibleUserDataModel_v13" +EXPECTED_LEGACY_CHECKSUM="+oGDYB1AZIk54P/liFbJ3aXArqvhW7YLFAy04AChJ+s=" +EXPECTED_TARGET_CHECKSUM="dX3y/Aa+rMRI3ZxRibOGIkyCHwrc0zgNO9OoBnS5G/Y=" + +fail() { + echo "[user-storage-model-audit][error] $*" >&2 + exit 1 +} + +require_nonempty_file() { + local path="$1" + local description="$2" + + [[ -f "$path" ]] || fail "$description is missing: $path" + [[ -s "$path" ]] || fail "$description is empty: $path" +} + +validate_xml() { + local path="$1" + + if ! xmllint --noout "$path" 2>/dev/null; then + fail "source model is not well-formed XML: $path" + fi +} + +require_attribute() { + local path="$1" + local model_description="$2" + local entity="$3" + local attribute="$4" + local type="$5" + local optional="$6" + local xpath + local count + + xpath="count(/model/entity[@name='$entity']/attribute[@name='$attribute' and @attributeType='$type' and @optional='$optional'])" + count="$(xmllint --xpath "$xpath" "$path" 2>/dev/null)" || + fail "unable to inspect $model_description source: $path" + + [[ "$count" == "1" ]] || + fail "$model_description must define exactly one optional $type $entity.$attribute attribute; found $count" +} + +command -v xmllint >/dev/null 2>&1 || fail "xmllint is required" +command -v xcrun >/dev/null 2>&1 || fail "xcrun is required" +require_nonempty_file "$COMPILER" "compatibility model compiler" +require_nonempty_file "$CHECKSUM_SOURCE" "Core Data checksum inspector" + +legacy_source="$SOURCE_DIR/$LEGACY_MODEL.xcdatamodel/contents" +target_source="$SOURCE_DIR/$TARGET_MODEL.xcdatamodel/contents" +legacy_compiled="$COMPILED_DIR/$LEGACY_MODEL.mom" +target_compiled="$COMPILED_DIR/$TARGET_MODEL.mom" + +require_nonempty_file "$legacy_source" "legacy source model" +require_nonempty_file "$target_source" "target source model" +require_nonempty_file "$legacy_compiled" "compiled legacy model" +require_nonempty_file "$target_compiled" "compiled target model" +validate_xml "$legacy_source" +validate_xml "$target_source" + +for source_spec in \ + "$legacy_source|legacy model" \ + "$target_source|target model"; do + source_path="${source_spec%%|*}" + source_description="${source_spec#*|}" + require_attribute "$source_path" "$source_description" "CDChainAccount" "ecosystem" "String" "YES" + require_attribute "$source_path" "$source_description" "CDMetaAccount" "tonAddress" "Binary" "YES" + require_attribute "$source_path" "$source_description" "CDMetaAccount" "tonContractVersion" "String" "YES" + require_attribute "$source_path" "$source_description" "CDMetaAccount" "tonPublicKey" "Binary" "YES" +done +require_attribute "$target_source" "target model" "CDChainAccount" "ethereumBased" "Boolean" "YES" + +temporary_dir="$(mktemp -d "${TMPDIR:-/private/tmp}/fearless-user-storage-audit.XXXXXX")" +trap 'rm -rf "$temporary_dir"' EXIT + +FEARLESS_COMPATIBILITY_MODELS_ROOT="$MODELS_ROOT" \ + "$COMPILER" --output-dir "$temporary_dir/generated" >/dev/null + +generated_legacy="$temporary_dir/generated/$LEGACY_MODEL.mom" +generated_target="$temporary_dir/generated/$TARGET_MODEL.mom" +require_nonempty_file "$generated_legacy" "generated legacy model" +require_nonempty_file "$generated_target" "generated target model" + +checksum_binary="$temporary_dir/core-data-model-checksum" +module_cache="$temporary_dir/module-cache" +mkdir -p "$module_cache" +if ! CLANG_MODULE_CACHE_PATH="$module_cache" \ + SWIFT_MODULECACHE_PATH="$module_cache" \ + xcrun swiftc "$CHECKSUM_SOURCE" -o "$checksum_binary"; then + fail "unable to compile the Core Data checksum inspector" +fi + +checksum_for_model() { + local path="$1" + local checksum + + if ! checksum="$("$checksum_binary" "$path" 2>/dev/null)"; then + fail "Core Data model cannot be loaded: $path" + fi + [[ -n "$checksum" ]] || fail "Core Data model has an empty checksum: $path" + printf '%s\n' "$checksum" +} + +generated_legacy_checksum="$(checksum_for_model "$generated_legacy")" +committed_legacy_checksum="$(checksum_for_model "$legacy_compiled")" +generated_target_checksum="$(checksum_for_model "$generated_target")" +committed_target_checksum="$(checksum_for_model "$target_compiled")" + +[[ "$generated_legacy_checksum" == "$EXPECTED_LEGACY_CHECKSUM" ]] || + fail "legacy source checksum changed: expected $EXPECTED_LEGACY_CHECKSUM, got $generated_legacy_checksum" +[[ "$committed_legacy_checksum" == "$EXPECTED_LEGACY_CHECKSUM" ]] || + fail "compiled legacy checksum changed: expected $EXPECTED_LEGACY_CHECKSUM, got $committed_legacy_checksum" +[[ "$generated_target_checksum" == "$EXPECTED_TARGET_CHECKSUM" ]] || + fail "target source checksum changed: expected $EXPECTED_TARGET_CHECKSUM, got $generated_target_checksum" +[[ "$committed_target_checksum" == "$EXPECTED_TARGET_CHECKSUM" ]] || + fail "compiled target checksum changed: expected $EXPECTED_TARGET_CHECKSUM, got $committed_target_checksum" + +[[ "$generated_legacy_checksum" == "$committed_legacy_checksum" ]] || + fail "compiled legacy model is stale: generated $generated_legacy_checksum, committed $committed_legacy_checksum" +[[ "$generated_target_checksum" == "$committed_target_checksum" ]] || + fail "compiled target model is stale: generated $generated_target_checksum, committed $committed_target_checksum" + +echo "[user-storage-model-audit] PASS" +echo "[user-storage-model-audit] Legacy checksum: $committed_legacy_checksum" +echo "[user-storage-model-audit] Target checksum: $committed_target_checksum" diff --git a/scripts/storage/compile-user-storage-compatibility-models.sh b/scripts/storage/compile-user-storage-compatibility-models.sh new file mode 100755 index 0000000000..9b7ce5189f --- /dev/null +++ b/scripts/storage/compile-user-storage-compatibility-models.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +MODELS_ROOT="${FEARLESS_COMPATIBILITY_MODELS_ROOT:-$ROOT_DIR/fearless/Common/Storage/CompatibilityModels}" +SOURCE_DIR="$MODELS_ROOT/Source" +OUTPUT_DIR="$MODELS_ROOT/Compiled" +DEPLOYMENT_TARGET="${FEARLESS_COMPATIBILITY_MODELS_DEPLOYMENT_TARGET:-14.1}" + +usage() { + cat <<'EOF' +Usage: compile-user-storage-compatibility-models.sh [--output-dir PATH] + +Compiles the repo-owned user-storage compatibility models with Xcode's Core +Data model compiler. The default output is the checked-in Compiled directory. + +Environment: + FEARLESS_COMPATIBILITY_MODELS_ROOT + Override the CompatibilityModels root (used by adversarial tests). + FEARLESS_COMPATIBILITY_MODELS_DEPLOYMENT_TARGET + Override the iOS deployment target passed to momc (default: 14.1). +EOF +} + +while [[ "$#" -gt 0 ]]; do + case "$1" in + --output-dir) + [[ "$#" -ge 2 ]] || { + echo "[user-storage-model-compile][error] --output-dir requires a path" >&2 + exit 64 + } + OUTPUT_DIR="$2" + shift 2 + ;; + --help|-h) + usage + exit 0 + ;; + *) + echo "[user-storage-model-compile][error] unknown argument: $1" >&2 + usage >&2 + exit 64 + ;; + esac +done + +command -v xcrun >/dev/null 2>&1 || { + echo "[user-storage-model-compile][error] xcrun is required" >&2 + exit 69 +} + +model_names=( + "LegacyEcosystemUserDataModel_v12" + "CompatibleUserDataModel_v13" +) + +for model_name in "${model_names[@]}"; do + source_path="$SOURCE_DIR/$model_name.xcdatamodel" + [[ -f "$source_path/contents" ]] || { + echo "[user-storage-model-compile][error] source model missing: $source_path/contents" >&2 + exit 66 + } +done + +sdk_root="$(xcrun --sdk iphoneos --show-sdk-path)" +temporary_dir="$(mktemp -d "${TMPDIR:-/private/tmp}/fearless-user-storage-models.XXXXXX")" +trap 'rm -rf "$temporary_dir"' EXIT + +for model_name in "${model_names[@]}"; do + xcrun momc \ + --sdkroot="$sdk_root" \ + --iphoneos-deployment-target "$DEPLOYMENT_TARGET" \ + --no-warnings \ + "$SOURCE_DIR/$model_name.xcdatamodel" \ + "$temporary_dir/$model_name.mom" + + [[ -s "$temporary_dir/$model_name.mom" ]] || { + echo "[user-storage-model-compile][error] momc produced an empty model: $model_name" >&2 + exit 65 + } +done + +mkdir -p "$OUTPUT_DIR" +for model_name in "${model_names[@]}"; do + cp "$temporary_dir/$model_name.mom" "$OUTPUT_DIR/$model_name.mom" + chmod 0644 "$OUTPUT_DIR/$model_name.mom" +done + +echo "[user-storage-model-compile] Compiled ${#model_names[@]} models into $OUTPUT_DIR" diff --git a/scripts/storage/core-data-model-checksum.swift b/scripts/storage/core-data-model-checksum.swift new file mode 100644 index 0000000000..1d4580a6b9 --- /dev/null +++ b/scripts/storage/core-data-model-checksum.swift @@ -0,0 +1,21 @@ +import CoreData +import Darwin +import Foundation + +guard CommandLine.arguments.count > 1 else { + fputs("usage: core-data-model-checksum.swift [...]\n", stderr) + exit(EX_USAGE) +} + +for path in CommandLine.arguments.dropFirst() { + let url = URL(fileURLWithPath: path) + + guard let model = NSManagedObjectModel(contentsOf: url) else { + fputs("unable to load Core Data model: \(path)\n", stderr) + exit(EX_DATAERR) + } + + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + print(model.versionChecksum) + withExtendedLifetime(coordinator) {} +} diff --git a/scripts/storage/test-cdmetaaccount-codable-contract.sh b/scripts/storage/test-cdmetaaccount-codable-contract.sh new file mode 100755 index 0000000000..4a774ef4dd --- /dev/null +++ b/scripts/storage/test-cdmetaaccount-codable-contract.sh @@ -0,0 +1,147 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +readonly AUDIT_SCRIPT="$SCRIPT_DIR/audit-cdmetaaccount-codable-contract.sh" +readonly TEMPORARY_DIR="$( + mktemp -d "${TMPDIR:-/private/tmp}/fearless-cdmetaaccount-codable-tests.XXXXXX" +)" +trap 'rm -rf "$TEMPORARY_DIR"' EXIT + +fail() { + printf '%s ERROR: %s\n' "[cdmetaaccount-codable-audit-test]" "$*" >&2 + exit 1 +} + +new_fixture() { + local name="$1" + local fixture="$TEMPORARY_DIR/$name" + mkdir -p "$fixture/fearless" + printf '%s\n' "$fixture" +} + +run_audit() { + local fixture="$1" + FEARLESS_CDMETAACCOUNT_CODABLE_ROOT="$fixture" \ + bash "$AUDIT_SCRIPT" 2>&1 +} + +expect_success() { + local label="$1" + local fixture="$2" + local output + + if ! output="$(run_audit "$fixture")"; then + fail "$label unexpectedly failed: $output" + fi + [[ "$output" == *"PASS: explicit MetaAccountMapper boundary preserved"* ]] || + fail "$label did not emit the success contract: $output" + printf '%s\n' "[cdmetaaccount-codable-audit-test] PASS: $label" +} + +expect_failure() { + local label="$1" + local expected_message="$2" + local fixture="$3" + local output + local status + + set +e + output="$(run_audit "$fixture")" + status=$? + set -e + + [[ "$status" -ne 0 ]] || fail "$label unexpectedly passed" + [[ "$output" == *"$expected_message"* ]] || + fail "$label failed without '$expected_message': $output" + printf '%s\n' "[cdmetaaccount-codable-audit-test] PASS (rejected): $label" +} + +bash "$AUDIT_SCRIPT" >/dev/null +printf '%s\n' "[cdmetaaccount-codable-audit-test] PASS: canonical source" + +[[ -x /usr/bin/python3 ]] || + fail "macOS system Python is required for the compatibility self-test" +FEARLESS_CDMETAACCOUNT_CODABLE_PYTHON_BIN=/usr/bin/python3 \ + bash "$AUDIT_SCRIPT" >/dev/null +printf '%s\n' "[cdmetaaccount-codable-audit-test] PASS: macOS system Python" + +fixture="$(new_fixture safe-boundaries)" +cat >"$fixture/fearless/Safe.swift" <<'SWIFT' +struct CDMetaAccountSnapshot: CoreDataCodable {} +let mapper: CodableCoreDataMapper + +// extension CDMetaAccount: CoreDataCodable {} +/* + let dormantExample: CodableCoreDataMapper + */ +SWIFT +expect_success "token boundaries and comments" "$fixture" + +fixture="$(new_fixture direct-extension)" +cat >"$fixture/fearless/Dangerous.swift" <<'SWIFT' +extension CDMetaAccount: CoreDataCodable {} +SWIFT +expect_failure \ + "direct empty-codec extension" \ + "CDMetaAccount must not directly conform to CoreDataCodable" \ + "$fixture" + +fixture="$(new_fixture adversarial-extension)" +cat >"$fixture/fearless/Dangerous.swift" <<'SWIFT' +extension + SSFAccountManagmentStorage + .CDMetaAccount + : Sendable, + /* whitespace and comments must not hide the conformance */ + CoreDataCodable +{} +SWIFT +expect_failure \ + "qualified multiline conformance" \ + "CDMetaAccount must not directly conform to CoreDataCodable" \ + "$fixture" + +fixture="$(new_fixture direct-class-conformance)" +cat >"$fixture/fearless/Dangerous.swift" <<'SWIFT' +final class CDMetaAccount: NSManagedObject, CoreDataCodable {} +SWIFT +expect_failure \ + "direct class conformance" \ + "CDMetaAccount must not directly conform to CoreDataCodable" \ + "$fixture" + +fixture="$(new_fixture direct-codable-mapper)" +cat >"$fixture/fearless/Dangerous.swift" <<'SWIFT' +let mapper: CodableCoreDataMapper +SWIFT +expect_failure \ + "direct CodableCoreDataMapper" \ + "CodableCoreDataMapper must not target CDMetaAccount" \ + "$fixture" + +fixture="$(new_fixture adversarial-codable-mapper)" +cat >"$fixture/fearless/Dangerous.swift" <<'SWIFT' +let mapper: RobinHood.CodableCoreDataMapper< + Dictionary, + /* the explicit wallet mapper remains mandatory */ + SSFAccountManagmentStorage + .CDMetaAccount +> +SWIFT +expect_failure \ + "qualified multiline nested-generic CodableCoreDataMapper" \ + "CodableCoreDataMapper must not target CDMetaAccount" \ + "$fixture" + +fixture="$(new_fixture wrapped-codable-mapper)" +cat >"$fixture/fearless/Dangerous.swift" <<'SWIFT' +let mapper: CodableCoreDataMapper> +SWIFT +expect_failure \ + "wrapped CDMetaAccount CodableCoreDataMapper" \ + "CodableCoreDataMapper must not target CDMetaAccount" \ + "$fixture" + +printf '%s\n' \ + "[cdmetaaccount-codable-audit-test] PASS: 3 positive + 6 negative/adversarial cases" diff --git a/scripts/storage/test-user-storage-compatibility-model-audit.sh b/scripts/storage/test-user-storage-compatibility-model-audit.sh new file mode 100755 index 0000000000..af958a2b27 --- /dev/null +++ b/scripts/storage/test-user-storage-compatibility-model-audit.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +AUDIT_SCRIPT="$SCRIPT_DIR/audit-user-storage-compatibility-models.sh" +SOURCE_MODELS="$ROOT_DIR/fearless/Common/Storage/CompatibilityModels" +temporary_dir="$(mktemp -d "${TMPDIR:-/private/tmp}/fearless-user-storage-audit-tests.XXXXXX")" +trap 'rm -rf "$temporary_dir"' EXIT + +fail() { + echo "[user-storage-model-audit-test][error] $*" >&2 + exit 1 +} + +new_fixture() { + local name="$1" + local fixture="$temporary_dir/$name" + + mkdir -p "$fixture" + cp -R "$SOURCE_MODELS/." "$fixture/" + printf '%s\n' "$fixture" +} + +expect_failure() { + local label="$1" + local expected_message="$2" + local fixture="$3" + local output + local status + + set +e + output="$(FEARLESS_COMPATIBILITY_MODELS_ROOT="$fixture" "$AUDIT_SCRIPT" 2>&1)" + status=$? + set -e + + [[ "$status" -ne 0 ]] || fail "$label unexpectedly passed" + [[ "$output" == *"$expected_message"* ]] || + fail "$label failed without expected message '$expected_message': $output" + echo "[user-storage-model-audit-test] PASS (rejected): $label" +} + +FEARLESS_COMPATIBILITY_MODELS_ROOT="$SOURCE_MODELS" "$AUDIT_SCRIPT" >/dev/null +echo "[user-storage-model-audit-test] PASS: canonical models" + +fixture="$(new_fixture legacy-checksum-mutation)" +perl -0pi -e \ + 's/name="canExportEthereumMnemonic"/name="canExportEthereumMnemonicChanged"/' \ + "$fixture/Source/LegacyEcosystemUserDataModel_v12.xcdatamodel/contents" +expect_failure "mutated immutable legacy schema" "legacy source checksum changed" "$fixture" + +fixture="$(new_fixture target-ecosystem-removal)" +perl -0pi -e 's/name="ecosystem"/name="ecosystemRemoved"/' \ + "$fixture/Source/CompatibleUserDataModel_v13.xcdatamodel/contents" +expect_failure "target missing ecosystem" "CDChainAccount.ecosystem" "$fixture" + +fixture="$(new_fixture target-ton-removal)" +perl -0pi -e 's/name="tonAddress"/name="tonAddressRemoved"/' \ + "$fixture/Source/CompatibleUserDataModel_v13.xcdatamodel/contents" +expect_failure "target missing TON address" "CDMetaAccount.tonAddress" "$fixture" + +fixture="$(new_fixture target-ethereum-based-removal)" +perl -0pi -e 's/name="ethereumBased"/name="ethereumBasedRemoved"/' \ + "$fixture/Source/CompatibleUserDataModel_v13.xcdatamodel/contents" +expect_failure "target missing public ethereum flag" "CDChainAccount.ethereumBased" "$fixture" + +fixture="$(new_fixture duplicate-required-field)" +perl -0pi -e \ + 's|()|$1\n $1|' \ + "$fixture/Source/CompatibleUserDataModel_v13.xcdatamodel/contents" +expect_failure "duplicate compatibility field" "CDChainAccount.ecosystem attribute; found 2" "$fixture" + +fixture="$(new_fixture malformed-source)" +printf '%s\n' '' > \ + "$fixture/Source/CompatibleUserDataModel_v13.xcdatamodel/contents" +expect_failure "malformed source XML" "source model is not well-formed XML" "$fixture" + +fixture="$(new_fixture empty-compiled-model)" +: > "$fixture/Compiled/CompatibleUserDataModel_v13.mom" +expect_failure "empty compiled target" "compiled target model is empty" "$fixture" + +fixture="$(new_fixture corrupt-compiled-model)" +printf '%s\n' 'not a Core Data model' > \ + "$fixture/Compiled/CompatibleUserDataModel_v13.mom" +expect_failure "corrupt compiled target" "Core Data model cannot be loaded" "$fixture" + +fixture="$(new_fixture stale-compiled-model)" +cp "$fixture/Compiled/LegacyEcosystemUserDataModel_v12.mom" \ + "$fixture/Compiled/CompatibleUserDataModel_v13.mom" +expect_failure "stale compiled target" "compiled target checksum changed" "$fixture" + +echo "[user-storage-model-audit-test] PASS: 1 canonical + 9 negative/adversarial cases" diff --git a/scripts/test-codecov-coverage-contract.sh b/scripts/test-codecov-coverage-contract.sh new file mode 100755 index 0000000000..0dd04e9ad8 --- /dev/null +++ b/scripts/test-codecov-coverage-contract.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +AUDIT="$ROOT_DIR/scripts/audit-codecov-coverage-contract.sh" +SOURCE="$ROOT_DIR/.github/workflows/codecov.yml" +mkdir -p "$ROOT_DIR/build/test-tmp" +tmp_dir="$(mktemp -d "$ROOT_DIR/build/test-tmp/codecov-coverage-contract.XXXXXX")" +trap 'rm -rf "$tmp_dir"' EXIT + +fail() { + echo "[codecov-coverage-contract-test][error] $*" >&2 + exit 1 +} + +expect_rejected() { + local label="$1" + local workflow="$tmp_dir/$negative_count.yml" + local output="$tmp_dir/$negative_count.log" + cp "$SOURCE" "$workflow" + shift + "$@" "$workflow" + if "$AUDIT" "$workflow" > "$output" 2>&1; then + fail "$label unexpectedly passed" + fi + negative_count=$((negative_count + 1)) +} + +delete_text() { + local text="$1" + local workflow="$2" + TEXT="$text" perl -0pi -e 's/\Q$ENV{TEXT}\E//' "$workflow" +} + +replace_text() { + local from="$1" + local to="$2" + local workflow="$3" + FROM="$from" TO="$to" perl -0pi -e \ + 's/\Q$ENV{FROM}\E/$ENV{TO}/ or die "fixture mutation missed\n"' \ + "$workflow" +} + +"$AUDIT" "$SOURCE" >/dev/null +positive_count=1 +negative_count=0 + +expect_rejected \ + "coverage generation removed" \ + delete_text "-enableCodeCoverage YES" +expect_rejected \ + "result bundle removed" \ + delete_text '-resultBundlePath "$RESULT_BUNDLE"' +expect_rejected \ + "profdata fail-closed check removed" \ + delete_text "-type f -name '*.profdata' -print -quit" +expect_rejected \ + "profdata readability check removed" \ + delete_text 'xcrun llvm-profdata show "$COVERAGE_PROFILE"' +expect_rejected \ + "Codecov upload made non-blocking" \ + replace_text "fail_ci_if_error: true" "fail_ci_if_error: false" +expect_rejected \ + "Codecov OIDC removed" \ + replace_text "use_oidc: true" "use_oidc: false" +expect_rejected \ + "mutable Codecov action reference" \ + replace_text \ + "codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f" \ + "codecov/codecov-action@v7" + +[[ "$positive_count" == "1" && "$negative_count" == "7" ]] || + fail "unexpected test counts: $positive_count positive, $negative_count negative" + +echo \ + "[codecov-coverage-contract-test] $positive_count positive + $negative_count adversarial cases passed" diff --git a/scripts/test-coredata-release-gate.sh b/scripts/test-coredata-release-gate.sh new file mode 100644 index 0000000000..4cc9dd5057 --- /dev/null +++ b/scripts/test-coredata-release-gate.sh @@ -0,0 +1,526 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +readonly GATE="$SCRIPT_DIR/ci/run-coredata-release-gate.sh" +readonly CDMETAACCOUNT_CODABLE_TEST="$SCRIPT_DIR/storage/test-cdmetaaccount-codable-contract.sh" +readonly TEMPORARY_DIR="$(mktemp -d "${TMPDIR:-/private/tmp}/fearless-coredata-gate-tests.XXXXXX")" +trap 'rm -rf "$TEMPORARY_DIR"' EXIT + +readonly FIXTURE_ROOT="$TEMPORARY_DIR/repository" +readonly BIN_DIR="$TEMPORARY_DIR/bin" +readonly PHONE_FIXTURE="$TEMPORARY_DIR/SubstrateDataModel.sqlite" +readonly SIMULATOR_UDID="11111111-2222-3333-4444-555555555555" +readonly OTHER_SIMULATOR_UDID="AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE" + +RUN_NUMBER=0 +RUN_DIRECTORY="" +CASE_ENV=() +GATE_ARGS=() + +fail() { + printf '%s\n' "[coredata-release-gate-test][error] $*" >&2 + exit 1 +} + +assert_output_contains() { + local expected="$1" + local file="$2" + grep -Fq -- "$expected" "$file" || + fail "expected '$expected' in $(basename "$file")" +} + +assert_argument_once() { + local expected="$1" + local count + count="$(grep -Fxc -- "$expected" "$RUN_DIRECTORY/arguments" || true)" + [[ "$count" == "1" ]] || + fail "expected exactly one xcodebuild argument '$expected', found $count" +} + +run_gate() { + local label="$1" + RUN_NUMBER=$((RUN_NUMBER + 1)) + RUN_DIRECTORY="$TEMPORARY_DIR/run-${RUN_NUMBER}-${label}" + mkdir -p "$RUN_DIRECTORY" + + env \ + FEARLESS_CORE_DATA_TEST_HARNESS=1 \ + FEARLESS_CORE_DATA_ROOT_DIR="$FIXTURE_ROOT" \ + FEARLESS_CORE_DATA_XCODEBUILD_BIN="$BIN_DIR/xcodebuild" \ + FEARLESS_CORE_DATA_XCRUN_BIN="$BIN_DIR/xcrun" \ + FEARLESS_CORE_DATA_PYTHON_BIN="${PYTHON_BIN:-python3}" \ + FAKE_ARGUMENT_LOG="$RUN_DIRECTORY/arguments" \ + FAKE_ENVIRONMENT_LOG="$RUN_DIRECTORY/environment" \ + FAKE_SIMULATOR_UDID="$SIMULATOR_UDID" \ + FAKE_OTHER_SIMULATOR_UDID="$OTHER_SIMULATOR_UDID" \ + FAKE_CORE_MANIFEST="$SCRIPT_DIR/ci/manifests/coredata-release-core-tests.txt" \ + FAKE_PHONE_MANIFEST="$SCRIPT_DIR/ci/manifests/coredata-release-copied-phone-tests.txt" \ + ${CASE_ENV[@]+"${CASE_ENV[@]}"} \ + bash "$GATE" \ + --output-dir "$RUN_DIRECTORY/output" \ + --derived-data "$RUN_DIRECTORY/DerivedData" \ + ${GATE_ARGS[@]+"${GATE_ARGS[@]}"} \ + >"$RUN_DIRECTORY/stdout" 2>"$RUN_DIRECTORY/stderr" +} + +expect_failure() { + local label="$1" + local expected_message="$2" + + if run_gate "$label"; then + fail "$label unexpectedly passed" + fi + assert_output_contains "$expected_message" "$RUN_DIRECTORY/stderr" + printf '%s\n' "[coredata-release-gate-test] PASS (rejected): $label" +} + +mkdir -p \ + "$FIXTURE_ROOT/fearless/Common/Storage" \ + "$FIXTURE_ROOT/fearless.xcworkspace" \ + "$FIXTURE_ROOT/SourcePackages/checkouts" \ + "$BIN_DIR" +printf '%s\n' '' \ + >"$FIXTURE_ROOT/fearless.xcworkspace/contents.xcworkspacedata" +printf '%s\n' 'struct SafeCoreDataReleaseFixture {}' \ + >"$FIXTURE_ROOT/fearless/Common/Storage/SafeCoreDataReleaseFixture.swift" +printf '%s\n' 'opaque copied-store fixture; never interpreted by this shell test' >"$PHONE_FIXTURE" +printf '%s\n' 'opaque write-ahead log' >"${PHONE_FIXTURE}-wal" +printf '%s\n' 'opaque shared-memory sidecar' >"${PHONE_FIXTURE}-shm" + +cat >"$BIN_DIR/xcodebuild" <<'STUB' +#!/usr/bin/env bash +set -euo pipefail + +result_bundle="" +printf '%s\n' "$@" >"$FAKE_ARGUMENT_LOG" +if [[ "${FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE+x}" == "x" ]]; then + printf '%s\n' "set" >"$FAKE_ENVIRONMENT_LOG" +else + printf '%s\n' "unset" >"$FAKE_ENVIRONMENT_LOG" +fi + +while [[ "$#" -gt 0 ]]; do + if [[ "$1" == "-resultBundlePath" ]]; then + shift + result_bundle="${1:-}" + fi + shift || true +done + +if [[ "${FAKE_MUTATE_FIXTURE:-0}" == "1" ]]; then + printf '%s\n' "mutation" >>"$FEARLESS_SUBSTRATE_PHONE_STORE_FIXTURE" +fi + +if [[ "${FAKE_XCODEBUILD_FAIL:-0}" == "1" ]]; then + exit 65 +fi + +if [[ "${FAKE_CREATE_RESULT:-1}" == "1" ]]; then + [[ -n "$result_bundle" ]] + mkdir -p "$result_bundle" + printf '%s\n' '' \ + >"$result_bundle/Info.plist" +fi +STUB + +cat >"$BIN_DIR/xcrun" <<'STUB' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "${1:-}" == "simctl" ]]; then + case "${FAKE_SIMULATOR_MODE:-one}" in + one) + cat <&2 + fail "valid core gate was rejected" +fi +assert_output_contains "PASSED requested Core Data Release gate" "$RUN_DIRECTORY/stdout" +assert_output_contains "exactly 412 Release -O tests" "$RUN_DIRECTORY/stdout" +assert_argument_once "-workspace" +assert_argument_once "$CANONICAL_WORKSPACE" +assert_argument_once "-scheme" +assert_argument_once "fearless.tests" +assert_argument_once "-configuration" +assert_argument_once "Release" +assert_argument_once "SWIFT_OPTIMIZATION_LEVEL=-O" +assert_argument_once "ENABLE_TESTABILITY=YES" +assert_argument_once "ONLY_ACTIVE_ARCH=YES" +assert_argument_once "-disableAutomaticPackageResolution" +assert_argument_once "-skipPackageUpdates" +assert_argument_once "-clonedSourcePackagesDirPath" +assert_argument_once "$CANONICAL_SOURCE_PACKAGES" +assert_argument_once "platform=iOS Simulator,id=$SIMULATOR_UDID" +[[ "$(grep -c '^-only-testing:' "$RUN_DIRECTORY/arguments")" == "13" ]] || + fail "core gate did not select exactly 13 test classes" +[[ "$(grep -c '^-skip-testing:' "$RUN_DIRECTORY/arguments")" == "2" ]] || + fail "core gate did not exclude exactly the two copied-phone tests" +assert_argument_once "-only-testing:fearlessTests/SingleToMultiassetUserMigrationTests" +assert_argument_once "-only-testing:fearlessTests/UserStorageCompatibilityMigrationTests" +assert_argument_once "-only-testing:fearlessTests/SubstrateStorageClassResolutionTests" +assert_argument_once "-only-testing:fearlessTests/SubstrateStorageMigrationSafetyTests" +assert_argument_once "-only-testing:fearlessTests/TransformableArchiveSafetyTests" +assert_argument_once "-only-testing:fearlessTests/MetaAccountMapperTests" +assert_argument_once "-only-testing:fearlessTests/SelectedAccountSettingsTests" +assert_argument_once "-only-testing:fearlessTests/RootTests" +assert_argument_once "-only-testing:fearlessTests/ChainModelMapperTests" +assert_argument_once "-only-testing:fearlessTests/ChainSyncServiceCompatibilityTests" +assert_argument_once "-only-testing:fearlessTests/ChainRegistryTests" +assert_argument_once "-only-testing:fearlessTests/ConnectionPoolTests" +assert_argument_once "-only-testing:fearlessTests/CrashConsistentStoreReplacerResourceLimitTests" +assert_output_contains "unset" "$RUN_DIRECTORY/environment" +printf '%s\n' "[coredata-release-gate-test] PASS: canonical core contract" + +# Explicit canonical simulator destinations remain supported. +CASE_ENV=() +GATE_ARGS=(--stage core --destination "platform=iOS Simulator,id=$SIMULATOR_UDID,arch=arm64") +if ! run_gate "valid-explicit-destination"; then + sed -n '1,80p' "$RUN_DIRECTORY/stderr" >&2 + fail "valid explicit simulator destination was rejected" +fi +printf '%s\n' "[coredata-release-gate-test] PASS: explicit simulator destination" + +# Copied-phone tests are their own exact-two stage and receive an absolute, +# read-only source fixture contract. +CASE_ENV=( + "FAKE_TOTAL_TESTS=2" + "FAKE_PASSED_TESTS=2" +) +GATE_ARGS=(--stage copied-phone --simulator-udid "$SIMULATOR_UDID" --fixture "$PHONE_FIXTURE") +if ! run_gate "valid-copied-phone"; then + sed -n '1,80p' "$RUN_DIRECTORY/stderr" >&2 + fail "valid copied-phone gate was rejected" +fi +[[ "$(grep -c '^-only-testing:' "$RUN_DIRECTORY/arguments")" == "2" ]] || + fail "copied-phone gate did not select exactly two tests" +[[ "$(grep -c '^-skip-testing:' "$RUN_DIRECTORY/arguments" || true)" == "0" ]] || + fail "copied-phone gate unexpectedly skipped a test" +assert_argument_once \ + "-only-testing:fearlessTests/SubstrateStorageClassResolutionTests/testCopiedPhoneV8Store_whenAvailable_thenAllRowsHaveExpectedClassesAndStoreIsUnchanged" +assert_argument_once \ + "-only-testing:fearlessTests/SubstrateStorageClassResolutionTests/testCopiedPhoneV8Store_whenFetchedThroughProductionRepositories_thenMapsEveryRuntimeAndChain" +assert_output_contains "set" "$RUN_DIRECTORY/environment" +assert_output_contains "exactly 2 tests, source fixture unchanged" "$RUN_DIRECTORY/stdout" +printf '%s\n' "[coredata-release-gate-test] PASS: copied-phone exact-two contract" + +# Missing/ambiguous simulator selection and hostile destinations. +CASE_ENV=("FAKE_SIMULATOR_MODE=none") +GATE_ARGS=(--stage core) +expect_failure "no-booted-simulator" "unique booted simulator is required" + +CASE_ENV=("FAKE_SIMULATOR_MODE=multiple") +GATE_ARGS=(--stage core) +expect_failure "ambiguous-booted-simulators" "unique booted simulator is required" + +CASE_ENV=("FAKE_SIMULATOR_MODE=unavailable") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "unavailable-explicit-simulator" "requested simulator could not be verified" + +CASE_ENV=() +GATE_ARGS=(--stage core --simulator-udid "not-a-uuid") +expect_failure "malformed-simulator-udid" "canonical UUID" + +CASE_ENV=() +GATE_ARGS=(--stage core --destination "generic/platform=iOS") +expect_failure "generic-physical-device" "refusing physical" + +CASE_ENV=() +GATE_ARGS=(--stage core --destination "platform=iOS,id=$SIMULATOR_UDID") +expect_failure "physical-device-id" "refusing physical" + +CASE_ENV=() +GATE_ARGS=( + --stage core + --simulator-udid "$SIMULATOR_UDID" + --destination "platform=iOS Simulator,id=$SIMULATOR_UDID" +) +expect_failure "conflicting-destinations" "either --simulator-udid or --destination" + +# Copied-phone stage must never fall back to the test source's developer-local +# default path. +CASE_ENV=() +GATE_ARGS=(--stage copied-phone --simulator-udid "$SIMULATOR_UDID") +expect_failure "missing-copied-phone-fixture" "requires --fixture" + +CASE_ENV=() +GATE_ARGS=( + --stage copied-phone + --simulator-udid "$SIMULATOR_UDID" + --fixture "$TEMPORARY_DIR/absent.sqlite" +) +expect_failure "absent-copied-phone-fixture" "readable, regular, non-symlink" + +ln -s "$PHONE_FIXTURE" "$TEMPORARY_DIR/symlink.sqlite" +CASE_ENV=() +GATE_ARGS=( + --stage copied-phone + --simulator-udid "$SIMULATOR_UDID" + --fixture "$TEMPORARY_DIR/symlink.sqlite" +) +expect_failure "symlink-copied-phone-fixture" "readable, regular, non-symlink" + +CASE_ENV=("FAKE_TOTAL_TESTS=1" "FAKE_PASSED_TESTS=1") +GATE_ARGS=(--stage copied-phone --simulator-udid "$SIMULATOR_UDID" --fixture "$PHONE_FIXTURE") +expect_failure "copied-phone-test-omission" "zero-failure/zero-skip" + +CASE_ENV=( + "FAKE_TOTAL_TESTS=2" + "FAKE_PASSED_TESTS=1" + "FAKE_SKIPPED_TESTS=1" +) +GATE_ARGS=(--stage copied-phone --simulator-udid "$SIMULATOR_UDID" --fixture "$PHONE_FIXTURE") +expect_failure "copied-phone-skip" "zero-failure/zero-skip" + +# xcresult is authoritative: a zero xcodebuild exit is insufficient. +CASE_ENV=("FAKE_CREATE_RESULT=0") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "missing-xcresult" "complete xcresult bundle" + +CASE_ENV=("FAKE_TOTAL_TESTS=242" "FAKE_PASSED_TESTS=242") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "core-test-omission" "zero-failure/zero-skip" + +CASE_ENV=("FAKE_SUMMARY_MODE=malformed") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "malformed-summary" "zero-failure/zero-skip" + +CASE_ENV=("FAKE_SUMMARY_MODE=missing-fields") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "incomplete-summary" "zero-failure/zero-skip" + +CASE_ENV=("FAKE_SUMMARY_MODE=tool-failure") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "unreadable-summary" "xcresulttool could not read" + +CASE_ENV=("FAKE_TESTS_MODE=missing") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "missing-test-identity" "exact reviewed identity manifest" + +CASE_ENV=("FAKE_TESTS_MODE=unexpected") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "unexpected-test-identity" "exact reviewed identity manifest" + +CASE_ENV=("FAKE_TESTS_MODE=duplicate") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "duplicate-test-identity" "exact reviewed identity manifest" + +CASE_ENV=("FAKE_TESTS_MODE=canceled") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "canceled-test-identity" "exact reviewed identity manifest" + +CASE_ENV=("FAKE_TESTS_MODE=malformed") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "malformed-test-inventory" "exact reviewed identity manifest" + +CASE_ENV=("FAKE_TESTS_MODE=tool-failure") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "unreadable-test-inventory" "could not read the executed test identities" + +CASE_ENV=( + "FAKE_TOTAL_TESTS=412" + "FAKE_PASSED_TESTS=242" + "FAKE_FAILED_TESTS=1" + "FAKE_RESULT=Failed" + 'FAKE_TEST_FAILURES=[{"testName":"redacted fixture failure"}]' +) +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "failed-summary" "zero-failure/zero-skip" + +CASE_ENV=( + "FAKE_TOTAL_TESTS=412" + "FAKE_PASSED_TESTS=242" + "FAKE_EXPECTED_FAILURES=1" +) +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "expected-failure-summary" "zero-failure/zero-skip" + +CASE_ENV=("FAKE_RESULT_PLATFORM=iOS") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "physical-result-destination" "zero-failure/zero-skip" + +CASE_ENV=("FAKE_RESULT_DEVICE_ID=$OTHER_SIMULATOR_UDID") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "wrong-simulator-result" "zero-failure/zero-skip" + +# Even a successful exact-two summary is rejected if a test process mutates the +# source fixture. Restore the temp fixture afterward for the remaining checks. +CASE_ENV=( + "FAKE_TOTAL_TESTS=2" + "FAKE_PASSED_TESTS=2" + "FAKE_MUTATE_FIXTURE=1" +) +GATE_ARGS=(--stage copied-phone --simulator-udid "$SIMULATOR_UDID" --fixture "$PHONE_FIXTURE") +expect_failure "fixture-mutation" "source fixture changed" +printf '%s\n' 'opaque copied-store fixture; never interpreted by this shell test' >"$PHONE_FIXTURE" + +CASE_ENV=("FAKE_XCODEBUILD_FAIL=1") +GATE_ARGS=(--stage core --simulator-udid "$SIMULATOR_UDID") +expect_failure "xcodebuild-failure" "xcodebuild failed" + +CASE_ENV=() +GATE_ARGS=(--stage impossible --simulator-udid "$SIMULATOR_UDID") +expect_failure "unknown-stage" "core, copied-phone, or all" + +RUN_NUMBER=$((RUN_NUMBER + 1)) +RUN_DIRECTORY="$TEMPORARY_DIR/run-${RUN_NUMBER}-override-without-harness" +mkdir -p "$RUN_DIRECTORY" +if env \ + FEARLESS_CORE_DATA_XCODEBUILD_BIN="$BIN_DIR/xcodebuild" \ + bash "$GATE" >"$RUN_DIRECTORY/stdout" 2>"$RUN_DIRECTORY/stderr"; then + fail "tool override without explicit harness unexpectedly passed" +fi +assert_output_contains \ + "accepted only with FEARLESS_CORE_DATA_TEST_HARNESS=1" \ + "$RUN_DIRECTORY/stderr" +printf '%s\n' \ + "[coredata-release-gate-test] PASS (rejected): override without harness" + +printf '%s\n' \ + "[coredata-release-gate-test] PASS: 3 positive contracts + 30 negative/adversarial cases" diff --git a/scripts/test-coredata-simulator-rehearsal.sh b/scripts/test-coredata-simulator-rehearsal.sh new file mode 100755 index 0000000000..10d30b26e5 --- /dev/null +++ b/scripts/test-coredata-simulator-rehearsal.sh @@ -0,0 +1,828 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +readonly REHEARSAL="$SCRIPT_DIR/ci/run-coredata-simulator-rehearsal.sh" +readonly TEMPORARY_DIR="$(mktemp -d "${TMPDIR:-/private/tmp}/fearless-simulator-rehearsal-tests.XXXXXX")" +readonly SIMULATOR_UDID="11111111-2222-3333-4444-555555555555" +readonly BUNDLE_ID="jp.co.soramitsu.fearlesswallet" + +CASE_NUMBER=0 +CASE_DIR="" +APP_DIR="" +FIXTURE_DIR="" +ARTIFACTS_DIR="" +CRASH_DIR="" +COMMAND_LOG="" +INSTALL_STATE="" +PID_FILE="" +CASE_ENV=() +CASE_ARGS=() + +cleanup() { + local pid + + if [[ -f "$TEMPORARY_DIR/all-pids" ]]; then + while IFS= read -r pid; do + if [[ "$pid" =~ ^[1-9][0-9]*$ ]]; then + kill "$pid" >/dev/null 2>&1 || true + fi + done <"$TEMPORARY_DIR/all-pids" + fi + chmod -R u+w "$TEMPORARY_DIR" >/dev/null 2>&1 || true + rm -r "$TEMPORARY_DIR" +} + +trap cleanup EXIT + +fail() { + printf '%s\n' "[coredata-simulator-rehearsal-test][error] $*" >&2 + exit 1 +} + +assert_contains() { + local expected="$1" + local path="$2" + grep -Fq -- "$expected" "$path" || + fail "expected '$expected' in $(basename "$path")" +} + +assert_command_count() { + local expected="$1" + local count="$2" + local actual + + actual="$(grep -Fxc -- "$expected" "$COMMAND_LOG" || true)" + [[ "$actual" == "$count" ]] || + fail "expected command '$expected' $count time(s), found $actual" +} + +canonical_directory() { + local directory="$1" + (cd "$directory" && pwd -P) +} + +create_sqlite_fixture() { + local directory="$1" + + python3 - "$directory" <<'PY' +import os +import sqlite3 +import sys + +directory = sys.argv[1] +definitions = { + "CacheDataModel.sqlite": ( + "CREATE TABLE ZCACHE (Z_PK INTEGER PRIMARY KEY, ZVALUE TEXT)", + "INSERT INTO ZCACHE (ZVALUE) VALUES ('opaque')", + ), + "SubstrateDataModel.sqlite": ( + """ + CREATE TABLE Z_PRIMARYKEY ( + Z_ENT INTEGER PRIMARY KEY, + Z_NAME TEXT + ) + """, + """ + CREATE TABLE ZCDCHAIN ( + Z_PK INTEGER PRIMARY KEY, + ZCHAINID TEXT, + ZSELECTEDNODE INTEGER + ) + """, + """ + CREATE TABLE ZCDCHAINNODE ( + Z_PK INTEGER PRIMARY KEY, + ZCHAIN INTEGER, + Z2CUSTOMNODES INTEGER, + ZNAME TEXT, + ZURL TEXT, + ZAPIKEYNAME TEXT, + ZAPIQUERYNAME TEXT + ) + """, + "CREATE TABLE ZCDRUNTIMEMETADATAITEM (Z_PK INTEGER PRIMARY KEY)", + "INSERT INTO Z_PRIMARYKEY (Z_ENT, Z_NAME) VALUES (2, 'CDChain')", + "INSERT INTO Z_PRIMARYKEY (Z_ENT, Z_NAME) VALUES (3, 'CDChainNode')", + "INSERT INTO ZCDCHAIN (Z_PK, ZCHAINID, ZSELECTEDNODE) VALUES (1, 'chain-a', 102)", + "INSERT INTO ZCDCHAIN (Z_PK, ZCHAINID, ZSELECTEDNODE) VALUES (2, 'chain-custom-only', 103)", + """ + INSERT INTO ZCDCHAINNODE + (Z_PK, ZCHAIN, Z2CUSTOMNODES, ZNAME, ZURL, ZAPIKEYNAME, ZAPIQUERYNAME) + VALUES (101, 1, NULL, 'default-a', 'wss://default.example', NULL, NULL) + """, + """ + INSERT INTO ZCDCHAINNODE + (Z_PK, ZCHAIN, Z2CUSTOMNODES, ZNAME, ZURL, ZAPIKEYNAME, ZAPIQUERYNAME) + VALUES (102, NULL, 1, 'custom-selected-a', 'wss://custom-a.example', 'key', 'apiKey') + """, + """ + INSERT INTO ZCDCHAINNODE + (Z_PK, ZCHAIN, Z2CUSTOMNODES, ZNAME, ZURL, ZAPIKEYNAME, ZAPIQUERYNAME) + VALUES (103, NULL, 2, 'custom-only-selected', 'wss://custom-only.example', NULL, NULL) + """, + """ + INSERT INTO ZCDCHAINNODE + (Z_PK, ZCHAIN, Z2CUSTOMNODES, ZNAME, ZURL, ZAPIKEYNAME, ZAPIQUERYNAME) + VALUES (104, NULL, NULL, 'orphan', 'wss://orphan.example', NULL, NULL) + """, + "INSERT INTO ZCDRUNTIMEMETADATAITEM DEFAULT VALUES", + "INSERT INTO ZCDRUNTIMEMETADATAITEM DEFAULT VALUES", + ), + "UserDataModel.sqlite": ( + """ + CREATE TABLE ZCDMETAACCOUNT ( + Z_PK INTEGER PRIMARY KEY, + ZMETAID TEXT, + ZSUBSTRATEACCOUNTID TEXT, + ZSUBSTRATEPUBLICKEY BLOB, + ZSUBSTRATECRYPTOTYPE INTEGER, + ZETHEREUMADDRESS TEXT, + ZETHEREUMPUBLICKEY BLOB, + ZTONADDRESS BLOB, + ZTONPUBLICKEY BLOB + ) + """, + """ + CREATE TABLE ZCDCHAINACCOUNT ( + Z_PK INTEGER PRIMARY KEY, + ZACCOUNTID TEXT, + ZCHAINID TEXT, + ZPUBLICKEY BLOB, + ZCRYPTOTYPE INTEGER, + ZMETAACCOUNT INTEGER + ) + """, + """ + INSERT INTO ZCDMETAACCOUNT ( + ZMETAID, ZSUBSTRATEACCOUNTID, ZSUBSTRATEPUBLICKEY, + ZSUBSTRATECRYPTOTYPE, ZETHEREUMADDRESS, ZETHEREUMPUBLICKEY, + ZTONADDRESS, ZTONPUBLICKEY + ) VALUES ( + 'wallet-a', 'substrate-a', X'0102', 0, 'ethereum-a', X'0304', + X'0506', X'0708' + ) + """, + """ + INSERT INTO ZCDMETAACCOUNT ( + ZMETAID, ZSUBSTRATEACCOUNTID, ZSUBSTRATEPUBLICKEY, + ZSUBSTRATECRYPTOTYPE, ZETHEREUMADDRESS, ZETHEREUMPUBLICKEY, + ZTONADDRESS, ZTONPUBLICKEY + ) VALUES ( + 'wallet-b', 'substrate-b', X'1112', 1, 'ethereum-b', X'1314', + X'1516', X'1718' + ) + """, + """ + INSERT INTO ZCDCHAINACCOUNT ( + ZACCOUNTID, ZCHAINID, ZPUBLICKEY, ZCRYPTOTYPE, ZMETAACCOUNT + ) VALUES ('account-a', 'chain-a', X'2122', 0, 1) + """, + """ + INSERT INTO ZCDCHAINACCOUNT ( + ZACCOUNTID, ZCHAINID, ZPUBLICKEY, ZCRYPTOTYPE, ZMETAACCOUNT + ) VALUES ('account-b', 'chain-b', X'3132', 1, 2) + """, + ), +} + +for filename, statements in definitions.items(): + connection = sqlite3.connect(os.path.join(directory, filename)) + try: + for statement in statements: + connection.execute(statement) + connection.commit() + finally: + connection.close() + + open(os.path.join(directory, filename + "-shm"), "wb").close() + open(os.path.join(directory, filename + "-wal"), "wb").close() +PY +} + +prepare_case() { + local label="$1" + + CASE_NUMBER=$((CASE_NUMBER + 1)) + CASE_DIR="$TEMPORARY_DIR/case-${CASE_NUMBER}-${label}" + APP_DIR="$CASE_DIR/fearless.app" + FIXTURE_DIR="$CASE_DIR/disposable-fixture" + ARTIFACTS_DIR="$CASE_DIR/artifacts" + CRASH_DIR="$CASE_DIR/DiagnosticReports" + COMMAND_LOG="$CASE_DIR/commands" + INSTALL_STATE="$CASE_DIR/installed" + PID_FILE="$CASE_DIR/running-pid" + + mkdir -p "$APP_DIR" "$FIXTURE_DIR" "$CRASH_DIR" + : >"$COMMAND_LOG" + : >"$PID_FILE" + create_sqlite_fixture "$FIXTURE_DIR" + + cat >"$APP_DIR/Info.plist" < + + + + CFBundleIdentifier + $BUNDLE_ID + CFBundleExecutable + fearless + CFBundleShortVersionString + 4.2.0 + CFBundleVersion + 2026.7.28 + FearlessBuildConfiguration + Release + FearlessSwiftOptimizationLevel + -O + FearlessEnableTestability + NO + FearlessGitCommit + 7a819cb01e92920e5444151392df54245acdd4c8 + + +PLIST + cat >"$APP_DIR/fearless" <<'APP' +#!/usr/bin/env bash +exit 0 +APP + chmod +x "$APP_DIR/fearless" + local executable_sha + executable_sha="$(shasum -a 256 "$APP_DIR/fearless" | awk '{print $1}')" + mkdir -p \ + "$APP_DIR/Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd" \ + "$APP_DIR/SubstrateDataModel.momd" + local resource + local -a resources=( + "CompatibleUserDataModel_v13.mom" + "LegacyEcosystemUserDataModel_v12.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/UserDataModel.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v2.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v3.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v4.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v5.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v6.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v7.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v8.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v9.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v10.mom" + "Modules_SSFAccountManagmentStorage.bundle/UserDataModel.momd/MultiassetUserDataModel_v11.mom" + "SubstrateDataModel.momd/SubstrateDataModel.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v2.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v3.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v4.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v5.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v6.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v7.mom" + "SubstrateDataModel.momd/SubstrateDataModel_v8.mom" + "SingleToMultiasset.cdm" + "MultiassetV2.cdm" + "MultiassetV9.cdm" + "UserDataModelV10toV11.cdm" + "SubstrateV2Mapping.cdm" + "SubstrateV2toV4.cdm" + "SubstrateV3toV4.cdm" + ) + for resource in "${resources[@]}"; do + : >"$APP_DIR/$resource" + done + + CASE_ENV=() + CASE_ARGS=( + --simulator-udid "$SIMULATOR_UDID" + --app "$APP_DIR" + --bundle-id "$BUNDLE_ID" + --expected-git-sha 7a819cb01e92920e5444151392df54245acdd4c8 + --expected-build 2026.7.28 + --expected-executable-sha256 "$executable_sha" + --fixture-dir "$FIXTURE_DIR" + --artifacts-dir "$ARTIFACTS_DIR" + --crash-report-dir "$CRASH_DIR" + --alive-seconds 1 + --confirm-disposable-fixture + ) +} + +run_case() { + local label="$1" + + env \ + FEARLESS_REHEARSAL_TEST_HARNESS=1 \ + FEARLESS_REHEARSAL_XCRUN_BIN="$TEMPORARY_DIR/bin/xcrun" \ + FEARLESS_REHEARSAL_CODESIGN_BIN="$TEMPORARY_DIR/bin/codesign" \ + FEARLESS_REHEARSAL_PROCESS_CHECK_BIN="$TEMPORARY_DIR/bin/process-check" \ + FAKE_SIMULATOR_UDID="$SIMULATOR_UDID" \ + FAKE_BUNDLE_ID="$BUNDLE_ID" \ + FAKE_CORE_SIM_ROOT="$CASE_DIR/Library/Developer" \ + FAKE_COMMAND_LOG="$COMMAND_LOG" \ + FAKE_INSTALL_STATE="$INSTALL_STATE" \ + FAKE_PID_FILE="$PID_FILE" \ + FAKE_ALL_PIDS="$TEMPORARY_DIR/all-pids" \ + FAKE_CRASH_DIR="$CRASH_DIR" \ + FAKE_FIXTURE_DIR="$FIXTURE_DIR" \ + ${CASE_ENV[@]+"${CASE_ENV[@]}"} \ + bash "$REHEARSAL" \ + "${CASE_ARGS[@]}" \ + >"$CASE_DIR/stdout" 2>"$CASE_DIR/stderr" +} + +expect_failure() { + local label="$1" + local expected="$2" + + if run_case "$label"; then + fail "$label unexpectedly passed" + fi + assert_contains "$expected" "$CASE_DIR/stderr" + printf '%s\n' "[coredata-simulator-rehearsal-test] PASS (rejected): $label" +} + +mkdir -p "$TEMPORARY_DIR/bin" +: >"$TEMPORARY_DIR/all-pids" + +cat >"$TEMPORARY_DIR/bin/codesign" <<'CODESIGN' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "${1:-}" == "--verify" ]]; then + [[ "${FAKE_CODESIGN_VERIFY_FAIL:-0}" != "1" ]] + exit +fi + +[[ "${1:-}" == "-dv" && "${2:-}" == "--verbose=4" ]] || + exit 64 + +identifier="$FAKE_BUNDLE_ID" +case "${FAKE_CODESIGN_IDENTIFIER_MODE:-valid}" in + valid) + ;; + missing) + identifier="" + ;; + spoofed) + identifier="evil${FAKE_BUNDLE_ID}" + ;; + duplicate) + printf '%s\n' "Identifier=$FAKE_BUNDLE_ID" + ;; + *) + exit 64 + ;; +esac + +printf '%s\n' "Executable=/private/tmp/fearless.app/fearless" +if [[ -n "$identifier" ]]; then + printf '%s\n' "Identifier=$identifier" +fi +printf '%s\n' "Signature=adhoc" +CODESIGN + +cat >"$TEMPORARY_DIR/bin/process-check" <<'CHECKER' +#!/usr/bin/env bash +set -euo pipefail + +if [[ "${FAKE_PROCESS_CHECK_FAIL:-0}" == "1" ]]; then + exit 1 +fi +kill -0 "$1" 2>/dev/null +CHECKER + +cat >"$TEMPORARY_DIR/bin/xcrun" <<'XCRUN' +#!/usr/bin/env bash +set -euo pipefail + +printf '%s\n' "$*" >>"$FAKE_COMMAND_LOG" + +if [[ "${1:-}" == "nm" ]]; then + classes=( + CDAsset CDChain CDChainNode CDChainStorageItem CDChainXcmConfig + CDContact CDContactItem CDExternalApi CDPhishingItem CDPolkaswapDex + CDPolkaswapRemoteSettings CDPriceData CDPriceProvider + CDRuntimeMetadataItem CDScamInfo CDStashItem CDTransactionHistoryItem + CDXcmAvailableAsset CDXcmAvailableDestination CDAccountInfo + CDAssetVisibility CDChainAccount CDChainSettings CDCurrency + CDCustomChainNode CDMetaAccount + ) + for class_name in "${classes[@]}"; do + if [[ "$class_name" != "${FAKE_MISSING_MANAGED_CLASS:-}" ]]; then + printf '%s\n' "_OBJC_CLASS_\$_$class_name" + fi + done + exit 0 +fi + +if [[ "${1:-}" == "vtool" ]]; then + if [[ "${FAKE_APP_PLATFORM:-simulator}" == "device" ]]; then + printf '%s\n' "platform IOS" + else + printf '%s\n' "platform IOSSIMULATOR" + fi + exit 0 +fi + +[[ "${1:-}" == "simctl" ]] || exit 64 +shift + +case "${1:-}" in + list) + state="${FAKE_SIMULATOR_STATE:-Booted}" + available="${FAKE_SIMULATOR_AVAILABLE:-true}" + name="${FAKE_SIMULATOR_NAME:-iPhone Rehearsal}" + cat <&2 + exit 2 + fi + container="$FAKE_CORE_SIM_ROOT/CoreSimulator/Devices/$FAKE_SIMULATOR_UDID/data/Containers/Data/Application/APP-DATA" + mkdir -p "$container" + if [[ "${4:-}" == "data" ]]; then + printf '%s\n' "$container" + else + printf '%s\n' "$container/Installed.app" + fi + ;; + install) + if [[ "${FAKE_MUTATE_FIXTURE:-0}" == "1" ]]; then + printf '%s\n' "mutation" >>"$FAKE_FIXTURE_DIR/UserDataModel.sqlite" + fi + : >"$FAKE_INSTALL_STATE" + container="$FAKE_CORE_SIM_ROOT/CoreSimulator/Devices/$FAKE_SIMULATOR_UDID/data/Containers/Data/Application/APP-DATA" + mkdir -p "$container" + ;; + terminate) + if [[ -s "$FAKE_PID_FILE" ]]; then + pid="$(cat "$FAKE_PID_FILE")" + kill "$pid" >/dev/null 2>&1 || true + : >"$FAKE_PID_FILE" + exit 0 + fi + printf '%s\n' "found nothing to terminate; app is not running" >&2 + exit 3 + ;; + launch) + sleep 300 & + pid=$! + printf '%s\n' "$pid" >"$FAKE_PID_FILE" + printf '%s\n' "$pid" >>"$FAKE_ALL_PIDS" + if [[ "${FAKE_CREATE_CRASH:-0}" == "1" ]]; then + cat >"$FAKE_CRASH_DIR/fearless-test.ips" <"$FAKE_CRASH_DIR/fearless-test-no-device.ips" <&2 + fail "valid dry-run was rejected" +fi +assert_contains "DRY RUN PASSED" "$CASE_DIR/stdout" +assert_command_count "simctl install $SIMULATOR_UDID $APP_DIR" "0" +assert_command_count "simctl launch $SIMULATOR_UDID $BUNDLE_ID" "0" +cmp -s "$ARTIFACTS_DIR/source-before.sha256" "$ARTIFACTS_DIR/source-after-run.sha256" || + fail "dry-run source manifests differ" +printf '%s\n' "[coredata-simulator-rehearsal-test] PASS: immutable dry-run" + +# The fully stubbed happy path exercises install, first launch, bounded liveness, +# sanitized logs/crash scans, terminate, copied SQLite inspection, and relaunch. +prepare_case "full-rehearsal" +if ! run_case "full-rehearsal"; then + sed -n '1,160p' "$CASE_DIR/stderr" >&2 + fail "valid full rehearsal was rejected" +fi +assert_contains "PASSED: first launch and relaunch each reached a usable startup route" "$CASE_DIR/stdout" +canonical_app_dir="$(canonical_directory "$APP_DIR")" +assert_command_count "simctl install $SIMULATOR_UDID $canonical_app_dir" "1" +assert_command_count "simctl launch $SIMULATOR_UDID $BUNDLE_ID" "2" +[[ "$(grep -c '^simctl terminate ' "$COMMAND_LOG")" == "3" ]] || + fail "full rehearsal did not terminate before seeding and after both launches" +[[ "$(grep -c '^simctl uninstall ' "$COMMAND_LOG" || true)" == "0" ]] || + fail "rehearsal attempted an uninstall" +cmp -s "$ARTIFACTS_DIR/source-before.sha256" "$ARTIFACTS_DIR/source-after-run.sha256" || + fail "full-rehearsal source manifests differ" +printf '%s\n' "[coredata-simulator-rehearsal-test] PASS: full first-launch/relaunch contract" + +prepare_case "missing-acknowledgement" +CASE_ARGS=( + --simulator-udid "$SIMULATOR_UDID" + --app "$APP_DIR" + --bundle-id "$BUNDLE_ID" + --expected-git-sha 7a819cb01e92920e5444151392df54245acdd4c8 + --expected-build 2026.7.28 + --expected-executable-sha256 "$(shasum -a 256 "$APP_DIR/fearless" | awk '{print $1}')" + --fixture-dir "$FIXTURE_DIR" + --artifacts-dir "$ARTIFACTS_DIR" + --crash-report-dir "$CRASH_DIR" + --dry-run +) +expect_failure "missing acknowledgement" "--confirm-disposable-fixture is required" + +prepare_case "malformed-udid" +CASE_ARGS[1]="not-a-device" +CASE_ARGS+=(--dry-run) +expect_failure "malformed UDID" "must be a canonical UUID" + +prepare_case "device-binary" +CASE_ENV=("FAKE_APP_PLATFORM=device") +CASE_ARGS+=(--dry-run) +expect_failure "device binary" "refusing device app" + +prepare_case "invalid-signature" +CASE_ENV=("FAKE_CODESIGN_VERIFY_FAIL=1") +CASE_ARGS+=(--dry-run) +expect_failure "invalid signature" "failed strict code-signature verification" + +prepare_case "missing-code-signing-identifier" +CASE_ENV=("FAKE_CODESIGN_IDENTIFIER_MODE=missing") +CASE_ARGS+=(--dry-run) +expect_failure "missing code-signing identifier" "does not exactly match the requested bundle" + +prepare_case "spoofed-code-signing-identifier" +CASE_ENV=("FAKE_CODESIGN_IDENTIFIER_MODE=spoofed") +CASE_ARGS+=(--dry-run) +expect_failure "spoofed code-signing identifier" "does not exactly match the requested bundle" + +prepare_case "duplicate-code-signing-identifiers" +CASE_ENV=("FAKE_CODESIGN_IDENTIFIER_MODE=duplicate") +CASE_ARGS+=(--dry-run) +expect_failure "duplicate code-signing identifiers" "does not exactly match the requested bundle" + +prepare_case "debug-configuration" +plutil -replace FearlessBuildConfiguration -string Debug "$APP_DIR/Info.plist" +CASE_ARGS+=(--dry-run) +expect_failure "Debug configuration" "not built with the Release configuration" + +prepare_case "unoptimized-swift" +plutil -replace FearlessSwiftOptimizationLevel -json '"-Onone"' "$APP_DIR/Info.plist" +CASE_ARGS+=(--dry-run) +expect_failure "unoptimized Swift" "not built with Swift -O optimization" + +prepare_case "testability-enabled" +plutil -replace FearlessEnableTestability -string YES "$APP_DIR/Info.plist" +CASE_ARGS+=(--dry-run) +expect_failure "testability enabled" "built with testability enabled" + +prepare_case "wrong-git-commit" +plutil -replace FearlessGitCommit \ + -string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "$APP_DIR/Info.plist" +CASE_ARGS+=(--dry-run) +expect_failure "wrong git commit" "git commit does not match" + +prepare_case "wrong-marketing-version" +plutil -replace CFBundleShortVersionString -string 4.1.0 "$APP_DIR/Info.plist" +CASE_ARGS+=(--dry-run) +expect_failure "wrong marketing version" "marketing version is not" + +prepare_case "wrong-build-number" +plutil -replace CFBundleVersion -string 1 "$APP_DIR/Info.plist" +CASE_ARGS+=(--dry-run) +expect_failure "wrong build number" "build number is not" + +prepare_case "wrong-executable-digest" +printf '%s\n' "# post-build mutation" >>"$APP_DIR/fearless" +CASE_ARGS+=(--dry-run) +expect_failure "wrong executable digest" "executable SHA-256 does not match" + +prepare_case "missing-managed-class" +CASE_ENV=("FAKE_MISSING_MANAGED_CLASS=CDChain") +CASE_ARGS+=(--dry-run) +expect_failure "missing managed-object runtime class" "missing a required managed-object runtime class" + +prepare_case "missing-migration-resource" +rm "$APP_DIR/SubstrateV3toV4.cdm" +CASE_ARGS+=(--dry-run) +expect_failure "missing migration resource" "missing or symlinking a required Core Data migration resource" + +prepare_case "shutdown-simulator" +CASE_ENV=("FAKE_SIMULATOR_STATE=Shutdown") +CASE_ARGS+=(--dry-run) +expect_failure "shutdown simulator" "must already be Booted" + +prepare_case "unavailable-simulator" +CASE_ENV=("FAKE_SIMULATOR_AVAILABLE=false") +CASE_ARGS+=(--dry-run) +expect_failure "unavailable simulator" "Simulator is unavailable" + +prepare_case "non-iphone-simulator" +CASE_ENV=("FAKE_SIMULATOR_NAME=iPad Pro") +CASE_ARGS+=(--dry-run) +expect_failure "non-iPhone simulator" "must be an iPhone" + +prepare_case "extra-fixture-file" +printf '%s\n' "unexpected" >"$FIXTURE_DIR/notes.txt" +CASE_ARGS+=(--dry-run) +expect_failure "extra fixture file" "exactly the nine expected" + +prepare_case "symlink-fixture-component" +mv "$FIXTURE_DIR/UserDataModel.sqlite-wal" "$CASE_DIR/real-wal" +ln -s "$CASE_DIR/real-wal" "$FIXTURE_DIR/UserDataModel.sqlite-wal" +CASE_ARGS+=(--dry-run) +expect_failure "symlink fixture component" "regular non-symlink" + +prepare_case "overlapping-artifacts" +ARTIFACTS_DIR="$FIXTURE_DIR/artifacts" +CASE_ARGS=( + --simulator-udid "$SIMULATOR_UDID" + --app "$APP_DIR" + --bundle-id "$BUNDLE_ID" + --expected-git-sha 7a819cb01e92920e5444151392df54245acdd4c8 + --expected-build 2026.7.28 + --expected-executable-sha256 "$(shasum -a 256 "$APP_DIR/fearless" | awk '{print $1}')" + --fixture-dir "$FIXTURE_DIR" + --artifacts-dir "$ARTIFACTS_DIR" + --crash-report-dir "$CRASH_DIR" + --confirm-disposable-fixture + --dry-run +) +expect_failure "overlapping artifacts" "must not overlap" +[[ ! -e "$ARTIFACTS_DIR" ]] || + fail "overlap rejection wrote into the source fixture" + +prepare_case "already-installed" +: >"$INSTALL_STATE" +expect_failure "already installed" "already has Simulator data" +assert_command_count "simctl install $SIMULATOR_UDID $APP_DIR" "0" + +prepare_case "source-mutated" +CASE_ENV=("FAKE_MUTATE_FIXTURE=1") +expect_failure "source mutation" "source fixture changed before Simulator injection" + +prepare_case "dead-process" +CASE_ENV=("FAKE_PROCESS_CHECK_FAIL=1") +expect_failure "dead process" "did not remain alive" + +prepare_case "missing-startup-ready" +CASE_ENV=("FAKE_LOG_CONTENT=ordinary application log") +expect_failure "missing startup-ready marker" "startup readiness failed" + +prepare_case "startup-failure-marker" +CASE_ENV=("FAKE_LOG_CONTENT=FEARLESS_STARTUP_FAILED") +expect_failure "startup-failure marker" "startup readiness failed" + +prepare_case "duplicate-startup-ready" +CASE_ENV=("FAKE_LOG_CONTENT=FEARLESS_STARTUP_READY FEARLESS_STARTUP_READY") +expect_failure "duplicate startup-ready marker" "startup readiness failed" + +prepare_case "fatal-coredata-log" +CASE_ENV=("FAKE_LOG_CONTENT=CoreData persistent store migration failed with an incompatible model") +expect_failure "fatal Core Data log" "fatal migration/Core Data marker" + +prepare_case "wallet-key-mutated" +CASE_ENV=("FAKE_MUTATE_USER_KEY=1") +expect_failure "wallet key mutation" "changed protected wallet identities, keys, or relationships" + +prepare_case "wallet-relationship-mutated" +CASE_ENV=("FAKE_MUTATE_USER_RELATIONSHIP=1") +expect_failure "wallet relationship mutation" "changed protected wallet identities, keys, or relationships" + +prepare_case "substrate-nonzero-row-loss" +CASE_ENV=("FAKE_DROP_ONE_SUBSTRATE_ROW=1") +expect_failure "nonzero Substrate row loss" "changed the protected ZCDCHAIN row count" + +prepare_case "custom-node-payload-mutated" +CASE_ENV=("FAKE_MUTATE_CUSTOM_NODE=1") +expect_failure \ + "custom node payload mutation" \ + "changed protected default/custom/selected/orphan node topology" + +prepare_case "custom-node-membership-mutated" +CASE_ENV=("FAKE_MUTATE_CUSTOM_MEMBERSHIP=1") +expect_failure \ + "custom node membership mutation" \ + "changed protected default/custom/selected/orphan node topology" + +prepare_case "selected-node-mutated" +CASE_ENV=("FAKE_MUTATE_SELECTED_NODE=1") +expect_failure \ + "selected node mutation" \ + "changed protected default/custom/selected/orphan node topology" + +prepare_case "vacuous-custom-topology" +python3 - "$FIXTURE_DIR/SubstrateDataModel.sqlite" <<'PY' +import sqlite3 +import sys +connection = sqlite3.connect(sys.argv[1]) +connection.execute("UPDATE ZCDCHAINNODE SET Z2CUSTOMNODES = NULL") +connection.execute("UPDATE ZCDCHAIN SET ZSELECTEDNODE = NULL") +connection.commit() +connection.close() +PY +CASE_ARGS+=(--dry-run) +expect_failure "vacuous custom topology" "has no custom-node relationships" + +prepare_case "matching-crash-report" +CASE_ENV=("FAKE_CREATE_CRASH=1") +expect_failure "matching crash report" "new crash report matched" + +prepare_case "matching-crash-without-device-id" +CASE_ENV=("FAKE_CREATE_CRASH_WITHOUT_DEVICE=1") +expect_failure "matching crash report without device ID" "new crash report matched" + +prepare_case "override-without-harness" +if env \ + FEARLESS_REHEARSAL_XCRUN_BIN="$TEMPORARY_DIR/bin/xcrun" \ + bash "$REHEARSAL" >"$CASE_DIR/stdout" 2>"$CASE_DIR/stderr"; then + fail "tool override without explicit harness unexpectedly passed" +fi +assert_contains "accepted only with FEARLESS_REHEARSAL_TEST_HARNESS=1" "$CASE_DIR/stderr" +printf '%s\n' \ + "[coredata-simulator-rehearsal-test] PASS (rejected): override without harness" + +printf '%s\n' \ + "[coredata-simulator-rehearsal-test] PASS: 2 positive + 39 negative/adversarial contracts" diff --git a/scripts/test-ios-release-archive-signing-contract.sh b/scripts/test-ios-release-archive-signing-contract.sh new file mode 100755 index 0000000000..cc629f5dc5 --- /dev/null +++ b/scripts/test-ios-release-archive-signing-contract.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +readonly BUILD_SCRIPT="$SCRIPT_DIR/ci/build-audited-ios-release-archive.sh" +readonly IDENTITY_AUDIT="$SCRIPT_DIR/ci/audit-ios-release-identity.sh" +readonly FIXTURES="$(mktemp -d "${TMPDIR:-/tmp}/fearless-release-archive-signing-tests.XXXXXX")" +trap 'rm -rf "$FIXTURES"' EXIT + +fail() { + printf '%s ERROR: %s\n' "[ios-release-archive-signing-test]" "$*" >&2 + exit 1 +} + +contains_workspace_signing_override() { + grep -Eq \ + '^[[:space:]]*"?(CODE_SIGN_IDENTITY|CODE_SIGN_STYLE|DEVELOPMENT_TEAM|PROVISIONING_PROFILE(_SPECIFIER)?)=' \ + "$1" +} + +[[ -f "$BUILD_SCRIPT" && ! -L "$BUILD_SCRIPT" ]] || + fail "archive build script is missing or unsafe" +[[ -f "$IDENTITY_AUDIT" && ! -L "$IDENTITY_AUDIT" ]] || + fail "release identity audit is missing or unsafe" + +# Command-line build-setting overrides apply to every target in a workspace. +# Profiles and manual signing must remain target-scoped, so neither is allowed +# in the xcodebuild argument vector assembled by this script. +if contains_workspace_signing_override "$BUILD_SCRIPT"; then + fail "archive script contains a workspace-wide signing/profile override" +fi + +# Prove the gate rejects both quoted/unquoted spellings and the legacy profile +# key. These mutations reproduce the class of command-line override that makes +# dependency targets fail with "does not support provisioning profiles." +override_number=0 +while IFS= read -r override; do + override_number=$((override_number + 1)) + mutant="$FIXTURES/override-$override_number.sh" + cp "$BUILD_SCRIPT" "$mutant" + printf '%s\n' "$override" >>"$mutant" + contains_workspace_signing_override "$mutant" || + fail "gate accepted workspace-wide override mutation: $override" +done <<'OVERRIDES' +CODE_SIGN_STYLE=Manual + "CODE_SIGN_STYLE=Automatic" +CODE_SIGN_IDENTITY=Apple Distribution + "CODE_SIGN_IDENTITY=Apple Distribution" +DEVELOPMENT_TEAM=YLWWUD25VZ + "DEVELOPMENT_TEAM=YLWWUD25VZ" +PROVISIONING_PROFILE=01234567-89AB-CDEF-0123-456789ABCDEF + "PROVISIONING_PROFILE=01234567-89AB-CDEF-0123-456789ABCDEF" +PROVISIONING_PROFILE_SPECIFIER=Fearless App Store + "PROVISIONING_PROFILE_SPECIFIER=Fearless App Store" +OVERRIDES + +grep -Fq \ + 'bash "$SCRIPT_DIR/audit-ios-signed-release-artifact.sh"' \ + "$BUILD_SCRIPT" || + fail "archive script no longer invokes the signed-artifact audit" +grep -Fq -- \ + '--expected-signing-certificate-sha1 "$EXPECTED_SIGNING_CERTIFICATE_SHA1"' \ + "$BUILD_SCRIPT" || + fail "signed-artifact audit is not bound to the reviewed certificate" +grep -Fq -- \ + '--expected-profile-uuid "$EXPECTED_PROFILE_UUID"' \ + "$BUILD_SCRIPT" || + fail "signed-artifact audit is not bound to the reviewed profile UUID" +grep -Fq -- \ + '--expected-profile-name "$EXPECTED_PROFILE_NAME"' \ + "$BUILD_SCRIPT" || + fail "signed-artifact audit is not bound to the reviewed profile name" +grep -Fq 'require_setting CODE_SIGN_STYLE "Manual"' "$IDENTITY_AUDIT" || + fail "release identity no longer requires target-scoped Manual signing" +grep -Fq \ + 'require_setting CODE_SIGN_IDENTITY "$EXPECTED_SIGNING_IDENTITY"' \ + "$IDENTITY_AUDIT" || + fail "release identity no longer requires the target-scoped distribution identity" +grep -Fq \ + 'require_setting PROVISIONING_PROFILE_SPECIFIER "$EXPECTED_PROFILE_NAME"' \ + "$IDENTITY_AUDIT" || + fail "release identity no longer requires the target-scoped App Store profile" + +printf '%s\n' \ + "[ios-release-archive-signing-test] PASS: canonical contract and $override_number workspace-wide override mutations" diff --git a/scripts/test-ios-release-identity-audit.sh b/scripts/test-ios-release-identity-audit.sh new file mode 100755 index 0000000000..eb39fdb5b9 --- /dev/null +++ b/scripts/test-ios-release-identity-audit.sh @@ -0,0 +1,377 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +readonly AUDIT="$REPO_ROOT/scripts/ci/audit-ios-release-identity.sh" +readonly FIXTURES="$(mktemp -d "${TMPDIR:-/tmp}/fearless-release-identity-tests.XXXXXX")" + +trap 'rm -rf "$FIXTURES"' EXIT + +pass_count=0 +fail_count=0 + +run_pass() { + local label="$1" + shift + + if "$@" >/dev/null 2>&1; then + pass_count=$((pass_count + 1)) + else + printf '[ios-release-identity-test] expected pass: %s\n' "$label" >&2 + exit 1 + fi +} + +run_reject() { + local label="$1" + shift + + if "$@" >/dev/null 2>&1; then + printf '[ios-release-identity-test] expected rejection: %s\n' "$label" >&2 + exit 1 + fi + fail_count=$((fail_count + 1)) +} + +settings="$FIXTURES/settings.json" +jq -n '[ + { + target: "fearless", + buildSettings: { + PRODUCT_BUNDLE_IDENTIFIER: "jp.co.soramitsu.fearlesswallet", + MARKETING_VERSION: "4.2.0", + CURRENT_PROJECT_VERSION: "2026.7.28", + CODE_SIGN_ENTITLEMENTS: "fearless/WalletConnect.entitlements", + CODE_SIGN_IDENTITY: "Apple Distribution: Soramitsu Co., Ltd. (YLWWUD25VZ)", + CODE_SIGN_STYLE: "Manual", + DEVELOPMENT_TEAM: "YLWWUD25VZ", + PROVISIONING_PROFILE_SPECIFIER: "Fearless App Store 2026.7.26", + SWIFT_OPTIMIZATION_LEVEL: "-O", + ENABLE_TESTABILITY: "NO" + } + } +]' > "$settings" + +debug_settings="$FIXTURES/debug-settings.json" +jq -n '[ + { + target: "fearless", + buildSettings: { + PRODUCT_BUNDLE_IDENTIFIER: "jp.co.soramitsu.fearlesswallet.dev", + CODE_SIGN_ENTITLEMENTS: "fearless/WalletConnect.dev.entitlements", + CODE_SIGN_STYLE: "Automatic", + DEVELOPMENT_TEAM: "YLWWUD25VZ" + } + } +]' > "$debug_settings" + +dev_entitlements="$REPO_ROOT/fearless/WalletConnect.dev.entitlements" + +run_audit() { + local info_plist="${4:-$REPO_ROOT/fearless/Info.plist}" + local wallet_connect_service="${5:-$REPO_ROOT/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift}" + local debug_settings_file="${6:-$debug_settings}" + local debug_entitlements_file="${7:-$dev_entitlements}" + + IOS_RELEASE_AUDIT_TEST_HARNESS=1 \ + IOS_EXPECTED_BUILD_NUMBER=2026.7.28 \ + IOS_RELEASE_SETTINGS_JSON="$1" \ + IOS_DEBUG_SETTINGS_JSON="$debug_settings_file" \ + IOS_RELEASE_SCHEME_FILE="$2" \ + IOS_RELEASE_ENTITLEMENTS_FILE="$3" \ + IOS_DEBUG_ENTITLEMENTS_FILE="$debug_entitlements_file" \ + IOS_RELEASE_INFO_PLIST_FILE="$info_plist" \ + IOS_RELEASE_WALLET_CONNECT_SERVICE_FILE="$wallet_connect_service" \ + bash "$AUDIT" +} + +run_debug_fixture() { + local debug_settings_file="$1" + local debug_entitlements_file="${2:-$dev_entitlements}" + + run_audit \ + "$settings" \ + "$scheme" \ + "$entitlements" \ + "$REPO_ROOT/fearless/Info.plist" \ + "$REPO_ROOT/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift" \ + "$debug_settings_file" \ + "$debug_entitlements_file" +} + +scheme="$REPO_ROOT/fearless.xcodeproj/xcshareddata/xcschemes/fearless.xcscheme" +entitlements="$REPO_ROOT/fearless/WalletConnect.entitlements" +run_pass canonical run_audit "$settings" "$scheme" "$entitlements" + +dev_scheme="$FIXTURES/dev.xcscheme" +sed 's/buildConfiguration = "Release"/buildConfiguration = "Dev"/' \ + "$scheme" > "$dev_scheme" +run_reject dev-archive run_audit "$settings" "$dev_scheme" "$entitlements" + +duplicate_scheme="$FIXTURES/duplicate.xcscheme" +sed 's###' \ + "$scheme" > "$duplicate_scheme" +run_reject duplicate-archive-action \ + run_audit "$settings" "$duplicate_scheme" "$entitlements" + +scheme_symlink="$FIXTURES/scheme-link" +ln -s "$scheme" "$scheme_symlink" +run_reject scheme-symlink \ + run_audit "$settings" "$scheme_symlink" "$entitlements" + +mutate_setting() { + local key="$1" + local value="$2" + local destination="$3" + + jq --arg key "$key" --arg value "$value" \ + '.[0].buildSettings[$key] = $value' "$settings" > "$destination" +} + +wrong_bundle="$FIXTURES/wrong-bundle.json" +mutate_setting PRODUCT_BUNDLE_IDENTIFIER jp.co.soramitsu.fearless "$wrong_bundle" +run_reject wrong-bundle run_audit "$wrong_bundle" "$scheme" "$entitlements" + +wrong_version="$FIXTURES/wrong-version.json" +mutate_setting MARKETING_VERSION 4.1.9 "$wrong_version" +run_reject wrong-version run_audit "$wrong_version" "$scheme" "$entitlements" + +wrong_build="$FIXTURES/wrong-build.json" +mutate_setting CURRENT_PROJECT_VERSION 7 "$wrong_build" +run_reject wrong-build run_audit "$wrong_build" "$scheme" "$entitlements" + +debug_optimization="$FIXTURES/debug-optimization.json" +mutate_setting SWIFT_OPTIMIZATION_LEVEL -Onone "$debug_optimization" +run_reject debug-optimization \ + run_audit "$debug_optimization" "$scheme" "$entitlements" + +testable_release="$FIXTURES/testable-release.json" +mutate_setting ENABLE_TESTABILITY YES "$testable_release" +run_reject testable-release \ + run_audit "$testable_release" "$scheme" "$entitlements" + +automatic_signing="$FIXTURES/automatic-signing.json" +mutate_setting CODE_SIGN_STYLE Automatic "$automatic_signing" +run_reject automatic-signing \ + run_audit "$automatic_signing" "$scheme" "$entitlements" + +wrong_signing_identity="$FIXTURES/wrong-signing-identity.json" +mutate_setting CODE_SIGN_IDENTITY "Apple Development" "$wrong_signing_identity" +run_reject wrong-signing-identity \ + run_audit "$wrong_signing_identity" "$scheme" "$entitlements" + +wrong_profile="$FIXTURES/wrong-profile.json" +mutate_setting PROVISIONING_PROFILE_SPECIFIER \ + "Another App Store Profile" "$wrong_profile" +run_reject wrong-profile \ + run_audit "$wrong_profile" "$scheme" "$entitlements" + +empty_profile="$FIXTURES/empty-profile.json" +mutate_setting PROVISIONING_PROFILE_SPECIFIER "" "$empty_profile" +run_reject empty-profile \ + run_audit "$empty_profile" "$scheme" "$entitlements" + +wrong_team="$FIXTURES/wrong-team.json" +mutate_setting DEVELOPMENT_TEAM AAAAAAAAAA "$wrong_team" +run_reject wrong-development-team \ + run_audit "$wrong_team" "$scheme" "$entitlements" + +dev_entitlement_setting="$FIXTURES/dev-entitlement-setting.json" +mutate_setting CODE_SIGN_ENTITLEMENTS \ + fearless/WalletConnect.dev.entitlements "$dev_entitlement_setting" +run_reject dev-entitlement-setting \ + run_audit "$dev_entitlement_setting" "$scheme" "$entitlements" + +extra_target="$FIXTURES/extra-target.json" +jq '. + [.[0]]' "$settings" > "$extra_target" +run_reject duplicate-fearless-target \ + run_audit "$extra_target" "$scheme" "$entitlements" + +malformed_settings="$FIXTURES/malformed-settings.json" +printf '%s\n' '{"not":"an array"}' > "$malformed_settings" +run_reject malformed-settings \ + run_audit "$malformed_settings" "$scheme" "$entitlements" + +mutate_debug_setting() { + local key="$1" + local value="$2" + local destination="$3" + + jq --arg key "$key" --arg value "$value" \ + '.[0].buildSettings[$key] = $value' \ + "$debug_settings" > "$destination" +} + +debug_production_bundle="$FIXTURES/debug-production-bundle.json" +mutate_debug_setting \ + PRODUCT_BUNDLE_IDENTIFIER \ + jp.co.soramitsu.fearlesswallet \ + "$debug_production_bundle" +run_reject debug-production-bundle \ + run_debug_fixture "$debug_production_bundle" + +debug_production_entitlements="$FIXTURES/debug-production-entitlements.json" +mutate_debug_setting \ + CODE_SIGN_ENTITLEMENTS \ + fearless/WalletConnect.entitlements \ + "$debug_production_entitlements" +run_reject debug-production-entitlements \ + run_debug_fixture "$debug_production_entitlements" + +debug_manual_signing="$FIXTURES/debug-manual-signing.json" +mutate_debug_setting CODE_SIGN_STYLE Manual "$debug_manual_signing" +run_reject debug-manual-signing \ + run_debug_fixture "$debug_manual_signing" + +debug_wrong_team="$FIXTURES/debug-wrong-team.json" +mutate_debug_setting DEVELOPMENT_TEAM AAAAAAAAAA "$debug_wrong_team" +run_reject debug-wrong-development-team \ + run_debug_fixture "$debug_wrong_team" + +duplicate_debug_target="$FIXTURES/duplicate-debug-target.json" +jq '. + [.[0]]' "$debug_settings" > "$duplicate_debug_target" +run_reject duplicate-debug-target \ + run_debug_fixture "$duplicate_debug_target" + +malformed_debug_settings="$FIXTURES/malformed-debug-settings.json" +printf '%s\n' '{"not":"an array"}' > "$malformed_debug_settings" +run_reject malformed-debug-settings \ + run_debug_fixture "$malformed_debug_settings" + +mutate_entitlements() { + local filter="$1" + local destination="$2" + + plutil -convert json -o - "$entitlements" | + jq "$filter" | + plutil -convert xml1 -o "$destination" - +} + +extra_cloud="$FIXTURES/extra-cloud.entitlements" +mutate_entitlements \ + '.["com.apple.developer.icloud-container-identifiers"] += ["iCloud.evil"]' \ + "$extra_cloud" +run_reject extra-cloud run_audit "$settings" "$scheme" "$extra_cloud" + +missing_applinks="$FIXTURES/missing-applinks.entitlements" +mutate_entitlements \ + '.["com.apple.developer.associated-domains"] = ["webcredentials:fearlesswallet.io"]' \ + "$missing_applinks" +run_reject missing-applinks \ + run_audit "$settings" "$scheme" "$missing_applinks" + +wrong_group="$FIXTURES/wrong-group.entitlements" +mutate_entitlements \ + '.["com.apple.security.application-groups"] = ["group.com.walletconnect.sdk"]' \ + "$wrong_group" +run_reject wrong-group run_audit "$settings" "$scheme" "$wrong_group" + +keychain_group="$FIXTURES/keychain-group.entitlements" +mutate_entitlements \ + '.["keychain-access-groups"] = ["group.jp.co.soramitsu.fearlesswallet"]' \ + "$keychain_group" +run_reject unexpected-keychain-group \ + run_audit "$settings" "$scheme" "$keychain_group" + +extra_entitlement="$FIXTURES/extra-entitlement.entitlements" +mutate_entitlements \ + '.["com.apple.developer.healthkit"] = true' \ + "$extra_entitlement" +run_reject unexpected-entitlement \ + run_audit "$settings" "$scheme" "$extra_entitlement" + +entitlements_symlink="$FIXTURES/entitlements-link" +ln -s "$entitlements" "$entitlements_symlink" +run_reject entitlements-symlink \ + run_audit "$settings" "$scheme" "$entitlements_symlink" + +debug_entitlements_production_group="$FIXTURES/debug-production-group.entitlements" +plutil -convert json -o - "$dev_entitlements" | + jq '.["com.apple.security.application-groups"] = ["group.jp.co.soramitsu.fearlesswallet"]' | + plutil -convert xml1 -o "$debug_entitlements_production_group" - +run_reject debug-production-group \ + run_debug_fixture "$debug_settings" "$debug_entitlements_production_group" + +debug_entitlements_missing_group="$FIXTURES/debug-missing-group.entitlements" +plutil -convert json -o - "$dev_entitlements" | + jq 'del(.["com.apple.security.application-groups"])' | + plutil -convert xml1 -o "$debug_entitlements_missing_group" - +run_reject debug-missing-group \ + run_debug_fixture "$debug_settings" "$debug_entitlements_missing_group" + +debug_entitlements_legacy_group="$FIXTURES/debug-legacy-group.entitlements" +plutil -convert json -o - "$dev_entitlements" | + jq '.["com.apple.security.application-groups"] = ["group.com.walletconnect.sdk"]' | + plutil -convert xml1 -o "$debug_entitlements_legacy_group" - +run_reject debug-legacy-group \ + run_debug_fixture "$debug_settings" "$debug_entitlements_legacy_group" + +debug_entitlements_extra_group="$FIXTURES/debug-extra-group.entitlements" +plutil -convert json -o - "$dev_entitlements" | + jq '.["com.apple.security.application-groups"] += ["group.evil"]' | + plutil -convert xml1 -o "$debug_entitlements_extra_group" - +run_reject debug-extra-group \ + run_debug_fixture "$debug_settings" "$debug_entitlements_extra_group" + +debug_entitlements_keychain_group="$FIXTURES/debug-keychain-group.entitlements" +plutil -convert json -o - "$dev_entitlements" | + jq '.["keychain-access-groups"] = ["group.jp.co.soramitsu.fearlesswallet.walletconnect"]' | + plutil -convert xml1 -o "$debug_entitlements_keychain_group" - +run_reject debug-explicit-keychain-group \ + run_debug_fixture "$debug_settings" "$debug_entitlements_keychain_group" + +debug_entitlements_production_cloud="$FIXTURES/debug-production-cloud.entitlements" +plutil -convert json -o - "$dev_entitlements" | + jq '.["com.apple.developer.icloud-container-identifiers"] = ["iCloud.jp.co.soramitsu.fearlesswallet"]' | + plutil -convert xml1 -o "$debug_entitlements_production_cloud" - +run_reject debug-production-cloud \ + run_debug_fixture "$debug_settings" "$debug_entitlements_production_cloud" + +debug_entitlements_symlink="$FIXTURES/debug-entitlements-link" +ln -s "$dev_entitlements" "$debug_entitlements_symlink" +run_reject debug-entitlements-symlink \ + run_debug_fixture "$debug_settings" "$debug_entitlements_symlink" + +hardcoded_build_plist="$FIXTURES/hardcoded-build.plist" +cp "$REPO_ROOT/fearless/Info.plist" "$hardcoded_build_plist" +plutil -replace CFBundleVersion -string 1 "$hardcoded_build_plist" +run_reject hardcoded-bundle-version \ + run_audit "$settings" "$scheme" "$entitlements" "$hardcoded_build_plist" + +hardcoded_version_plist="$FIXTURES/hardcoded-version.plist" +cp "$REPO_ROOT/fearless/Info.plist" "$hardcoded_version_plist" +plutil -replace CFBundleShortVersionString -string 4.2.0 \ + "$hardcoded_version_plist" +run_reject hardcoded-marketing-version \ + run_audit "$settings" "$scheme" "$entitlements" "$hardcoded_version_plist" + +missing_production_group_service="$FIXTURES/missing-production-group.swift" +sed \ + 's/static let productionGroupIdentifier = "group.jp.co.soramitsu.fearlesswallet"/static let productionGroupIdentifier = "group.com.walletconnect.sdk"/' \ + "$REPO_ROOT/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift" \ + > "$missing_production_group_service" +run_reject wallet-connect-production-group-mismatch \ + run_audit "$settings" "$scheme" "$entitlements" \ + "$REPO_ROOT/fearless/Info.plist" "$missing_production_group_service" + +missing_development_group_service="$FIXTURES/missing-development-group.swift" +sed \ + 's/group\.jp\.co\.soramitsu\.fearlesswallet\.walletconnect/group.com.walletconnect.sdk/' \ + "$REPO_ROOT/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift" \ + > "$missing_development_group_service" +run_reject wallet-connect-development-group-mismatch \ + run_audit "$settings" "$scheme" "$entitlements" \ + "$REPO_ROOT/fearless/Info.plist" "$missing_development_group_service" + +hardcoded_group_service="$FIXTURES/hardcoded-wallet-connect-group.swift" +sed \ + 's/groupIdentifier: groupIdentifier/groupIdentifier: Self.walletConnectGroupIdentifier/' \ + "$REPO_ROOT/fearless/ApplicationLayer/Services/WalletConnect/WalletConnectService.swift" \ + > "$hardcoded_group_service" +run_reject wallet-connect-hardcoded-group \ + run_audit "$settings" "$scheme" "$entitlements" \ + "$REPO_ROOT/fearless/Info.plist" "$hardcoded_group_service" + +printf '%s\n' \ + "[ios-release-identity-test] PASS: $pass_count positive and $fail_count negative/adversarial cases" diff --git a/scripts/test-ios-signed-release-artifact-audit.sh b/scripts/test-ios-signed-release-artifact-audit.sh new file mode 100755 index 0000000000..0b4832b6f4 --- /dev/null +++ b/scripts/test-ios-signed-release-artifact-audit.sh @@ -0,0 +1,410 @@ +#!/usr/bin/env bash +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +readonly AUDIT="$SCRIPT_DIR/ci/audit-ios-signed-release-artifact.sh" +readonly HASH_ARCHIVE="$SCRIPT_DIR/ci/hash-ios-archive.sh" +readonly TEMPORARY_DIR="$(mktemp -d "${TMPDIR:-/private/tmp}/fearless-signed-audit-tests.XXXXXX")" +readonly EXPECTED_GIT_SHA="7a819cb01e92920e5444151392df54245acdd4c8" + +trap 'rm -rf "$TEMPORARY_DIR"' EXIT + +RUN_NUMBER=0 +CASE_DIR="" +ARCHIVE="" +APP="" +SIGNED_ENTITLEMENTS="" +PROFILE="" +SIGNING_CERTIFICATE="" +CASE_ENV=() + +fail() { + printf '%s\n' "[ios-signed-release-audit-test][error] $*" >&2 + exit 1 +} + +assert_contains() { + local expected="$1" + local file="$2" + grep -Fq -- "$expected" "$file" || + fail "expected '$expected' in $(basename "$file")" +} + +prepare_case() { + local label="$1" + RUN_NUMBER=$((RUN_NUMBER + 1)) + CASE_DIR="$TEMPORARY_DIR/case-${RUN_NUMBER}-${label}" + ARCHIVE="$CASE_DIR/fearless.xcarchive" + APP="$ARCHIVE/Products/Applications/fearless.app" + SIGNED_ENTITLEMENTS="$CASE_DIR/signed-entitlements.plist" + PROFILE="$CASE_DIR/profile.plist" + SIGNING_CERTIFICATE="$CASE_DIR/signing-certificate.cer" + mkdir -p "$APP" "$CASE_DIR/output" + + python3 - "$ARCHIVE/Info.plist" "$APP/Info.plist" \ + "$SIGNED_ENTITLEMENTS" "$PROFILE" "$SIGNING_CERTIFICATE" \ + "$EXPECTED_GIT_SHA" <<'PY' +import datetime +import plistlib +import sys + +( + archive_path, + app_path, + entitlements_path, + profile_path, + certificate_path, + git_sha, +) = sys.argv[1:] +team = "YLWWUD25VZ" +bundle = "jp.co.soramitsu.fearlesswallet" +application_id = f"{team}.{bundle}" +certificate = b"canonical Fearless App Store signing certificate" +capabilities = { + "com.apple.developer.associated-domains": [ + "applinks:fearlesswallet.io", + "webcredentials:fearlesswallet.io", + ], + "com.apple.developer.icloud-container-identifiers": [ + "iCloud.jp.co.soramitsu.fearlesswallet" + ], + "com.apple.developer.icloud-services": ["CloudKit"], + "com.apple.security.application-groups": [ + "group.jp.co.soramitsu.fearlesswallet" + ], +} +signed = { + **capabilities, + "application-identifier": application_id, + "com.apple.developer.team-identifier": team, +} +profile_entitlements = { + "com.apple.developer.associated-domains": "*", + "com.apple.developer.icloud-container-development-container-identifiers": [ + "iCloud.jp.co.soramitsu.fearlesswallet" + ], + "com.apple.developer.icloud-container-environment": [ + "Production", + "Development", + ], + "com.apple.developer.icloud-container-identifiers": [ + "iCloud.jp.co.soramitsu.fearlesswallet" + ], + "com.apple.developer.icloud-services": "*", + "com.apple.developer.ubiquity-container-identifiers": [ + "iCloud.jp.co.soramitsu.fearlesswallet" + ], + "com.apple.developer.ubiquity-kvstore-identifier": f"{team}.*", + "com.apple.security.application-groups": [ + "group.jp.co.soramitsu.fearlesswallet" + ], + "application-identifier": application_id, + "com.apple.developer.team-identifier": team, + "get-task-allow": False, + "beta-reports-active": True, + "keychain-access-groups": ["YLWWUD25VZ.*", "com.apple.token"], +} +archive = { + "ApplicationProperties": { + "ApplicationPath": "Applications/fearless.app", + "CFBundleIdentifier": bundle, + "SigningIdentity": "Apple Distribution: Fearless Test ($team)", + "Team": team, + } +} +app = { + "CFBundleExecutable": "fearless", + "CFBundleIdentifier": bundle, + "CFBundleShortVersionString": "4.2.0", + "CFBundleVersion": "2026.7.28", + "FearlessBuildConfiguration": "Release", + "FearlessEnableTestability": "NO", + "FearlessGitCommit": git_sha, + "FearlessSwiftOptimizationLevel": "-O", +} +profile = { + "CreationDate": datetime.datetime(2026, 1, 1), + "DeveloperCertificates": [certificate], + "Entitlements": profile_entitlements, + "ExpirationDate": datetime.datetime(2035, 1, 1), + "Name": "Fearless App Store", + "TeamIdentifier": [team], + "TeamName": "Fearless", + "UUID": "11111111-2222-3333-4444-555555555555", +} +for path, payload in ( + (archive_path, archive), + (app_path, app), + (entitlements_path, signed), + (profile_path, profile), +): + with open(path, "wb") as destination: + plistlib.dump(payload, destination) +with open(certificate_path, "wb") as destination: + destination.write(certificate) +PY + + printf '%s\n' '#!/usr/bin/env bash' 'exit 0' >"$APP/fearless" + chmod +x "$APP/fearless" + printf '%s\n' "opaque production profile" >"$APP/embedded.mobileprovision" + CASE_ENV=() +} + +run_audit() { + local label="$1" + local executable_sha + local archive_sha + local signing_certificate_sha1 + executable_sha="$(shasum -a 256 "$APP/fearless" | awk '{print $1}')" + archive_sha="$(bash "$HASH_ARCHIVE" "$ARCHIVE")" + signing_certificate_sha1="$( + shasum -a 1 "$SIGNING_CERTIFICATE" | awk '{print $1}' + )" + + env \ + FEARLESS_SIGNED_AUDIT_TEST_HARNESS=1 \ + FEARLESS_SIGNED_AUDIT_CODESIGN_BIN="$TEMPORARY_DIR/bin/codesign" \ + FEARLESS_SIGNED_AUDIT_SECURITY_BIN="$TEMPORARY_DIR/bin/security" \ + FAKE_SIGNED_ENTITLEMENTS="$SIGNED_ENTITLEMENTS" \ + FAKE_SIGNING_CERTIFICATE="$SIGNING_CERTIFICATE" \ + FAKE_PROFILE_PLIST="$PROFILE" \ + ${CASE_ENV[@]+"${CASE_ENV[@]}"} \ + bash "$AUDIT" \ + --archive "$ARCHIVE" \ + --expected-git-sha "${EXPECTED_GIT_OVERRIDE:-$EXPECTED_GIT_SHA}" \ + --expected-build 2026.7.28 \ + --expected-executable-sha256 "${EXPECTED_EXECUTABLE_SHA_OVERRIDE:-$executable_sha}" \ + --expected-archive-sha256 "${EXPECTED_ARCHIVE_SHA_OVERRIDE:-$archive_sha}" \ + --expected-signing-certificate-sha1 "${EXPECTED_SIGNING_CERTIFICATE_SHA_OVERRIDE:-$signing_certificate_sha1}" \ + --expected-profile-uuid 11111111-2222-3333-4444-555555555555 \ + --expected-profile-name "Fearless App Store" \ + --receipt "$CASE_DIR/output/receipt.json" \ + >"$CASE_DIR/stdout" 2>"$CASE_DIR/stderr" +} + +expect_failure() { + local label="$1" + local expected="$2" + if run_audit "$label"; then + fail "$label unexpectedly passed" + fi + assert_contains "$expected" "$CASE_DIR/stderr" + printf '%s\n' "[ios-signed-release-audit-test] PASS (rejected): $label" +} + +mutate_plist() { + local path="$1" + local expression="$2" + python3 - "$path" "$expression" <<'PY' +import datetime +import plistlib +import sys + +path, expression = sys.argv[1:] +with open(path, "rb") as source: + value = plistlib.load(source) +scope = {"value": value, "datetime": datetime} +exec(expression, scope, scope) +with open(path, "wb") as destination: + plistlib.dump(value, destination) +PY +} + +mkdir -p "$TEMPORARY_DIR/bin" +printf '%s\n' \ + '#!/usr/bin/env bash' \ + 'set -euo pipefail' \ + 'if [[ "${FAKE_CODESIGN_VERIFY_FAIL:-0}" == "1" && "${1:-}" == "--verify" ]]; then exit 1; fi' \ + 'if [[ "${1:-}" == "-d" && "${2:-}" == --extract-certificates=* ]]; then' \ + ' prefix="${2#--extract-certificates=}"' \ + ' cp "$FAKE_SIGNING_CERTIFICATE" "${prefix}0"' \ + 'elif [[ "${1:-}" == "-d" ]]; then' \ + ' cp "$FAKE_SIGNED_ENTITLEMENTS" /dev/stdout' \ + 'fi' \ + >"$TEMPORARY_DIR/bin/codesign" +printf '%s\n' \ + '#!/usr/bin/env bash' \ + 'set -euo pipefail' \ + '[[ "${FAKE_SECURITY_FAIL:-0}" != "1" ]] || exit 1' \ + 'cp "$FAKE_PROFILE_PLIST" /dev/stdout' \ + >"$TEMPORARY_DIR/bin/security" +chmod +x "$TEMPORARY_DIR/bin/codesign" "$TEMPORARY_DIR/bin/security" + +prepare_case canonical +if ! run_audit canonical; then + sed -n '1,100p' "$CASE_DIR/stderr" >&2 + fail "canonical signed archive was rejected" +fi +assert_contains '"archiveTreeSHA256"' "$CASE_DIR/output/receipt.json" +assert_contains '"distributionProfile": "valid-app-store"' "$CASE_DIR/output/receipt.json" +printf '%s\n' "[ios-signed-release-audit-test] PASS: canonical signed archive" + +prepare_case wrong-build +mutate_plist "$APP/Info.plist" \ + 'value["CFBundleVersion"] = "2026.7.27"' +expect_failure wrong-build "archived build number is not the expected fresh build" + +prepare_case wrong-commit +EXPECTED_GIT_OVERRIDE="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +expect_failure wrong-commit "embedded git commit" +unset EXPECTED_GIT_OVERRIDE + +prepare_case executable-digest +EXPECTED_EXECUTABLE_SHA_OVERRIDE="$(printf 'a%.0s' {1..64})" +expect_failure executable-digest "executable SHA-256" +unset EXPECTED_EXECUTABLE_SHA_OVERRIDE + +prepare_case archive-digest +EXPECTED_ARCHIVE_SHA_OVERRIDE="$(printf 'b%.0s' {1..64})" +expect_failure archive-digest "archive SHA-256" +unset EXPECTED_ARCHIVE_SHA_OVERRIDE + +prepare_case wrong-team +mutate_plist "$PROFILE" \ + 'value["TeamIdentifier"] = ["AAAAAAAAAA"]' +expect_failure wrong-team "signed entitlements or embedded distribution profile" + +prepare_case wrong-archive-team +mutate_plist "$ARCHIVE/Info.plist" \ + 'value["ApplicationProperties"]["Team"] = "AAAAAAAAAA"' +expect_failure wrong-archive-team "xcarchive metadata" + +prepare_case archive-path-includes-products +mutate_plist "$ARCHIVE/Info.plist" \ + 'value["ApplicationProperties"]["ApplicationPath"] = "Products/Applications/fearless.app"' +expect_failure archive-path-includes-products "xcarchive metadata" + +prepare_case archive-path-traversal +mutate_plist "$ARCHIVE/Info.plist" \ + 'value["ApplicationProperties"]["ApplicationPath"] = "../Applications/fearless.app"' +expect_failure archive-path-traversal "xcarchive metadata" + +prepare_case archive-path-absolute +mutate_plist "$ARCHIVE/Info.plist" \ + 'value["ApplicationProperties"]["ApplicationPath"] = "/Applications/fearless.app"' +expect_failure archive-path-absolute "xcarchive metadata" + +prepare_case archive-path-wrong-app +mutate_plist "$ARCHIVE/Info.plist" \ + 'value["ApplicationProperties"]["ApplicationPath"] = "Applications/attacker.app"' +expect_failure archive-path-wrong-app "xcarchive metadata" + +prepare_case archive-path-missing +mutate_plist "$ARCHIVE/Info.plist" \ + 'del value["ApplicationProperties"]["ApplicationPath"]' +expect_failure archive-path-missing "xcarchive metadata" + +prepare_case development-identity +mutate_plist "$ARCHIVE/Info.plist" \ + 'value["ApplicationProperties"]["SigningIdentity"] = "Apple Development: Unsafe"' +expect_failure development-identity "distribution identity" + +prepare_case development-profile +mutate_plist "$PROFILE" \ + 'value["ProvisionedDevices"] = ["DEVICE-UDID"]' +expect_failure development-profile "signed entitlements or embedded distribution profile" + +prepare_case non-testflight-profile +mutate_plist "$PROFILE" \ + 'del value["Entitlements"]["beta-reports-active"]' +expect_failure non-testflight-profile "signed entitlements or embedded distribution profile" + +prepare_case enterprise-profile +mutate_plist "$PROFILE" \ + 'value["ProvisionsAllDevices"] = True' +expect_failure enterprise-profile "signed entitlements or embedded distribution profile" + +prepare_case get-task-allow +mutate_plist "$SIGNED_ENTITLEMENTS" \ + 'value["get-task-allow"] = True' +expect_failure get-task-allow "signed entitlements or embedded distribution profile" + +prepare_case expired-profile +mutate_plist "$PROFILE" \ + 'value["ExpirationDate"] = datetime.datetime(2026, 2, 1)' +expect_failure expired-profile "signed entitlements or embedded distribution profile" + +prepare_case profile-expiring-too-soon +mutate_plist "$PROFILE" \ + 'value["ExpirationDate"] = datetime.datetime.now() + datetime.timedelta(days=7)' +expect_failure profile-expiring-too-soon "signed entitlements or embedded distribution profile" + +prepare_case replaced-walletconnect-group +mutate_plist "$SIGNED_ENTITLEMENTS" \ + 'value["com.apple.security.application-groups"] = ["group.com.walletconnect.sdk"]' +expect_failure replaced-walletconnect-group "signed entitlements or embedded distribution profile" + +prepare_case unexpected-signed-keychain-group +mutate_plist "$SIGNED_ENTITLEMENTS" \ + 'value["keychain-access-groups"] = ["group.jp.co.soramitsu.fearlesswallet"]' +expect_failure unexpected-signed-keychain-group "signed entitlements or embedded distribution profile" + +prepare_case profile-missing-keychain-group +mutate_plist "$PROFILE" \ + 'del value["Entitlements"]["keychain-access-groups"]' +expect_failure profile-missing-keychain-group "signed entitlements or embedded distribution profile" + +prepare_case profile-signing-certificate-mismatch +mutate_plist "$PROFILE" \ + 'value["DeveloperCertificates"] = [b"unrelated distribution certificate"]' +expect_failure profile-signing-certificate-mismatch "signed entitlements or embedded distribution profile" + +prepare_case wrong-profile-uuid +mutate_plist "$PROFILE" \ + 'value["UUID"] = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE"' +expect_failure wrong-profile-uuid "signed entitlements or embedded distribution profile" + +prepare_case wrong-profile-name +mutate_plist "$PROFILE" \ + 'value["Name"] = "Unreviewed App Store Profile"' +expect_failure wrong-profile-name "signed entitlements or embedded distribution profile" + +prepare_case profile-unauthorized-associated-domains +mutate_plist "$PROFILE" \ + 'value["Entitlements"]["com.apple.developer.associated-domains"] = ["applinks:attacker.example"]' +expect_failure profile-unauthorized-associated-domains "signed entitlements or embedded distribution profile" + +prepare_case profile-missing-production-cloud-environment +mutate_plist "$PROFILE" \ + 'value["Entitlements"]["com.apple.developer.icloud-container-environment"] = ["Development"]' +expect_failure profile-missing-production-cloud-environment "signed entitlements or embedded distribution profile" + +prepare_case profile-wrong-ubiquity-container +mutate_plist "$PROFILE" \ + 'value["Entitlements"]["com.apple.developer.ubiquity-container-identifiers"] = ["iCloud.jp.co.soramitsu.fearlesswallet.dev"]' +expect_failure profile-wrong-ubiquity-container "signed entitlements or embedded distribution profile" + +prepare_case profile-unexpected-entitlement +mutate_plist "$PROFILE" \ + 'value["Entitlements"]["com.apple.developer.healthkit"] = True' +expect_failure profile-unexpected-entitlement "signed entitlements or embedded distribution profile" + +prepare_case unexpected-signed-entitlement +mutate_plist "$SIGNED_ENTITLEMENTS" \ + 'value["com.apple.developer.healthkit"] = True' +expect_failure unexpected-signed-entitlement "signed entitlements or embedded distribution profile" + +prepare_case development-cloud +mutate_plist "$SIGNED_ENTITLEMENTS" \ + 'value["com.apple.developer.icloud-container-identifiers"] = ["iCloud.jp.co.soramitsu.fearlesswallet.dev"]' +expect_failure development-cloud "signed entitlements or embedded distribution profile" + +prepare_case signature-failure +CASE_ENV=("FAKE_CODESIGN_VERIFY_FAIL=1") +expect_failure signature-failure "strict code-signature" + +prepare_case profile-decode-failure +CASE_ENV=("FAKE_SECURITY_FAIL=1") +expect_failure profile-decode-failure "could not be decoded" + +prepare_case override-without-harness +if env \ + FEARLESS_SIGNED_AUDIT_CODESIGN_BIN="$TEMPORARY_DIR/bin/codesign" \ + bash "$AUDIT" >"$CASE_DIR/stdout" 2>"$CASE_DIR/stderr"; then + fail "tool override without harness unexpectedly passed" +fi +assert_contains "only in the explicit test harness" "$CASE_DIR/stderr" +printf '%s\n' "[ios-signed-release-audit-test] PASS (rejected): override without harness" + +printf '%s\n' \ + "[ios-signed-release-audit-test] PASS: 1 positive + 33 negative/adversarial contracts" diff --git a/scripts/test-matrix.sh b/scripts/test-matrix.sh index 3e082c6be2..fb8ab7ce08 100755 --- a/scripts/test-matrix.sh +++ b/scripts/test-matrix.sh @@ -184,13 +184,11 @@ run_tests() { run_tests Debug if [[ "${HOST_ARCH}" == "x86_64" ]]; then - echo "\n==> Skipping Release simulator tests on x86_64 host due to missing native package symbols for simulator linking" + echo "\n==> ERROR: Release simulator tests are mandatory and cannot run on this x86_64 host" >&2 + echo "Dispatch this job to an arm64 macOS runner; a Debug-only result is not release evidence." >&2 + exit 78 else run_tests Release fi -if [[ "${HOST_ARCH}" == "x86_64" ]]; then - echo "\n==> Debug tests passed; Release simulator tests were skipped on x86_64 host" -else - echo "\n==> All tests passed in Debug and Release" -fi +echo "\n==> All tests passed in Debug and Release" diff --git a/scripts/test-testflight-publication-readiness-audit.sh b/scripts/test-testflight-publication-readiness-audit.sh new file mode 100755 index 0000000000..658cf62922 --- /dev/null +++ b/scripts/test-testflight-publication-readiness-audit.sh @@ -0,0 +1,430 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +AUDIT="$ROOT_DIR/scripts/audit-testflight-publication-readiness.sh" +TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/testflight-publication-test.XXXXXX")" +CASES=0 +EXPECTED_CASES=70 + +cleanup() { + rm -rf "$TMP_DIR" +} +trap cleanup EXIT INT TERM + +fail() { + echo "[testflight-publication-test][error] $*" >&2 + exit 1 +} + +sha256_file() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$1" | awk '{print $1}' + else + shasum -a 256 "$1" | awk '{print $1}' + fi +} + +make_fixture() { + local fixture="$1" + mkdir -p \ + "$fixture/config" \ + "$fixture/docs" \ + "$fixture/scripts/ci" \ + "$fixture/.github/workflows" + cp "$ROOT_DIR/config/testflight-publication-readiness.json" "$fixture/config/" + cp "$ROOT_DIR/docs/testflight-publication-readiness.md" "$fixture/docs/" + cp "$ROOT_DIR/docs/release-checklist.md" "$fixture/docs/" + cp "$ROOT_DIR/scripts/ci/run-pr.sh" "$fixture/scripts/ci/" + cp "$ROOT_DIR/.github/workflows/codecov.yml" "$fixture/.github/workflows/" + cp "$ROOT_DIR/scripts/audit-testflight-publication-readiness.sh" "$fixture/scripts/" + cp "$ROOT_DIR/scripts/test-testflight-publication-readiness-audit.sh" "$fixture/scripts/" + chmod +x \ + "$fixture/scripts/audit-testflight-publication-readiness.sh" \ + "$fixture/scripts/test-testflight-publication-readiness-audit.sh" +} + +new_fixture() { + local name="$1" + local fixture="$TMP_DIR/$name" + make_fixture "$fixture" + printf '%s\n' "$fixture" +} + +set_json() { + local manifest="$1" + local field_path="$2" + local json_value="$3" + node - "$manifest" "$field_path" "$json_value" <<'NODE' +const fs = require('node:fs'); +const [path, fieldPath, encoded] = process.argv.slice(2); +const document = JSON.parse(fs.readFileSync(path, 'utf8')); +const segments = fieldPath.split('.'); +let cursor = document; +for (const segment of segments.slice(0, -1)) cursor = cursor[segment]; +cursor[segments.at(-1)] = JSON.parse(encoded); +fs.writeFileSync(path, `${JSON.stringify(document, null, 2)}\n`); +NODE +} + +replace_once() { + local path="$1" + local needle="$2" + local replacement="$3" + node - "$path" "$needle" "$replacement" <<'NODE' +const fs = require('node:fs'); +const [path, needle, replacement] = process.argv.slice(2); +const source = fs.readFileSync(path, 'utf8'); +const first = source.indexOf(needle); +if (first === -1) throw new Error(`mutation marker is missing in ${path}: ${needle}`); +if (source.indexOf(needle, first + needle.length) !== -1) { + throw new Error(`mutation marker is ambiguous in ${path}: ${needle}`); +} +fs.writeFileSync(path, source.slice(0, first) + replacement + source.slice(first + needle.length)); +NODE +} + +expect_failure_with_digest() { + local label="$1" + local fixture="$2" + local digest="$3" + local expected="$4" + local output status=0 + output="$( + TESTFLIGHT_PUBLICATION_AUDIT_ROOT="$fixture" \ + TESTFLIGHT_PUBLICATION_AUDIT_EXPECTED_MANIFEST_SHA256="$digest" \ + bash "$AUDIT" 2>&1 + )" || status=$? + [[ "$status" -ne 0 ]] || fail "$label unexpectedly passed" + grep -Fq -- "$expected" <<<"$output" || + fail "$label failed for the wrong reason; expected '$expected', got: $output" + CASES=$((CASES + 1)) + echo "[testflight-publication-test] rejected $label" +} + +expect_failure() { + local label="$1" + local fixture="$2" + local expected="$3" + local digest + digest="$(sha256_file "$fixture/config/testflight-publication-readiness.json")" + expect_failure_with_digest "$label" "$fixture" "$digest" "$expected" +} + +baseline="$(new_fixture baseline)" +TESTFLIGHT_PUBLICATION_AUDIT_ROOT="$baseline" bash "$AUDIT" >/dev/null || + fail "valid blocked TestFlight publication baseline was rejected" +CASES=$((CASES + 1)) +echo "[testflight-publication-test] accepted valid blocked baseline" + +fixture="$(new_fixture schema-version)" +set_json "$fixture/config/testflight-publication-readiness.json" schemaVersion 2 +expect_failure "schema version drift" "$fixture" "schemaVersion must be 1" + +fixture="$(new_fixture platform)" +set_json "$fixture/config/testflight-publication-readiness.json" platform '"android"' +expect_failure "platform drift" "$fixture" "platform must be ios" + +fixture="$(new_fixture distribution-channel)" +set_json "$fixture/config/testflight-publication-readiness.json" distributionChannel '"app-store-production"' +expect_failure "distribution channel drift" "$fixture" "distribution channel drifted" + +fixture="$(new_fixture assessment-timestamp)" +set_json "$fixture/config/testflight-publication-readiness.json" assessedAtUTC '"2026-07-26T13:26:12Z"' +expect_failure "assessment timestamp drift" "$fixture" "assessment timestamp drifted" + +fixture="$(new_fixture evidence-contract)" +set_json "$fixture/config/testflight-publication-readiness.json" evidenceBoundary.contract '"raw-build-output"' +expect_failure "evidence boundary drift" "$fixture" "evidence boundary contract drifted" + +fixture="$(new_fixture evidence-method)" +set_json "$fixture/config/testflight-publication-readiness.json" evidenceBoundary.observationMethod '"api"' +expect_failure "fabricated observation method" "$fixture" "observation method drifted" + +fixture="$(new_fixture raw-tracked)" +set_json "$fixture/config/testflight-publication-readiness.json" evidenceBoundary.rawAttestationsTracked true +expect_failure "ignored raw attestations claimed tracked" "$fixture" "ignored raw attestations must not be claimed as tracked" + +fixture="$(new_fixture raw-location)" +set_json "$fixture/config/testflight-publication-readiness.json" evidenceBoundary.rawAttestationsLocation '"tracked-source"' +expect_failure "raw attestation location drift" "$fixture" "raw attestation location drifted" + +fixture="$(new_fixture stale-state-accepted)" +set_json "$fixture/config/testflight-publication-readiness.json" evidenceBoundary.currentStateRevalidationRequired false +expect_failure "mutable state revalidation removed" "$fixture" "mutable App Store Connect state must require revalidation" + +fixture="$(new_fixture source-commit)" +set_json "$fixture/config/testflight-publication-readiness.json" artifact.sourceCommit '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "artifact source commit drift" "$fixture" "artifact source commit drifted" + +fixture="$(new_fixture bundle-id)" +set_json "$fixture/config/testflight-publication-readiness.json" artifact.bundleIdentifier '"jp.co.soramitsu.fearlesswallet.dev"' +expect_failure "artifact bundle drift" "$fixture" "artifact bundle identifier drifted" + +fixture="$(new_fixture build-number)" +set_json "$fixture/config/testflight-publication-readiness.json" artifact.buildNumber '"2026.7.15"' +expect_failure "artifact build drift" "$fixture" "artifact build number drifted" + +fixture="$(new_fixture archive-digest)" +set_json "$fixture/config/testflight-publication-readiness.json" artifact.preUploadArchiveTreeSHA256 '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "archive tree digest drift" "$fixture" "pre-upload archive tree SHA-256 drifted" + +fixture="$(new_fixture executable-digest)" +set_json "$fixture/config/testflight-publication-readiness.json" artifact.executableSHA256 '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "executable digest drift" "$fixture" "executable SHA-256 drifted" + +fixture="$(new_fixture receipt-digest)" +set_json "$fixture/config/testflight-publication-readiness.json" artifact.signedArchiveAuditReceiptSHA256 '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "signed audit receipt drift" "$fixture" "signed archive audit receipt SHA-256 drifted" + +fixture="$(new_fixture rehearsal-digest)" +set_json "$fixture/config/testflight-publication-readiness.json" artifact.preservedDataArchiveRehearsalResultSHA256 '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "archive rehearsal result drift" "$fixture" "preserved-data archive rehearsal result SHA-256 drifted" + +fixture="$(new_fixture upload-status)" +set_json "$fixture/config/testflight-publication-readiness.json" upload.status '"failed"' +expect_failure "upload success removed" "$fixture" "upload status must remain success" + +fixture="$(new_fixture upload-time)" +set_json "$fixture/config/testflight-publication-readiness.json" upload.uploadedAtUTC '"2026-07-26T13:17:00Z"' +expect_failure "upload timestamp drift" "$fixture" "upload timestamp drifted" + +fixture="$(new_fixture post-upload-tree)" +set_json "$fixture/config/testflight-publication-readiness.json" upload.postUploadArchiveTreeSHA256 '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "post-upload tree drift" "$fixture" "post-upload archive tree SHA-256 drifted" + +fixture="$(new_fixture post-upload-attestation)" +set_json "$fixture/config/testflight-publication-readiness.json" upload.postUploadAttestationSHA256 '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "post-upload attestation drift" "$fixture" "post-upload attestation SHA-256 drifted" + +fixture="$(new_fixture xcode-mutation)" +set_json "$fixture/config/testflight-publication-readiness.json" upload.xcodeMutation '"unbounded"' +expect_failure "Xcode mutation scope widened" "$fixture" "Xcode post-upload mutation scope drifted" + +fixture="$(new_fixture reconstructed-tree)" +set_json "$fixture/config/testflight-publication-readiness.json" upload.reconstructedPreUploadArchiveTreeMatched false +expect_failure "reconstructed tree mismatch accepted" "$fixture" "reconstructed pre-upload archive tree match must remain true" + +fixture="$(new_fixture signature)" +set_json "$fixture/config/testflight-publication-readiness.json" upload.embeddedAppSignatureVerified false +expect_failure "embedded signature failure accepted" "$fixture" "embedded app signature verification must remain true" + +fixture="$(new_fixture processing-status)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.processingStatus '"ready-to-submit"' +expect_failure "TestFlight status regressed" "$fixture" "TestFlight processing status must remain testing" + +fixture="$(new_fixture external-testing)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.externalTestingActive false +expect_failure "external testing disabled" "$fixture" "external TestFlight testing must remain active" + +fixture="$(new_fixture group-name)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.externalGroup.name '"Internal Only"' +expect_failure "external group drift" "$fixture" "external group name drifted" + +fixture="$(new_fixture group-id)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.externalGroup.id '"00000000-0000-0000-0000-000000000000"' +expect_failure "external group identifier drift" "$fixture" "external group identifier drifted" + +fixture="$(new_fixture group-testers)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.externalGroup.testerCount 123 +expect_failure "external group tester snapshot drift" "$fixture" "external group tester count snapshot drifted" + +fixture="$(new_fixture group-builds)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.externalGroup.buildCount 1 +expect_failure "external group build snapshot drift" "$fixture" "external group build count snapshot drifted" + +fixture="$(new_fixture group-missing-build)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.externalGroup.containsBuild false +expect_failure "external group build assignment removed" "$fixture" "external group must contain build 2026.7.26" + +fixture="$(new_fixture public-count)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.externalGroup.publicLinkTesterCount 121 +expect_failure "public-link tester snapshot drift" "$fixture" "public-link tester count snapshot drifted" + +fixture="$(new_fixture public-limit)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.externalGroup.publicLinkTesterLimit 501 +expect_failure "public-link limit drift" "$fixture" "public-link tester limit drifted" + +fixture="$(new_fixture link-disabled)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.publicLink.enabled false +expect_failure "public link disabled" "$fixture" "public TestFlight link must remain enabled" + +fixture="$(new_fixture link-private)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.publicLink.shareableToAnyoneWithLink false +expect_failure "anyone-with-link access removed" "$fixture" "public TestFlight link must remain shareable to anyone with the link" + +fixture="$(new_fixture link-origin)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.publicLink.url '"https://evil.example/join/012KzFyD"' +expect_failure "hostile public-link origin" "$fixture" "public TestFlight URL drifted" + +fixture="$(new_fixture link-digest)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.publicLink.urlSHA256 '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "public-link digest drift" "$fixture" "public TestFlight URL SHA-256 drifted" + +fixture="$(new_fixture landing-page)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.publicLink.landingPageResolved false +expect_failure "landing page resolution removed" "$fixture" "public landing page resolution must remain true" + +fixture="$(new_fixture app-name)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.publicLink.landingPageApplicationName '"Lookalike Wallet"' +expect_failure "landing-page app identity drift" "$fixture" "public landing-page application identity drifted" + +fixture="$(new_fixture deep-link)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.publicLink.testFlightDeepLinkPresent false +expect_failure "TestFlight deep link removed" "$fixture" "public landing page must retain the TestFlight deep link" + +fixture="$(new_fixture what-to-test)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.whatToTestSHA256 '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "What to Test digest drift" "$fixture" "What to Test text SHA-256 drifted" + +fixture="$(new_fixture notifications)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.automaticTesterNotification false +expect_failure "tester notification drift" "$fixture" "automatic tester notification must remain recorded as enabled" + +fixture="$(new_fixture publication-attestation)" +set_json "$fixture/config/testflight-publication-readiness.json" testFlight.publicationAttestationSHA256 '"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"' +expect_failure "publication attestation drift" "$fixture" "publication attestation SHA-256 drifted" + +fixture="$(new_fixture symbolication-status)" +set_json "$fixture/config/testflight-publication-readiness.json" symbolication.status '"complete"' +expect_failure "symbolication falsely closed" "$fixture" "symbolication status drifted" + +fixture="$(new_fixture dsym-runtime-impact)" +set_json "$fixture/config/testflight-publication-readiness.json" symbolication.runtimeInstallLaunchOrMigrationImpact true +expect_failure "dSYM warning misclassified as runtime failure" "$fixture" "dSYM warnings must not be classified as an install, launch, or migration runtime failure" + +fixture="$(new_fixture app-dsym)" +set_json "$fixture/config/testflight-publication-readiness.json" symbolication.mainApplicationDSYMPresent false +expect_failure "main app dSYM removed" "$fixture" "main application dSYM presence must remain recorded" + +fixture="$(new_fixture vendor-dsym)" +set_json "$fixture/config/testflight-publication-readiness.json" symbolication.runtimeFrameworkMissingVendorDSYM '"sr25519lib.framework"' +expect_failure "runtime vendor dSYM gap drift" "$fixture" "runtime framework vendor-dSYM gap drifted" + +fixture="$(new_fixture static-stubs)" +set_json "$fixture/config/testflight-publication-readiness.json" symbolication.staticStubFrameworkWarnings '["libed25519.framework","blake2lib.framework","sr25519lib.framework"]' +expect_failure "static-stub warning order drift" "$fixture" "static stub framework warning inventory drifted" + +fixture="$(new_fixture symbolication-followup)" +set_json "$fixture/config/testflight-publication-readiness.json" symbolication.productionFollowUpRequired false +expect_failure "symbolication follow-up prematurely closed" "$fixture" "third-party production symbolication follow-up must remain required" + +fixture="$(new_fixture ready-status)" +set_json "$fixture/config/testflight-publication-readiness.json" readiness.status '"ready"' +expect_failure "premature readiness status" "$fixture" "TestFlight readiness must remain blocked" + +fixture="$(new_fixture publication-unverified)" +set_json "$fixture/config/testflight-publication-readiness.json" readiness.publicationVerified false +expect_failure "publication verification removed" "$fixture" "publicationVerified must remain true" + +fixture="$(new_fixture readiness-external)" +set_json "$fixture/config/testflight-publication-readiness.json" readiness.externalTestingActive false +expect_failure "readiness external testing drift" "$fixture" "readiness externalTestingActive must remain true" + +fixture="$(new_fixture install-fabrication)" +set_json "$fixture/config/testflight-publication-readiness.json" readiness.exactAppleDeliveredInstallVerified true +expect_failure "exact Apple-delivered install fabricated" "$fixture" "exact Apple-delivered TestFlight installation must not be claimed" + +fixture="$(new_fixture rehearsal-fabrication)" +set_json "$fixture/config/testflight-publication-readiness.json" readiness.preservedDataPostInstallRehearsalVerified true +expect_failure "post-install rehearsal fabricated" "$fixture" "post-install preserved-data rehearsal must not be claimed" + +fixture="$(new_fixture release-enabled)" +set_json "$fixture/config/testflight-publication-readiness.json" readiness.releaseEnabled true +expect_failure "release prematurely enabled" "$fixture" "releaseEnabled must remain false" + +fixture="$(new_fixture blocker-code)" +set_json "$fixture/config/testflight-publication-readiness.json" readiness.blockerCode '"ready"' +expect_failure "install blocker removed" "$fixture" "TestFlight blocker code drifted" + +fixture="$(new_fixture required-action)" +set_json "$fixture/config/testflight-publication-readiness.json" readiness.requiredAction '"Delete and reinstall."' +expect_failure "destructive install action accepted" "$fixture" "TestFlight required action drifted" + +fixture="$(new_fixture extra-key)" +set_json "$fixture/config/testflight-publication-readiness.json" unexpected true +expect_failure "unexpected manifest key" "$fixture" "top-level manifest keys drifted" + +fixture="$(new_fixture duplicate-key)" +replace_once "$fixture/config/testflight-publication-readiness.json" \ + $'{\n "schemaVersion": 1,' \ + $'{\n "schemaVersion": 1,\n "schemaVersion": 1,' +expect_failure "duplicate manifest key" "$fixture" "canonical two-space JSON without duplicate keys or trailing data" + +fixture="$(new_fixture trailing-data)" +printf '%s\n' '{"unexpected":true}' >> "$fixture/config/testflight-publication-readiness.json" +expect_failure "trailing JSON data" "$fixture" "invalid publication JSON" + +fixture="$(new_fixture digest-mismatch)" +set_json "$fixture/config/testflight-publication-readiness.json" schemaVersion 2 +expect_failure_with_digest \ + "manifest digest mismatch" \ + "$fixture" \ + "d66634ec2fce2305e2cc64e18e55c273dcc802bc82e074f658bef72ad8d53b26" \ + "publication manifest digest mismatch" + +fixture="$(new_fixture invalid-expected-digest)" +expect_failure_with_digest \ + "invalid expected digest" \ + "$fixture" \ + "not-a-digest" \ + "expected manifest digest must be exactly 64 lowercase hexadecimal characters" + +fixture="$(new_fixture manifest-symlink)" +mv "$fixture/config/testflight-publication-readiness.json" "$fixture/config/manifest.real" +ln -s manifest.real "$fixture/config/testflight-publication-readiness.json" +expect_failure_with_digest \ + "manifest symlink substitution" \ + "$fixture" \ + "d66634ec2fce2305e2cc64e18e55c273dcc802bc82e074f658bef72ad8d53b26" \ + "required regular file is missing or is a symlink: config/testflight-publication-readiness.json" + +fixture="$(new_fixture missing-manifest)" +rm "$fixture/config/testflight-publication-readiness.json" +expect_failure_with_digest \ + "missing manifest" \ + "$fixture" \ + "d66634ec2fce2305e2cc64e18e55c273dcc802bc82e074f658bef72ad8d53b26" \ + "required regular file is missing or is a symlink: config/testflight-publication-readiness.json" + +fixture="$(new_fixture documentation)" +replace_once "$fixture/docs/testflight-publication-readiness.md" \ + 'Do not uninstall the app or clear its container.' \ + 'Delete and reinstall the app.' +expect_failure "destructive documentation drift" "$fixture" "documented preserved-data install constraint" + +fixture="$(new_fixture checklist)" +replace_once "$fixture/docs/release-checklist.md" \ + 'bash ./scripts/test-testflight-publication-readiness-audit.sh && bash ./scripts/audit-testflight-publication-readiness.sh' \ + 'bash ./scripts/audit-testflight-publication-readiness.sh' +expect_failure "release checklist self-test wiring removed" "$fixture" "release-checklist TestFlight publication gate" + +fixture="$(new_fixture run-pr-test)" +replace_once "$fixture/scripts/ci/run-pr.sh" \ + 'bash "$WORKSPACE_DIR/scripts/test-testflight-publication-readiness-audit.sh"' \ + 'echo "TestFlight publication self-test skipped"' +expect_failure "PR publication self-test removed" "$fixture" "PR TestFlight publication adversarial self-test" + +fixture="$(new_fixture run-pr-audit)" +replace_once "$fixture/scripts/ci/run-pr.sh" \ + 'bash "$WORKSPACE_DIR/scripts/audit-testflight-publication-readiness.sh"' \ + 'echo "TestFlight publication audit skipped"' +expect_failure "PR publication audit removed" "$fixture" "PR TestFlight publication audit" + +fixture="$(new_fixture workflow-test)" +replace_once "$fixture/.github/workflows/codecov.yml" \ + 'bash ./scripts/test-testflight-publication-readiness-audit.sh' \ + 'echo "TestFlight publication self-test skipped"' +expect_failure "CI publication self-test removed" "$fixture" "CI TestFlight publication adversarial self-test" + +fixture="$(new_fixture workflow-audit)" +replace_once "$fixture/.github/workflows/codecov.yml" \ + 'bash ./scripts/audit-testflight-publication-readiness.sh' \ + 'echo "TestFlight publication audit skipped"' +expect_failure "CI publication audit removed" "$fixture" "CI TestFlight publication audit" + +if ((CASES != EXPECTED_CASES)); then + fail "executed $CASES cases; expected exactly $EXPECTED_CASES" +fi + +echo "[testflight-publication-test] passed $CASES cases (1 valid + $((CASES - 1)) negative/adversarial)"