From 61e16a77c4cb68b6d4e43de5740ce1b7d301c481 Mon Sep 17 00:00:00 2001 From: Sergey Kintsel Date: Fri, 13 Sep 2024 09:52:14 +0100 Subject: [PATCH] Add password for backups --- .../src/features/onboarding.feature | 1 + .../backedupAccountGroups.ts | 2 +- apps/desktop-e2e/src/steps/onboarding.ts | 12 +- apps/desktop/src/components/ErrorPage.tsx | 6 +- .../masterPassword/MasterPassword.tsx | 17 +- apps/desktop/src/utils/useSaveBackup.tsx | 38 ++++ .../src/views/settings/SettingsView.tsx | 45 ++-- apps/web/src/components/Menu/Menu.test.tsx | 13 +- apps/web/src/components/Menu/Menu.tsx | 5 +- .../web/src/components/Menu/useSaveBackup.tsx | 9 + .../SetupPassword/SetupPassword.tsx | 19 +- packages/crypto/src/AES.ts | 2 +- packages/state/package.json | 3 +- packages/state/src/hooks/backup.test.ts | 91 +++++++- packages/state/src/hooks/backup.ts | 55 +++-- .../state/src/hooks/getAccountData.test.ts | 2 - packages/test-utils/package.json | 8 +- .../src/fixtures/backups/V1Backup.json | 0 .../src/fixtures/backups/V21Backup.json | 5 + .../src/fixtures/backups/V2Backup.json | 0 pnpm-lock.yaml | 208 ++++++++++++++++-- 21 files changed, 454 insertions(+), 87 deletions(-) rename apps/desktop-e2e/src/{fixtures/backups => helpers}/backedupAccountGroups.ts (97%) create mode 100644 apps/desktop/src/utils/useSaveBackup.tsx create mode 100644 apps/web/src/components/Menu/useSaveBackup.tsx rename {apps/desktop-e2e => packages/test-utils}/src/fixtures/backups/V1Backup.json (100%) create mode 100644 packages/test-utils/src/fixtures/backups/V21Backup.json rename {apps/desktop-e2e => packages/test-utils}/src/fixtures/backups/V2Backup.json (100%) diff --git a/apps/desktop-e2e/src/features/onboarding.feature b/apps/desktop-e2e/src/features/onboarding.feature index 6996e6fc81..c80edd4780 100644 --- a/apps/desktop-e2e/src/features/onboarding.feature +++ b/apps/desktop-e2e/src/features/onboarding.feature @@ -170,6 +170,7 @@ Feature: User Onboarding | | | TestAccount | + @focus Scenario: User imports a backup file Given I am on the welcome page diff --git a/apps/desktop-e2e/src/fixtures/backups/backedupAccountGroups.ts b/apps/desktop-e2e/src/helpers/backedupAccountGroups.ts similarity index 97% rename from apps/desktop-e2e/src/fixtures/backups/backedupAccountGroups.ts rename to apps/desktop-e2e/src/helpers/backedupAccountGroups.ts index d04e44573f..2f3e1e0755 100644 --- a/apps/desktop-e2e/src/fixtures/backups/backedupAccountGroups.ts +++ b/apps/desktop-e2e/src/helpers/backedupAccountGroups.ts @@ -1,7 +1,7 @@ import { mnemonic1 } from "@umami/test-utils"; import { DEFAULT_DERIVATION_PATH_TEMPLATE } from "@umami/tezos"; -import { type AccountGroup, AccountGroupBuilder } from "../../helpers/AccountGroup"; +import { type AccountGroup, AccountGroupBuilder } from "./AccountGroup"; export const v1BackedupAccountGroups = async () => { const expectedGroups: AccountGroup[] = []; diff --git a/apps/desktop-e2e/src/steps/onboarding.ts b/apps/desktop-e2e/src/steps/onboarding.ts index 85a07c9d3a..2455d985c3 100644 --- a/apps/desktop-e2e/src/steps/onboarding.ts +++ b/apps/desktop-e2e/src/steps/onboarding.ts @@ -6,11 +6,8 @@ import { mnemonic1 as existingSeedphrase } from "@umami/test-utils"; import { DEFAULT_DERIVATION_PATH_TEMPLATE } from "@umami/tezos"; import { type CustomWorld } from "./world"; -import { - v1BackedupAccountGroups, - v2BackedupAccountGroups, -} from "../fixtures/backups/backedupAccountGroups"; import { type AccountGroup, AccountGroupBuilder } from "../helpers/AccountGroup"; +import { v1BackedupAccountGroups, v2BackedupAccountGroups } from "../helpers/backedupAccountGroups"; import { AccountsPage } from "../pages/AccountsPage"; export const BASE_URL = "http://127.0.0.1:3000"; @@ -83,7 +80,12 @@ When("I upload {string} backup file", async function (this: CustomWorld, backupF const fileChooserPromise = this.page.waitForEvent("filechooser"); await this.page.getByTestId("file-input").click(); const fileChooser = await fileChooserPromise; - await fileChooser.setFiles(path.join(__dirname, `../fixtures/backups/${backupFileName}`)); + await fileChooser.setFiles( + path.resolve( + __dirname, + `../../../../packages/test-utils/src/fixtures/backups/${backupFileName}` + ) + ); }); Then(/I am on an? (\w+) page/, async function (this: CustomWorld, pageName) { diff --git a/apps/desktop/src/components/ErrorPage.tsx b/apps/desktop/src/components/ErrorPage.tsx index 4027b4c6a5..08b98ecd0c 100644 --- a/apps/desktop/src/components/ErrorPage.tsx +++ b/apps/desktop/src/components/ErrorPage.tsx @@ -1,11 +1,11 @@ import { Box, Button, Center, Heading, Link, VStack } from "@chakra-ui/react"; -import { downloadBackupFile } from "@umami/state"; import { useOffboardingModal } from "./Offboarding/useOffboardingModal"; import { ModalContentWrapper } from "./Onboarding/ModalContentWrapper"; import { NoticeIcon, ReloadIcon } from "../assets/icons"; import BackgroundImage from "../assets/onboarding/background_image.png"; import colors from "../style/colors"; +import { useSaveBackup } from "../utils/useSaveBackup"; const feedbackEmailBodyTemplate = "What is it about? (if a bug report please consider including your account address) %0A PLEASE FILL %0A%0A What is the feedback? %0A PLEASE FILL"; @@ -16,9 +16,11 @@ const refresh = () => { export const ErrorPage = () => { const { modalElement: OffboardingModal, onOpen: onOpenOffboardingModal } = useOffboardingModal(); + const { content: saveBackupModal, onOpen: saveBackup } = useSaveBackup(); return (
+ {saveBackupModal} { title="Oops! Something went wrong!" > - diff --git a/apps/desktop/src/components/Onboarding/masterPassword/MasterPassword.tsx b/apps/desktop/src/components/Onboarding/masterPassword/MasterPassword.tsx index 67775a54c6..1e8d5a7234 100644 --- a/apps/desktop/src/components/Onboarding/masterPassword/MasterPassword.tsx +++ b/apps/desktop/src/components/Onboarding/masterPassword/MasterPassword.tsx @@ -14,9 +14,11 @@ import { EnterPassword } from "./password/EnterPassword"; export const MasterPassword = ({ account, onClose, + onVerify, }: { - account: MasterPasswordStep["account"]; - onClose: () => void; + account?: MasterPasswordStep["account"]; + onClose?: () => void; + onVerify?: (password: string) => void; }) => { const restoreFromMnemonic = useRestoreFromMnemonic(); const restoreFromSecretKey = useRestoreFromSecretKey(); @@ -25,10 +27,19 @@ export const MasterPassword = ({ const { isLoading, handleAsyncAction } = useAsyncActionHandler(); const toast = useToast(); + const handleSubmit = (password: string) => handleAsyncAction(async () => { await checkPassword?.(password); + if (onVerify) { + return onVerify(password); + } + + if (!account) { + throw new Error("No account data provided."); + } + switch (account.type) { case "secret_key": await restoreFromSecretKey(account.secretKey, password, account.label); @@ -41,7 +52,7 @@ export const MasterPassword = ({ }); } toast({ description: "Account successfully created!", status: "success" }); - onClose(); + onClose?.(); }); if (passwordHasBeenSet) { diff --git a/apps/desktop/src/utils/useSaveBackup.tsx b/apps/desktop/src/utils/useSaveBackup.tsx new file mode 100644 index 0000000000..9fbbd7be2d --- /dev/null +++ b/apps/desktop/src/utils/useSaveBackup.tsx @@ -0,0 +1,38 @@ +import { + Modal, + ModalCloseButton, + ModalContent, + ModalHeader, + useDisclosure, +} from "@chakra-ui/react"; +import { useDownloadBackupFile } from "@umami/state"; + +import { MasterPassword } from "../components/Onboarding/masterPassword/MasterPassword"; + +export const useSaveBackup = () => { + const { isOpen, onClose, onOpen } = useDisclosure(); + const downloadBackupFile = useDownloadBackupFile(); + + return { + content: ( + + + + + + downloadBackupFile(password).then(onClose)} + /> + + + ), + onOpen, + }; +}; diff --git a/apps/desktop/src/views/settings/SettingsView.tsx b/apps/desktop/src/views/settings/SettingsView.tsx index fe36cc67c9..bdcc71f18a 100644 --- a/apps/desktop/src/views/settings/SettingsView.tsx +++ b/apps/desktop/src/views/settings/SettingsView.tsx @@ -1,6 +1,5 @@ import { Box, Button, Flex, Heading } from "@chakra-ui/react"; import { useDynamicModalContext } from "@umami/components"; -import { downloadBackupFile } from "@umami/state"; import { type PropsWithChildren } from "react"; import { DAppsDrawerCard } from "./DAppsDrawerCard"; @@ -11,6 +10,7 @@ import { ChangePasswordForm } from "../../components/ChangePassword/ChangePasswo import { ClickableCard, SettingsCardWithDrawerIcon } from "../../components/ClickableCard"; import { useOffboardingModal } from "../../components/Offboarding/useOffboardingModal"; import { TopBar } from "../../components/TopBar"; +import { useSaveBackup } from "../../utils/useSaveBackup"; export const SettingsView = () => ( @@ -27,33 +27,28 @@ export const SettingsView = () => ( const GeneralSection = () => ( - {/* - TODO: implement this - - - Light - - Dark - - - */} ); -const BackupSection = () => ( - - - - Download backup file - - - - -); +const BackupSection = () => { + const { onOpen, content } = useSaveBackup(); + + return ( + + {content} + + + Download backup file + + + + + ); +}; const AdvancedSection = () => { const { modalElement: OffboardingModal, onOpen: onOpenOffboardingModal } = useOffboardingModal(); @@ -62,10 +57,6 @@ const AdvancedSection = () => { return ( - {/* - TODO: implement this - {}} /> - */} ({ jest.mock("@umami/state", () => ({ ...jest.requireActual("@umami/state"), - downloadBackupFile: jest.fn(), + useDownloadBackupFile: jest.fn(), })); let store: UmamiStore; @@ -89,11 +89,18 @@ describe("", () => { it("calls downloadBackupFile function when Save Backup is clicked", async () => { const user = userEvent.setup(); + const mockDownloadBackupFile = jest.fn(); + jest.mocked(useDownloadBackupFile).mockReturnValue(mockDownloadBackupFile); + await renderInDrawer(, store); await user.click(screen.getByText("Save Backup")); - expect(downloadBackupFile).toHaveBeenCalled(); + await user.type(screen.getByLabelText("Set Password"), "password"); + await user.type(screen.getByLabelText("Confirm Password"), "password"); + await user.click(screen.getByRole("button", { name: "Save Backup" })); + + expect(mockDownloadBackupFile).toHaveBeenCalled(); }); it("calls toggleColorMode function when Light mode is clicked", async () => { diff --git a/apps/web/src/components/Menu/Menu.tsx b/apps/web/src/components/Menu/Menu.tsx index 92dc455d23..3d9acc6833 100644 --- a/apps/web/src/components/Menu/Menu.tsx +++ b/apps/web/src/components/Menu/Menu.tsx @@ -1,13 +1,13 @@ import { Switch } from "@chakra-ui/react"; import { useColorMode } from "@chakra-ui/system"; import { useDynamicDrawerContext, useDynamicModalContext } from "@umami/components"; -import { downloadBackupFile } from "@umami/state"; import { AddressBookMenu } from "./AddressBookMenu/AddressBookMenu"; import { AdvancedMenu } from "./AdvancedMenu/AdvancedMenu"; import { AppsMenu } from "./AppsMenu/AppsMenu"; import { GenericMenu } from "./GenericMenu"; import { LogoutModal } from "./LogoutModal"; +import { useSaveBackup } from "./useSaveBackup"; import { BookIcon, CodeSandboxIcon, @@ -25,6 +25,7 @@ export const Menu = () => { const { openWith: openDrawer } = useDynamicDrawerContext(); const { colorMode, toggleColorMode } = useColorMode(); const isVerified = useIsAccountVerified(); + const saveBackup = useSaveBackup(); const colorModeSwitchLabel = colorMode === "light" ? "Light mode" : "Dark mode"; @@ -43,7 +44,7 @@ export const Menu = () => { { label: "Save Backup", icon: , - onClick: downloadBackupFile, + onClick: saveBackup, }, { label: "Apps", diff --git a/apps/web/src/components/Menu/useSaveBackup.tsx b/apps/web/src/components/Menu/useSaveBackup.tsx new file mode 100644 index 0000000000..11539daac1 --- /dev/null +++ b/apps/web/src/components/Menu/useSaveBackup.tsx @@ -0,0 +1,9 @@ +import { useDynamicModalContext } from "@umami/components"; + +import { SetupPassword } from "../Onboarding/SetupPassword"; + +export const useSaveBackup = () => { + const { openWith } = useDynamicModalContext(); + + return () => openWith(); +}; diff --git a/apps/web/src/components/Onboarding/SetupPassword/SetupPassword.tsx b/apps/web/src/components/Onboarding/SetupPassword/SetupPassword.tsx index 9385643beb..136de518fe 100644 --- a/apps/web/src/components/Onboarding/SetupPassword/SetupPassword.tsx +++ b/apps/web/src/components/Onboarding/SetupPassword/SetupPassword.tsx @@ -19,6 +19,7 @@ import { useAppDispatch, useAsyncActionHandler, useCurrentAccount, + useDownloadBackupFile, useGetDecryptedMnemonic, useGetNextAvailableAccountLabels, useIsPasswordSet, @@ -44,7 +45,13 @@ type FormFields = { curve: Exclude; }; -export type Mode = "mnemonic" | "secret_key" | "new_mnemonic" | "verification" | "add_account"; +export type Mode = + | "mnemonic" + | "secret_key" + | "new_mnemonic" + | "verification" + | "add_account" + | "save_backup"; type SetupPasswordProps = { mode: Mode; @@ -66,6 +73,12 @@ const getModeConfig = (mode: Mode) => { buttonLabel: "Create Account", subtitle: "Set a password to unlock your wallet. Make sure to store your password safely.", }; + case "save_backup": + return { + icon: LockIcon, + title: "Encrypt Backup", + buttonLabel: "Save Backup", + }; case "mnemonic": case "secret_key": return { @@ -96,6 +109,7 @@ export const SetupPassword = ({ mode }: SetupPasswordProps) => { const isPasswordSet = useIsPasswordSet(); const getDecryptedMnemonic = useGetDecryptedMnemonic(); const currentAccount = useCurrentAccount(); + const downloadBackupFile = useDownloadBackupFile(); const form = useMultiForm({ mode: "onBlur", @@ -154,6 +168,9 @@ export const SetupPassword = ({ mode }: SetupPasswordProps) => { return openWith(, { size: "xl" }); } + case "save_backup": { + await downloadBackupFile(password); + } } return onClose(); diff --git a/packages/crypto/src/AES.ts b/packages/crypto/src/AES.ts index e94d2d3bc1..3df50c73b9 100644 --- a/packages/crypto/src/AES.ts +++ b/packages/crypto/src/AES.ts @@ -18,7 +18,7 @@ export const encrypt = async (data: string, password: string): Promise", () => { ); }); }); + + describe("v21 backups", () => { + const originalLocation = window.location; + const originalLocalStorage = window.localStorage; + + beforeEach(() => { + delete (window as any).location; + delete (window as any).localStorage; + + (window as any).location = { reload: jest.fn() }; + (window as any).localStorage = { setItem: jest.fn(), clear: jest.fn() }; + }); + + afterEach(() => { + window.location = originalLocation; + window.localStorage = originalLocalStorage; + }); + + it("throws is the password is invalid", async () => { + const { + result: { current: restoreBackup }, + } = renderHook(() => useRestoreBackup(), { store }); + + await expect(() => restoreBackup(v21Backup, "password", {} as any)).rejects.toThrow( + "Error decrypting data: Invalid password" + ); + }); + + it("restores from a v21 backup file", async () => { + const persistor = { pause: jest.fn() } as any; + + const { + result: { current: restoreBackup }, + } = renderHook(() => useRestoreBackup(), { store }); + + await act(() => restoreBackup(v21Backup, "123123123", persistor)); + + expect(persistor.pause).toHaveBeenCalledTimes(1); + expect(window.localStorage.clear).toHaveBeenCalledTimes(1); + expect(window.localStorage.setItem).toHaveBeenCalledTimes(2); + expect(window.localStorage.setItem).toHaveBeenCalledWith( + "persist:accounts", + '{"items":"[{\\"type\\":\\"mnemonic\\",\\"curve\\":\\"ed25519\\",\\"pk\\":\\"edpkuRxYBCmrSKLS72hB4eDiG1trmQ7mjBuVXV1HbC9rJ1dM4zdA2Y\\",\\"address\\":{\\"type\\":\\"implicit\\",\\"pkh\\":\\"tz1bho3Q3CXUktUGCx7A5Rfcv5o419iso6vx\\"},\\"derivationPath\\":\\"44\'/1729\'/0\'/0\'\\",\\"derivationPathTemplate\\":\\"44\'/1729\'/?\'/0\'\\",\\"seedFingerPrint\\":\\"e54ef832\\",\\"label\\":\\"Account\\",\\"isVerified\\":true}]","seedPhrases":"{\\"e54ef832\\":{\\"iv\\":\\"2bdc675526692daeee315bf0\\",\\"salt\\":\\"a1fbd322343b83868830454a2fabc1a2425674fcfbfefa576bc990329857773c\\",\\"data\\":\\"15e172fdab4e4f0fb5e22e39ad279962560ea45b9e4e82ca9d6408b960e675e71b267cceee5c85d2c83b7e3f48f6812157421da39c4f7594b5978d0ed97ce3b297f6ec53f117acb6acff16f3e6986fa662f060f6574504a48f13c2667a862032769dad60baa6d7158f71bffa6cfb3f5fb40c164fb580a0b71074ae00e018ea96c3352b9204ad48e873bf5095a759d1cedc3c1df408f24c1a51870f19ae3a682ab68c9f8ea60d3a8f0414\\"}}","secretKeys":"{}","_persist":"{\\"version\\":8,\\"rehydrated\\":true}","current":"\\"tz1bho3Q3CXUktUGCx7A5Rfcv5o419iso6vx\\""}' + ); + expect(window.localStorage.setItem).toHaveBeenCalledWith("persist:root", expect.any(String)); + }); + }); +}); + +describe("useDownloadBackupFile", () => { + const originalLocalStorage = window.localStorage; + MockDate.set("2021-01-01T02:05:01.000Z"); + + beforeEach(() => { + delete (window as any).localStorage; + window.localStorage = { getItem: (data: string) => data } as any; + }); + + afterEach(() => { + window.localStorage = originalLocalStorage; + }); + + it("fetches an encrypted state backup", async () => { + const linkMock: any = { click: jest.fn() }; + const { + result: { current: downloadBackupFile }, + } = renderHook(() => useDownloadBackupFile()); + jest.spyOn(document, "createElement").mockReturnValueOnce(linkMock as any); + + await downloadBackupFile("123123123"); + + expect(linkMock.download).toEqual("UmamiV2Backup_2021-01-01.json"); + expect(linkMock.click).toHaveBeenCalledTimes(1); + + const href: string = linkMock.href; + expect(href.startsWith("data:text/json;charset=utf-8,")).toBe(true); + const data = JSON.parse(decodeURIComponent(href.replace("data:text/json;charset=utf-8,", ""))); + + const decrypted = await decrypt(data, "123123123", "V2"); + + expect(decrypted).toEqual( + '{"persist:accounts":"persist:accounts","persist:root":"persist:root"}' + ); + }); }); diff --git a/packages/state/src/hooks/backup.ts b/packages/state/src/hooks/backup.ts index 8dcbb5068b..d0eec8542a 100644 --- a/packages/state/src/hooks/backup.ts +++ b/packages/state/src/hooks/backup.ts @@ -1,13 +1,16 @@ import { DEFAULT_ACCOUNT_LABEL } from "@umami/core"; -import { type EncryptedData, decrypt } from "@umami/crypto"; +import { type EncryptedData, decrypt, encrypt } from "@umami/crypto"; import { type Persistor } from "redux-persist"; +import { useValidateMasterPassword } from "./getAccountData"; import { useRestoreFromMnemonic } from "./setAccountData"; const isV1Backup = (backup: any) => backup["recoveryPhrases"] && backup["derivationPaths"]; const isV2Backup = (backup: any) => !!backup["persist:accounts"]; +const isV21Backup = (backup: any) => ["data", "iv", "salt"].every(key => key in backup); + export const useRestoreBackup = () => { const restoreV1 = useRestoreV1BackupFile(); @@ -18,17 +21,18 @@ export const useRestoreBackup = () => { if (isV2Backup(backup)) { return restoreV2BackupFile(backup, password, persistor); } + if (isV21Backup(backup)) { + return restoreV21BackupFile(backup, password, persistor); + } throw new Error("Invalid backup file."); }; }; +type V1Backup = { recoveryPhrases: [EncryptedData]; derivationPaths: [string] }; export const useRestoreV1BackupFile = () => { const restoreFromMnemonic = useRestoreFromMnemonic(); - return async ( - backup: { recoveryPhrases: [EncryptedData]; derivationPaths: [string] }, - password: string - ) => { + return async (backup: V1Backup, password: string) => { const encrypted: [EncryptedData] = backup["recoveryPhrases"]; // The prefix `m/` from V1 can be ignored. const derivationPaths = backup.derivationPaths.map((path: string) => @@ -53,8 +57,9 @@ export const useRestoreV1BackupFile = () => { }; }; +type V2Backup = { "persist:accounts": string; "persist:root": string }; export const restoreV2BackupFile = async ( - backup: { "persist:accounts": string; "persist:root": string }, + backup: V2Backup, password: string, persistor: Persistor ) => { @@ -80,18 +85,34 @@ export const restoreV2BackupFile = async ( window.location.reload(); }; -export const downloadBackupFile = () => { - const storage = { - "persist:accounts": localStorage.getItem("persist:accounts"), - "persist:root": localStorage.getItem("persist:root"), - }; +export const restoreV21BackupFile = async ( + encryptedBackup: EncryptedData, + password: string, + persistor: Persistor +) => { + const backup = JSON.parse(await decrypt(encryptedBackup, password, "V2")) as V2Backup; + return restoreV2BackupFile(backup, password, persistor); +}; + +export const useDownloadBackupFile = () => { + const validateMasterPassword = useValidateMasterPassword(); + + return async (password: string) => { + await validateMasterPassword?.(password); - const downloadedDate = new Date().toISOString().slice(0, 10); + const storage = { + "persist:accounts": localStorage.getItem("persist:accounts"), + "persist:root": localStorage.getItem("persist:root"), + }; + const rawBackup = JSON.stringify(storage); + const encryptedBackup = await encrypt(rawBackup, password); - const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(JSON.stringify(storage))}`; - const link = document.createElement("a"); - link.href = jsonString; - link.download = `UmamiV2Backup_${downloadedDate}.json`; + const link = document.createElement("a"); - link.click(); + const currentDate = new Date().toISOString().slice(0, 10); + link.href = `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify(encryptedBackup))}`; + link.download = `UmamiV2Backup_${currentDate}.json`; + + link.click(); + }; }; diff --git a/packages/state/src/hooks/getAccountData.test.ts b/packages/state/src/hooks/getAccountData.test.ts index d1d9012800..d747ce7baf 100644 --- a/packages/state/src/hooks/getAccountData.test.ts +++ b/packages/state/src/hooks/getAccountData.test.ts @@ -109,8 +109,6 @@ describe("getAccountDataHooks", () => { const signers = [mockMnemonicAccount(0), mockMnemonicAccount(1), mockMnemonicAccount(2)]; const multisig = { ...mockMultisigAccount(0), signers: signers.map(s => s.address) }; - console.log(signers); - addTestAccounts(store, signers); store.dispatch(multisigsActions.setMultisigs([multisig])); diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 18688f6941..0c659843f8 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -5,13 +5,19 @@ "module": "./dist/index.js", "main": "./dist/index.cjs", "types": "./dist/index.d.ts", + "files": [ + "src/fixtures/backups/V1Backup.json", + "src/fixtures/backups/V2Backup.json", + "src/fixtures/backups/V21Backup.json" + ], "exports": { ".": { "@umami/source": "./src/index.ts", "import": "./dist/index.js", "require": "./dist/index.cjs", "types": "./dist/index.d.ts" - } + }, + "./backups/*": "./src/fixtures/backups/*" }, "devDependencies": { "@types/eslint": "^8", diff --git a/apps/desktop-e2e/src/fixtures/backups/V1Backup.json b/packages/test-utils/src/fixtures/backups/V1Backup.json similarity index 100% rename from apps/desktop-e2e/src/fixtures/backups/V1Backup.json rename to packages/test-utils/src/fixtures/backups/V1Backup.json diff --git a/packages/test-utils/src/fixtures/backups/V21Backup.json b/packages/test-utils/src/fixtures/backups/V21Backup.json new file mode 100644 index 0000000000..6dda11f7ef --- /dev/null +++ b/packages/test-utils/src/fixtures/backups/V21Backup.json @@ -0,0 +1,5 @@ +{ + "iv": "8a7f12b7a15b72b0c0a9dc10", + "salt": "8aed3fb2b02d99c0c7d5eef02630d6c5f2e150f1bf624e04809d084edf1c59e3", + "data": "21dea1a60fe65bacb18c430e27ca8871a90a475ecb35f774ebe50206e2d9913ce2338114ccec7cc0479c5b730a74ef2c48ba5bcb3d9cb88a733e3081853678ff64bd50591097fea03ddbca7e5fe5db55b6efc79033b1b0cc95b920885ec655e2fdcf58ca560ae9d92b22d8a3157f11cf2546906ae966381f56e89e47fa84df15bb17a232132832c1d912f66ca02048c52e3761b1396d47770fa950493cee996b900253e011f8a7dadf4537c8de5b175c5b7274f8296d6ca26c5135155ccdddc75d17cc14ee8c2073d3e8ecb6b3bdec36d3f2517a688ccfb730a4925433d90f6fa8b528356c90f19c622725dd01faf28c38c4f4245206b277c707b0dfeb9e5e68e66b36ef5cafff8fb0b25c706f3787b277f800cb86d57f70fc4de9e3f18541014bfa03cf706b4ad2c36f2bb66eebe5f67f0a341338b74207f3e9bb609088fefc41ea10acb864fecfa29c2ba957b35e275dcd3b2303f33cbebbc1a1b0f30fbe40f8bcb9c3cce768d7b295590777864369a6c7a1ca84bb619b295026b241bd5713dd88a2f8f96fcabf5eeb1a5fc89ee1ab6edacbefa5c6063c54eb709d77a68d4e9158f3b1e60675ceea14c66f0595244c2ecc83b4b70439e416c2d189b40115eb964b385fc0df86e6cbd07d744e6e438f7baac1b2e98e0f262db1e537b6309ca3d5ef8da57598777b85e45fdf989293ed54312b6f016dc4238cec0e0100fc4ef2c365738b91f523578584a45e01c99f2c86b1ea45f211b76949b9279f3c90043c2171e9fc78fe9a426b0fe7d04d6dbbd721c27a2d6fc4bf8edb5a16ee8a21dd4e34849e494ee36b8e135c42a1738d1b8f82a3fb585f89cf1ae1d79c5b3d8922b99ddbb17ab8de18d916dff31047d996ddf82b4f2e24116f2ddcf416d7fd9a77b5de0203d4ab5dd8ff36c84a1789aa2bb482fdf7b2b4f674438d00404016273b14a25032314da9a6f74f377fe2d9bf18a2afb260a2fc442849f9c9684b2ad6000ec914e50528d4c2074580cbbf45ff49174c61a703bfb4deca0568f4afce8ad50e38d874813e8fea582b8dbdb5967ec0512f35de618cf93bba011a33c6a2d4e4b5aaabf33b603a92e9d09e1b0620b12e9b4bf98f39de0d7435b5097640de07b3e333c299c6d530aa613e15408686e8b3ea5d430b793622cae37e1759ef5fe2b29cda2ef999b85e3b265d624e566d50bbfe230db66227c58b733c09e2d092e9767222d6bf690d68a41d901206112e56b15fee8c0c0b6ddcae4573d54157e30cc220875d87c3b339f44ea9750934af0d84c13d76b279cd4f1c07784f0de2b7727e9c38b6429407b177e4e6fe0dcf951bc3690b67f4f2b0c043f3b6c16eafc1b806212eb9f93e4b083647ad2df6a7a4e30e9fa84e69f68b4ddad41ee5a3f8e19491c2180a032d827344d296ce45f67054e15285c64e6fac68cfbca78a62f06c8271d5d2a82e128a9959a236c5ea1de930779d6b97f6139c6b6dfabad71fe7e86f4303b1e1b8dcc41f72f8bddb52c08412654cb70564bf932470a67e514655b6a642440ccc8df0fb8bc0cb7a404f9fe3f3e5ce3707931b25a14636c68b043466e05a5ad409bada573c1c5abbda3a97b357babbdbdcd745b33f2dbe8e8919ec76d1f0c26c0cbb51a06ce00f835f47705bcaa59434f12e8100cef4618cef7243c319a2f61a4ec8cbf6b9c44f01888f8c539ea3cf805e40ce25832643a3ecb66fccce2b6bd36f9474b7c1516df27dc11df5d6abdafbf24e9d962ea7a15ec0ec0024f7cfd215aedff90da13cbf4f368ffe14b9679a52f80dc0ecca94d27bd624c099d5ffaca2277458b989abeb0f349d945c074b3b6927ca035d14a17eb92702812920d2069a7347b3b11313224f8808de5b391735b80afbad0b67e8cc5c4866ab73d4feb656bcedfac769340012b31a3271157a7d31427a3ea388a97383e24bc742221097eb7b9e95bc10f1197f91c7fcbaa56e87dc894fcf7b406f2317bd85740e6c3d5671d603491e56404a31591076075f5d4a48daa1456a6e82adbbf6ce28794bafc289070641ded293651ee05aa8d52d8661d117628c8e9a4934b8fd46cf92fb7d926e609cd81252e682f1e5a692dae3b36788d032349f45153feac8dbfdfa668bc31e2ace6fc59ecc8fe4d5cf8a0fe157c32ee734417c738e265de46c5bdb90adc7293d0024417976f6a9ca7c62bc979e797442d3b78e7939b7be4fe9e2f4696285d8c7eccf45a4b789d6f0daed12658b502967cec27820f8fca4834ef3b6f2f3771fba29ea2c237665b3ee26b0f3274d97191d394ffff3c7f57e020ea4c829dcdb9f086f4bd1bdf40fc27c09a1114c20e1250861de9dc768098af0c97c9720a2fc6c48b482eccc279e0ac97fd4a472cc293ca987fadb8623b1c4884c7550af1f40e7953483b40f9477f6b9af96b4a320b75826beb15288444b80a77c2a9724561459160ba22b5e9a4ff2f4c587fe8c7cfa2a576d6383538ace30aa1416067baa4a4a4f416d92efa777756275bc1e9ab9e814d6b245da46e050d1f5c1db89ecc5b08f7fe07986701c6f167812daf2c91e7af334ce90bf368a5fa99d560a204010a8bf3a908dea47f684a3186a43c1e529a2eada65d40727eb70a8b55a368f25828d53afe5dd9608e7731fcea651e3b65e1b230b1bbd84a63003ef06d811693d8b3389a73a883fbfe0ae151955ba7f91e970d38085bba428c42e877235e8599539e7ae2e096383708d295968c5bd439d3284527246de9a0b82d86e77935e0c3c0b87605deb045da393cca1f7d01ac50f363c51af9676710aafa4470237fdb19b77dbf86316817e97d97a74a1f9a9b23bfcf2bddd5129109b36d5b65bc0a56b2172cc43b94a78f456e05f07bc1585dbb92737bfaed859c0cfffb8c89deb1b88a9d4ed4ea9ad370e8a7dde7d455b7a5357c2293e5f08596e6f8367d3eeca5051d6216c28259012162ae04ea5ca8b81260e319201fcd52e94f61e35cff49b5102bc6732831ffa8d433d4c28bed4fe4cedc49129c84ab1cb8073421f20a41af20f1c08c3de5cb832919e8dfd93062f24929abc4250b7c16dbed88ed3bc98a6533117613e1ee97508eb3141abe51e4982293f00bdf4ac0213107e7cecedd3762ce5c7f2d00ba79500fc78e5e70204960958b287c0f9101dbc940ad0852e21eef06e2349906f13b51f65cd665c446ef39c5cb4a85a1c531ea3dc3cf386263e2887d4d6711be7ae040bdd9456c0f3d6e0a67ac86ca95c0c11e66d9c5f8de87cb7477a9e39969ddf754ebb280e07c1f8ee010c7b3bb8479324b654b5c6301e5b632e093dcd5c813e54e0a3a6612016fa7f8dc6ffd789ea05db8a5cec4f88a5bbb25fff362fe4e6c64ab1ed7a9be74fff6a46e474c2b68d3ae168b209fc5a1e32e645084c34c1e0eaca8fd53905b225ecf67628cd01826475d6d0f338373999e2b773d4ba840f669a1dec38e2607c967c77d836dcdefd3ad12a02666c15cf597ebc433696c3cc79ede810ab1ebbb3ce8170d35a3c70c94e5992dd5ab6bdd09c795f3d4f0e752e35bd5431ba8c372bc32d18b3685d1ed2949f17b103323bb105b06180d1c720fc3f3a09bdd55a029a7f760585095cbd1dea82167f69c386735bc55481165620b5d19f8027657795a1e0940f755a81c8912a63202c124939b54238e1a40585c116a9c3703a4a11473c908aeb0f633f32296a57cb72817d2871bd881659af43b61c81477013f7403b713835390c755cc7ef9ef8f93db598f6d5564526d673d9dacab06f170e9551b38c3dacf1f7c368ff77fee79d6d3276d15acfb92fc291b7546936393c9b280935e66e43236132882b9929db1c242993a94314b87508890bee316dc8d2a2cd54d92a8855068c47d4aa6c43d23b18f435cba0065713ecc85a870c9b79d9b4a3ce953e545d208444308f855f51401db4b46c88c2c2a3d3355174a50163a66c9ede01d57790e9d8a165fa75cdc70f2fd398e8d8352523c1e072565b33286a3cd42fa63bfd09dbdcc98105b24aac0bfb1f1ce446c0f1bda504c11ed58762eb7150ed476d6f1719e1343a4080652385199f7a21322be0daf4d94a464ee4a4a6665fa796f3708d83cff1b496ea420166509a4c56e9939ee7b90b1fcc160bebf03f355c6023bbdb8d58c2af3fe21a47440677fec66fb0893db141a1656e1bd46ff4bc47a9544f25a0778ae02a4a37161cc0428671d0a1fe9995498b9d6ece2600d32e4c9700126f594ee76a82608b9369664fc70be52b1027d2d583a407e13b11199423196206bc7d5cd4c492adcc70f33474e59a297dbd49d4aafcbef502223af6605c3de01728842be55275fbc7b8ff311c6a4b9f9f88714bf0c4997c54c1f18dc60e0b934484772e56bf4a6f8a1dc8eb1412635bc080cc042f1334e22f032cb8da239faf96268fd843e94eeeaec8f1b6f00da044c40889318b3fa12b5dea8c66edac772fca8b5f0e0b0c6fd5c971bdeb78ba019512e1f7b16ed5e31fdde6bbbb42f2e075f1a1ca6ee8a34d879fe68165d5378bfb998f9c17d3152b15730b868f80fc091401ef25ffd6528e1cb5c59618044d77e715379ba3e344dfb4c35dd2eb6cd660c80a95d5b2b02df73d2fa7814baf61a060c95dd3412f363dc2326e375b94a783c842338a7115448b667361c1ecd4e6dd64a32c0b46d8f52826267b40f758f785c75e1b72554a5f91021a9fd5a59b12e432f957a5c0e35ba0cd35ec6d5e239f08d4e404bacd38d42e5715ac4993f26c1e21cff7ed840a144a346884d1d182305a9f900c2edeaf7a4bdb053f13c4945faa3ab2ca7889e1819265ffe46b2c134a8b11e2f5b297e368deffdecd62142014aa508cab74764c33a9e182dce996ce124a2fd202b80b1c2e2f60726635de0cf039f0281256bc30e4d1375be7b3cd859a7ab782c054da340f72267d18a8bd77b9625a113ce9d43ef27f56182522a5963a270be1076c809d996f5589a5e58562c987215ed89b148833f04220ed46836c93f18d3d2d1601ba8b0bcc837081310324cdde2ee4c425ff2756fd964623d1a3c768c9db68ed1f6224e212e1c28c016f326d6d996addcbd1147cc600bb65fb57c0067c2ce710cda5e88a269c7731edb2eeba92d78ba3c93dfd78de1c21cc5eedda3651904b989d748986886c8f785881987dc87630292ae033f250c47974e013c630bb66854a8d6e839393fddd862184e6c085a55db200f4328521083709227285a7691bc0383364fe4220951a9cd0459b838d8ed17933130ff03d42a7997a9309e3994b92bd1f98e6d3a5ee18f89807c06b42136d13ebbe2190be6930cf94369cf8dfb2bd371b21edfbde829a7fc6e723c12f2676a5ff1014c0a9262f86f61ba2ef5878a616b3f323c5e2f4113c839be347626aaf3f71bf40c92c5722237e080f0eaeb00544279f46b2cc765d49a0c4cde63bbb7edc72dc82e60ba575318a621277dd9e0c96545672031b9aa5fe06302bc888cf05110a850fd2a87cd032345f1b56f21b4abd2615fc7de845d901c10e7ed1274e20597d6f01bc29d0830727edcf23908225d4837de9332f62d0a4ff1baa6dabe4ed6e399bd0e7c573fb0884123d1a831274e3a812d74fbf9d18103ede1961852344153936611357a9a4f611b4c55fa29ad98cd2da2c843af6df8cecaeef8eb50edaab812e1a57f46882c0935c963b65cfdb21cbb223244d3f3578db52696f70760df00174ea70e54e232599471c9ea5e0fd946bbf568f7060596539d9ef4e12ac821250479334a92d07d40d7593023f9d97f590820de3f27e140201b9a037606610b4a050887518355325d9aa5f90db14c62f67fb21ef16f5bfbad282c70b6b289a624bf840c3ed6b93935bf66a25a4d892b9e6bfe8d380f8508c695b3d7ab2f0d7dba14d8d19ba1c7b6c5db6e189e9e0ac9adf21ddddcf33e825d29069f886e36ebade906188c604c084356ccf6ab51c82858aec458a114f5a6f3afcbacae14b543daa61c5cf2887605070ba9e018f2acb8bce77d6db812c78d85bf927181f8c11d3b64ecf4daa9a5fe7b2642959fe39e75d179447c75a174b7748ef6fe24dfdd6b8f82773efcb22d94c3ea92a2daf4e094a8a9418fe992ddb394312be8a24113deeba82eef414486e85a10f352805d7aca7f6ebb29e026dae4e5ba920bb63eb5ca34a7977d9d7c73586a4c84048a33f627c90c6628802d8dca1f980b514eb22eeeda9b4861d4c373af219812c5111d78fbcf80a06e0c528d92057d2136df8e5edd0235f7f0c3bedab5ac2841701318a90a0c14a1f3897580c6734b83443e1cc4dc5ecee0f98dcf3b9fb504b57c9a7cc58dbb06c0713cc966dee6a68d07075a0408a27b5274ef7764c0b51df83891bccc89320c61e4e2fd638a546f4b5f403816a8f9705d39015bffd60d56150917259fc6ac2c28c66d943182edcf0014ad42dc64f07dcd0b0fd0ff7364f19686d6acd2233113795c075d625eb5a546a0a23ab39bde0e9c56b6b928f15a5f92ab89269f0da9c59caf9a81b2039063288c7e8563b559d69565d324a5d9fd69653e0324817434a5207e4667655090b87054654964b69c8793fa9c1dd1c8b60f2a7bd74b257655ba7cecc9dc27c45a07174a5611c1c8cfe2ebf034387515c6bf412350572df1c2554f254a6c39e19283818b405308b490e9a702972eb665db9f9fd3451afca5cf9993f59cbc984a06c96a9829a6e37cc747b39aab42f715770dcd68973c5e3d764505f6a86f1620c220f23b7d65f6a59e2ba5552fbac20e32dd9cb7c0fe8604861820a62aa105fc0a1910d7ab7b6c4cd0937a06551f08bb6bfb1786ec6df68f5d378088c6e3ec760c98f7b861b95ef0a61364d3d864ea6273be727bfc71ce0f3e511a0093a6564c83f38990287c453d5a0b7ff214f76f85b6ecb1c8e6d2225c85c20f256cfca407f28bd4b2ce07e094b859aaf9bebc3f9da19a1e33e3b2f89080f3519a762cfe550c42c4c4e5e41156f90b9dd51cff1209c58d1f64a62f7063a64e78e3488fa4497a3aae1dbb301eaf93cd802e77f8e3458afd2d53d5cc74a8300cc7b0cee9931c4cc1de89af9fb0b0e146f9489c2c118c168872d690ddaa8a8844612942cdb4642e524d6a86bc293687350f43e72a54e2ee469276113b869171d9c8d64c27adae93037c5515ebdf809096456b12d8a15ccafd71f31c99aa1e185c8200aa3c7ebbb2c4b6bc18e370b4437cc632e90e3d2a8479973507f82ea03aa2328ea5242ab2ede3706d9558feba39da534105db1fa57a16ff3eaade5216cb49a510ecb652fe75b78ce5a41829b1ed1c82d5ff4b20c90e4024c6acee9efc326dd1c4234dccaf70add35a3bd39a0ae96c68c62ce14715b0d6a1b34fc5f2e1f1bd10cf21c311ec19dc38f46f03f5e458c959798cd5f6869ddab51155afb4eaa442a59ed791a892e5b6f894c4d989e62e4ff9c5ecfd0c43bca9ef7fb3cb74a389ac8d2bdc45d1a4e83aa1464e046b7594f2d7cdfd3d35e0c90d8f433f60b8bd7d94f5e031884cc6924ed33561edd5534dc087078f34c8010915c96ee726ce963bd4fe55dd7d7e5fd76cc478f171a7cd08a4ff6d3ea4a126b51c85dbbdc6e121a7e190dbeedf8520dbaff80ab58416be7add6431c5bb8d335848b0fc955c6e8ec6dbfe9f80d167015db3519e2552110a6cdd902465fae635ffe5869ebc8267a5920f13c47ec4afe364d5449c0213c7bdbf92f9391508e5207046816ee0f1eabc89e24d6e08339a84dd58361a1f4f37d37d79646b5d2aab2be4da5ea91f326a3509c1c15bb8bd1afc8415b793a2f79c403d9893095d8a57f37c5c281cda59e7f9f5c90ff1b68198f9ac878ce112663b4d848be54692691ddf1f1da88755f27c88bf7adc33eb200cd5d1f8137f9ab22981c5c02b8c0ecbf5492319adb484a2f30bdbb63ac1670529bbcd39b903809a98cfa605dadc54bca17eff79ea969c0babe66d9cfb05025ced19c7f6dce71eba9040a8d8169603d5b6affa4a01d14780e2c318298c7dde515e8f0d01c30f3544e602f25cf35d3ecee39d0d1609886934d80ff61fb8eb48f9edfe1f165f8a49b38c5e6d341730390ce7954bd693a8c581fef8706ff360617dfe633ab3dcc251c40b2b0244b7dc3cbf8501f27fd0c35f26b9eec81952c15a610b0d7f5b08adb5eafa44142a1a22cbb92d1331250ecacd23a213459ea8fd0c74790eaaa98815ac9a27b7ece480b64ff036e9500ef39ca1cf1b1ca8113b9011a117946b2a8f380799d15d0e67b1851832ac75ae22bfe573dbcc85cbfec83d234f8d124061d17dc668d7630a67fcdf781f58d8a3dd63bc3649dd7f46ea89ffc1248e9962a5e3757cbf10502299e8937a1c10cbe4412e665ec7d95f9dd69fe5a195ac286b964ced550fd52ea6191fb22b89c6ea1b3ff8c086c1bc676c4abe5e16957e3162169ca2ee53e917a907380add19f3cb08ccfc141c053d430180946580f4baa07b3384a96e5604d37b67bd358729d81a2cab9fcbabc4dcbcd364eef80da521bfe5907edea40b2865e0f7a7ec419b5632338a358fe4ff440ef3d545898c6c1080277d6634f241c5c8fc973de48cc7c6280c7e256c01c6c52a7cd9a3b6e44c80e8deeb37967eebb6a36a5ea3d3c2721a7f8693dee648d1dfe9b10d3b9f5332116822efadc69bf6316c631315ce7b54ba95d4fd02c5a7b7ea38eaa2a61b46b579f23317a50f8d8ba1770d765cc4958ed2932a3eb35311a681aab27a3b69dc73544103d8ee1beb81036c18def2e776f5060b2fcb3bf1a5f50bb566876e284880f3a84d553b1d7ee0092bffd75f59f541c525faee7b1eb374cfe656c0f7a412a7383e32e105bfce46c94ac264a65d6dc49c0f4a2b7f42fb351c231d0171da84424cdaefeeb85603308c15e4aac143cc003f2269da13db6e05266377e771107db94c0d9d35846f0a154f13129fab37e599374d1e9b3ab8acd04e3677970666c0a989519156448e84d07453c39025c9d5afea7e0df564898a336a32c383a85b20c5aa74bcbede01e127b3cbf114cdb9d2295074346023743c22282a9f203968a6b5689aff6ded3b0334196a08451b2a54d4450a214ded37c40f0c2b5df696b324363e5dbbbbdb058447f3a6dbfb3d26ed8728da4359c0a26554be6312c5dc71f19256d31840de907d7214de1f461591eccc38e2b8ff8f2f364555fe3361661416b14643b831e77707501d6f222ce5f627d32ec2780a1877d6cab680e084221fab6e2a81ff36bfddf508e52bf183b6014c12bb9779c1b65ecd0d9d4fca3b270919a1b5aa871b93dce94cce251c8a81cb7afb07f61499352f9056444214990a727f6277a9c5607df0bb540d7617069c3fade0cfb58efcebb3672fd00db193d15f3db14460711691cc143eb854df21e270aaa8dcc76d4f7b1bdf7b72a02b20ea1f7a6a3efd0c66f413a275aa36b65295c6eb5badcbe3798bdba86f743efba6d3719df3aaadb06ad3e95aa17376489df765af399aa0ab0c6a25ad5e4665614dabf47b816a7edfaa8ec12466d25feecddffa7617c846d829453112e9235ad39352f7b4faae9d987a74331911bf7e60fcfa714a0a39b60647d35fa40fe6302347324daeda603097ef5347010442a41318158ba7195670c4206e683bbdf9372bfba3b94096de6a73e2804b43783f82d9bcd33acb2447dc711a2bd544aed1f5ed562a65fc999d6207da870256923b95f4312fd34d7680de7497cd4a765b3d4b860864bcd41a625d103c1b6980f5244a94bfc368fe179818e178c1decef97ccab4913047e9a0191796f3d177f1b687af8b7d9cbd456a9909cd85f3311472d3713466e55d63edc4554e4485e2e60c2490191b76f84cf0f6834718c8f05ef2cb94efd65f80b8692d64ec15b1f1cc5e808597c9ff10177c6a35f7670d0f4633d80eef25c6319bef80cb8b6ab4db1299426bb9ab4197e2c725c51e16338d516ca8658a085b4cb050db98ee3c08f019fb3c7dc7c718961b5d61127020ac955fb72cfa5b679e7f817ff86999b501ef91c85b5bc54bc11b19e20ceefbff6c65b690bfc71ca4ddfc280c1c4e4e59364a8788b84e75c59ab652c426d85ff434316e629d6362569573ee915c2265a72800fd730258dba016aeefaf1fb41dd9afed794900d34a5b4de2249201f409ee2942fe07cd3b0bdf13fe51c5b22a1a5a30e585a2fe677c02a479c3cdaa6a415bb218bd9b3b26c80db75a583d7b28d3dbe471cce3716b1f3cc137d2c40cc988897fab41944ff1b40c60bb737dc886fe2b2f462fe3cd11783cf9a7fad0c041e1262cf86304f8bd7c03b5d9b66b54d2e784f5fe8f91f133f9cdb1491881240e6c4467499541310a2dfc113b570a74a173340305df37c6bed282b6eb2beeb32912cf1de02e11fd82ac232ae06fbf1d5de14b03d773ce3f853c0e5a43a5a3ca733c824baa9032eae8bd14f3e4db5d6f355af4f3d78a8c75fda303bcef493449c893ce526ad5a1cee69d11b6df9d5216bb6c07ebbadd087a4a0019afb5643eaefcdfeebd75b9d358418557da825d7740bca2b18a040e1585ffdf44a63b1f3f509be4522e7c6c232b9a1edefecaa997dd62366b233ab4b07249a368e327821487c90ffb32ae5be211e5a00ef20639bec3afbc2797119e3580c065d9d014071c37ad7a7eae9885adb8a3becb8378b45517e77300635dc99ae9a6552faa74441829969f873a81b48386d974174ba4f386750790dc04c5dcf0befae10a48d220d6d6730d1b50b529f4c0589f32439664b6d4f34d6c8c847c7a84b856d2fafbd0b36db8c978f00292eb26721d074dc775db435f22b19fe02c5c9b98b42c487ecf1f0bc91b205e53a58131cca2e873094c417eb5859acac8ddb34fab16120642113609bcfc36a2c35e5ec5f051542ebbad894cfd1c2b157cbf73ad778793c3493593d5319d1ca92162f3e6d916be7903605a9f8e3f36aae8d046fff109c86e972fcf095d4c07b35f391abdb10e8b4aea64d091c6b346f2650c2aa08a8ee7df6da9e443ee5cd3d2876cd776af5d985f72898eb70ddcd0a8dd4f940cf11f6869dc40fc50ad405f7b2f04834e007e9025e05c5749d6dc97d40bd6f51e461a1034584f78c0fc65544e6cf34b4ae5c92decb6c0b3f37283ec4d0d95c2b25a54d8e75490657605efeb92ad96f659409ab56b50b56af074be6fc18c8a08995f7f7b4ca4c3c37abbd55c3f2e894624b037f28d5beba6312d099943e4f45cd90a3fbb4b42e8c9cd01c5e8ff7ec3ced38555488d206875674c0e8bb6c12074256f51d85f67b2b7fbcc22a46a8d1f862360332dfbe4ff47b2e75ba1c937e0dac977eda744f3c8ff0bab9137b8fa0730989e3f1e26fb8a2bb3d43cc3ab11097dc1c437ed75528241615a0bd9bc1a96582e307e2e54331f5cdb15c138b8d41343063f5eacf329f5dc29b259ad4757280685018c38ec7e06b83ca24bb80dc02f70242ac69417636f654ba35ead1e8e17066acb7af3d4630fb2910deb6b5d1c89bdbf5a2b682f7bf9d0d064c79815881ec602f67406efc56e705283ecbfacc4892065631241daf6830fd16ff7c9acf974564595397f96e3023d9ffb8becb352b4f1ca0813d01c6ccefc410430eea26af135d2d7496ed1d498c77e69b69885d82342008a43f36b59ea33586229b37ba7d4475ca70b237c0c9985993af2dd1737c7569c95217ca6fb8f20793a51d65b9d1ffd2492eaf42a4d9b97830776f76900e3e8c0ca6116191c8f7e931eea0e739cbdb30d452e8f671d88237f97a96262afeda212ea44bbb8779f8bccbee3c9561c91842911f69af588e8a58f93f4d1aa4770a8958da46c5638e4880ffc8f058728be45bc20c8628880976b98d40b3617f8c947fa5024005b7720e8087cde5bcd34c41984fcfde161ccee5de4296424acdf8e5b5181cac7eea9f6c9f65af165f3825eda7d03b04af67dff8e6f1dcdaf42f9e90e4a2102926f79fd4157ac8de1d41c34077f0b871f1b13f5f0b315a02d9c6a6c7d85c806c7a4d93292e2ad077c282f0d8c6e41dd809566f05578c43bd3dd283b5d57a3f9bc9ae02c063ac9f0f40d6b9fecbf671eefbe7eee3740c1ebb8a722607058b0d808055b6eee60cb78295d2eaeec845cda99a412774b067b14aa170b3a21a6e12888cd475f51f309d4c383b7fb5b0320d9dd9aee97f0e1ac96053f27c3f8ef3c9341c3045267417c9fd344cba0fb1d4250594107ab534947fb51878eb46a3f64c292833083105d2459356ab24bbcdc6fb6029034ca50db7033d2a42e11b735b32467b180443d6c1810934ce9ed6c7a2b87d690fc81af80ea0b1e141ef055d2e56d6563872b2a6616028460d67b9c17ca2b7f5ca158c4a98a9f1cfdb3b42b6d56c24dadbd469ee0e44abe44e5b53859eb7a60dae32fb0d77a19fdc126047663141d0c95b1fb640f1dead2bcd8332eb05a2d71d739a2fe01b89cc4561146f34a3d32ff44cc9c396cdbba4b0dccdc6b76b3de32f08e726d7ac97efef853ccaa19a771a1491c49c911e7c9cf456dc7d093d2baad891eb314140f2f4b2849699ccf77b68ee3a13287e4a4ef9feb3a94514a326b6f30be0a2f9c3a1bbcba1d7298fba3063c77dd4477aabaa7baa9f56545a9eb9a6c78ebb89c79443825c00b743966f560041977e44a1f5230900f43f72c0b1ab9b9e83c2afdf1e184ca72005f6b5a87f3d92a91a73a5fffcef21caf0cb25563302bcc0c37abf6bbbc28e9735ab1217ce5163de559fc594e21867b204bf1ebcf9320f21821c5d287e7e157470bf7955eee4d2f90aeb600874681493716ec745a30e69b0c97db03e93622e31726a14df7e664d1959597ab618b66ef7b6755a3e26a5d964c1af0bea18918d0b2b19407e9d96fd7936802b2be928113620498ebc3592227c19c15a76974d625987fb0b8ed76c401e1b862088f28b1726da51c359fc174781e7aed33358ff4b5e8db4583496c633133f6e05a9add3868aea7c1ebd516923316a701335d4cdef993adce193cb91cbbba95fbcabe13b1500c7c828f98657e746b27d9919e35401c65bd277d05292cf82a52d64e41ec1104e80d8f5ed3b3b4d35c12ca88a2b151eaa936679c86a569da29b872357c1b6b127a2fe14c9fce32c9e2e28c6485c7badaea8aa90374a118d20a81698cdc69e665ac4fb7e5384655bbba4e761cdf6992feea9edf6602024fab775b5ad860524c83d9fff0315065dba054a3ddfe93d584feaa2ea7f433b657e0c38653b7cc356b3cddd535e33f182a011061185a4d946719f420defd08812a3716019504dc9e852b3be6ac1914445a80be512aadadc0f3cb7fcd2ccf96f8b409c72fc0d399f57a429a16f5e6effb214be719f5dfa2bf38c76237413117e8df2d5a10dad4a9ebdfe7bbf99e8cf15ee76f97ab277279ec9149973c876ff59b3e04385c82f952beec55c73c70ef3cfe8b1c4a924f02d6f5382afa1ddd0d542136594b04fd3a9edc4c71ff0dff537651837bdbcf4dacb95ff030379613a7693a95f5464cca09134d81b58a44bb847e5f4207635d43df3bd336c164668e9a497975ef9108ac1880d0c080e738ab1221f75fae6baa073598c69d4cd51cd77facd3816a76bc3b51e05876d821d64c0ea1d497fbad5e5e5a405d74bf4a8e31a95102a3781079ef9efd6a154d3a0692ccf754eb138391fa048c7e00ce5ac2410acb7fb196dc44799a535199fb8c5f2d0ecedba08d6587f61355f11af9dc55b3edf74bff82e38994831b6f0fe7e26917ad1bdc5559cb1119ec4104dfe52371025346531209241ba930d00976a9804cb95e4125d173a3d7fa97b0c6270d324bc4e2a41175a4f0f39b4a60a62c9a2b0ee20bd39ad6f3933a1463c85c5cac75fad7804bbb39ec033c8afa9d127661193fd043a69d4e4066e481bc30d20d936b0a663d7c57173a66e0f7d006f30c97cf361df2464eba2a07488ad580109f42ad9674e288e310197de71b8459027fb5d70a9b4c5800d1f765306d7c4e28ba0b19822bc055ab9361890520b33f776db932cd892aeaaedb308657ec8a121668764dbc910bc7b79a4280f117734830561f8bbd09891f79754537b3488388c17ef0a94e76cdcdaa22f80f78a22f7e46ea126e2724fde29199629cf10e865106be8da5bb46eedfd74cb5833628a71b5e68854d33ffe57a83169c7be90f163b568acd9906e322d9dd03a28ca2771a8b518a7688bd85bfb9f15f7b9554d45af98578bbe8464039edad65d71623704e559fd45cf83ef91e0910c794e741f278218375616b3c9a64eeebaa31784f9ae8b05e8cbdb051fc807c6660fc0c04b92f577daf6c9ace7404707320ca78b0c4a26c7cbb2cd28fd9f17270ea53973135066e55b7494a3e016857237b0a39909416594261460a1744b7c08354525676658f50219cf69bf54a046fb3194a12b651b4095b7bd47fdf07c721950df8fd5e860af1edef8aa787f8b5e6830218c977744ac9fc804815555e3447d292beb994e7f658fb38b89b1b778ee8e67c30ea54dd9719026e21669acef063aff5c0aa8e765e95422696a49e4c26dfc8a4a91c57c040a687618476f15330814d0e5f9c90d49a4cebdffc0b84ce99cb1c1725042c8ef54ee5842ce704ccb91386d82c8abba4bcdb230ecfe8736f6999bcdf2f8d15ed316765a8b4a8966a65ad5eb560bdf9f9b0087d348bc964103c3fcdcf5a660a7a9d1e16f47e5e69064c100f03e21e8d5e2be85211391e6643207ac70b690544c738bec2032b0a420a6232ec923c8444d92fcd527e153077a28f499c98c03326ac519861517c3d207960e4a7edec48ade32b529d4e3e9077ee06c29a5b58a683d9c7bdbde10e4b5820f9390159a8f786dfc9bdfddcb77eb444f76865eb8c849fd82180b55f153678b6b7dbdf77a5789f201ba69799dfb6779364f9fb6933c9bf43c80a12d65654f192b406280625928985e2caf6f5b6b6a34e725b0c75b8b3861812180af98519bd71b267d5441b91ad17af287d282bdbfb24dfd142c47bcbcb3fa3caffd3defbef058273ab4397c34864100e55e833fbf54c0aee30c2d15bb8193247f45d58903ca2573e82ad9672be699443286baf200a61885bd5877022362af1aadca429c769aaa895bafe48571d27bffb57a4f6180e1e461114ae14b83e306ea89ef51ad5adee93cd130124b4e8952f08ab278216fdbb90e6a5485f63a6d0caedb05546679a8a78be36884f65d8685c0a054b93b7f7bb3a119e3415a6b669bdee40d86f165d0212deaeb6e51291d42a7b77a810386458b409840b949ac54388aa74d396cfc4ab7a1a7f018f4681bf0797b9bc8dd12e5ae50096214cebe48ddfdd422266cdaa1142bc5ebb6944073218fed6bca3cdcb3af89e2852b9eaa93aa2956c8e55b706ae9098b36ea6f143542316a52a8bed08a86a8da31312ce86f263e548bbcc865cfed992b58be0c6cfa853e1063cdbcf807296c34d73feea4b4d7ee4833f6f92033f9b24d2b6545992e3ac928683d5f6c1111d7dba8dec1a916cf22d8a6656d67cf12a761134bc4784b0aa8e2610b1b9f751c88cf3b55c135b7b5523ff2ba153cc41273ad50feef1c4885eb7c98b92e9747c77368a6881ecfd94a97111e82a507e99f7802f6e93ede66d297c2d417356a2e5b43ac3568e69364e14bb8ce72f4e7074c1cc6c497da07addb202bfa1091bd35b24db7630db1c3a87457dccc05b104e1ee3a2d8a3074c16ac0af33f864337512129d6f1118ef5c7c35b13771eaf1224a9493ab341537ba494a99b087220b99a98b993de5537bc106a595c0d1eaed77f6cea224acf0b2b06271dfdcb34b315824924a1b34dcddec7792f6b48ddd5e2539879a071b17705afb194165cb977d53af302ca68643a1202d0e68ab0194100987f11f24dbf589c05a0ea9df1834c56a3d90057af290510c988564324139c18461b0fdf2cf650bf01bfe164b16b6c3534a1b8708fab88f2f4c63a12c24c267d3d8866e4c2f592f5cf8f5311bd1340dbe844777c9a507bddc29d43107a40f4b9df8bcb68b6fa276b0657e904314a9d1ac2cbd76f909f6ea8cb2ce3f6678d30a2b0afe99ec85962ce3ac6c65ff23ed6a46e1d048f9cfeeca7d9a5101d3fad8b7064b0bae6a53604f9d420f376c4a15909f2a3f84578357c4ac0ba242f894db46bdd26be75a7ef97d5aa5197a72452ce622230fa4c738feb64f846ec75c4a4123d5fea457cf2c48d2451189640983b71e27ff2875f230a58c9973275ed88a344e7bcafd8fb0966c68b4359192e5b0c7266f216b0c14b13ade224694908593318a15115da04d4aef3cfa2c6f28665a8d80c4c28e471d866de7fecff5543775fc93bf5256fca2eabfd40ec424047845b51b3889657afa68af17eb5bb0677b75c06a7616c68a6e6e8905a586e77684079872e64d3045c5f84bf4adc0a593932e59235e49dfdd5b83365486b7734541cf675c97d269caab279ea7a097ff5f34af73e11fe60cf0d9f5285cc2044f6b724900efd43581055917fedf7be6dcbc7a6818ac15e45d4d943c553ee32e9de93c3b8a0f148d51b6adada233581b2ea3e9f7b30c57c72b75b0e30cbd9dc43caf0f52ec77c7f630fa22f757ea874bc1c2b55893737f9600b168c87ee0b8030786d34b1c3c1a540ad4fe24b1e73fafe69f3b78e30742f7b03d863ea4c6b77d8dd64fd311a1f7548432a939c17ca8a3a9e342bce054adb6d5de78d569c260711d1f2f54b75f8e10c0517603b34606970c8fa08d6226013fcaaad30ac914fb97e3599a43d15720b9e2f3420f123b98d476ae5d86444d48096223dae1b67d2799627c6f24d6e488a717d5e5de8853611fed882aa5ca2cc21edf7b63492cdd30eaa44af7ae73183fcc4fee7a6cc75a96763e270bbe50837c9bda22e0224c8f0d51079ac1fa1017af34d9ab5e69f9f8b33b14d399707e0139bd66052f983c902ff2045f1cc21c19a53774ec01fb25627e08e1dcc5a7ad863a940c61f49c886ed230d2f919cd7389fa4533b28116aba63c6c373affeb5797c9a34653c1d05cf854aa8ac19e30269c44774af696d2aa68cdd82ffcdd30c49667ad2383f8772805032a935e5788346a4dc0b9628ac8badaa58d3f718ae16087dba60430c0e33e0b47d820699ab4f568dbfa46ed8dd7c6b2f2aec48d1ab2e3fa76ecbb03150f5ede2764c78d2cee3629c0f493291c9f6ccd081908f7d2a8793c812d906bb02a7da01bc7ab01267cc40b4ff5c54b81468a259b5bdd8a19f88a84fa59c345b3a75a0cd8bea4d3de21a393d704cedba574a62c0f47f57a0870a284b82c7653bce9a3e4fc01ed5fb55d33e281b7464493500c561eaf78ebb9aee4afa62de7900596ec6fcd34c45e8f7812f54dff45732d350d75ede387976cc97296799543d5fdd08e346634f10ee4a4b0a3c22914b7fbb79a7b2713a666560948f92141e4d071283ed59e356cb5ae8ceeea2ab76a9a64e20f435ffd7cca9bb0a69f614cad1b27073b887956eabc09a3868577284cc00636f2cdfead3cddd2384b76368d3560cb289e81a40171dbcf8a78c3f81fd63f282a3397d65318175fd75d70da41c1a2d126291cd0630f6406019f0c6003e9acfc01d07a28c05e345b95bf8c323ab2adb2a9894fdcd5cc68e1109a831164215e6d062c72aa2ea51be0822beaf60cb76428901095c67dc7dd10fbe717dd208f66bf898cabbace58f43c41155d640db3ddfb69df4cbee922abae29a8d622d9ae0df8150d9553e1503b8197f36962ba991ba6ef71aa4ba85d65b7fa2e14a7b4b42759fcda9ce0402e9254d2fe5a804faa827d5b4f32ab0c6d6e39b0bf8a9488742184d23fbd2181091e8fb66c5c59d5dd9d606877c1ad66910b7f7cf64c21d8831fe07b68c306d7dcf573901fe0f29872417838a5b464023b23e2936732731ddad79f219167e4a85f63976f07b472babe60eff0551eaba63e65ab231e5f35b06dade9aa05da55522f417f7109df62dbab727be2ca462a78aaa63a939007b26f68956d355773a0a664b1cd7c99df6d9c1bd0e50bf8b5faf9b8062fc29396daf6ef5d01af34f54e61ff01d2b7056e7fb4d7ef335db4bbbbcb3b40f55583760c6b40d480e23b83692fa56805b60375aee825e064f464108e2769ecb88947124ec3a1255563ce4a2a7247e072db871cd6ea1010a843ba8721a218270e0a56de5a19d00942e896f2f2e6c49f24eb2d94a94c361da2a58aa0cf1da849b89177fe7b02ffaac027645693b3080aa979c90b2fc697a6badff1ea6f0aa8cdf276bfa4eaabd061f8919caf45ab917c78308462c4ea479516a088bbef1eebce85519c08c1673a176eb150c54a2d343978b13644d12803178e0028cda7cd6f5dce2091f21e628a5ac7cac0849d29e67c7f774d036754649992e776dec6a199756cb3b40c79ddc383a98c6a713e04fa8ee4fe92955e5dcb3a698541d1ebc248d87fc644e1daac502bb96c141e4d94446962e893d1b9fa22028edc0144bceaf988dae26fdc2a432c7f1d238f7d702f30272bfabfebc56bbaeb4bc47ed17283cfd26eb040adedbf383f1c6af48a3c47400aaad70d3762d9ebc4b37dc7e26f7c227e9c62d265a502d52be797bd43b289c4a826e8d1c45f554d24e5a488c096a6eb7930bcd736916233c391e1f454123250f716fe9ad031176a7bda8965170ca3a4b33eff406e663868e16a43fe799a9c53971d4b7bfaa37d0e7941bc461f1dd3ce2468ec332eeb7b7ae596074127f20a20d1942aec88e2c2408bd6d60f8d6157c087c2fdd14ea44909a692759a259306dffd0296407a5648003b025ce08dcb9d093abd1855424e1dca275994c2803c25882ad81253782f67907c080f289cd9601192388d18d12959547785b0ebf3d73f15c289588740438c878ea7291ec4bb73db96a515d00c1e8743d5aad644ea08483caa560c374cec6dc866781da409632bddc66c855631f548f618ef1a26c384aa2645eb9d9e43b1dcdc71b0d4ce46a676760ab34e0ab84e17d247bb5b00ed2544e533dffe57f9cd00315406791ea06783c647b71c4f702844613455c505dff748e380201542f72c75c34796032900608172f5783c7eafce256c6e31a74211c1b11164730800858a07bad47836db2087353f1f4d393b0b77d1eed74e59bd5e440d87f9d4adf2f418415929f289f8f935468fbd5f451e4cde4618719f12b75af0d4d7484a75898c410ca0ef1fb40519834b19921eee18cd0945e345cf2ee054c1f0eed4055aa66976157712a3486a13b3956cfd91e5280c3f551f4390b91ae4bd9c2f03730609e7434a88e48080af3c3cb871877c79f8020bb7e66b13ef889a21729d570af03d9bf296c63de96e6af3656166e3c1df0fe9941716410f9eebb14b3d4291b9dfa6d40fe78fb3bc2df63a9b3a8b89f10de443c228e24771537204212568226014773de98d181617b48ecc642b37753533346243b65018a4d1c1e1537cd09ac7178cb0a2a575afb80786d63c94d038505919aa6c33c73af9be881d3a267d069dc05366bef01f02851fcf1758df79588bd39965642b1f43c0ef443a82938bf0f23a8a3c25a70735558e67b9bf9156dc3352ab5ca2e1846a1d532a11b2393f9103f782417b5b2fc0dff8798d6ceeecc32ad8e35642ebc99e3e9445555cabe1ab67bb9b2e3b8db81ff70e6bfe8da56dbc9dde211da2e73e3f6a6d39470239778080411394e80a1d87b8dec731b60edf20f648b899d734fd77136757deaa15dbe93761a6e92251fc747883c15c4b827d3fe6579497e8b06fceaef5c74f67ab9877362222fdb53eb4587efe80f9acb8b62e48dfab16d6abf49136f525442509ca9a90043b4c6c249a8df57afd9ccfd06d69fb4b02cbc37b0fb5a3cb11a73bf20131f7a6e2abac7024f41c93782b7e43786dcd499e8ec3af29a4d2a587759b1829317587e084d06dd0d3c748494dd99ffc40d85cd999a13ae124b1b177ffc16ff80b3820cb38fe55fad0b5b5a7d45b0160f048a44cbe85801cb25ca68c9b1ca9c2b4b0d4271655ea974b46b058a6b96f550352380fee76dd01d6d3957347f5ea842c44d432d6eaf692c22c47114e14d1e5952a990ba7d628b852f8e80e8e66c166d0cd89cba60ac0d16be2e09b91cc864d71716112c7f52bf575ef5c9c8e0e338239eded603380c154a2d66f7336cf06924ddca458ebd16e9df7433d918e4c6166d9da834822429dfbd4a7251105bf350aaec9471370682d593c0885939b4bd4c77e36d86bc5cba45a1c031cab93729c066f99f0de4de522b9302e37907901bbc42706168d53505486fb808264fdfc97ea48624a6c5f57b4c9e0a4b69d54573e87248e8556e240074056a5b6b0eabfcf874b240cab5c3c23181e3d4fdfba64d3a1e75ad6ae536aa24ad07b3daa3508e0e0af08d1ca86a9a57092bb2211dc1f92cc043dc68698f25cbf6dc64e50244a67635063460cc9e9855796b86242a97cc7908f6c62025bc3ade8279a73dfb1fa489f14df3f9c957e8bb9093881bed6c907718a4df16173fb36c61d84a65642b5af0a07d85b85c590dac33bf038a8e4be0e9a255dde2568e77a270ec60a6dfca09de32aa7eb7dd3f55307ea110e4385daef76932d4174f92c1e7780358f90088a150b449b65344b9f8d41158953e62eb1cc8f4c494e39302a597264050ba4c59be2ac00298c0c826a01a05f289ecb82e670de330b50338b315481388f501af1943b472df0d1b8e0fd91d196d4cdf3fdc27f10f7981d04fe7bbf09844d72c61be5af4eb3a3f82aeede28186c51d27e699e66600664690a7c465098eb8b000141987be441c03f142c0e888c0bbf3c531f5415793a4fb0ff58e4e7e68d84189f8c23da643e275ec34a21fc32acd44ec078a7bae6ebd35b3a9363f9b2e2519406a7064f190e33ecd76738caaf69c0ef66c8523958cabe74e6107bba719fa8f68d38775b5e6ae64449dcec633636c2e49abeb5d4fc958a23f2d143299bb7a4851e5e07a0af3e5f4e0096cde5bc4ab9ec1bca4fafd086f92f98282f481de5a83febbdae85df5531de8a81c1707b66900ca6af911a0b923256baffb4c170d37ee8e1eb5c5379a3192a8599e161f3e96a30a0e8093011c550461773d225ab77ecedf467d2a9248e2997f0d9d220f1bd836a8a66b06f26deacd747b17289170ddfe0c81b0684eb79ce438e0e325ecb5cd312aaddac774d20501efe46c0dfe9ac33dbabb0da5ff6f7825ac73744dd03d38298811ae49302d9d736627b984e5794237d00c6168d1c151e832750df2641399d0f8b74ae1da6308e268dbd9cfd7d3d54c677e7ca4ad3fea9f53c708f2197e85b13d83ff961d04a246577dd1638a4209c47d50fc901238ebff39291e002dd738b8f9b8f8effde6df40c335659ac6aa942364c2f66ebda921760736eb45137652101487a0711a9e257d7dcd4cd9bc639d35d3d797711d6bce0edbbad09086ac5d9db1a8f431980aed369993cc4be78a4a842fc071fb57b8c24c85f3746b8fcc373c59e6ddb557ac59899bf08449f23c6fbf7fc6896d92c5bee0700381c959dd353093c90f9ff464aa0853a6492ec18fe4fb349e73d9329ab91050a8f758a11d2c0896e7ceb7654bf0da1228ede3f89542491eb538ce7555fae534ad0e368fc743ff4771ee4582a79884f98437bc2580e8c393082b739886960cc7ce09ee727ff18d06b3cd3c8453b39f5121ec553427ff82b10510b11aeda7a529d1d14568fe263ac7cc8a7dbb5798af4e878ee0216d9d76438319eb9ddfe6ed5af7afe9d195c30c4e9b44d2d5f4c199a42bf40f6530f2e7f75225aa9e01245ab8f710240b382bc6669dfd36a25358660b452bff82549d984747324bbdcd5160a3a46ce6fadaca024ce3498ddf62e74a88b4cf7b18e24ff4803dc51ae59ba0ac7cbb8ae55b596a16f9a2c910e2a0133a9367c33b1c5e2c42c23986f54eee6be193691e2eaddf19a9e62c3747372b64c2a710ce67cd8783b0fad1c1a345077bafd423e7bd75b86756cdd8ca9b73db601c60f754cdd0fc0b8626d276cc3e3dddc5930b0b290763e156377babba71542452ce6e7347652969888d83c0ac518e22e37599cb7f994ac4d1acb02b5f15d555d6385261977a40fa2ca576029b7575b2855c9941eb4681f6422fb72ed62b1318dd97e891f69660cbc30d7bdf0a321302c5996ffe0e6fc0735606266813e2a846ac5104244ff89999518dd252fee944f25dbb58e3396aa8940d8a6fdf078d495f54a1d4134091059eebef0add559544b4b09e45822ff3fff73e8557cacc8ad797fe002e7e16f5883b4907fa0b3f2f29f5c8933dfc30dd03a6e1329774d7943edbd07d6aa2444b3d22a0ce7635dceaa6fce01a7e621a6e404f6bbf3ad0f66bd367e193c24771a100a465530073405128527947642f9285f80aa8d41cd2cd53da806db5a2379106e5456c449faf956b7e016d22f0921e1ca35144d7a116615c6cba2be8e83ea13297a52919c00493a062a7351c69e789e2d4fd2afb28d906ede930cbb426c712eb5305d402ea9e46294a202a9b0c330ba948c5f8d84baaff83991f9245070c25695fee3fa4281f88391d18a5833f12e3bffa93b7e758360688889f30cb75b37511465180bb4818d5f3696395af22fed6ef5dd1a266d3dc041fa1f6b05a96d47dab49b91a533a365b980b44b607406199c8d2b96229e8d8f611bac885470ccafae57ba1be385b2e31fd2dd4e50d036d04335b8234876d0f32c32bfa4e9f8419e382f4ff9eca924fd612357e1514273fc41134e14e814dadbd635b577f6c2a2653758e93dd4c58a008c3412490dc095dc2442ba06949b6437a2afabc7aca21573124d39b8602de47950afc10eece0f6ab953745f814efcf2b8cd284698afc0d3cddeb1846cad4e03052e4dbedbda8fe0681abfe823177d6dab9cc376fafa371129531161e9bfe073393bba2132f42f91eefacba9a1aedd876483019c80869608ffd3d3fdda7dc91d904b41d09d4a5b197a7482961f6e1808490edc012e2951559815573d24aab6b448c5f301786816ccf76493fb1c92f8925158152dae2950e483f7a29a65d5a42c653cda95ae091b877f1208c9e28d45c078b6feba058b135b0a981ec79bd9250581ff8f50cd0bc1a1b8a2aa223bacf879cb9ccc3625c6290c201ca623ed8c03b072c6802b16c7cf4141e6cc8891e3debdf4876c3d47ad4b8e9638c3cf5b21d5261847b5769de3f897caf34bf259dce137fecaf17295b2054deb38b6d1681caf9ac028aac05f543dde06e40e7013db33012ec8e91ffb37d7a8138c016f63c0f7abbe780a2cfa0e0e3f6aa5d3d9fdc22e46ff48ac635654a5522d97b8b6cbba06d8dfbc3f4c1990e3719712dabaaaf7df305f23775c68f2f26f2baab646997e714fb0d993ec0094c1539142b50021423773a8142baea317dedf199171d3947fd4f0ade9fa5df7a3a1a808d2ba8a08f793f255625ee3582a9b867c0cda9413794a7dabaf535e4497bf004551b79ce56fdd2caa28f4bce5fa910a4c26ef40d5c01faaadd7a68d0048d021529cc43cf0a29fa9f196d8e61f3f658eb4d6c6acb36b5f1579571bfd70970a44f3202f6bf8a8f9bf37e66c7a04c3b5fe84cda87b6b9c47638dced60d91573f1b28b8918826342e9d3ad111bc9eca896b90b0643cd920aa71b286cbf2ff7b09009275feb2f034dd91b0af7f9364edb3c87234709c72a52334d320308dc6c775e1ce6b471b4a5d0f2f75bd485fb801060e57b273176928313d9c4abc559f908e2798574e2d929d75ba8feb407f88de46eae9035a5c52f9e4ee4c61125bebb52eb62c85e9daef270b20edc92d1c1ae865f3a2e13fcd38d9eef7d3a8759be82970b4655d85c67a0ff0a139a866a30491aec3f19012f95b240ae148cc37a9da7d2d137484774ddb644ca65136900aafb97debde4b1f56968a7fffb4205610f1d5d8acc81bc3481d28d98a3b20cdbaa5098b2bd7ecd972d8699ce90601fd9ff2b591b5edace9bff63b8d08f37daddafd88862223a4a03d2e7fd045e868773967c40b36ea09ea1ba67d87ece5b7137e15ec797363d32213d22fc996ace9449acfaeb52815c2e3ba927f33e8bf031351bdb211129e61fffdb176e7ebc2d678815a6a7c59939740d9af3e5a52f82994bdbe6bd4e127000b6bceed883067d1dfc19f06ff5ed4abee71698685713fe65d706b5dc5caba07e7e1c2c7ae085d21437c4456a447e138e7f77f37b6f1b2812d2bb3b59a44f955ff3303fc42b71728b7574684435711c18cd27259f45c916f600e801d2bbfa998d24b4dabc1ad1fe859e62ec414a766c2658b62c04d22a14ad43f234888be6f61021666d42a428a1b285725ebd23fd85b6d1b93dd37fbdda74e53e37282e72b3dee31592b47508b1c0a4610f80920eddb8594e3fb96a1107a0d54ccd5a2ed897fa620790dcf181f5225a2b75f788ba328dd9b0283e18a0ae175413c7b48ceb7bb9fa79d75486d812bdfbc90ec1d98dfb4f1c4fa6a370b55f329f669fb833d6155862f7126619d3f31e9629fdde7309b4bb21b9fcb101a34eba093d4bd0503b52df83682cc8edbf8f7b644db5a785243e7a98ab1f18d883a0592f8eb40d44bc0018277ceea176a72a2c0531a5f23d00ca28927daea44410d5adc33c89f92665424899b398d10e697e581edf9154d57b1a85ef44ed9cf20b19b7b0348b14ef7e96a60e931d5f50b48ac47436c5dabbe4ec5fad9a49c50ed1bf3acbd7d10acc0e2175b28ac46c524e81cbd34e11b3f7a3d3a4352284dc84044e81be3d6013cb527306d73f6daeaaff403357dde31b9c951d5c3494dfb1dfed1d81bbc4f74736c1c62bbefbe041e5b21bef07e501cc5ef32a839846b4f1454903c12e1d45b7272574f05f0522fe640200ea2278f9c581b33447bfc3792f8eb2370435eae96e18fd21a850112643881d7ce9e634efa4d1888fed1841caff416a0b9aaaeb79bc3ca77db87baf0cbfc22f74532bf367da0a69e05392a1c59baf592112db533e11d8ca6db7c346ee23d4b557a48acb36d9c568cca28163420f72af0feb191168c24daedcd560d560fd83956805039c382743f724d292d39a269931391ef4e2caeac4912ce754ca3d3a858de9056e2cb1c3d12f47a41c6e4fdb87343a5af21867ff71ef86a1906fe6cba2204297e38ada4e22af0786dc7f0097272f2c1a741b252862d09e95af57f639de29769fad0551e784b90c3992ae7e7d3094db28bf3beb43acadd9c0ed4a9d1196de8345cebefc1a56463ca4d7fbe271cf81b1d9c42d9c4f81baec640da83e3181e98d17c4913f9303666e5c9403643fb2bcc0ac9918a8c867126335cfc06fa6ecbd977fc0872d6d54bcb90f885bd90b0a3347b965a24304affa930f6aadbd06d4d4b6df2f1b5fd83941ddf00cceef31b70076b582754e578125d6507dd0f599fdf951e13b74ff0c120694a873f7de8d2f80a08dce5d77c76b1ee36fa4dac8179f5ddedebea98d92093ebfc4ba7e3780f5d5de13c1c82a435cd8d15315b40f3ba32e502258a49919bf0440b5f1e6fbab0cd4bf4efc338ffadf94c350fddadaa4afddc7f3c1636230052a9eb273f54271d840d933377864e641692158c92a3c924264b4c74f5966b733a68e1b1cd5b1382901a9dfdefead597abbdf09d1d9fb68451ce672528ac69dfc80101940d9d298509945d3512a6dbf3b435309ca2265c7cbff3deb55b344915a7f1b8d46078434d2b4f6379a4f854638cc6e7d77a6ce3fe1b838dc4e18475a8a92b481319a3f3f0c0bffeaab9ae1a69515b5f7786244edf5491b7f87e0f22d56b3259fd0b4c7e5d6d3f2cce17fe7e10cd719e6ed1f90803e492968f4bc867696bb22fe27b650181447b45740c6670df920ce84b2cf6910b09ef3b740f668696d1cb1dee0922860b72bed2a9fb1566bb395a26f39ae0abb1ba674ef7b03f3b812fd73a6fd83134fd5014cc16993bb6101b5845604465c21e65ba9d8ed6b80a699d4b38cef827eb52662c627c5dea7695f6323ffc09842e4e65b90e12eff05e390ffac8d76a76fad2ed9e00a980e4e34ec651af9f6010443915de44a2533c516df78897e6398666d3d4246b169c41afbf421017818fe91848605c41e4f6a0871c9c8f8cf022ef49fb4d4815d75b1a838d9876d9fde119f552ff11b2a7990bb6141e8b6da71457e5f09703381ddda35fbfdddc5171e9f101bf0934c4fcc0169656eccb696854a976900d5a591160b174756cd1b3ff5027af051507d77b2e2640cd00e64d768ec27f3cc5335681734988ebeb598c60733df001781ba17e506ea46d8c784d95e7dfddc2f4d1841f63b2c52976109750d186f17455925f0441b2313b126290239524e57fc4bacc6dc9c8e5949ba250e4469823ab7b7ea906be2f9e6d778260ef6b6b5e9ec30d05749473eba6842c24279954a21c380c4533f1f2c8efd50a1625f5c8af8a6a76222ec81f32eed1156ac4cf3220956ccf2e9bcc45b2b5be6060a2197bd6c3cce9cf31723158c87067d4cd7fb7c79e5ed409baf4d36c101ece201d77f908507b02ecbba984298bf9bde4402ae04d064e6a8fcf87bdeabdea9fdabc116bea8febdd4a3e7bea536f24b24827e496a823ba1589381d92ce193e8575bd97ee5e2a107f6a34eca1f255db0b25b4792e89aea7f490bd84c023704b9187c253f081bf69e2f71f811915733dbce9d364d6bed471e0241c1c92fb2988d76c36e03212a794eccb0f206e81465a2e9ec58fefb6577f16ddaa7ed81bf478078f5d9577ba371bb644a2438753938e00e806429da36ad6a66ab4dc5b9a9007f7c6fa2254925918bfd5e3ba5a25439925546c75ed86847b305c4112e0498284f7baf13cf9c58d52e7f98fd304d6a07c2de2a7ea0214ab3d673abb20a1273c6dd54f7c4eb32139d7d9cf7912032e629fde338985c81b02f68b2629bb619c772ff577150cf38e61a501d94b512a6834351527e227fb618c584be7b518b9c292c4654629a3d02de304b92f863759a1c9dbae127cad36e4f433db253731e280e12b76c06c653266049c4bb0faf2cb62d3df02d74473bf545160b52f83bb6c7630ba586e5a95b02860b58e02f50e8c07d4811bb3cf7bac3fb2c2e051bfb772b779f771d17bd44920aa1ebf440302b49bcab297c13fa5a4886a2a4ab910f011e3dbb148c7208e1947ae2f211b966c5055b241fb58d0b1317e3c83c29a96e79ef899b6e9286630ea497dccb5f1f47be5428169d837a088b9ab6470895510004a18b705a907028c1b1478998580501c79301dd9e0551db5d030d7c7e2a04acdc09173ca96bd1e4a5f8f453636959c9d012b637587502480834d1ca5225878d951aa494185e093d2e91d41e495f5b4fa6826046743fbf273d8322576f1da0887227008e0caff5b2f65c45d1a51e1c66f8400e356b0b40c970a0c4bb22531745fe18b1cbcf75df9ace9b34e1749892a5d6d24174141b95e9a8b99cd514cdf082409766eedfeab64d9debea7b28a13fb7b27d3bffcb0077e2f243b97374a856d734ac67ff6779854e7c154bbb829c0c33641cb08a55e94186e26814018c303d07ae3fc2717332a40ee4ba9e3d201fe6f4a57c746900858fe6172508db29cfc1b395ca8ae51ba12b3113de8ca858212e79d3f323ba5fa2d989d3c7d63a73a417cec2caaf70d93e63d400a77794c219bf5a84de2f6e314e64094568ed70d0abc135cc8a100beb8bf4ff2bcfa1a2a5d8eb645a2bbb85e6d2b76f34b86da7c982516bf7703ea709d06fd2639452bddcf4be611ded9c9f1214acd7dbde6c48fe04e6cd0807f3357a7ff9de7d76937b9d4064b8a55d168c312fe3e9a228eba61f5f33cee59611e6ac958ec7685a5cfd67ced5a4a6a4cbfd7e75177923a970299f99ac3da547987e6777cd04526fd8db0bd716a65b1e8de7275959ed9f6441061d6e164a1569e96e5aae01ccf3959407a62279a86582012daa344ae78ab3c1ea6ba306a66159ec990ae9d21f97142d60cb53260120572d9fa5a7c5d3c89c8e8b2f62a151b2c6cbd8e2e28eb1720e363f4011751dfe678a6fc6c81f39a65361a70e86e0cec3ae26deae5346badd63286f0dda2c42da4446a8e9ceaefb7f491bf2f1e46868c5096d1a2cfbbb2365a1fb29026b3d57183adbab9e6927fcb4d1efac9a08a098d2fdd63224f77354360ef299868d1fe4b5c18b1d456edb3ba268c127b274b893221c1fa406b23723f28e753a56168e47452497517f657eba195e917053f9172ca3beafdd6ef17d8bda2b03bfb0edc677fbca99348331eff8f63b18483a748cd679cae2d16256db9d7534c721b85eece28664a0b1393a487e96385869d9b6f810fb27ded205e63941875bee978e242d05b09b9bcfd0f69d356a006033c2fd88877289b0f1908aa385e191aba9dcd12f030e1b71e04f5ccab526aa26d1e7bb7074994dd5fea70abd60da8bb3c98aa717c1008703f45bd8c314ba4f3d85ac75ee83f4143f2d207265d61a5f06b1412ef96a2df4f4c0b9a35e57643c2876f121a715a005efc391ccba5b6afa8abed14625a708bb7079141b26ec990ca2a7e56d466806c5cc1e076ba3d6b613917c000a79fb223c849c4150f5ac5e81618925fc05a3ebde559a0387c6c4b1c1440cbf347509968be851801618587a455c648573723d7565924d50783a85fbb8a58a89908e09ec055d8a5f3f4cd816eb672aefdfe88fdf3e4bc9c3674a72869fb2c05008093cd10bb7d50a9c8476a37c52fea0a457de3bde7e1f445a1bb5f7cfe1020c6fcaa00e339e38b0c376518972e7e23c551df2c23ada9f2fb49cb069d36e7d9cd9892ca2b59d83631b3d90487652c01a9e17942e1e1e819af825767130750bcf1406b5dab7c77e1b3e4a9d008d3efda01b33326e791c63dce79e9d03b86bdd0f5f4271fe113ffdfd0073dc3d4608ecfd69da1058cf72b6a42a4d5f7db13e62b357fd31527b7385d70395af5b048b18cf4e3067527f8ad350e2b52460dc838884ceee39e65159a46ed573c2585fa312c9a8cac35fefe29113f8dcfa0c8001a742a96af0895560585617764a279e9e2f18af24123ffd98bd0144154fbdcff9cec9f0959cbc36fb24feec48cf23799f4247ec714dfa46bc45a8c5780252d69fc3e7bb011f5d3a435ede5380f5d3f97e89780800ed983cc96423f30d495e30238c0e55425785819e94aec61729a587d14e43e2d9047befbf4b784d3d90e1fd0951b5bdce7659459a51df254f6245492cc83c0cb7c8c5a0fc4c4376081fbac357bf651408a9491de6cc38e3e5a13d67acec22dc0940c36f689ce9afc0459c298ef7d440023203c456c57f7bd1cc5ba031ebeec6f02f366c82b356b372a3e618c93b91fb5e8f5ffd4683c25371d65a44380992671ebf3fbc33021f1e930beecbe1747f1444c684778e4f6ede026b0060bcfbe92895e1b4270238b220f191a4ef17af6a246f296192231fe857edbb8d5148a6f66dbaebf2252acf97e5fc0832fdf355cd8e404190af0f4bd3e6ce7a0008bd83e687b368fbcbf432ca3a59d8f61c897785527763e6a64602c6243e2e1b7adfd4e6312618cba87156bfda01642ba653d632e7be86a264e937d887c7ab5e11edb56c4581ae286c73b6c2037f08878257958a6678a46af962907078c92a18012999bd7cf6bd1b4bc569f3a10d490f90b3adf898e1273aea295d3b0ef82037023ccc7abeaced21d0920c1f5a720efe2f9f916c26a153c931937d8ff155397ce3fc2a121bdf87e8b2f0162b55ee5471c9dd8910ba701f7006a36e8062e34f11ff5a17876b9212052770c67ab668430da25f599acb0394ac1c87e3cd47ed06356d837aaa62252751ddd43df5ba13b7560a21f2316ddf8e6c5caf48d4ca9e5e46b3fc44fcf2611d1df80aef37f59d62600beca16690ecdd8eb385b81199418498cb54fa6692d2411c7f147b92886785aa6592b6a2bd75eb93b2880093437500c4dbc568e2eeaccc1da675b8dbd62d04fa3d36b94d44a2be83993a8fb0d5d30bb67f10f7a718b820e5d7a935f54ffbf00eadf54b49dc3e3d70ec2e8304ac6dcac1d7bd4365e03470839b60ae5bd81f8ccd194bf00faa400c823feaf71c7e55dff683507f0bfb1867e89fd0981628fd6afcbd01242b2b26285ce0bef72b2b722de07e576d59f11246c14265ce3e4c5802181f1fce58efab3a1a5d6b4f3913e209c54d1f63cbe9aebf2b160bab0cacf9990c9c6f8f2ffe4c1421aac2bef683374d6ccb7fa4f581e4b33711fc3f08e07b1436bfcca788cc606b963d17eccf3a25be2a1584c31cd17751dfb7cce452d97db7fc35ab1d33f43c47fb642ba8252cad8b3cebf669463de38fd2a2fa7624493fac108759c59a0545196c3b2898ba4a29826d69a06733e2bf321a36c1e9e1fcce7a1cd1009326f753d699c895a3ea9acb827fba53888078bef1e6ff03e808b629a234cd3dc606803705b76a88d55a69b94dcbcec5dc7965a950cef5910f4a1372af62bbe0f1d8f17e941274b7b08d33595839a36e63f989cf3d64b4a4e7ccda95e4107250432760c2b3802bc2f1c8a80f5cda6a8ef26c9ab27d641d85199f541491405fe9d493ea2f7c143e1ab943e21b99647f7e8764b2be64ddc46952f24f8254021abd15f48ef9e36e5a63c4d882a89750674f2954e21c7e71db378e77e4b7b8c86cb067838b1786797c13f62d221f21279540c80ef59e8d97c93cac7cf37d96182b22020a1ec174aabe3a5da6a3b49126ec02fbd69876863517ce9ad2faf6c9af25dfd168bc3f8ec23c9e7de70df71a655c42dae52711606160d6c9519fda1a549780f2d75f28407b84f066a1e1ae99e33ae1407d17bf6b3936f4d1d57ed446da73663b32c749969502b25de8f0c3633516c5124b25bd8b4aeb97e557d14aa55202b3f3b0b346f3a2761c6c6e696d92053f8d5b27a8d5b0744c693d91e7c70867451b2a3ad80393fb227c657c1f7f3238df0e4ed567d8ae808852238bae6e1e1ed6db8d47c2ed7ee3749c40c686984ace6a0922f350d9ad488d8a305aedef4fef96c2987204195f46687df2090fc93fe4f2ac00bd2938a5fc69dc21f743affacc36e345cf7d38a7371e59ee977d725e72873461511189f3de1eb136e6b3ae39b5df02ab66d31ac3fa85c417b88a9692f8cd6bd8b2d0a71f9997b57343f849bb2a0bc3b703c37b704f009423b45a1f4df27e054ebefb6b41629bed029212c449ea90ac7b390371615caa1e78b6f873b000979fc20a3b2f16141a1c179ed4e71ee3863adc222e5754d750eae30daa7a666a96fb9e70c8751e0bdc3e657ff55b962bb68a5bfefb245043ff798f5641350fcd0bb6712051622ccc7c93ac0ea3d12e3a90adc460e345c42b55fc2a002f0a755a8aaee6472c4ec693b76c5257ea01dfb5898506166f3427ec0f41bf3a91b29cde77927fc11aaa908995cbec01a8bea1b3f4128256c0c863943e781154acd5ca3193d2ebf82cc5da133553a0a5b47bcf74d505d2ff4a458f0d2679123c8ba6593c43f9f02022b02013a59b74a3f530ecc807836b77118a48cb46148f1dea1246434f4c203082b9cb7543882336b17f204ce99566ea6d2e8d689a2610aa74bf3105bf22db59169afe9a1f955d2a87004bffac71ea65c9445a0f0c339c39c1986a629f15b201811ae1c82ec42ddbf62807eb28818992f28d32fa9503fe022969815f63f1f3c2acf119f0b2c1706d8a333fa39cec289ac00e7829bde19e59ba286ecaa7147aa20ca3eb711e18ab0028cfefebc952dd3872774ff9379500fe19ee476ea84716e4d13124d45d700432c9746540a6d87f06f4e637cd7379a8d5ea507f2d3eff7f3df6492bad12077e0b6a928020760a9429caadd86c1240b381c3eda091e953bfed4d3e5460929e90ecd5e98c9e77be7ef28f4a4471336248468c4f22daacae99876f0348ecb6a9458c9e1602048f8b2437662ac4a36a6cb0c86c3d02aada2d6479eec3b7a6f757739cd13c33fa3891b6ccbbafd2c511610f8562368c2d936022ec874ad2ef820c94b1bd729ca0c7a3909550d5bf6ecf669fc182e426d444df5d4ff11a411cffce74dc2f534b995cede19e548362db3e88c5c29ed4c496c17172574e932a30fa02dea2e5f78c6b833f95d9ccd18435dc54af3ca668917e2321e53b1f4c10f2070a68d4651556524e5cdb5c807df65ad0ccc04a38a1976f965761da9aa26b371bcaa557e7f427d3526baceb59712010e769580bfd6f6686d99abab511a122f69c3d92bb06d0914a65f36f5ffdf0e2018341dec535a992610cec336302d3c060f6d93782c85c2c890647b97701dd4c42b20be1cb8a32407b27474a31c09a9cba665086d7d5a6559a19a62b991dd93e4113cca1b0b420e3eae4ac17b3dad4d73f472ee8fc4d432e885f2c75ef63ff5d1aafb1f3aca42545f21bfdd69333b088fe1340c7bb0683866ca94e2907630f8e390c9eb732f04fc81994430cea2bce11a6339f037c30630a1564ae189505f22b8b3e68d81fc1d64a211250b23c56198a0fbece802617c98c2396a73cf9c0b9c58ce9b2387a9df68af1c912cf5a2d808272f37534a478e8f0b7b2e0a1c85396ea00228a7d2639b8bb06c5bf437192a908b2af52a2d3e4dbada77c5def961380d189437028adf04befceef0113a68d95cc9a182a971bdff0519f8237c636d02796d851f35027979988b0729592d405bae5437cb3756153cfe79bb9d3b6e99f86bb10f82d4faa96d7f3e06d33a49329aaf4e5496d1d9361685b260a82712abe3fe2ed8a472e63e74ee6a166f899fe3df39cdcc8d56bf9e39765dccf673a0d96698919baaedc4ee724713fdd32099a000a42475be33b5059e4871beea560a425d0055e175fc3e2af1ccdb3ce088f5f2f8d8728a10f38f5aad1923911c348edbc74fe8681a4c6aec5b5c13305f8c06bb70b815585eb07646f0c40d2deced7b36e92f072a90bcbe607a3f11643e9e468b7d624074c5087a0dabcd1d4250a786b46b53877cb6b276cc698248c36a18a2672130866732fd855bb5a91417d3ecfdee07b741dd06b9d88eb6ab045169cf6143e0eaeffb169a48f1c77871ded901973fb7a6a84ab5dc0c104839e8feafb2abab13b6f1da3c31cd8426e6b9676bebe4126734dedc0b758541ce16fbd1f7371ffe0aeec222775bed3bfcdef163df476ec8c317d4b38c34a451f299911370dbbb4742bf22feefa97e9c19265abff67ef7420588311437329beacc6dfe7f1d374366cb5d65c5618ff1a7e32b078c410f484bf7d18138f6f95bfb7f50082bbf48b5d342feb8a042a65a241e3cc61057bde4982e8ae26c9bd25a8476531576016ab975e5d8dca4ba09fae311e6b7d883e744d463e772c694836d7bc6a715815af0558e92eaf8189973ac17448e522af63367700d3516c6c5c0ad5658104a605310da6d7561eaf860deeb6ce4b41b1c7fd2feaf2f0ba7dfa8cbcb6754fadf9f73e1b43b0a66765cda75129a6bbc6a08bd9f509bc094c4868fd02c01024d0811ec5677ca5e5f9c5fa1373cae3c4b4bc929bf7f00658f00021384892c26a52f33926028ed7ed9107f9fa4bf694ba391882142959de069bcc4f3382cf24987d0f683e73f0cccb7023842cb283a31722bf0a30c31b377eeccfa9f66ecbda86ffa13214fa14320b6ea39f925565d618370563826a11d5c750ec0c8f57956d7ad3e2a3428439d8d5fc2687848cfd8a46a30517124d14c0e44330ad00bf38a162e301dfb7f48e91604741f3d217fae7a6c6e7f9cba8235ee3cf5e98c49e30398fd80ea25cb8117aa38f1ea524d3996b19e8eee0da237f9a8261ec7420b519503364ec453a8ec9668174495dd2ec13bc30b20de04c1426d3b3eeca4e533524f872d5bfe3b3f0c7e991ff7bd3de0501331b807fb6ec5444ce488de797122bc4f8df18ebec70bf4285a0c01886cba0bdf9c2778eaa795473f9533b50642c83225a65d398b3c4b9e14efe7f0e501ea21a3ab0a4eb42c99de53a7e63db472047536fe66609bcc9b3b0596853e8100afd883a2db60c598d630715f7a1841b073b9b77397ec4f1ae95f2b8cd7cc005dc3da2eebe6050a5ebed0c6bdae47908525fc8a6de552062d130325cfd6b2a7169800cd9d085bc1bbbc09c50234c8655de5b436c69df0393e3b7da4ddf6d8f1405be1e1852ea7d02e1f1742249951685be058dfdd122c5fad209beeb9608eff0807e96f494b025682924bcdcf18c339eacccd406a9eaefd9df3e4381a5c0c55402e8130c8eae653a92ac6f48fb89506115b9fe9feb556ccf3b24bbb2455f98348ed696ae8929a87cdfd08a6520ae573c9de512fd9cf56372f2266346b2e0bef0376362350884f8421347b82abaaff528c5e76baaa0a6eaeaa583219559cd827ce153cd75441aadb1d4428ef26665f1c64b8e6ee36cda8d5e3b74d171957920d0695cf9239b075aa2cd6874685a526725205c64d39608c06c44bc0b29596a48b857714e32025c8476bfe2305ea95c1d52d5c984c134974bd445639c408a6c84d288980e7887bf8740315ea01f924dcf117ca4aa39c4f83c5899573735c1e866e4d9afcfab9ba88699671435a86da646f19a9adf8782c89a4fc6c6a18730fc43c4b1cd51cfa5800f62dbbae4becbfccdebca05a9f7fde1912cce0ce464abde1ba8d5c20070e5d5328a9095cfd37c6010b3cf9c7d14b002ca55f232ca8e66929bc222b530f7ab3b8b8ebc0c38d20bb4c8b185a55c3626f213e023d249cd59019c3f6718307dbeea2596f75d9e3c407001d11935eafa467aea4134027961f8724ef3f0f79b0980406ae455704d987aa589b937e8a3345444c220ce2cd0e531150fa8900fb59aa1468a7b5d24aa5eb362a9f19bac2dcd880038a729d75f6ea8287626f3afe2a3487bb29b254f7bce8ed390662fec037bb4255bfab8e7bf4bf2aae571d2e656e631482b8dcaba610e64ff73087295f7353a9c7c46bd042706f8a9bde942287adb0c5667013e6ffdc31b77ee13ca3ac3c1874268fc555194582106fa42f91ae3f6a09c9e3b00270cd6b3b096e9d20bc2fc1080cbd2d5ef6a1bcd720be0717ed569c8f1588cf2e4e288865fbd62f05e25ed22161c28c5164fc5f3aa6af9d6a7e5a9d002e3d5bc3bc12d17826c0bf78a1ba7e25594dc0dcb49b1d7ce11f222417071c6deb532a8bf1998bd8e0e4a2d5c407e81acf2c441b1807791aa4929538f921611894165915fe5a6b17e90fa556c9a29fb40f1da73a05e1169521d7692ccd0e5ceae2fcc3776f594b7bbf3a4b3510c5d5abd46523ca571d33cf1cf107b0fbd3e1dcb8d80928a53d8321c77c284cef832d5eef4e2071f426c3a439a945237d5146d7d24450ac420a87bd1e94a909f5f8da29dc3120b3eae912cfad92279342cdc58a34831540df05ad6228f990ba701ab1d9644d3f2398c0755772ec7d56e8f1be972272fb4ea4188fe1eb6c6bd5147ee1cd134d2b75aed489b670f67c6aed7e73b477830bee357fcd56a85022e91acebf244921a48db71a5193f6442ef40a2da5945b3cc5ebca5ee79956b565059832fe228c76e407af4ccfc9b4f3ff82b0cacdb4c55c94206257a26461dbabd5e4b70072edebef7985c5d90587d918266b9c6c9091254874874678ff4a126a1f0b6d9f3a8c43aa2b4ba85de42c2ed31e0f2bf38d705ff021c29e5b5293ea98dc8f525220cadee2aeb5e488499d36d3079ef13d8062e7df7aa6a858e13b40ee8568aea7c1879734cbf15411418ef93e9d1689ce031dc4a030ea983d49d2bff8ecd676defe521f85cbedc3a8400fd13a52b599b9d706d22902e454128fe5d619efa67617373fa156d45fdb5e5e86cb9df1ddc36aee95747973a71c1145f680bc237de108322f379ebeff822188893578a6beb0cb9cb0e433e1ea3694b02ddf1223b8e119554254d5d8a14bc25e07d311604550ef1fa3bce1fb30aa268988a95ae75c6f2c22e62633ca672891b1b61ed13a2abc5431983e90444cdf183c7e63fdcbcb91ac6da30af351888a8d096d7ca4c9063b6f758840d9b2b8292c1bb292f78eba506010d6c79f3f63a2118d0bffe7a551c1e8823b97673b8fcdf9ee97ff3481bd304e26bd15af06a677f26f3f96ff679e4fd25e2b8837eb1c5d91b76cdcefc234440f4df70fb1f83edb15c46749c278ad2d417a3f75d9e076d9d7e03c74c4fc813a7489b07167aa892b621afd50ee7715879466f4b2bc13a6b55e65cab824ee76e415cb3faa03f1183cd3a9a0771ccb56b0897a955d09aac100461059b57d45c2b1015a04fe63ae2fb1899421ceb310ab3e8c8ca2aa334aaf42a2457e255675c429faf403582e82638a9916fc4ce736b0b04f4487ca93e832e9a8c621c7804ccf9715ddc007a8fa17b4d35d4577291ba92a57bbdacaef1b314d85c623c66d138a51feb9fb5cc964a8930959002e7786605b0d7bad4d1a59d2538fc5e3c59227eb852839308686266fd57564ae654a0e4679ff4c5d9ae2d9cf363d726e4d8009a46b85097477264eb7c574d3c729e280a753b1b73f732a65837c2cdf748728f7fbcee1b233473ffb05db5379166e0f8c773800c47e2e6a50a9c2ca0338f41503522b1855b0506c57201978d617e156a13cf2a0df3396e122c7d51f9ebf7427be3b8fc1825fd8bd6d5864a1b86aac2c0712b54aabf22308e81cf6e32fb00ee21fc4cfa235335bc5601b06ae28ad07b68cfbc06f6140f03499a63f8b5f163bb3ac9e7094123a423ff55eb4f243675068c2ab343cc3e6a19418e41192d7819964a5da5a9939b69fb95dad044add5924bfd9f43720d011c0ad3fbf0a9737684fb0643877229eb80620aa507cc0012be88515588ddd59bd310efa02bc1be056a65de3441539b6f775fbc23abed4792df0740d25710beb73f31276b44cddfb4d330bddb421881e1f31bf04a17d974435b2618afdcd80c4424d216970d97dc80526d7c9d28bd2894c6fe2fc1b9b9ca7ca95b00260f5c139420cd7b27b4ca7c2312d8b1332338c599ff63b53207edab1cc31a2605eebc5c6e4e4fdef15aa4da3c49c04688da69148e9819ab1b42f9911cc7c90182f5e9ba8e82cd667a80ef09c075e51fd1eb0b60338b851f4a5093b02581686085cb38eea456dddd974a11e45a46400a30b56e20ef2106a59a35572b8d3c1a1ffe2f78acfe4ed9450c78165618dfa8a89239967d24e19568e14664c90b14db6d13a3c0394a1c0e4c2370bd61b6537f996fc2a31d8e4bbb896ba681f12fd40c85297b4aa7ba39a8e1a16ef6d2d15997c50ba97fe78c1bf9a5fe634d178450a56d4408503b008c355fad029189aaac13c0ea4553bb56e608a0fbf8503dd05a36c75e643b381a65490f5b329a5129efcb86758c95cc044f2d87fa883e95c8578e48cc4e9521ae037f07d2bd6869539bf7b8ea7b300854656e21089e15dd0b944f10690f46545de0bef80a6bd4c6d022ad89a84efbbfbc70efffc7012d1637cf62c497d19db99270be214bf2805f02ca4a0ebcc8325b59cc0473f31e3290613669e088b390e6aa97eb3fd9978e57dd7dde256960d811e3fc4b055467622bf24063c9ad8395a773922bad33f61f05c19d3b52787ee656c4d67c98b2ddff62f23cd8a38efa3cc82ff6a4dd89222471b88dac9856151adc5fd9878a4f66abcd221811c359dfcc7c4d84d8d052d9ecf2240354cc05a5336e22510fcdf73a2932b76f650bfdfa115ff08ddacdd1625c78463dd849b9669f6412229177dc8d9aefa597f414bfd20e97ee633dae6cf91dd8365d59c62e6532f4552c6bce6c22e520527c04cee7651735b750fc2a028886e2d6096a0c641cf4cfe59000bf21f99ff348973a90de8073d9e30138af959cfbc3416a1032508127920dc28050faef05472700808fd9c7e0261e234a9eed10d3b58bed04fb6730aa59f30887870350e7c58a69b2d63e9d6e6c9fd9fd90b6fc56c8ed33883958a25c000bf4d25bc32fc17f56e736237699bbfd0309a1223a6b2972799ed698b6cb13f87212226dfbdb0d15f541227866d478b3df2cf8d80036f6c516d7ba3c2672816f943baf7ded3308ff9803cda4e445be7f910c22ec5f53975a5844f0c930496e60de530ff7f21b699ddaacab8734dbe7f79e53e3def139207e9f501fd318733f72ee0f3e453264b3ac7a89a4873def54bf202439e42a8c1227e244709cfcb94c09253e069f573cc7ba8b76960334c889fd1eb78f00b676c1d801d98d5665e50ebd7952d956f8c3b4573bd99bf25f285a508a70e4748f08d4a7d214b30f291a83615b857b711593016cfcbb95750552a6453c69157e2a81885e560354dc6fd47ab57eafb15e2c3845913491e3c56e1b1841f5400fc3e0ca3a14a6c9a02db933d41f323cd8a257b2f8f35ecee1b9f172575d018eac9c619e9e757a410a2b832bc80d443f27cabcc61a1dedcec8ffc082174266a8ca3cdc59b520fad1f9954ae0327264c633d8bddc488a0579c15dc2b5e4d4a95705739b38223cbccb3f4e11a89cbeac33c6be2d8b73105cdf90c2f190b68a7224f03d0b173b1fb57a64782d1b61185459291108e5c89a787205be9854dd5422b907634f481a83743da728b577bbf6cf46f191391b9aa3b62cb504a3d57d578b311aca9d5b466dc74fda4669409a55e5e7fba2cd7118dd69c4b7be060330b7a9be50696c3cbfcd3a1169df31af700cf7e4cc281b57949f6cc5e68a8cae91aa293a3ae277648cfb326fe333f2f29c05a954a99669356c1a9a219f6c1a4ef24348b4321bb3b1a4d855e69178f5c89a331265dec1de5ed9802fed23c3a420416bd1ed98fdce3256290d069164239e2a1b16e8a691c28f86e88a78676e1815528931f0725e67b4ae24d94be2f23af8913406c8daf923d9bd2ff96a08924fae285eef1a09a73334f2f148c23c6b96b83319115bf609ae056bb450d4d1c76249eae67648db0774f2ed1a7d5aac04f4b902944affaaefd946d9b84fe28edb7b8b479ab3e9ce177d6970aee97a04a4db3df15ce879f1d0b2a3435fa9564c9daa289bb7a7e054357f5750adbcb948e4fdc3d0229e625cfd2d15def662254deab525b3a261e7bab444032f21547a45f1474b9a4da313d1425b0ab290edebdeead1223a1f9d56fb2013e4457b6957a29730aac8eb23e4fde3d6a79775ff1b17ca103498ad0b3077b9b847f64ea8481684eb3659d458fa2654b5ba77e9daa62bec77756f0c7ff3071cfcb9c268de9b55e9e120f85ee2ae6b28cecf870435ca2f340e72b60453737a1a2b4adfa859699297b88826f7e79e4ae5780283bb675f987bf652deb676bed4e74f53c6f893670dd641f7bd79d133a6db7f98fa73c05c01c0ee2694dd783904a367c1848088191039fa09452055325052935281a175bf2d935a565920aa10b9bba656adc32fc01749c7f258db5e7b6783d8918e24f5cbf0522b8170f6d63e1d53d395e0827fd665f5dd2848961ce2a24ca4a1ebd06aa87991ca52f1e80e0ad0272edb586f646b901f76c1be8e439232e47925dc6b50b71b4f3fa73f3de4e288afdb2458d0e30498785c5b98fc50916dbc221294825d330603544f612021ab0eaeb334e6f83b41fa7accacca32a02157bca067fb80a793fb0dcb3a7a04f6f9fca773fe60f9236c96bd3addb4c4bdd18111a6b930a84ad7504c06215b165b9bee32ad4067efb6c5b557b4190fadfd686d8073a176443e152980009749f05b8379f4a18022e32985c1e269c58ae87d8f8481425f510c5b15bf078aae411940b90baf10281f541d6edad04095cbad166fa0550fc4a981c57c8045e990962813aae7b3e08e407e314e3b7058249abb36886338cf78d7e4910a37c396420d9699c05f1487cc8d8f7da6468dc3f3acc36a66a03b9597128adb70596bf709f1e583d9456ba64c8d4fcaf516791d4e48392a7a5ae2e803e0d993a4db410932c1d6d4f678f6e7c9fbfe802a76c8f280d2282bb04c1b521d6d03c6905d558242316ce33f23cac22c9e1a92922dfca1080243ab22274b9febbd48a730860831997fef8ca6a145fcce6493eaff56b99d1446d2ea9512dcacd0bceb29fb0e550ea912f1d12a2ee54840a98c2f92ed4b4222f18ff526711cb436108d6495d3638c5c6fee834a2f053fa6cd4d1a5e6fdd32d6f3eba1b2124deca53056311f8852976e98eb729a391258c8653eb05f5f64a07080a81f133b0c777360860309cd03197bb3379a396594232cd5b1786fc94e406338dae62a876e9cca9b61aa35b659086a7b0ee9c1a2dabbffbb4ae6508ad8002c3e732847038d6051f4a0598b36e97154737a3ad1c0814765bc5055d39ac8b1f79ffaa6d987ad8a7939d8dfb333087efafe9a513d0ddd3d86b50dabc787baaa997e9c062c2c84fd503035c4db566e2c181a8293eee3af29e9620756de4d55053f668bb26b90662ef30d268b0ee5cbd1c6bc7af6394a678227c23c93e50d20f55ce960e3b2e1a155318ce63b26c63d2a873a1706f01e3ef587a435a47e01c1b0bed5edaf5cb42b9286873ea8af0e6f8d33dde5ee55f0938371f06f8cd820cb4c6747669c444aaa82a20f399da328433ddea208302184bef713455d4ce02cc8e6ac8a3f14506f74d11c9560ed409f8b0d71e13b23d23aa285b00693584e8e3a56c08800493a13179e1d927435d210a51c9617e00ab31c49a90ac191181600b9d300b14890af99982760d7af7a80b70ce7eb59322e5f40323b6ad7f3eb2652ad13ac8d0b8ce91c286c6c6d64e0b5879ba80db189b8f6b25993a4746492d8d8432133d712121dc2736f5895309f77abcb4bae3d56d04ba78838ffb686dc2caf984eea613df1d1c1fdedc1634010d626a707e2f464fa7aa77197909004784bcc7a1e9a4970ecfb85895359993fd2cfd1004f044f86567d58827200eae3fb5e514cc6e4a5c9703d83ce06a7c29d938f4c63fb876aaf7700bfcf4dafd5d64f9a0582a704a2588ad21df6ba68ec83bb4d0a8cd5fe830e37d08a10883a2ffdf492ea43717bbf33c6916b22536cbf4227ad629c4c3ecc34c0418f2175b815a48a233855e60e64d5c97a62b9f9dcfd747d9dc261e0a8fc0e4c48bb05e794e0f44797f60f9b26a90f9b3bc5725b562bc04cc2ca7ae700895a5e23be3fe277aa55b022f02877c77aa77a2e79f78e0f018971f24f678df7559d25ae80925bdc38af2c3587ee39e49870188ea6e4b67fbfbc02742fc494700b6ca667b02090ed977d7b533dadb0dd3231a9cead624ecbf7fcbd412901a4f64c3349ac736c43b6930251c17ab2b17ffdcafb80ea4c89edcf8e367a3f930082d483a5d21f784219b422adb4980662f92573e213d79e242d884ce18625fe3100ff249f09b719036327c4e308d32670fc8930d7e26d2e6dc0e97f2c1d5df66f1c1f37d93f48dfb9e595a1ff8a92d44dffdff08f44d1f8477909979d4ba3c5edd9f5ccf491ea96ff0ef924beba24baac549db911992d1116ef15a08ef035f7e98cb7987d9cced9526f020789603c414fb695858a93a442f7b2db4e1e70580b7e08ffe05ffd84a1d686d62625b3362b0f95189b4a46582a326d745a45eed8e159021fac39d653be934bfe0c369617333fcf6bb4015a0b9df1d2969bce554a1d449388e8890933f8e85a67747993bab13221c3d68aca0e101db17c724a9c2cb02de6460360a3fcde6b2fd11a81f916f9b52a19f8794232b580a478c4cb82859f261acccab0c5a572f7708579ed99489589ba04c6b25d46b5e56002a6b4dadf23a6ec5c10ebffec7cbddafe0b9aeec6caba3be87bf7c84dbbe743533223bc042714f8707189f26003b5efea9b366f3be3ad21975354c0afb4bc4ce36cc22ccbd6bfdbe82c8a21f9fe15fc6ff0486d4bea072b619cac6fbd2c2c4d686270863e0b27de123c6232fe1dee90517b4ad0e5e988ee67090bfbf8540bae86e088346cdf76181ab6754bfd9749a261d0989cc3cb7038ab33314783948685e737c74e8e407b03201b589e3e7930dc93e032645b28cffab354391ec514aca075310c34a9b47bd3ceac7b9dc5109ebff9bdadb014c4bac62b83ee2f1cafef246cdeb584073659eae21ed50ae479f4e47eb668a4b9324a7f60031264555cb51a1100f8bb938189b489629ca5369c3acfea15be6b64818babefdcf187a373596584ec13e67e19fe91e8879c54592824a5b0d067dc6a09551b56cc3cb837e75a281a1bc50dd06d0b971b346b340f733ad9a7a075ca3125d7a9229a0871dbdc354289551aced2aa8b4e73306c9a983f2dc99f0748891b66c029961e41121d058549b5f3fec777722338c70cce75d624665279b04368c887eff433505c19f6f4d8b167e229095b9a3249e0c25146e903f520a053292ef04c305fc14bef80c68c91db9866e4180a3c19be7ff463a4acaf8feddec3343b1a24a327d59174ed04dbe381ef7b003d6325c79e40eae2d8ef160feaab2ee1757dca6738a2b103a4e16a8399690f137673cd42321734c25f35521181267bb6825f334ef638f4ed58181410e925e6044cbf9ee5a6dc3ae525063b3c87cc0435f42910e3a09325f0216dcec1be7f8650ebacd455d64904fca54fb165fae4ddfe4d26be96e89591c788859c51667e3e1847da491d9be5ad4367583bea8ff73b2655cbffd69304511f780d270815f9368af49a29b92c563226866c22ab234519286d813d3341b9c1a6ab3082d5ca39bb67c8260a3de643f1cea005c4e57934f3fa18a19e77c4a4caccbd7884e46f5ad96336e249393e78a173e1d4140b5c8d90845f02b370b9b9b20f388b17889b0c1222519a2bfc66ae00191e763f5a892645f52f46541fa8c4049d659ec50157779c8afd2fe85a0e9dc86ff56b40402912e14fd58998811c035c7ab4844fcbb655275500d68ade13c7dff51f4bc361f22a26f51b3003a93109cc825e77d89512387fb51eb164199c40f5330abbf8b241dabe692527b133607a0ef0eca951930e5500a5ee2a66dd6d7af861ab4ad44a27b73a316e108e46f867b6acc5542791b10d62c3728654d6faf34ffce8c2ab1c3dfa0e23110440a7798c764ecfb97ada1ee13e372f81b163458f40e7b4a847dc0b78656c456794886fa174735bbb5da82f85bf7307d895233ef5e8096d473226c79f138f9fa25fc55d5b67db00ce3027694b3cce717157827dffd2a2673707d728e9e88267c9494f7cd09dfcc31cf22ea3e3737437cc068adf00966a2244c40d8a49e4dcf71785c2d632b7b1175b4ee695b533a694d460940af0fdb13fb1cf9facaee59112a17180b75b255f6ecd9ad080db64b110cd2e201bb0bf82893910a5ab8ec675e66b805422c7152d037f5c87c7fa4392a9580ac3c154cbd8dd9ff22505b417893bf75ca5cf301b205234a84a783bd586f08fdd845b3606d9093bc03822bf551938d7d06bf4f66a49f92ea5e1843a619905ce381e73154d5d381405a6661fa24e9b3824acd7dd3ece96497e3a425c0803c23a43faa4e9cd9529aa45332f5c0222559ac872f3d3d49dc72e9200de08c66f893fc3804c5edda50c00be140a738e9b1ae2fc0b1817f27fa2f8cae3d40cdd7c558c317501b3b8386d7c3645b41c65af984e97acc1e2b056d06fc2be17de9d362936ab89f56888dd9365efacf1435d47df4096dbf7da45f4ab039bbed2917402d54253bda9f7c848d88df0d44294e622bb160ebb4eb6116c2845cf46ec32c74ae42736f28a0a67a7c1594e9f36d108c52e46b50568e317cf6028445e86b19355f0068013d0ba543aeccd7b19c49d9d2dda25ea13111cdf8a35d7e97965bb3e57b1f42d97fad387d327ea5868a37f9a2c40e3b6bd63d1d544ce96283fdd64c3e924cebad57ce2f744335e091f315b746c0697630ec292722fd213f7c9d7ab1bd45e82742906225becca7d27e95afe68c0448dbca5689916406829ef18c41b351e95b3921e7556290ff12bd4257b659bbcabe03ac0c6b45043ce3ba013813fb983df5a087ca040c427e2203329b5e25c8f5dde8683dabcc4dd763af8c49c5bfc9f9d884a6caed9885f5935640cc06e04dc74133ccc0831cd2b165f715028ccf15254824be0ba3ef148599b74901cf9ad0a69a9ce6dbc21f504b5884c8ff3ed79d6874f8c3bcff5270a93cefa7ecc7625fb785f46d98cd2aaa01e6918c55ee3a4789da5b62843aa1227416fd9c5437c6d9f22a550ace6e5e1de8a243b0ac58cc568a8914a7a1ab998adb5f653e83bc0f37cc4ab6bbe8a8b12eb67f92523308502977ca9ae4479edab489de510326230e75fca05f68b7a15790065251ec30abbc3a57a376804707a47c4800659142484695ac026187f3019dc8221044ac2769e7759636ea725e7843a523d5f5f96bd511c7b043b250971400a6e286fe1c6a5116f9cfd090f1cdc3ba2448d25b34f72c1859831ba379b5f26d33f6e20453b717009ccc8d962a18f87971bcf521b635c22d5ec0006fa67365e00df04647df1f0600470d46d769f7ffc1c1541148ab4f551bd93da0e1705d187edd52b0299393cb000ed68ee6cedf00ba80ba22627de4e25392a647a37917e9a7114eabfbc59381bed5ff2ce381a8f1915b3bb747ec406c2b3c5d9414d60462806b652ba48cc064362be4601615a6692546b1ebbccaddea59796663b41770ad752d2b3ad426aea059553e83366e35028703f4c52d5891211ba2d377eb942375d472c9cf51070ed32a0df0ee74a243ba5605805c38e99ab0957d4da228f4aa14562d75da325ff56cfc0e584d30f18754b2fe9b23e58f985b7dbb1b46dd5ceb827f79e1fb0e360ad67a90dc42a5eee0c04e58daa5a332e2dd4e007b4bfb276077e2a9faf18e17efa32bb8b6e089dcc2cab11a406093299af07faa1b0806e670848ff4e0ebd55f0d94017831cffb978dbaef8702bb0ee2e242719c229e7d8ef50f4a926e96bc668bfa35c35c4581d7c9f318a3d7a78e722081bc9b717699fdf1d6bd13b902c3a5bed965af7a401b5a830f56e8ed3db21c843e18df7d966bba85bbdbec10e2008143d0526d686c55ba0a3daf71eada3360c3a0fd93bb005aa12f148353d3f613514f7e110a7013d894e82cc6abf86f843e592194eb9a5da13628a13035f0cc7ac55af2e926c7514eb50d3a04e06a1ae0cca203fbcf5774f589f6fd1383c08b4dfe7512662c638cb98297a01cb9fb1a0ba4897ac1ef8393c3a079b1e73d72a2aaa5390cb55dbcf3d58a4280619ac03ecce4e9c306e5fafa29e2ea2e750848e815cfa86886f7bcf2a81197e209246462dfda2e583549fee79783a971ed0df11ab5ab452f826b050e62309938901275f4f8c4885af3dc6026bc6a9a34f1cb9969262aebb88fbcd2385ecd8c1effe72c9adc779714216b41db26c573aa366d6794fdfb1c7e273531d6ba327f648b4accf2ac590d3a2f5ff9e4eae3bfebe214f641d1ee0b203aa416a5d0742e4dc125503d3cfaac10da76a3d58f722e373819f2626a0691707b9756ab21b533536beea21e63b78673acfdd27b483db0265e5e75b0d0db447b28de0e96d8326c343dcacd944f7139e9c0c3fc01641a9e14fcff97310bd45f22a0d1373d3504aff6f80f824c1165d89c015a7614a2f281c75ac4ee6dbc7c8045ef2a2c721a993b17620bdd79c9793f7b222acca357b7c1ffb04a18f5997d037734743915c697248134e7940f54b5f39f6245786b038582cbc565b5db86d9abb116f8d00c439aa83981ce99a698dc3f22ca6b3c98d758d96e4805ea886d40bb919fd7e0fc52f6863eb525d5af5ce746568588c7f6857bb56e268333e8b8d73d745a47c481e8615e3169bdaeb0dc58c6a9d9af35ca78bb89d0cad3bcee7350d13045097ea3c36981193f3e0a16e6c91a45bdd607913621bb5d19cf9ae4bd91db1bd2526bbb64c6445906813c9d03fef68a9870bf1f0171e37099df500f4bc02710cf26fce951d36c0e23c6aa7960032d92baca56f71ae96eecc0d103194e38599cfc175545d3d8cc9ecdbb0223e3e91626efae5a7ae553adfb2cb6c056689ce7d037a935e0ed887221894b9d17e02bfbe9c7769cbcee5cdf834f12381bface0bb6423bb321cd29e221279edcf642f1cc10111958aa5cdd005203de88f243102437bcb61f89cdaa1f0ed56db7d7a7db20dca53cbadecfa80f49378aeff9193ae9e80e7f0d0098caf21e4ed8e7101a70d4602debc64af3a9cb84bb0d494a0dfb1b56dbad411a733931f359f09ad868a67fadeb6339a0560bd30052efc901b7c5620e72287444db523e8865a75430f50c7a1797f729f7c7423dac521e8cd820a7db0972443246b9bc0f6dbef0d4abae5a348f4e1bf0978a21ce097275884096a6b185dae4b582206d7e020bccb7481ba1592b370aef5555611d1c6cd2f5c8f564a164b32db4af1baaabcf2d0f1bface9783d4a3e2fb0759811687cd1e3a5cf905cdb1a7375c2b97009dcb1c5716be9ab72c6fb47a1c7d1e30562e7f6339f0360d141277a8f21addb75ec7deed7d057fabfaa2d0e2a5ac0b3846512aa2a91c8f3f629b60b85b16d60f3d5b23e775dc23d05876a31fb08db95d2187ac77b5c3088495e50b4cb0f216b944bf43c6bc40e44b0b0f3762b06b866d8696153ae0a9604cdc51227a1540025cf1b574f1198c02ff1d572402a5a2e763ba6dd9e4bca44517f5e70eb687a8f59f0af0eba87ce00886c2942496854bba9a65b309b78327f2a348c9068aac6e992a61a688ef1cfc363be29bb1b5749f0f599877e4da941e4c418323bc8fc46e9acc19fc7593fa7c99d7062252afc4d1ed1eb581048982334c7ebdfddca7859d6a18378584333b0b0c82cade1cba4b34473087d39cada6d8fea99e28fb21e8d70b55c9197c8332b47bcd9fe85e5278edcc0987d5991ba0c21ecb2109c19d35b2bcfaaf5b83d8b89a6fd8cf3dee01903d846cb10b20af565819ed9ed2f35d2e2a56b4cb2e50f113958b6a2a23d8081d85ab23da67320b2c4befc7fe53cda23c3a00ac0b43f6c3ee61241914a5f08f8d38f78c89779ce59a6ecdca5915d0b788b5fb8e9e5ef7cb6cb5f1071c709afe539a18602d9fa292a969d0ad941ad4ac936ab24e4cb4c359d061a1061455d32062ec0e63aae397d409da880eab2cb4a2a25801bd2d705e1f0d83218afc282aa72cdb97bd3d46e227a4d0180dcd289725e321bbc99176217c5a4cafab746263a14721f5e1b2d6b58631056616f0e36f21695d6661427557f7ae5b38ca854d09a9d1f5856091d464dab9b9ee828152d34857ffacba42d3ff67785df6d742218a77085d83d0b72932fab418ff5773fd2a118c60b98e7f8bedc05b55d6e70e4feee37588e74acf88f6e197eed14ff6a7dfb62c53176da5b26f498c58b4424b48a9299b6248969429bd8c0ba241a64ae66f8a92370d455c399fdcd45256c186ce14cefcc2a73f530a091e54501d3f2b5020cf313a870771c210a48603d611947cf731f2d99e76ba9592223b4f301a0270d1281b64e4e619674c6cade8eb2f69f93844de02b61dafcb6e9318bd095b8335e60a5ec40269ad1554bc438b6ef4ab81c8331272bbad789fa644144b917c94ec3e2f69bb1552b67d44ec309c1ae135da33d7538509e727e95b2b5d5ac09b860b590ae6193a59dfb4773bb33574824058704cb09a0d95d89c0c0a935b0127568f17c26a9101f1f109bcfb1b0c39c9290a9561307d3b916f668b39ef4f3d72b668959ef6ea7857cc41365364a115e7f8a8464ae8cc63b39a18d168c7ac7fd438d44e6e7fa0870e80b5d11b757cb1f71cc989f9eb9764145137bb4ae3e9e83ad83383b345e4530550a8332d19c60b7dff87ae9aa89493f18d52c88a7d81f062bc4c59af92777a3b70408ce73c79d2a8144d287e6786163f8bfe0115fb4c253471e887fe31920cd9762fbc38f32ff603e8776cae06e6271cc4c558f1f27a85d513e83f1d7d4b9aee94d56b42405519b111c0fbbce1e7062d4ba7d6e5846c19f2724d3e567dd5db62c7bf5f4e1f49485ea754dec0accdc17024591500af430f3f4deae219689ae036b86d3f16717abb754658b65b178e8cba63293245c872c8eadaa0905ab7857a54ac163f02f4e736e6cdea8412ab432242a073c011ba5370a25007097e31c3c52b4d5f4acc560c0fa1d9db8762b591f9509f1739c72eb1ed6371d300374b97615f04c1cca6493b136ceb24eb570f2d879d152755fc00b75d155c71d2f647288abf6a54c6cbed3f74d8a1beb30425ad22342309d1253e7ed424f693b1a5daebe368549fb76f3cb23692fe8f0dde3f6db6ae3935eef188c8bd310cd3b5bfd49ea91c2e04e5a00e768e3a42005cfc2b77526e1bc8bf1bdbb36a7e2743a926c1767411b45e218f6acee957777129f45e34b363363defb252a190534af245591fa9807afff6ee8f7dd04358bc71cf86462c3812d6f240cba7e749139754102cb2f657789c6848a71eea0ed2007c7f67aceefb7dcbf49f03e4cb36f15e4f4fa7a7ab1862d3ba904235fdc1bf5351f72fef56cbd125ef30b27207ddab71c31db2bdc9db8b85267f074d28951480af6e7b3e5b148857d2a9fd459975d8df47534926b1f39c2a9bc1ab5a15498eda5c01b9d8a5fbb0c9b3d13fa36c366eb70defd0de09896e4053fdaf7f833591dc32eb65feef2cb56a7be68261405dcf74165f87e592e77a3c74de1bb219eec3cc70509e17570ac57d7c4cf577f57dede8695df06cad4b2e3c52b2102f836d9fba6079035b9d72da9829bcc9ff6c4efd00fee0cbc1374771407a20691dfa2ea48ca4d8eb2dc9919f9b66ff4d723818a40ed292d6898aaa037d7a83df61b938b0d31b292af936f720a1dedffa580f745ec7551a8baf50685ab8faf5ef778aa2a49e93af6a0b841df39034bb366d8193f0c9a4fe7bdcfd6a95f436633ff6af2560147f210854e53b14037e7902613748cf2d337031d2414c2b47c8f17e5ab010674f52d727af07c387e6654019b9ff707aa57dc2ada448cc2ce191e40b5d45179434eb6c96c82dcd909000c7796ee4430acb2566c6e7200378b1154e046ee54140661a345dc5d08a41e2c140653ead1068b1d51e91bbbc0216c16868c39e6880d89ef1f4af7fae61edcc0ce89092117f1a4d10361e264ff9cb82681d5b2410d9271c88566d7c5512e10117af92753b8c80254131ab60ec5a8ef6562a6f1f8aaee72fbd8b1c0e335ecedfa1e9e9bd8251fb4161d436fa8baa0c3d5f3efed48cfd339ddb51eca395e08041eff9fd51101b6c5428bcb0db4659309e62fc556178e59f16dc7e612e3e99166ac2e90579412a836987a8dd0ffcd7ab42700746632c752c13ec4581a9e368fe2a6451e23fd715521d042c64307b8cd44d76ed65e167704a63cb799645ea1216ba89556cb52e7a532f450542ce9701ade340f792fc96cfaf3dadbd2806f1f60eb9cc0f2e4349be93d60d1793351a93b65355158ff2c3099e879827561b9ed469072235ab82d831c99b36a00794546bb3bad9ecbbacaf5c4e6d08f6c5e312b7e7a7664329b5fcef5d39a24315369304c05bc23b3205a17f6e401095186ce807fc429ff1c1e776835c6762fcbeae2515e5b74ce4a157bfe82910ae046dc4ff94bbf35df0a3b09b6257042205f16d95cfeda433839ff01f28619a11892bd9ac75b691305616479c4e1fe1b102c764f286fce7964d2e0468c7838aa1608a7b06d3343b85ae84d10577e4ec550b9d8a37ebeec95497b929f7e9fd2c3985cd8d2dee1ae4b8ad83e496393efc953e350f6e0bbfab16e56976b10c9dc0b4a8b6a8047296958de05058edaa5e4c6b68f31eeec392c8254454b98f99269c28135173c355fba01f3a749bfb150a59885d01d64a7e57ec2fb0860ca431762f72de4358471bf5fe374077518cfe486b3fd535063dd4b999a2abde2618f90094dad531292f166afc1e8dbee7ec74fc28a7192afd8c053e8208de2bf6f7f2e7396590e4156ad417aee66bd9dae5ecf728df0b6dfee7517cddfe6bf8236a0af67f4fb2c2d7e868324cc31f3e5db18b979df957c9371ae9d3030c5732274421e6c51483b1afa96baa006d4682ca399a281683cd5a85ec87324d27af0b86a026b87980242757c2b5df9f7d6a46197f92f890dfe8226fd1bde81cec7a6a0b849f62d198a0707a94c0a0c3f0a6b2916871213b24299554ff195cf6eee2d678b94d0bdeeaca2bb0a13b997b3e524eb42b4f59cc3f23106da3ff9a95091bc89fd342c44fc00f78310f29c91f4f8a747de1897327ba070acb50619faf8fc440b0afdaeac36bb90674265213e8e77a79eb34817b526f8471539b7c13e667326c3797f2659bc0123205c2344ac5d32e48e098c2ee9025444100a90d205e756209b185c2acef1ac66260f4ad6649ddab17f37b9c8ee2e9327ebdb239748090e36fabd8ae902f7792b25ca78197a4f246c14466e6039842e2a63b4163420ad931b843be20696128ed719049c65af65d1457adb97d9cc8f130f7b4dc10f11a0a43480d3556c6bc9b7b9fec2e4f67cfbd849d6f2059b61b38a96e83273fcb4dc43cbfc0eff146cb3389d8ba5038b9e51da20a6b76343339a281514ed0563b50e956973914e48deb73a774608989ae31be2cece2e9c67587af152ec3626f178dbaa0fb8ed24dc63dbf946c728c407e8996db959a1bf413cea0ddabaf002e5fd316aa24fa5dd1a53b23fa300701c17949b848d99d7858274f72c2f379bb3e3b5afdefc0053d68b7fee5a6ba5daaeeb6dec08f23726b27b1305ba723c90cbacbbe7235e611ff145c725f19fed873840fb21b6180adf0887558fc30acfc9cd15f8ccb397fcd7ef8822025d143601ca45b3e84d26684c4234d894fe4d4cd6ff8f7a1de06eda35c6ef05d2fdf9db1e4967b2e01efbe929aef2d9e594a15c86619c09d2b496ef9624fe816b14c1de0b834af2cd6248796fbdf545c47ed90d722678386eba9db0c078c2470c21ffd84b87254221def8354677008cd5d1cefe711201c2ceb70c8a2ce26f523fa0b4b0315af2efce598c4f3283561c25904a91baa3b9a28b294b9b5ceba23a219b8daa160c1595490d0f36b5853e997a9cffcd45af658881f19ab6128c1ab7137a11327b2ce3ab498732ffba2046692cbe7d689aea9373da4da9d34f217be3b570188b81929ceba254c9ac17521a5de00d1ce96f7e6fe49d5f1f3d1e95e112db6a735c06e20f1ecef008ceb1886b89fa2858b64dd7988c50e75dfd84ecf72f094bf2275a345b2ccad57da4d77fc2ec3d42443f776bbf1355dc8f09b3d299af3a7079a8f2f1a4fd243aaf06bbef2b489db50368f8667ccc719710ea5cfd79684f949583e0656cc002cc0f9d951f8cccdd9e45fa9ba4ccd38817061e74c1b4e4f7b7106e7a23deef3cf0cc9175d2ba569b3b25b6f69b0081bb93f6f3de10c53eeedb48f5d43da5d1bbf6a8a76d6debf63503f1c6df90e2d513bbf373e37c6d173b23f131f491936f2eeb779ca112e64e4e710aac2d0c60b1eaa469349c8e82e1ab54b698d0651e4192db80027db46dfb5aedcc646144460b034ef62c7c88a644436987143180ee584b9be0c94ef86a847db918198975da7a9e72b40a4b958c85bc3bd8a491eb4de792efb3638ba89c73d478ec1b539738a2c61d9991dfcb570236c18d98354cd5257f1e81f7de42e4a22bb6e952b7f7cf37f77c449a66bb8e6e3599f05435a466445437b1981cd0093fb18a25e07b1da56ae71043470318a5ed1fd123c8ff375606de2df5e33923eaddae421931ec8f1f242263ef4dd63ae86c7ddb9bd8b721ce01eaf827e78b88f93f64e37e56015461cad2079db3088916044f23688175cbe81619088d981f1b88b9561b700334342641d3346112001a1919e0d0154c15d112dcea4020086852be5339317295152eb57208e711eedc35e2e61fa49e7a67993bbf2456c62601b8aaa055eda872505f19b62834cedeb7a8cd888c351efc25b9896b12f44d4f7f1b2f65749fde0cd30d7ac537832f251701b0e02365c20eedec1861c9a27489e9546b1d3bde589530dbc9ca88b67cbcef08a770b2b813f227a1d9ff9b68995ae7948d05dccdc9f7d3be4b6fa4a568037c28b3400bb46ecb25d0f99e89d8626f4d973af60f8dd3d946c5751543df68e5d10d78c3b4b0e9c666983b9bec8aa4599443ff2eba37a1faae22e7047cbd39f5e8e66b3acfbaebf727c76bdfd1c8048387d0eb399747159facd1c13216e95701d83132f0b930d03ed93d17aeab5a31c1138c4d432b312605e022a7a93a8fcf56a5c96e7bbb89cc122ce6871baa2cc3d4189a03e36ce35c575e1c7c459ec9b3eef61b59eed6f2af3cc18b0e53d007af6338b3fd164c47a3dd34b24f56b34309e8989c76ff8eebe968c8132583989fda6ec561da26c9c59d1d08e8637676aeef9f012da59dd78a5fd8a9265f8d24125dfa7b30fb55673a8d3ee05cea0f1f85c97fb6a767aa55f6d2335947109bd65c1bd3a99eddebd09a24b10725e37485adf01981e9b4a49f8f8e6c0ad2a74b3f64efffb3c2fe1e683e39e2d9d454599cc7f02145b3dbb2b8002ee48a69266cc799339f184741eac7c258e4d94a405b036ced85b8600a70df3091dc421f8947ed90d54f40e04021159b7eb1b00a09bf93270714563b907022b7a1f4276f78058733168417437eeeba5302976c5adf57d08386990f5fd2261b8a33a108eddeb92c252cadfdb704169d63886f0e662106a3a6867566331b0167ad5067388ca8c7d93800c45bdf9a82534da9c1cccd7db5bb68bce0aba9f4d091be0c4f70388e9cf7f8c9745c438d0030b7c1895ab790e24ca69c8b07a286497890669604ac63455765dfd5fe69bacea31ec33c3df364af156f1df409a7b6abfaa17d183c7526460ffd50750d22fb2d1faa9c200ecdc4c7b14a686a240a7fdb33f1aebb706a8bd96c7611ba81ece092d40e2bfa47b881830885f499f9f062a74e058725e683450b201b84531da413f8d5c96bb2fc984a8fb76c6207251ec7f72cc8ba477ac3ce9c2e7847b90692271fcdbf777a31ac8d913c575051d5b0dd1f548d643f06275d0998ed046e80ed28c7228cca64c2df66502d47904981c469acf15d8b444a00026fb8447fd7bd30b107b16131a00210ee34326daa04c46c97af7cd11463df79abe19c6a09d62091a92480f7c4363d6e564398e106c35a53ea2d8a56deae890f070b4e665da0028aa031ca5cd3d5d29a0aba537416ea77b28e5539af86bf3c41ced06d63f3c146b72f43782ffcba9e5a9ab07c0d36c0871a2b515ecd22af20b18aea4cf2703b9bb200ebb94a7c7f4c962635bd03da1835b323f359d46136be025a6774fa77117c4a1243288fa07d2e5a903eaee314e0accae48617208630083d36dc3128ac427a376441538ae41caeb5ba9f51e347fb067591641fbbc1446aa38fcf5396f7a8a052ddde44e43dd9215a5bc1cc3cc8235201858d6143addac347f7e51e3dda5068c4282e22e9250a1c7f8ced7bb39b1a2b22f21abbada1d762c7cc67af782bc170f229de4c1c1ba3cc02dfcb2ea8031758e1e8fa1369ec03216788009e8a6c9bf63a78552b0f42dbd2166ab60b2638ce8cd348e4287d517558f98ab1a48fde9d0dd779264df782190a8b18f6350e1d4c0fa46116b5608dfe1f61e4f42676ca602513165a7ccd6f166f16648e9265122d61eca1692c9917a6c57508982b40cc233ef0f98cbd65387df3994cd15dddab1d5f533c5c61fa87d8059e7f5281b1aa398ec0c7fe0498ccd6b94c090b1487e6a83579239b1c4cf19c77802ada887296b00a6e96d311b6af3f4cf0a15d71756e8c74487e671a68ebc1a0724d388256bb703e3cb9d280a03ef0ab07c216c5b292bb56a9c9b8969c5495d247f281306a4e44887b06c2599fef208ceca2d7197d101b7eecf6081f2d0686e5885c6d92d2db9177aca03b7f855d1a1dd362515a586a08c1f7b6f3dfeda31092ad6b346a8b06d297611638f4ad76210373372956626bdeabfefa63fe38f96166aa9b8266a3ad7c1e5f168ee3e2bf97a0f0e72ac1e594820addd52fedc0a00946ca8e5e1c7193f3fce39afca2b8f4e85059880b4baed0db16e2ae9743ac43041d490583b3810c5765d518e46567e12b74bfc95c00aa0f1875d0a5f8abe624400b9f890a432345e3a94cbb135185a1acf7c1710fa38c0ff298157c1d361328b8df1dc5172e611312cda3649c682ca16dc65256d3b7e27cf82f32e65ad256034011486001dda82fd085148bf785cd65a714c4f436325ffcc72281c3bb57c1c4cd766f75eb20186f7c2adb6758a21b386856cb18a02eac8ccf291fe9f659abbdd16475afe1090c3e35f4f91f8eebbb60fd266b4790e4c9cab8044c9df7efa61566882a44d3edb4e85cd1d04c465ecd1f428ea4e54a6a149d1d52c4df24ed21a7437364b7a7ab2f87586b61394ba018974ff7ff29881d4e6a9bc0100086a3a6cf3755dd40816c40e950c64261238397a6d370d4c51fe9ad0004d96a38ddf2f3b6d83df81aa68bc96b0fb3732924be6de7bdbe340a6dc8d10caa4cac4dbdc123eef3d7b289213e0f29ae99ba8da9f20bcce93221f5af5a1f43699960e86cb96bc9a6eb1ed5d20bea43fef5b8f3451ba3f3139f50b7843ef07daef80bc4cd44bd5aeaae1894a41f99688508f0b05345fb56cd185c5aacae105053ba6f94542004c754ddf9ba0df5e8191652725deb9a7446d08b74fbf614f3cc606003edc537478e950927f01a60d8bd8fe0ae2a7a566da951dfabc7df6eff60e155080c2c917812e97a3a6a9bb9f2b4affe13edeec7c8a10c4773c7752d7fc2ca20c20abd03d83dbc9dd3786e80f3980051c4dea2809131da79f6eb2e0d9254f83d9876ccac6b99b373cee9d0cf890b4f4a098f711d43d5da1f586b7a14ffe286348b65e457bafe797247f492430bd451cedb65724ac00b9ac0f17591d7e3648f45765ee34d095d5d21497e6146dcdc1462cff449cbe3d2066eeb5c8ad46526fa89f75212e56e3919db89d93722a59ba5585d9de908658de9f89fc51dab333f34d7c01a56dc54a114498698bdaec5b7e4ea1ff8a48fbf69e9db366d1522d3d83209cc9c44c326d1f99f4b7a98f6220c9032a864c0b1bdf2fc49a4ec23a26bc229f6e69dd5046b915ac6a670fe2d535f3492db4843a75835bea0fc9229c28bd7ecfdaf5c8f1f25538f35ac889a1b7aa1bba2a94973d4d0dd10e5c3ab3f222657411c9e619661bf02bae7f45288293defb83368c12f3614ddb86cd2da50214a2ca8c4c6693a1d9be6be86a5b4c79626ee43391eb3bd39f18096affd57e2e903b04023d061297a978923c90b6e3790988e924b08cb27602486f4b3631742e519be7e94a2cfc28a4ffbae8135bcf6e512d4a53b4c9090b040068c62ab934a5894da04dc8c8fc49eb9908d02c186fcd7ad14718f990fff160e01d352ab5b88781f14d7b435c5b6fbb9a8382b7fd8535460ff862439694ad17d01fa0552ec60a8dc5dfcd29add888075f73f59b62e9766ef3f5b7df07cc53b142a89678e0ea2179e2abd30d88aa4ab293b3795784e7e8fd84e4c2270327088a92780a7ba9fef9b6c9e537c04a4ca015cdab59d68f257ff88d13d2aa71770235a056113d8dbbc67a0fcfa396dd2ad47d91989051c27fa3f4a9d85f9c098073d0443c9c8293259de16f757ff91e19302061b56007623d773263cb92da6d3ad2e5c87a933935432e132f17b950ec5a94de87d9e0ec22a978ae89f33e1bf39a88d8ebaf5792b83216c2353979d2d506e80a107eaa49382bb3b7e9044d8c5c3d34fad6c7dd5e53c3e63a38fcb72fbd51189ec660641d5fbfad7e2a6ba964e1839119f1deec89d7b68e2c574217f8e0511d75d8c0f627fc0cf2577258c45900d37f9b82dd01509045687e86a8c87d828e3902fad851313a547f64fea34c49001a7bb182b050b37fa9ac3c56688870581fc809054fe876af79022b92bde59b9607c72662861434457c8e5519bb2fe9e8e8ba85b686918f052b9899b07181bba4d341a1a30a23b1f9ed8af3b2fe57a313aeca6ed354b003abe76c032c88c65f746cf19f5fc582b0270bb172a16eda3f3a575cb37f10554ebd0c3fa13043b7d07b7b2561a3b37b0b55dab368461079263611760592fdab2f28a1f66edd88fd4515ab3a8d8ea11472fd62c7da2961a46e1c169759fb684fa12582875e51f9dc91a9d19e45dd750936f1faec943daf5b8bcb1ea22bb9926a0beb16de3b997fe42971c35a573c35a1ad351a644ed050f8bbe159592e69196cfd6402075ecb1771593b34553912b17319e658f2177cebb432f249283d5a6d3e8239006472c7555199d2e379d554e8a07dbe0cbd9357416abca50b52c03f499a2e7beff8d4afd4aa3364284196fcf5f234598b906c48dd572ced9d74c68eb47b54c990408902e7c4096128af53bb7aa24efa22c5c5fde1d55a81eaf56f59c126fef0246ae283350d84faaf3093ab89cf9f9139137889e2b036f4b779eef888fbfc7b740d08d1685b4f773008bcf46937b17c560867744e0c2c236d6b9700b04a881b41d1a9a13c94825c3424177bc034f46a039a4aa224a7dfd8f3937816dcb5afe30a8f26639476d55c78402461a4639f0a6fb01cf80d6f2b516dfc55759e1964ce6cb0eaa3b463f5631dfc3dae57e42a9dcda31d97422f7aec1cd8548ba38f753a502ae31092eb27377cc757a068bb53d6351894cec6abbdb2f178d356063a94dd2ec42b7d39fd204c8d6b0f0ffbb118b9903ced51e807a6fa34bca8b72cf97e30fe55ed2bb23d7a28ab747beef6bc6aa2c9235e6278a74b4147e8181a22c4cfc8c36edfaa3a574a9f01dec9fbc71fb806cfa69824e84e23449c7348a411aa1e40b8038f612757376bb47e83936b719a1bd32dabf62910dd359482da966204888c353786311518620ef6e372f228d2d537ca016672a4a940f04559587b024d7a4d084a868fb52a3450cacb386b180e8501c0b784417a4981c425c7a1cdb934af8ea1453e7fed1c8e768da0155138b82b6eb8438d36fbdd917628a6f57c08a178b4502700ae48088aafea708f320cf3a6ea11f2991c1ee6a21849272416fa0c75f2b9a83e3a09e05c7b5b87f19a0744fddb5b2667a688c55087538f885e91e32675081fa169554b058ae01b116f69cb24674490932f33c854d239f53bf8c1bfaddf6369f67b2de361247e0a4f1b224292e820ebde4104ac5002051dc665cc4d0c09c6d0ba6131d5cf6f2f8f44cbe26166380326830cf1e56d9aed5c71ea0658e8cc58fca5984442582f49ffad5fdb6283bcd76336d1ae5a755acd8fa8e0ee05d59a6dd915a52512d3d88a721c1417d8ccf133b8f9a3e6e74943a8743e3aed1c339fd810ab792ad6ebc29f6937216694997f2188ee52a369049579c2e27ab7ee128276cdf7008f178fcd95f3bb8f59986fda0cdabaf028a3b03317db190e9b0861c0e06c4326e9552c8c0ffde1770364444e524dc42d5f89a5c1c41da988882a1fd77bffab53d6b053c69076617a6aad88e9bd47b82bf4f80c9d4444896ffe029a827f100aec553e78cd532bc36a64f5e3b178ac9e952cb4ee6084f227c25514c2c2943deb022ba13e1bb6e6410a5deba4c4e7e9b1b18105c010a5949e7e6aa075d73607cbfbb98c538c3d62b5e64fcb9ec2be985c91096c25bee4a3c5385b8aef4346e02f732607da0db9d00dba3dd9fbb8f0d35e1f7bb18e1d29ed56b7d411bb19ac625f14a6c1fea243125707972a0d0c964b7510eb3e567c258a78507dbcc06668e64be735c2a63ea7f93b6228fbc9e2e11245b39f4cf5344fe2386fa01fc9963aeb120b5dd7002be8ae12e5fa3f48038e6e1ba609fdda8620bc0faae2ca617bd73b561878915f0a063457c7ad1d0d9a2c464b8cde0edadb192409997c814a5789cb81eb2dee0d8b8849ced5eee38fd2dbc3fba583375a2ac677fe48c8ba7e8604812f66e65b383daf98e228119d2289818f5e737466344712450e02866b2413e11b0e5660923acaa20f442b290187c37ba2c96c463df03944c8e91a1e6d2cd7b7061b8ab0c95bf1726b70adb2cfe891686e81c6dbc446f76c4c85df4c0b581771fe3d6e88ad8de097099a6719afd9131b2235509e6f88f6ab73e351273581bd6cecaa069b470e0cf17b8c9e1186d307da8fe20f3e93565ec622983a94567e5f5d6e422d3616ea6beaf9a9a938b8f51d3488f6a9995d100c7365c25e9a30635790004f90e235f696c654446cdeeb5723801562ae9e0beffa18482537f4d15358e88ee5f9399e711683491491f47c4c17f54052547c20d5ff6b38f4248aa893982141d53e1275a2b2d25c842a793ecb998e91010ac8ad0b4f39329e27fe34320cb8ecf4c1b0596875cf52e26afef94693a021588a931865782cf8583ef416f777919dde317322b7e3dd90e218c046fdbdae57f6deef330dcd90ce3e286d2b9883633e171e6c8d979a89b01e880be9f21fd7e5c8e9cdbd6d6b59ce37e070bea87c7b3853da5237ffc954b892a598adac5a864127d7ac9cea4f3a1b30d3c919e4136b2982b9c4a26604f6a453030761c353e118abcd8b15c65e9b3f234d778b78f4f1fb8a80d4b3ed380cddff4891082ac33135b27d9cbfe2cd6dbd42c7143b05ced83819a008f20ac1c98ee2426282c894edf615d964ab24f7407626b467e6c46e0df9da3b341df721ebe5035f17c79c598aec3c96c30305e9e319fb4e493c4fe6b3cda9537f2c7e9edb59eee6d0e1635a5a9ecd721a30868036c2347c1b4022f3ada90c03a0231893ffc8f61826a688976d9f83096abac148883e462c29e45901ab020fb7b74cafa7ed87edea2ce1ee0fcffaf4b36d687bf8a11207c89deb5a9f87ecf9c1c6c426a24860df54483fd28d2dfb442be139afd9600568504d103c92d78b94f3b3db982f16dd1c8fa42cb227757bf64a0d703147275deecc0971b8238fbf891e83352ee9d0a3d8db9aa83918270e63baa1ba003bb77aa87c3ee0928c3f866230c73e12659315e3335d353fc99fa0a37d4db0e70da8a16a37186c0153a38d51f40a5bae42a0751a5c7e7cfe91049945d08a63282867998a459b2ac4aed368182fd3aa1abb8366a153803caf883349908be59b819c0b9743ef73ea8e1f8246587e34c26dfa17450c08efbe8f2564d3ef79f0b2891ce7847aab02019bc3b6a294e9eed47ddf2f8cd77a7750d0e17f2ef73c3b9c680e85ca89641d4acebe71c2bad3946808f314ab88b6782f46ba73545f63b50bdb18473a46d39fcf93431b041c5f671d87f2d1001b3029b8b0cf0ad3616c56f7ddc0d343370cbcb07030d4e13e113519f2468cc979bb272e02e5bf0968ba3416ce282dc0708124bfe4d8af6d7b82d04fc8f4d20a837c74f44ae3fc5aff659956eefe11218a8ec19c3a1d922da9823a4beff0c22714f1d5428587680e37d01304a1b90023ff32b467df0ac86225bee788781a3f8a3817d3c657bf6f419d7edd910a35ea2e411d5189dfb4994037ec097f4d4759095edbcc393746d2a5a47414dfa9bf9db7b52db3d31a2c7f8eabab82adf01b132bceb267f451aa91d01f6ad435328ec932eebfe12ad550da81ce95ecf58421d20b798ed4a04a6a188dd9a5d834a502b0523babc877e664a3c951329c990a5ca63ff362ff056749344a46e9d6bab979a657c04b1443511795034b063793d6f459c83addab842d595bb4eb583db28fd4949ea14ef3acdc4d0a7a38c730fb155cab0a5d8d214397e3bb4d919f1448cac4bff969f9ad4c2cc718b0db849a90644f9f772dcc5978b75a857592381b9fe899a1761fc4d6c25fab3ae566cc18defee1439e7cff48c8e622bfe34d881d67225af2729759e645d98b20e1bda2d7f43cdd171626dff1f8f1de46204c9ec4e06c6dca057bf7e9c1ff3179b208212afb8668608b2a0785886654a233aa08140fc1ad7ac44c2cd37d9931c73c36af93137dd18ed22998778c86d1f80dd16cf5f41fb8bd2082be6d10d130005d1a4d1ba20b77f7e2edf1381188aa8cc0d6a8f64d86c2e87e1d2b8c7a4f8c076ba840416d027cc4bf331fb9101572bc43f6f605c9487ca5f5a966e3e068f866c337a4c80c03a841833f6507ac955981b2f545deb29a3a63a95562e6e8724e71a0a228b2a09866f83a410bc1cfbfb63b8ca67aac80ea1c87ee479ca8442fd98b53ab61a8b4912639acf49e106d552d227b2d8d71e8087ee5f39da2ae3b8a3387b2b01e07c475a6a2ec38cbda4db0f4fea37447f38cca16c3faf634fc00276b64bf4e4cc5547ced022cd4e7684ef5e25005c523b3deac9bcc1ca2175492ba8324ce75a6a4f1bccf7d4e7f1be4712551021f49ae89fb988d3c5c26ebf0603fc93f240aeeb06aef5811129ded7bad1012f59331014b7bc88160495ab9d86f46016434c79e03683c5ef6bcad749ad47d2cc3a206bdd514c7ee10715696e0604a9a55aa7f14676a12116cff9d8b714f2d7c003c29f663b61c30ebec0534b1529cc021e8e18cd99ae566cf397041bc97a0be5285ce3fe2b1c9921d402b604fffef965d5dbeee330ee8548255976f77dc61fadab0c596a6e953c5183c5c2bf8ea2d0e325eeb63903801785d2ad60d6a96bab142463a1b40e57c71217a435f53040d880160771b55b293e280eac9360f3d1790f3061db1009a3863d1304ab51d68c037e34869b40c83150b0b5b1c0275489aa472715c382ef1dcee0a64135745d70deefefec249c90b2d03fe35f6505f9295e27594367b3b3e5dec4ced7876b2e216d0e8579b2556ff7331cc3564805f1648411dab0dbdc62fca63762841703bc9baa05e86931ef98b9a7dcdf572a4e909b009f3462b84ae3fe2409b1f4cf50608f16e4f4f62bf6e824247b66884dee6fd33e5ade99154031389e93442108c04d7b79d50ebcf969611de0af274782ded07bb2f12e2aa780270485c54bff524bec65fb45df2cf3d27149f28b74c08370de57a7351d70d1036c409263661e7d0d53f9206faf8bcad3d1dca0a7c244384bcccf5ae0ff7df8e5caf65c344a4b7e31f82d7822df4d12693e55e781aa7e2bd68317a2356313f4abdd0158f96a99aaa7de20ee3d7d1e81498e658ccabbd6e257eb36086f95551ca8e3d0f3d0cb532b9e127014bf6ccf5da66f8ad74a47aba595452a5304a309d398bd4b4d6b61051d82e5ebcb29308a176951db68b90f666b1610bbecd22ba0798617499205233e9130c10438bcc1b43d58569e1891e216bdba431363d0127d28c66eddea49a3d92e0e25d56d26fc83dea35be158a09ec804a20c61d2da2b6395a5c4dfee50135a010074c07eba76ae60a407787da5f388da6b3850542539a512150d95dad8bf49744eff6e0f86a78abf112432a0d20ed8d4025a8430ae77fb4bdb9716c07ec8928071c736a764a903b6c15b306530cbc0d5fb53490f99422ce8b0a2e64c921f0a37e30928e4460e709f0991111460a6766c030ab1eae715cda44554a3db71530020d8a59805506cca2275c159da794f035f988a5696c98a7561edcb5bbf360c0494dc8eca6ef631602a18f7bf6b5e2ac10e0ed726d18cf3b3fa8a165dddee44835dbe9349ab4586bf9c7e75d761653ad0bdb66921dfb90a3790e60d2efcd5d1273bb8495c4fb66c84c53c744d5b5237c766f7ec45df0ba5beb800fa4128ed333398511180636c9b3565857ffc5ef8d32e3f054a599476dea3a2514b2c7420b698b8d8854f0bc61260d35231eaa4c832209c523a70b28c7832e438ed9fd1a4797fbb4e0c3af4ffc241ad2beaef7b394fa5701b04dbdaf474f9ebcbaa53f6b9682f7a8581495622d7cd54e28fe25cc10c280fee098701fa3c311cae52177314b2ef2ed1169745c9112374324baa813bfc96ebe0c6f36f867dc3b1be935932e7e9249b52a8f24321bb027091b48708ec2e2be9a9f5c08ef422c0dfdf53c031821ad8397ade37d55bedd7ad4640d30d07f74ec3111a7b9d94db530cc0d018b157eb791290dd7dd637a6d3e6d218839accc918ab23972182227349b4cc0f3a222bc0e908c18813bcd739ab9e04f30da86245268abcc321c2c2337c6be80cb015fcf2f93686421a759bdc4143635d383c8ae98cbecaa62c28170225bd8e02720d95602f628b6701efd6af9be43ef3e33a8dbe31548bdb45bb1388134819e36f4e8435a07eb156a015cd0fce7918c7c694dc91a0e1f74ea494c82f38561782ab3b2fd4229ce21283ea1b29c2c6d8c1565b823b6353278642533712c5b2cd314c02f356ab592d16018a6e4c7cb1378581fdbe8bbb24782baa6549ad9df088d3d7dbe4a20fb2d7565d34034ea166f179f4033e5c1b1f7942779d11032e325b1a4608db5e9dbef412c7cc723f77b09f62934606282af062a65f90750093ea6ce034df93d239e07640022dd176310feb1f7a3a8c04dc8be1dca689323da615050456fa2d277ec258de54c19f55586c1ebf5f425ea7b7895a5ed5d5512eedefed32a839ea6895487a26d842cabff4a1bc68755ac1c7b140ea230eed51e68938ee2c0848a6583bfbc878b82710bf47cea8c17e757ad2174866023781ebe6eb93eca233cd4662825c954e6f55e858c83046ccb2b64cdaa8ad7ba435c3dd6bfa84b0b02de6891b6a9f3087dac4ddd5a1560fc75c7f9075ecdceb03ad425bd9210e746e53afb4377c775291bb4d2c69776f6328ee2259c6f21c11654e2f83b672d186154d45cd1ed761fb059d79927f1781e167efd5c14d3931646d019d3d396328f33ebd8e781d68cc312737bbbc1709731d07172f9b54ace0c6c15d598f1642ee86fff4f3df46e323a57f13d6f8abd9993905ce952d45ab68b83aa5abd076a12c0b73408de1eee50afbba464480d0aab1aaf32112630a632dae3d12b3c6686fbc945ee0e5c4ff8687718e46a8cd5dbe9dee86a1b98b09f0d982241ba4c06a3e059af90a56c649895f5912cfd78931589b29999692a817660f3253a6877c367fac60bddfd3e13ddf3280f15a95fd9b053ff207cb55470e90d68b7675b7e9b5ca2debb65e345ca40d3ae99a0d1a03df3a756e8ed976c047ca24f5d4a3b7d736a142e553a9bed7669396ff64b77d5842952aad9730a00aef7e93654f1df3f37d93dd95fcebcabd89303b45203513cf53871cda657d35074ad0eea597b226fbab09395f4d790baab9ad229b113a4ffa4f7851c463edc0a4385e1fb37772cd9a" +} diff --git a/apps/desktop-e2e/src/fixtures/backups/V2Backup.json b/packages/test-utils/src/fixtures/backups/V2Backup.json similarity index 100% rename from apps/desktop-e2e/src/fixtures/backups/V2Backup.json rename to packages/test-utils/src/fixtures/backups/V2Backup.json diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7d39039b4..8eb9246660 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,7 +15,7 @@ importers: devDependencies: jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -880,7 +880,7 @@ importers: version: 2.5.2 jest-transformer-svg: specifier: ^2.0.2 - version: 2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0))(react@18.3.1) + version: 2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)))(react@18.3.1) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1010,7 +1010,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -1107,7 +1107,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1165,7 +1165,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1280,7 +1280,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1331,13 +1331,13 @@ importers: version: 2.30.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) eslint-plugin-jest: specifier: ^28.8.3 - version: 28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4) + version: 28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4) eslint-plugin-jest-dom: specifier: ^5.4.0 version: 5.4.0(@testing-library/dom@10.4.0)(eslint@8.57.0) eslint-plugin-playwright: specifier: ^1.6.2 - version: 1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4))(eslint@8.57.0) + version: 1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4))(eslint@8.57.0) eslint-plugin-react: specifier: ^7.36.1 version: 7.36.1(eslint@8.57.0) @@ -1364,7 +1364,7 @@ importers: devDependencies: jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -1440,7 +1440,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1498,7 +1498,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1653,6 +1653,9 @@ importers: madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) + mockstate: + specifier: ^0.0.7 + version: 0.0.7 prettier: specifier: ^3.3.2 version: 3.3.3 @@ -1704,7 +1707,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1786,7 +1789,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1867,7 +1870,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -8041,6 +8044,9 @@ packages: mockdate@3.0.5: resolution: {integrity: sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==} + mockstate@0.0.7: + resolution: {integrity: sha512-gKpNKnFNnxNZpDZUyc0O3Kcc3V5j4D5QW4OQtgWrZQ5U+wX/Q68ZOfTgqfWuhINc8CsAt4RH0CAMcFoTNXb93A==} + module-definition@6.0.0: resolution: {integrity: sha512-sEGP5nKEXU7fGSZUML/coJbrO+yQtxcppDAYWRE9ovWsTbFoUHB2qDUx564WUzDaBHXsD46JBbIK5WVTwCyu3w==} engines: {node: '>=18'} @@ -12728,6 +12734,41 @@ snapshots: - supports-color - ts-node + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.11 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.7 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 @@ -15755,6 +15796,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cross-env@7.0.3: @@ -16551,23 +16607,23 @@ snapshots: optionalDependencies: '@testing-library/dom': 10.4.0 - eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4): + eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4): dependencies: '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 optionalDependencies: '@typescript-eslint/eslint-plugin': 8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) - jest: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + jest: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) transitivePeerDependencies: - supports-color - typescript - eslint-plugin-playwright@1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4))(eslint@8.57.0): + eslint-plugin-playwright@1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4))(eslint@8.57.0): dependencies: eslint: 8.57.0 globals: 13.24.0 optionalDependencies: - eslint-plugin-jest: 28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4) + eslint-plugin-jest: 28.8.3(@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4) eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): dependencies: @@ -17755,6 +17811,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-config@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)): dependencies: '@babel/core': 7.25.2 @@ -17786,6 +17861,68 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@babel/core': 7.25.2 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.7 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.14.11 + ts-node: 10.9.2(@types/node@22.1.0)(typescript@5.5.4) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@babel/core': 7.25.2 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.7 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.1.0 + ts-node: 10.9.2(@types/node@22.1.0)(typescript@5.5.4) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -17982,7 +18119,7 @@ snapshots: transitivePeerDependencies: - supports-color - jest-transformer-svg@2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0))(react@18.3.1): + jest-transformer-svg@2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)))(react@18.3.1): dependencies: jest: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) react: 18.3.1 @@ -18046,6 +18183,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jiti@1.21.6: {} jju@1.4.0: {} @@ -18522,6 +18671,8 @@ snapshots: mockdate@3.0.5: {} + mockstate@0.0.7: {} + module-definition@6.0.0: dependencies: ast-module-types: 6.0.0 @@ -20339,6 +20490,25 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.1.0 + acorn: 8.12.1 + acorn-walk: 8.3.3 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.5.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29